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