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