Home | History | Annotate | Line # | Download | only in ntpd
refclock_shm.c revision 1.1.1.2
      1      1.1  kardel /*	$NetBSD: refclock_shm.c,v 1.1.1.2 2012/01/31 21:25:47 kardel 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.2  kardel 	snprintf(buf, sizeof(buf), "NTP%d", unit);
    143  1.1.1.2  kardel 	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.2  kardel 	up = emalloc(sizeof(*up));
    199  1.1.1.2  kardel 	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.2  kardel 
    237  1.1.1.2  kardel 	if (NULL == up)
    238  1.1.1.2  kardel 		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.2  kardel 	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