154359Sroberto/* 2285612Sdelphij * refclock_shm - clock driver for utc via shared memory 354359Sroberto * - under construction - 454359Sroberto * To add new modes: Extend or union the shmTime-struct. Do not 554359Sroberto * extend/shrink size, because otherwise existing implementations 654359Sroberto * will specify wrong size of shared memory-segment 754359Sroberto * PB 18.3.97 854359Sroberto */ 954359Sroberto 1054359Sroberto#ifdef HAVE_CONFIG_H 1154359Sroberto# include <config.h> 1254359Sroberto#endif 1354359Sroberto 14285612Sdelphij#include "ntp_types.h" 15285612Sdelphij 1654359Sroberto#if defined(REFCLOCK) && defined(CLOCK_SHM) 1754359Sroberto 1854359Sroberto#include "ntpd.h" 19285612Sdelphij#undef fileno 2054359Sroberto#include "ntp_io.h" 21285612Sdelphij#undef fileno 2254359Sroberto#include "ntp_refclock.h" 23285612Sdelphij#undef fileno 24285612Sdelphij#include "timespecops.h" 25285612Sdelphij#undef fileno 2654359Sroberto#include "ntp_stdlib.h" 27285612Sdelphij#include "ntp_assert.h" 2854359Sroberto 29285612Sdelphij#undef fileno 3082498Sroberto#include <ctype.h> 31285612Sdelphij#undef fileno 3282498Sroberto 3354359Sroberto#ifndef SYS_WINNT 3482498Sroberto# include <sys/ipc.h> 3582498Sroberto# include <sys/shm.h> 3682498Sroberto# include <assert.h> 3782498Sroberto# include <unistd.h> 3882498Sroberto# include <stdio.h> 3954359Sroberto#endif 4054359Sroberto 41285612Sdelphij#ifdef HAVE_STDATOMIC_H 42285612Sdelphij# include <stdatomic.h> 43285612Sdelphij#endif /* HAVE_STDATOMIC_H */ 44285612Sdelphij 4554359Sroberto/* 4654359Sroberto * This driver supports a reference clock attached thru shared memory 47285612Sdelphij */ 4854359Sroberto 4954359Sroberto/* 5054359Sroberto * SHM interface definitions 5154359Sroberto */ 5254359Sroberto#define PRECISION (-1) /* precision assumed (0.5 s) */ 5354359Sroberto#define REFID "SHM" /* reference ID */ 5454359Sroberto#define DESCRIPTION "SHM/Shared memory interface" 5554359Sroberto 5654359Sroberto#define NSAMPLES 3 /* stages of median filter */ 5754359Sroberto 5854359Sroberto/* 59285612Sdelphij * Mode flags 60285612Sdelphij */ 61285612Sdelphij#define SHM_MODE_PRIVATE 0x0001 62285612Sdelphij 63285612Sdelphij/* 6454359Sroberto * Function prototypes 6554359Sroberto */ 66285612Sdelphijstatic int shm_start (int unit, struct peer *peer); 67285612Sdelphijstatic void shm_shutdown (int unit, struct peer *peer); 68285612Sdelphijstatic void shm_poll (int unit, struct peer *peer); 69285612Sdelphijstatic void shm_timer (int unit, struct peer *peer); 70285612Sdelphijstatic void shm_clockstats (int unit, struct peer *peer); 71285612Sdelphijstatic void shm_control (int unit, const struct refclockstat * in_st, 72285612Sdelphij struct refclockstat * out_st, struct peer *peer); 7354359Sroberto 7454359Sroberto/* 7554359Sroberto * Transfer vector 7654359Sroberto */ 7754359Srobertostruct refclock refclock_shm = { 7854359Sroberto shm_start, /* start up driver */ 7954359Sroberto shm_shutdown, /* shut down driver */ 80285612Sdelphij shm_poll, /* transmit poll message */ 81285612Sdelphij shm_control, /* control settings */ 82285612Sdelphij noentry, /* not used: init */ 83285612Sdelphij noentry, /* not used: buginfo */ 84285612Sdelphij shm_timer, /* once per second */ 8554359Sroberto}; 86285612Sdelphij 8754359Srobertostruct shmTime { 88285612Sdelphij int mode; /* 0 - if valid is set: 89285612Sdelphij * use values, 9054359Sroberto * clear valid 91285612Sdelphij * 1 - if valid is set: 9254359Sroberto * if count before and after read of values is equal, 93285612Sdelphij * use values 9454359Sroberto * clear valid 9554359Sroberto */ 96285612Sdelphij volatile int count; 97285612Sdelphij time_t clockTimeStampSec; 98285612Sdelphij int clockTimeStampUSec; 99285612Sdelphij time_t receiveTimeStampSec; 100285612Sdelphij int receiveTimeStampUSec; 101285612Sdelphij int leap; 102285612Sdelphij int precision; 103285612Sdelphij int nsamples; 104285612Sdelphij volatile int valid; 105285612Sdelphij unsigned clockTimeStampNSec; /* Unsigned ns timestamps */ 106285612Sdelphij unsigned receiveTimeStampNSec; /* Unsigned ns timestamps */ 107285612Sdelphij int dummy[8]; 10854359Sroberto}; 109132451Sroberto 110285612Sdelphijstruct shmunit { 111285612Sdelphij struct shmTime *shm; /* pointer to shared memory segment */ 112285612Sdelphij int forall; /* access for all UIDs? */ 113132451Sroberto 114285612Sdelphij /* debugging/monitoring counters - reset when printed */ 115285612Sdelphij int ticks; /* number of attempts to read data*/ 116285612Sdelphij int good; /* number of valid samples */ 117285612Sdelphij int notready; /* number of peeks without data ready */ 118285612Sdelphij int bad; /* number of invalid samples */ 119285612Sdelphij int clash; /* number of access clashes while reading */ 120285612Sdelphij 121285612Sdelphij time_t max_delta; /* difference limit */ 122285612Sdelphij time_t max_delay; /* age/stale limit */ 123285612Sdelphij}; 124285612Sdelphij 125285612Sdelphij 126285612Sdelphijstatic struct shmTime* 127285612SdelphijgetShmTime( 128285612Sdelphij int unit, 129285612Sdelphij int/*BOOL*/ forall 130285612Sdelphij ) 131285612Sdelphij{ 132285612Sdelphij struct shmTime *p = NULL; 133285612Sdelphij 13454359Sroberto#ifndef SYS_WINNT 13554359Sroberto 136285612Sdelphij int shmid; 137285612Sdelphij 138285612Sdelphij /* 0x4e545030 is NTP0. 139285612Sdelphij * Big units will give non-ascii but that's OK 140285612Sdelphij * as long as everybody does it the same way. 141285612Sdelphij */ 142285612Sdelphij shmid=shmget(0x4e545030 + unit, sizeof (struct shmTime), 143285612Sdelphij IPC_CREAT | (forall ? 0666 : 0600)); 144285612Sdelphij if (shmid == -1) { /* error */ 145285612Sdelphij msyslog(LOG_ERR, "SHM shmget (unit %d): %m", unit); 146285612Sdelphij return NULL; 14754359Sroberto } 148285612Sdelphij p = (struct shmTime *)shmat (shmid, 0, 0); 149285612Sdelphij if (p == (struct shmTime *)-1) { /* error */ 150285612Sdelphij msyslog(LOG_ERR, "SHM shmat (unit %d): %m", unit); 151285612Sdelphij return NULL; 15254359Sroberto } 153285612Sdelphij 154285612Sdelphij return p; 15554359Sroberto#else 156285612Sdelphij 157285612Sdelphij static const char * nspref[2] = { "Local", "Global" }; 158285612Sdelphij char buf[20]; 159285612Sdelphij LPSECURITY_ATTRIBUTES psec = 0; 160285612Sdelphij HANDLE shmid = 0; 16154359Sroberto SECURITY_DESCRIPTOR sd; 16254359Sroberto SECURITY_ATTRIBUTES sa; 163285612Sdelphij unsigned int numch; 164285612Sdelphij 165285612Sdelphij numch = snprintf(buf, sizeof(buf), "%s\\NTP%d", 166285612Sdelphij nspref[forall != 0], (unit & 0xFF)); 167285612Sdelphij if (numch >= sizeof(buf)) { 168285612Sdelphij msyslog(LOG_ERR, "SHM name too long (unit %d)", unit); 169285612Sdelphij return NULL; 170285612Sdelphij } 171285612Sdelphij if (forall) { /* world access */ 17254359Sroberto if (!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION)) { 173285612Sdelphij msyslog(LOG_ERR,"SHM InitializeSecurityDescriptor (unit %d): %m", unit); 174285612Sdelphij return NULL; 17554359Sroberto } 176285612Sdelphij if (!SetSecurityDescriptorDacl(&sd, TRUE, NULL, FALSE)) { 177285612Sdelphij msyslog(LOG_ERR, "SHM SetSecurityDescriptorDacl (unit %d): %m", unit); 178285612Sdelphij return NULL; 17954359Sroberto } 180285612Sdelphij sa.nLength = sizeof(SECURITY_ATTRIBUTES); 181285612Sdelphij sa.lpSecurityDescriptor = &sd; 182285612Sdelphij sa.bInheritHandle = FALSE; 183285612Sdelphij psec = &sa; 18454359Sroberto } 185285612Sdelphij shmid = CreateFileMapping ((HANDLE)0xffffffff, psec, PAGE_READWRITE, 186285612Sdelphij 0, sizeof (struct shmTime), buf); 187285612Sdelphij if (shmid == NULL) { /*error*/ 188285612Sdelphij char buf[1000]; 18954359Sroberto FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, 19054359Sroberto 0, GetLastError (), 0, buf, sizeof (buf), 0); 191285612Sdelphij msyslog(LOG_ERR, "SHM CreateFileMapping (unit %d): %s", unit, buf); 192285612Sdelphij return NULL; 19354359Sroberto } 194285612Sdelphij p = (struct shmTime *)MapViewOfFile(shmid, FILE_MAP_WRITE, 0, 0, 195285612Sdelphij sizeof (struct shmTime)); 196285612Sdelphij if (p == NULL) { /*error*/ 197285612Sdelphij char buf[1000]; 198285612Sdelphij FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, 199285612Sdelphij 0, GetLastError (), 0, buf, sizeof (buf), 0); 200285612Sdelphij msyslog(LOG_ERR,"SHM MapViewOfFile (unit %d): %s", unit, buf); 201285612Sdelphij return NULL; 20254359Sroberto } 203285612Sdelphij 204285612Sdelphij return p; 20554359Sroberto#endif 206285612Sdelphij 207285612Sdelphij /* NOTREACHED */ 208285612Sdelphij ENSURE(!"getShmTime(): Not reached."); 20954359Sroberto} 210285612Sdelphij 211285612Sdelphij 21254359Sroberto/* 21354359Sroberto * shm_start - attach to shared memory 21454359Sroberto */ 21554359Srobertostatic int 21654359Srobertoshm_start( 21754359Sroberto int unit, 21854359Sroberto struct peer *peer 21954359Sroberto ) 22054359Sroberto{ 221285612Sdelphij struct refclockproc * const pp = peer->procptr; 222285612Sdelphij struct shmunit * const up = emalloc_zero(sizeof(*up)); 223285612Sdelphij 22454359Sroberto pp->io.clock_recv = noentry; 225285612Sdelphij pp->io.srcclock = peer; 22654359Sroberto pp->io.datalen = 0; 22754359Sroberto pp->io.fd = -1; 22854359Sroberto 229285612Sdelphij up->forall = (unit >= 2) && !(peer->ttl & SHM_MODE_PRIVATE); 230285612Sdelphij 231285612Sdelphij up->shm = getShmTime(unit, up->forall); 232285612Sdelphij 23354359Sroberto /* 23454359Sroberto * Initialize miscellaneous peer variables 23554359Sroberto */ 23654359Sroberto memcpy((char *)&pp->refid, REFID, 4); 237285612Sdelphij if (up->shm != 0) { 238285612Sdelphij pp->unitptr = up; 239285612Sdelphij up->shm->precision = PRECISION; 240285612Sdelphij peer->precision = up->shm->precision; 241285612Sdelphij up->shm->valid = 0; 242285612Sdelphij up->shm->nsamples = NSAMPLES; 24354359Sroberto pp->clockdesc = DESCRIPTION; 244285612Sdelphij /* items to be changed later in 'shm_control()': */ 245285612Sdelphij up->max_delay = 5; 246285612Sdelphij up->max_delta = 4*3600; 247285612Sdelphij return 1; 248285612Sdelphij } else { 249285612Sdelphij free(up); 250285612Sdelphij pp->unitptr = NULL; 25154359Sroberto return 0; 25254359Sroberto } 25354359Sroberto} 25454359Sroberto 25554359Sroberto 25654359Sroberto/* 257285612Sdelphij * shm_control - configure flag1/time2 params 258285612Sdelphij * 259285612Sdelphij * These are not yet available during 'shm_start', so we have to do any 260285612Sdelphij * pre-computations we want to avoid during regular poll/timer callbacks 261285612Sdelphij * in this callback. 262285612Sdelphij */ 263285612Sdelphijstatic void 264285612Sdelphijshm_control( 265285612Sdelphij int unit, 266285612Sdelphij const struct refclockstat * in_st, 267285612Sdelphij struct refclockstat * out_st, 268285612Sdelphij struct peer * peer 269285612Sdelphij ) 270285612Sdelphij{ 271285612Sdelphij struct refclockproc * const pp = peer->procptr; 272285612Sdelphij struct shmunit * const up = pp->unitptr; 273285612Sdelphij 274285612Sdelphij UNUSED_ARG(unit); 275285612Sdelphij UNUSED_ARG(in_st); 276285612Sdelphij UNUSED_ARG(out_st); 277285612Sdelphij if (NULL == up) 278285612Sdelphij return; 279285612Sdelphij if (pp->sloppyclockflag & CLK_FLAG1) 280285612Sdelphij up->max_delta = 0; 281285612Sdelphij else if (pp->fudgetime2 < 1. || pp->fudgetime2 > 86400.) 282285612Sdelphij up->max_delta = 4*3600; 283285612Sdelphij else 284285612Sdelphij up->max_delta = (time_t)floor(pp->fudgetime2 + 0.5); 285285612Sdelphij} 286285612Sdelphij 287285612Sdelphij 288285612Sdelphij/* 28954359Sroberto * shm_shutdown - shut down the clock 29054359Sroberto */ 29154359Srobertostatic void 29254359Srobertoshm_shutdown( 29354359Sroberto int unit, 29454359Sroberto struct peer *peer 29554359Sroberto ) 29654359Sroberto{ 297285612Sdelphij struct refclockproc * const pp = peer->procptr; 298285612Sdelphij struct shmunit * const up = pp->unitptr; 29954359Sroberto 300285612Sdelphij UNUSED_ARG(unit); 301285612Sdelphij if (NULL == up) 302285612Sdelphij return; 30354359Sroberto#ifndef SYS_WINNT 304285612Sdelphij 305285612Sdelphij /* HMS: shmdt() wants char* or const void * */ 306285612Sdelphij (void)shmdt((char *)up->shm); 307285612Sdelphij 30854359Sroberto#else 309285612Sdelphij 310285612Sdelphij UnmapViewOfFile(up->shm); 311285612Sdelphij 31254359Sroberto#endif 313285612Sdelphij free(up); 31454359Sroberto} 31554359Sroberto 31654359Sroberto 31754359Sroberto/* 31854359Sroberto * shm_poll - called by the transmit procedure 31954359Sroberto */ 32054359Srobertostatic void 32154359Srobertoshm_poll( 32254359Sroberto int unit, 32354359Sroberto struct peer *peer 32454359Sroberto ) 32554359Sroberto{ 326285612Sdelphij struct refclockproc * const pp = peer->procptr; 327285612Sdelphij struct shmunit * const up = pp->unitptr; 328285612Sdelphij int major_error; 32954359Sroberto 330285612Sdelphij pp->polls++; 331285612Sdelphij 332285612Sdelphij /* get dominant reason if we have no samples at all */ 333285612Sdelphij major_error = max(up->notready, up->bad); 334285612Sdelphij major_error = max(major_error, up->clash); 335285612Sdelphij 336285612Sdelphij /* 337285612Sdelphij * Process median filter samples. If none received, see what 338285612Sdelphij * happened, tell the core and keep going. 339285612Sdelphij */ 340285612Sdelphij if (pp->coderecv != pp->codeproc) { 341285612Sdelphij /* have some samples, everything OK */ 342285612Sdelphij pp->lastref = pp->lastrec; 343285612Sdelphij refclock_receive(peer); 344285612Sdelphij } else if (NULL == up->shm) { /* is this possible at all? */ 345285612Sdelphij /* we're out of business without SHM access */ 34654359Sroberto refclock_report(peer, CEVNT_FAULT); 347285612Sdelphij } else if (major_error == up->clash) { 348285612Sdelphij /* too many collisions is like a bad signal */ 349285612Sdelphij refclock_report(peer, CEVNT_PROP); 350285612Sdelphij } else if (major_error == up->bad) { 351285612Sdelphij /* too much stale/bad/garbled data */ 352285612Sdelphij refclock_report(peer, CEVNT_BADREPLY); 353285612Sdelphij } else { 354285612Sdelphij /* in any other case assume it's just a timeout */ 355285612Sdelphij refclock_report(peer, CEVNT_TIMEOUT); 356285612Sdelphij } 357285612Sdelphij /* shm_clockstats() clears the tallies, so it must be last... */ 358285612Sdelphij shm_clockstats(unit, peer); 359285612Sdelphij} 360285612Sdelphij 361285612Sdelphij 362285612Sdelphijenum segstat_t { 363285612Sdelphij OK, NO_SEGMENT, NOT_READY, BAD_MODE, CLASH 364285612Sdelphij}; 365285612Sdelphij 366285612Sdelphijstruct shm_stat_t { 367285612Sdelphij int status; 368285612Sdelphij int mode; 369285612Sdelphij struct timespec tvc, tvr, tvt; 370285612Sdelphij int precision; 371285612Sdelphij int leap; 372285612Sdelphij}; 373285612Sdelphij 374285612Sdelphijstatic inline void memory_barrier(void) 375285612Sdelphij{ 376285612Sdelphij#ifdef HAVE_ATOMIC_THREAD_FENCE 377285612Sdelphij atomic_thread_fence(memory_order_seq_cst); 378285612Sdelphij#endif /* HAVE_ATOMIC_THREAD_FENCE */ 379285612Sdelphij} 380285612Sdelphij 381285612Sdelphijstatic enum segstat_t shm_query(volatile struct shmTime *shm_in, struct shm_stat_t *shm_stat) 382285612Sdelphij/* try to grab a sample from the specified SHM segment */ 383285612Sdelphij{ 384293650Sglebius struct shmTime shmcopy; 385293650Sglebius volatile struct shmTime *shm = shm_in; 386285612Sdelphij volatile int cnt; 387285612Sdelphij 388285612Sdelphij unsigned int cns_new, rns_new; 389285612Sdelphij 390285612Sdelphij /* 391285612Sdelphij * This is the main routine. It snatches the time from the shm 392285612Sdelphij * board and tacks on a local timestamp. 393285612Sdelphij */ 394285612Sdelphij if (shm == NULL) { 395285612Sdelphij shm_stat->status = NO_SEGMENT; 396285612Sdelphij return NO_SEGMENT; 397285612Sdelphij } 398285612Sdelphij 399285612Sdelphij /*@-type@*//* splint is confused about struct timespec */ 400285612Sdelphij shm_stat->tvc.tv_sec = shm_stat->tvc.tv_nsec = 0; 401285612Sdelphij { 402285612Sdelphij time_t now; 403285612Sdelphij 404285612Sdelphij time(&now); 405285612Sdelphij shm_stat->tvc.tv_sec = now; 406285612Sdelphij } 407285612Sdelphij 408285612Sdelphij /* relying on word access to be atomic here */ 409285612Sdelphij if (shm->valid == 0) { 410285612Sdelphij shm_stat->status = NOT_READY; 411285612Sdelphij return NOT_READY; 412285612Sdelphij } 413285612Sdelphij 414285612Sdelphij cnt = shm->count; 415285612Sdelphij 416285612Sdelphij /* 417285612Sdelphij * This is proof against concurrency issues if either 418285612Sdelphij * (a) the memory_barrier() call works on this host, or 419285612Sdelphij * (b) memset compiles to an uninterruptible single-instruction bitblt. 420285612Sdelphij */ 421285612Sdelphij memory_barrier(); 422293650Sglebius memcpy(&shmcopy, (void*)(uintptr_t)shm, sizeof(struct shmTime)); 423285612Sdelphij shm->valid = 0; 424285612Sdelphij memory_barrier(); 425285612Sdelphij 426285612Sdelphij /* 427285612Sdelphij * Clash detection in case neither (a) nor (b) was true. 428285612Sdelphij * Not supported in mode 0, and word access to the count field 429285612Sdelphij * must be atomic for this to work. 430285612Sdelphij */ 431285612Sdelphij if (shmcopy.mode > 0 && cnt != shm->count) { 432285612Sdelphij shm_stat->status = CLASH; 433285612Sdelphij return shm_stat->status; 434285612Sdelphij } 435285612Sdelphij 436285612Sdelphij shm_stat->status = OK; 437285612Sdelphij shm_stat->mode = shmcopy.mode; 438285612Sdelphij 439285612Sdelphij switch (shmcopy.mode) { 440285612Sdelphij case 0: 441285612Sdelphij shm_stat->tvr.tv_sec = shmcopy.receiveTimeStampSec; 442285612Sdelphij shm_stat->tvr.tv_nsec = shmcopy.receiveTimeStampUSec * 1000; 443285612Sdelphij rns_new = shmcopy.receiveTimeStampNSec; 444285612Sdelphij shm_stat->tvt.tv_sec = shmcopy.clockTimeStampSec; 445285612Sdelphij shm_stat->tvt.tv_nsec = shmcopy.clockTimeStampUSec * 1000; 446285612Sdelphij cns_new = shmcopy.clockTimeStampNSec; 447285612Sdelphij 448285612Sdelphij /* Since the following comparisons are between unsigned 449285612Sdelphij ** variables they are always well defined, and any 450285612Sdelphij ** (signed) underflow will turn into very large unsigned 451285612Sdelphij ** values, well above the 1000 cutoff. 452285612Sdelphij ** 453285612Sdelphij ** Note: The usecs *must* be a *truncated* 454285612Sdelphij ** representation of the nsecs. This code will fail for 455285612Sdelphij ** *rounded* usecs, and the logic to deal with 456285612Sdelphij ** wrap-arounds in the presence of rounded values is 457285612Sdelphij ** much more convoluted. 458285612Sdelphij */ 459285612Sdelphij if ( ((cns_new - (unsigned)shm_stat->tvt.tv_nsec) < 1000) 460285612Sdelphij && ((rns_new - (unsigned)shm_stat->tvr.tv_nsec) < 1000)) { 461285612Sdelphij shm_stat->tvt.tv_nsec = cns_new; 462285612Sdelphij shm_stat->tvr.tv_nsec = rns_new; 46354359Sroberto } 464285612Sdelphij /* At this point shm_stat->tvr and shm_stat->tvt contain valid ns-level 465285612Sdelphij ** timestamps, possibly generated by extending the old 466285612Sdelphij ** us-level timestamps 467285612Sdelphij */ 468285612Sdelphij break; 469182007Sroberto 470285612Sdelphij case 1: 471285612Sdelphij 472285612Sdelphij shm_stat->tvr.tv_sec = shmcopy.receiveTimeStampSec; 473285612Sdelphij shm_stat->tvr.tv_nsec = shmcopy.receiveTimeStampUSec * 1000; 474285612Sdelphij rns_new = shmcopy.receiveTimeStampNSec; 475285612Sdelphij shm_stat->tvt.tv_sec = shmcopy.clockTimeStampSec; 476285612Sdelphij shm_stat->tvt.tv_nsec = shmcopy.clockTimeStampUSec * 1000; 477285612Sdelphij cns_new = shmcopy.clockTimeStampNSec; 478285612Sdelphij 479285612Sdelphij /* See the case above for an explanation of the 480285612Sdelphij ** following test. 481285612Sdelphij */ 482285612Sdelphij if ( ((cns_new - (unsigned)shm_stat->tvt.tv_nsec) < 1000) 483285612Sdelphij && ((rns_new - (unsigned)shm_stat->tvr.tv_nsec) < 1000)) { 484285612Sdelphij shm_stat->tvt.tv_nsec = cns_new; 485285612Sdelphij shm_stat->tvr.tv_nsec = rns_new; 486285612Sdelphij } 487285612Sdelphij /* At this point shm_stat->tvr and shm_stat->tvt contains valid ns-level 488285612Sdelphij ** timestamps, possibly generated by extending the old 489285612Sdelphij ** us-level timestamps 490285612Sdelphij */ 491285612Sdelphij break; 492285612Sdelphij 493285612Sdelphij default: 494285612Sdelphij shm_stat->status = BAD_MODE; 495285612Sdelphij break; 496285612Sdelphij } 497285612Sdelphij /*@-type@*/ 498285612Sdelphij 499285612Sdelphij /* 500285612Sdelphij * leap field is not a leap offset but a leap notification code. 501285612Sdelphij * The values are magic numbers used by NTP and set by GPSD, if at all, in 502285612Sdelphij * the subframe code. 503285612Sdelphij */ 504285612Sdelphij shm_stat->leap = shmcopy.leap; 505285612Sdelphij shm_stat->precision = shmcopy.precision; 506285612Sdelphij 507285612Sdelphij return shm_stat->status; 508285612Sdelphij} 509285612Sdelphij 510285612Sdelphij/* 511285612Sdelphij * shm_timer - called once every second. 512285612Sdelphij * 513285612Sdelphij * This tries to grab a sample from the SHM segment, filtering bad ones 514285612Sdelphij */ 515285612Sdelphijstatic void 516285612Sdelphijshm_timer( 517285612Sdelphij int unit, 518285612Sdelphij struct peer *peer 519285612Sdelphij ) 520285612Sdelphij{ 521285612Sdelphij struct refclockproc * const pp = peer->procptr; 522285612Sdelphij struct shmunit * const up = pp->unitptr; 523285612Sdelphij 524285612Sdelphij volatile struct shmTime *shm; 525285612Sdelphij 526285612Sdelphij l_fp tsrcv; 527285612Sdelphij l_fp tsref; 528285612Sdelphij int c; 529285612Sdelphij 530285612Sdelphij /* for formatting 'a_lastcode': */ 531285612Sdelphij struct calendar cd; 532285612Sdelphij time_t tt; 533285612Sdelphij vint64 ts; 534285612Sdelphij 535285612Sdelphij enum segstat_t status; 536285612Sdelphij struct shm_stat_t shm_stat; 537285612Sdelphij 538285612Sdelphij up->ticks++; 539285612Sdelphij if ((shm = up->shm) == NULL) { 540285612Sdelphij /* try to map again - this may succeed if meanwhile some- 541285612Sdelphij body has ipcrm'ed the old (unaccessible) shared mem segment */ 542285612Sdelphij shm = up->shm = getShmTime(unit, up->forall); 543285612Sdelphij if (shm == NULL) { 544285612Sdelphij DPRINTF(1, ("%s: no SHM segment\n", 545285612Sdelphij refnumtoa(&peer->srcadr))); 54654359Sroberto return; 54754359Sroberto } 54854359Sroberto } 549285612Sdelphij 550285612Sdelphij /* query the segment, atomically */ 551285612Sdelphij status = shm_query(shm, &shm_stat); 552285612Sdelphij 553285612Sdelphij switch (status) { 554285612Sdelphij case OK: 555285612Sdelphij DPRINTF(2, ("%s: SHM type %d sample\n", 556285612Sdelphij refnumtoa(&peer->srcadr), shm_stat.mode)); 557285612Sdelphij break; 558285612Sdelphij case NO_SEGMENT: 559285612Sdelphij /* should never happen, but is harmless */ 560285612Sdelphij return; 561285612Sdelphij case NOT_READY: 562285612Sdelphij DPRINTF(1, ("%s: SHM not ready\n",refnumtoa(&peer->srcadr))); 563285612Sdelphij up->notready++; 564285612Sdelphij return; 565285612Sdelphij case BAD_MODE: 566285612Sdelphij DPRINTF(1, ("%s: SHM type blooper, mode=%d\n", 567285612Sdelphij refnumtoa(&peer->srcadr), shm->mode)); 568285612Sdelphij up->bad++; 569285612Sdelphij msyslog (LOG_ERR, "SHM: bad mode found in shared memory: %d", 570285612Sdelphij shm->mode); 571285612Sdelphij return; 572285612Sdelphij case CLASH: 573285612Sdelphij DPRINTF(1, ("%s: type 1 access clash\n", 574285612Sdelphij refnumtoa(&peer->srcadr))); 575285612Sdelphij msyslog (LOG_NOTICE, "SHM: access clash in shared memory"); 576285612Sdelphij up->clash++; 577285612Sdelphij return; 578285612Sdelphij default: 579285612Sdelphij DPRINTF(1, ("%s: internal error, unknown SHM fetch status\n", 580285612Sdelphij refnumtoa(&peer->srcadr))); 581285612Sdelphij msyslog (LOG_NOTICE, "internal error, unknown SHM fetch status"); 582285612Sdelphij up->bad++; 583285612Sdelphij return; 584285612Sdelphij } 585285612Sdelphij 586285612Sdelphij 587285612Sdelphij /* format the last time code in human-readable form into 588285612Sdelphij * 'pp->a_lastcode'. Someone claimed: "NetBSD has incompatible 589285612Sdelphij * tv_sec". I can't find a base for this claim, but we can work 590285612Sdelphij * around that potential problem. BTW, simply casting a pointer 591285612Sdelphij * is a receipe for disaster on some architectures. 592285612Sdelphij */ 593285612Sdelphij tt = (time_t)shm_stat.tvt.tv_sec; 594285612Sdelphij ts = time_to_vint64(&tt); 595285612Sdelphij ntpcal_time_to_date(&cd, &ts); 596285612Sdelphij 597285612Sdelphij /* add ntpq -c cv timecode in ISO 8601 format */ 598285612Sdelphij c = snprintf(pp->a_lastcode, sizeof(pp->a_lastcode), 599285612Sdelphij "%04u-%02u-%02uT%02u:%02u:%02u.%09ldZ", 600285612Sdelphij cd.year, cd.month, cd.monthday, 601285612Sdelphij cd.hour, cd.minute, cd.second, 602285612Sdelphij (long)shm_stat.tvt.tv_nsec); 603294569Sdelphij pp->lencode = (c > 0 && (size_t)c < sizeof(pp->a_lastcode)) ? c : 0; 604285612Sdelphij 605285612Sdelphij /* check 1: age control of local time stamp */ 606285612Sdelphij tt = shm_stat.tvc.tv_sec - shm_stat.tvr.tv_sec; 607285612Sdelphij if (tt < 0 || tt > up->max_delay) { 608285612Sdelphij DPRINTF(1, ("%s:SHM stale/bad receive time, delay=%llds\n", 609285612Sdelphij refnumtoa(&peer->srcadr), (long long)tt)); 610285612Sdelphij up->bad++; 611285612Sdelphij msyslog (LOG_ERR, "SHM: stale/bad receive time, delay=%llds", 612285612Sdelphij (long long)tt); 61354359Sroberto return; 61454359Sroberto } 615285612Sdelphij 616285612Sdelphij /* check 2: delta check */ 617285612Sdelphij tt = shm_stat.tvr.tv_sec - shm_stat.tvt.tv_sec - (shm_stat.tvr.tv_nsec < shm_stat.tvt.tv_nsec); 618285612Sdelphij if (tt < 0) 619285612Sdelphij tt = -tt; 620285612Sdelphij if (up->max_delta > 0 && tt > up->max_delta) { 621285612Sdelphij DPRINTF(1, ("%s: SHM diff limit exceeded, delta=%llds\n", 622285612Sdelphij refnumtoa(&peer->srcadr), (long long)tt)); 623285612Sdelphij up->bad++; 624285612Sdelphij msyslog (LOG_ERR, "SHM: difference limit exceeded, delta=%llds\n", 625285612Sdelphij (long long)tt); 62654359Sroberto return; 62754359Sroberto } 628285612Sdelphij 629285612Sdelphij /* if we really made it to this point... we're winners! */ 630285612Sdelphij DPRINTF(2, ("%s: SHM feeding data\n", 631285612Sdelphij refnumtoa(&peer->srcadr))); 632285612Sdelphij tsrcv = tspec_stamp_to_lfp(shm_stat.tvr); 633285612Sdelphij tsref = tspec_stamp_to_lfp(shm_stat.tvt); 634285612Sdelphij pp->leap = shm_stat.leap; 635285612Sdelphij peer->precision = shm_stat.precision; 636285612Sdelphij refclock_process_offset(pp, tsref, tsrcv, pp->fudgetime1); 637285612Sdelphij up->good++; 63854359Sroberto} 63954359Sroberto 640285612Sdelphij/* 641285612Sdelphij * shm_clockstats - dump and reset counters 642285612Sdelphij */ 643285612Sdelphijstatic void shm_clockstats( 644285612Sdelphij int unit, 645285612Sdelphij struct peer *peer 646285612Sdelphij ) 647285612Sdelphij{ 648285612Sdelphij struct refclockproc * const pp = peer->procptr; 649285612Sdelphij struct shmunit * const up = pp->unitptr; 650285612Sdelphij 651285612Sdelphij UNUSED_ARG(unit); 652285612Sdelphij if (pp->sloppyclockflag & CLK_FLAG4) { 653285612Sdelphij mprintf_clock_stats( 654285612Sdelphij &peer->srcadr, "%3d %3d %3d %3d %3d", 655285612Sdelphij up->ticks, up->good, up->notready, 656285612Sdelphij up->bad, up->clash); 657285612Sdelphij } 658285612Sdelphij up->ticks = up->good = up->notready = up->bad = up->clash = 0; 659285612Sdelphij} 660285612Sdelphij 66154359Sroberto#else 662285612SdelphijNONEMPTY_TRANSLATION_UNIT 66354359Sroberto#endif /* REFCLOCK */ 664