Home | History | Annotate | Line # | Download | only in ntpd
refclock_shm.c revision 1.1.1.1.6.1
      1 /*	$NetBSD: refclock_shm.c,v 1.1.1.1.6.1 2012/04/17 00:03:48 yamt Exp $	*/
      2 
      3 /*
      4  * refclock_shm - clock driver for utc via shared memory
      5  * - under construction -
      6  * To add new modes: Extend or union the shmTime-struct. Do not
      7  * extend/shrink size, because otherwise existing implementations
      8  * will specify wrong size of shared memory-segment
      9  * PB 18.3.97
     10  */
     11 
     12 #ifdef HAVE_CONFIG_H
     13 # include <config.h>
     14 #endif
     15 
     16 #if defined(REFCLOCK) && defined(CLOCK_SHM)
     17 
     18 #include "ntpd.h"
     19 #undef fileno
     20 #include "ntp_io.h"
     21 #undef fileno
     22 #include "ntp_refclock.h"
     23 #undef fileno
     24 #include "ntp_unixtime.h"
     25 #undef fileno
     26 #include "ntp_stdlib.h"
     27 
     28 #undef fileno
     29 #include <ctype.h>
     30 #undef fileno
     31 
     32 #ifndef SYS_WINNT
     33 # include <sys/ipc.h>
     34 # include <sys/shm.h>
     35 # include <assert.h>
     36 # include <unistd.h>
     37 # include <stdio.h>
     38 #endif
     39 
     40 /*
     41  * This driver supports a reference clock attached thru shared memory
     42  */
     43 
     44 /* Temp hack to simplify testing of the old mode. */
     45 #define OLDWAY 0
     46 
     47 /*
     48  * SHM interface definitions
     49  */
     50 #define PRECISION       (-1)    /* precision assumed (0.5 s) */
     51 #define REFID           "SHM"   /* reference ID */
     52 #define DESCRIPTION     "SHM/Shared memory interface"
     53 
     54 #define NSAMPLES        3       /* stages of median filter */
     55 
     56 /*
     57  * Function prototypes
     58  */
     59 static  int     shm_start       (int unit, struct peer *peer);
     60 static  void    shm_shutdown    (int unit, struct peer *peer);
     61 static  void    shm_poll        (int unit, struct peer *peer);
     62 static  void    shm_timer       (int unit, struct peer *peer);
     63 	int	shm_peek	(int unit, struct peer *peer);
     64 	void	shm_clockstats  (int unit, struct peer *peer);
     65 
     66 /*
     67  * Transfer vector
     68  */
     69 struct  refclock refclock_shm = {
     70 	shm_start,              /* start up driver */
     71 	shm_shutdown,           /* shut down driver */
     72 	shm_poll,		/* transmit poll message */
     73 	noentry,		/* not used: control */
     74 	noentry,		/* not used: init */
     75 	noentry,		/* not used: buginfo */
     76 	shm_timer,              /* once per second */
     77 };
     78 
     79 struct shmTime {
     80 	int    mode; /* 0 - if valid set
     81 		      *       use values,
     82 		      *       clear valid
     83 		      * 1 - if valid set
     84 		      *       if count before and after read of values is equal,
     85 		      *         use values
     86 		      *       clear valid
     87 		      */
     88 	int    count;
     89 	time_t clockTimeStampSec;
     90 	int    clockTimeStampUSec;
     91 	time_t receiveTimeStampSec;
     92 	int    receiveTimeStampUSec;
     93 	int    leap;
     94 	int    precision;
     95 	int    nsamples;
     96 	int    valid;
     97 	int    dummy[10];
     98 };
     99 
    100 struct shmunit {
    101 	struct shmTime *shm;	/* pointer to shared memory segment */
    102 
    103 	/* debugging/monitoring counters - reset when printed */
    104 	int ticks;		/* number of attempts to read data*/
    105 	int good;		/* number of valid samples */
    106 	int notready;		/* number of peeks without data ready */
    107 	int bad;		/* number of invalid samples */
    108 	int clash;		/* number of access clashes while reading */
    109 };
    110 
    111 
    112 struct shmTime *getShmTime(int);
    113 
    114 struct shmTime *getShmTime (int unit) {
    115 #ifndef SYS_WINNT
    116 	int shmid=0;
    117 
    118 	/* 0x4e545030 is NTP0.
    119 	 * Big units will give non-ascii but that's OK
    120 	 * as long as everybody does it the same way.
    121 	 */
    122 	shmid=shmget (0x4e545030+unit, sizeof (struct shmTime),
    123 		      IPC_CREAT|(unit<2?0600:0666));
    124 	if (shmid==-1) { /*error */
    125 		msyslog(LOG_ERR,"SHM shmget (unit %d): %s",unit,strerror(errno));
    126 		return 0;
    127 	}
    128 	else { /* no error  */
    129 		struct shmTime *p=(struct shmTime *)shmat (shmid, 0, 0);
    130 		if ((int)(long)p==-1) { /* error */
    131 			msyslog(LOG_ERR,"SHM shmat (unit %d): %s",unit,strerror(errno));
    132 			return 0;
    133 		}
    134 		return p;
    135 	}
    136 #else
    137 	char buf[10];
    138 	LPSECURITY_ATTRIBUTES psec=0;
    139 	HANDLE shmid=0;
    140 	SECURITY_DESCRIPTOR sd;
    141 	SECURITY_ATTRIBUTES sa;
    142 	snprintf(buf, sizeof(buf), "NTP%d", unit);
    143 	if (unit >= 2) { /* world access */
    144 		if (!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION)) {
    145 			msyslog(LOG_ERR,"SHM InitializeSecurityDescriptor (unit %d): %m",unit);
    146 			return 0;
    147 		}
    148 		if (!SetSecurityDescriptorDacl(&sd,1,0,0)) {
    149 			msyslog(LOG_ERR,"SHM SetSecurityDescriptorDacl (unit %d): %m",unit);
    150 			return 0;
    151 		}
    152 		sa.nLength=sizeof (SECURITY_ATTRIBUTES);
    153 		sa.lpSecurityDescriptor=&sd;
    154 		sa.bInheritHandle=0;
    155 		psec=&sa;
    156 	}
    157 	shmid=CreateFileMapping ((HANDLE)0xffffffff, psec, PAGE_READWRITE,
    158 				 0, sizeof (struct shmTime),buf);
    159 	if (!shmid) { /*error*/
    160 		char buf[1000];
    161 		FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM,
    162 			       0, GetLastError (), 0, buf, sizeof (buf), 0);
    163 		msyslog(LOG_ERR,"SHM CreateFileMapping (unit %d): %s",unit,buf);
    164 		return 0;
    165 	}
    166 	else {
    167 		struct shmTime *p=(struct shmTime *) MapViewOfFile (shmid,
    168 								    FILE_MAP_WRITE, 0, 0, sizeof (struct shmTime));
    169 		if (p==0) { /*error*/
    170 			char buf[1000];
    171 			FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM,
    172 				       0, GetLastError (), 0, buf, sizeof (buf), 0);
    173 			msyslog(LOG_ERR,"SHM MapViewOfFile (unit %d): %s",unit,buf);
    174 			return 0;
    175 		}
    176 		return p;
    177 	}
    178 #endif
    179 }
    180 /*
    181  * shm_start - attach to shared memory
    182  */
    183 static int
    184 shm_start(
    185 	int unit,
    186 	struct peer *peer
    187 	)
    188 {
    189 	struct refclockproc *pp;
    190 	struct shmunit *up;
    191 
    192 	pp = peer->procptr;
    193 	pp->io.clock_recv = noentry;
    194 	pp->io.srcclock = (caddr_t)peer;
    195 	pp->io.datalen = 0;
    196 	pp->io.fd = -1;
    197 
    198 	up = emalloc(sizeof(*up));
    199 	memset(up, 0, sizeof(*up));
    200 	pp->unitptr = (caddr_t)up;
    201 
    202 	up->shm = getShmTime(unit);
    203 
    204 	/*
    205 	 * Initialize miscellaneous peer variables
    206 	 */
    207 	memcpy((char *)&pp->refid, REFID, 4);
    208 	if (up->shm != 0) {
    209 		up->shm->precision = PRECISION;
    210 		peer->precision = up->shm->precision;
    211 		up->shm->valid=0;
    212 		up->shm->nsamples=NSAMPLES;
    213 		pp->clockdesc = DESCRIPTION;
    214 		return (1);
    215 	}
    216 	else {
    217 		return 0;
    218 	}
    219 }
    220 
    221 
    222 /*
    223  * shm_shutdown - shut down the clock
    224  */
    225 static void
    226 shm_shutdown(
    227 	int unit,
    228 	struct peer *peer
    229 	)
    230 {
    231 	struct refclockproc *pp;
    232 	struct shmunit *up;
    233 
    234 	pp = peer->procptr;
    235 	up = (struct shmunit *)pp->unitptr;
    236 
    237 	if (NULL == up)
    238 		return;
    239 #ifndef SYS_WINNT
    240 	/* HMS: shmdt()wants char* or const void * */
    241 	(void) shmdt ((char *)up->shm);
    242 #else
    243 	UnmapViewOfFile (up->shm);
    244 #endif
    245 	free(up);
    246 }
    247 
    248 
    249 /*
    250  * shm_timer - called every second
    251  */
    252 static  void
    253 shm_timer(int unit, struct peer *peer)
    254 {
    255 	if (OLDWAY)
    256 		return;
    257 
    258 	shm_peek(unit, peer);
    259 }
    260 
    261 
    262 /*
    263  * shm_poll - called by the transmit procedure
    264  */
    265 static void
    266 shm_poll(
    267 	int unit,
    268 	struct peer *peer
    269 	)
    270 {
    271 	struct refclockproc *pp;
    272 	int ok;
    273 
    274 	pp = peer->procptr;
    275 
    276 	if (OLDWAY) {
    277 		ok = shm_peek(unit, peer);
    278 		if (!ok) return;
    279 	}
    280 
    281         /*
    282          * Process median filter samples. If none received, declare a
    283          * timeout and keep going.
    284          */
    285         if (pp->coderecv == pp->codeproc) {
    286                 refclock_report(peer, CEVNT_TIMEOUT);
    287 		shm_clockstats(unit, peer);
    288                 return;
    289         }
    290 	pp->lastref = pp->lastrec;
    291 	refclock_receive(peer);
    292 	shm_clockstats(unit, peer);
    293 }
    294 
    295 /*
    296  * shm_peek - try to grab a sample
    297  */
    298 int shm_peek(
    299 	int unit,
    300 	struct peer *peer
    301 	)
    302 {
    303 	struct refclockproc *pp;
    304 	struct shmunit *up;
    305 	struct shmTime *shm;
    306 
    307 	/*
    308 	 * This is the main routine. It snatches the time from the shm
    309 	 * board and tacks on a local timestamp.
    310 	 */
    311 	pp = peer->procptr;
    312 	up = (struct shmunit*)pp->unitptr;
    313 	up->ticks++;
    314 	if (up->shm == 0) {
    315 		/* try to map again - this may succeed if meanwhile some-
    316 		body has ipcrm'ed the old (unaccessible) shared mem segment */
    317 		up->shm = getShmTime(unit);
    318 	}
    319 	shm = up->shm;
    320 	if (shm == 0) {
    321 		refclock_report(peer, CEVNT_FAULT);
    322 		return(0);
    323 	}
    324 	if (shm->valid) {
    325 		struct timeval tvr;
    326 		struct timeval tvt;
    327 		struct tm *t;
    328 		int ok=1;
    329 		tvr.tv_sec = 0;
    330 		tvr.tv_usec = 0;
    331 		tvt.tv_sec = 0;
    332 		tvt.tv_usec = 0;
    333 		switch (shm->mode) {
    334 		    case 0: {
    335 			    tvr.tv_sec=shm->receiveTimeStampSec;
    336 			    tvr.tv_usec=shm->receiveTimeStampUSec;
    337 			    tvt.tv_sec=shm->clockTimeStampSec;
    338 			    tvt.tv_usec=shm->clockTimeStampUSec;
    339 		    }
    340 		    break;
    341 		    case 1: {
    342 			    int cnt=shm->count;
    343 			    tvr.tv_sec=shm->receiveTimeStampSec;
    344 			    tvr.tv_usec=shm->receiveTimeStampUSec;
    345 			    tvt.tv_sec=shm->clockTimeStampSec;
    346 			    tvt.tv_usec=shm->clockTimeStampUSec;
    347 			    ok=(cnt==shm->count);
    348 		    }
    349 		    break;
    350 		    default:
    351 			msyslog (LOG_ERR, "SHM: bad mode found in shared memory: %d",shm->mode);
    352 		}
    353 		shm->valid=0;
    354 		if (ok) {
    355 			time_t help;	/* XXX NetBSD has incompatible tv_sec */
    356 
    357 			TVTOTS(&tvr,&pp->lastrec);
    358 			pp->lastrec.l_ui += JAN_1970;
    359 			/* pp->lasttime = current_time; */
    360 			pp->polls++;
    361 			help = tvt.tv_sec;
    362 			t = gmtime (&help);
    363 			pp->day=t->tm_yday+1;
    364 			pp->hour=t->tm_hour;
    365 			pp->minute=t->tm_min;
    366 			pp->second=t->tm_sec;
    367 			pp->nsec=tvt.tv_usec * 1000;
    368 			peer->precision=shm->precision;
    369 			pp->leap=shm->leap;
    370 		}
    371 		else {
    372 			refclock_report(peer, CEVNT_FAULT);
    373 			msyslog (LOG_NOTICE, "SHM: access clash in shared memory");
    374 			up->clash++;
    375 			return(0);
    376 		}
    377 	}
    378 	else {
    379 		refclock_report(peer, CEVNT_TIMEOUT);
    380 		up->notready++;
    381 		return(0);
    382 	}
    383 	if (!refclock_process(pp)) {
    384 		refclock_report(peer, CEVNT_BADTIME);
    385 		up->bad++;
    386 		return(0);
    387 	}
    388 	up->good++;
    389 	return(1);
    390 }
    391 
    392 /*
    393  * shm_clockstats - dump and reset counters
    394  */
    395 void shm_clockstats(
    396 	int unit,
    397 	struct peer *peer
    398 	)
    399 {
    400 	struct refclockproc *pp;
    401 	struct shmunit *up;
    402 	char logbuf[256];
    403 
    404 	pp = peer->procptr;
    405 	up = (struct shmunit*)pp->unitptr;
    406 
    407 	if (!(pp->sloppyclockflag & CLK_FLAG4)) return;
    408 
    409         snprintf(logbuf, sizeof(logbuf), "%3d %3d %3d %3d %3d",
    410                 up->ticks, up->good, up->notready, up->bad, up->clash);
    411         record_clock_stats(&peer->srcadr, logbuf);
    412 
    413 	up->ticks = up->good = up->notready =up->bad = up->clash = 0;
    414 
    415 }
    416 
    417 #else
    418 int refclock_shm_bs;
    419 #endif /* REFCLOCK */
    420