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; 343338531Sdelphij refclock_report(peer, CEVNT_NOMINAL); 344285612Sdelphij refclock_receive(peer); 345285612Sdelphij } else if (NULL == up->shm) { /* is this possible at all? */ 346285612Sdelphij /* we're out of business without SHM access */ 34754359Sroberto refclock_report(peer, CEVNT_FAULT); 348285612Sdelphij } else if (major_error == up->clash) { 349285612Sdelphij /* too many collisions is like a bad signal */ 350285612Sdelphij refclock_report(peer, CEVNT_PROP); 351285612Sdelphij } else if (major_error == up->bad) { 352285612Sdelphij /* too much stale/bad/garbled data */ 353285612Sdelphij refclock_report(peer, CEVNT_BADREPLY); 354285612Sdelphij } else { 355285612Sdelphij /* in any other case assume it's just a timeout */ 356285612Sdelphij refclock_report(peer, CEVNT_TIMEOUT); 357285612Sdelphij } 358285612Sdelphij /* shm_clockstats() clears the tallies, so it must be last... */ 359285612Sdelphij shm_clockstats(unit, peer); 360285612Sdelphij} 361285612Sdelphij 362285612Sdelphij 363285612Sdelphijenum segstat_t { 364285612Sdelphij OK, NO_SEGMENT, NOT_READY, BAD_MODE, CLASH 365285612Sdelphij}; 366285612Sdelphij 367285612Sdelphijstruct shm_stat_t { 368285612Sdelphij int status; 369285612Sdelphij int mode; 370285612Sdelphij struct timespec tvc, tvr, tvt; 371285612Sdelphij int precision; 372285612Sdelphij int leap; 373285612Sdelphij}; 374285612Sdelphij 375285612Sdelphijstatic inline void memory_barrier(void) 376285612Sdelphij{ 377285612Sdelphij#ifdef HAVE_ATOMIC_THREAD_FENCE 378285612Sdelphij atomic_thread_fence(memory_order_seq_cst); 379285612Sdelphij#endif /* HAVE_ATOMIC_THREAD_FENCE */ 380285612Sdelphij} 381285612Sdelphij 382285612Sdelphijstatic enum segstat_t shm_query(volatile struct shmTime *shm_in, struct shm_stat_t *shm_stat) 383285612Sdelphij/* try to grab a sample from the specified SHM segment */ 384285612Sdelphij{ 385293650Sglebius struct shmTime shmcopy; 386293650Sglebius volatile struct shmTime *shm = shm_in; 387285612Sdelphij volatile int cnt; 388285612Sdelphij 389285612Sdelphij unsigned int cns_new, rns_new; 390285612Sdelphij 391285612Sdelphij /* 392285612Sdelphij * This is the main routine. It snatches the time from the shm 393285612Sdelphij * board and tacks on a local timestamp. 394285612Sdelphij */ 395285612Sdelphij if (shm == NULL) { 396285612Sdelphij shm_stat->status = NO_SEGMENT; 397285612Sdelphij return NO_SEGMENT; 398285612Sdelphij } 399285612Sdelphij 400285612Sdelphij /*@-type@*//* splint is confused about struct timespec */ 401285612Sdelphij shm_stat->tvc.tv_sec = shm_stat->tvc.tv_nsec = 0; 402285612Sdelphij { 403285612Sdelphij time_t now; 404285612Sdelphij 405285612Sdelphij time(&now); 406285612Sdelphij shm_stat->tvc.tv_sec = now; 407285612Sdelphij } 408285612Sdelphij 409285612Sdelphij /* relying on word access to be atomic here */ 410285612Sdelphij if (shm->valid == 0) { 411285612Sdelphij shm_stat->status = NOT_READY; 412285612Sdelphij return NOT_READY; 413285612Sdelphij } 414285612Sdelphij 415285612Sdelphij cnt = shm->count; 416285612Sdelphij 417285612Sdelphij /* 418285612Sdelphij * This is proof against concurrency issues if either 419285612Sdelphij * (a) the memory_barrier() call works on this host, or 420285612Sdelphij * (b) memset compiles to an uninterruptible single-instruction bitblt. 421285612Sdelphij */ 422285612Sdelphij memory_barrier(); 423293650Sglebius memcpy(&shmcopy, (void*)(uintptr_t)shm, sizeof(struct shmTime)); 424285612Sdelphij shm->valid = 0; 425285612Sdelphij memory_barrier(); 426285612Sdelphij 427285612Sdelphij /* 428285612Sdelphij * Clash detection in case neither (a) nor (b) was true. 429285612Sdelphij * Not supported in mode 0, and word access to the count field 430285612Sdelphij * must be atomic for this to work. 431285612Sdelphij */ 432285612Sdelphij if (shmcopy.mode > 0 && cnt != shm->count) { 433285612Sdelphij shm_stat->status = CLASH; 434285612Sdelphij return shm_stat->status; 435285612Sdelphij } 436285612Sdelphij 437285612Sdelphij shm_stat->status = OK; 438285612Sdelphij shm_stat->mode = shmcopy.mode; 439285612Sdelphij 440285612Sdelphij switch (shmcopy.mode) { 441285612Sdelphij case 0: 442285612Sdelphij shm_stat->tvr.tv_sec = shmcopy.receiveTimeStampSec; 443285612Sdelphij shm_stat->tvr.tv_nsec = shmcopy.receiveTimeStampUSec * 1000; 444285612Sdelphij rns_new = shmcopy.receiveTimeStampNSec; 445285612Sdelphij shm_stat->tvt.tv_sec = shmcopy.clockTimeStampSec; 446285612Sdelphij shm_stat->tvt.tv_nsec = shmcopy.clockTimeStampUSec * 1000; 447285612Sdelphij cns_new = shmcopy.clockTimeStampNSec; 448285612Sdelphij 449285612Sdelphij /* Since the following comparisons are between unsigned 450285612Sdelphij ** variables they are always well defined, and any 451285612Sdelphij ** (signed) underflow will turn into very large unsigned 452285612Sdelphij ** values, well above the 1000 cutoff. 453285612Sdelphij ** 454285612Sdelphij ** Note: The usecs *must* be a *truncated* 455285612Sdelphij ** representation of the nsecs. This code will fail for 456285612Sdelphij ** *rounded* usecs, and the logic to deal with 457285612Sdelphij ** wrap-arounds in the presence of rounded values is 458285612Sdelphij ** much more convoluted. 459285612Sdelphij */ 460285612Sdelphij if ( ((cns_new - (unsigned)shm_stat->tvt.tv_nsec) < 1000) 461285612Sdelphij && ((rns_new - (unsigned)shm_stat->tvr.tv_nsec) < 1000)) { 462285612Sdelphij shm_stat->tvt.tv_nsec = cns_new; 463285612Sdelphij shm_stat->tvr.tv_nsec = rns_new; 46454359Sroberto } 465285612Sdelphij /* At this point shm_stat->tvr and shm_stat->tvt contain valid ns-level 466285612Sdelphij ** timestamps, possibly generated by extending the old 467285612Sdelphij ** us-level timestamps 468285612Sdelphij */ 469285612Sdelphij break; 470182007Sroberto 471285612Sdelphij case 1: 472285612Sdelphij 473285612Sdelphij shm_stat->tvr.tv_sec = shmcopy.receiveTimeStampSec; 474285612Sdelphij shm_stat->tvr.tv_nsec = shmcopy.receiveTimeStampUSec * 1000; 475285612Sdelphij rns_new = shmcopy.receiveTimeStampNSec; 476285612Sdelphij shm_stat->tvt.tv_sec = shmcopy.clockTimeStampSec; 477285612Sdelphij shm_stat->tvt.tv_nsec = shmcopy.clockTimeStampUSec * 1000; 478285612Sdelphij cns_new = shmcopy.clockTimeStampNSec; 479285612Sdelphij 480285612Sdelphij /* See the case above for an explanation of the 481285612Sdelphij ** following test. 482285612Sdelphij */ 483285612Sdelphij if ( ((cns_new - (unsigned)shm_stat->tvt.tv_nsec) < 1000) 484285612Sdelphij && ((rns_new - (unsigned)shm_stat->tvr.tv_nsec) < 1000)) { 485285612Sdelphij shm_stat->tvt.tv_nsec = cns_new; 486285612Sdelphij shm_stat->tvr.tv_nsec = rns_new; 487285612Sdelphij } 488285612Sdelphij /* At this point shm_stat->tvr and shm_stat->tvt contains valid ns-level 489285612Sdelphij ** timestamps, possibly generated by extending the old 490285612Sdelphij ** us-level timestamps 491285612Sdelphij */ 492285612Sdelphij break; 493285612Sdelphij 494285612Sdelphij default: 495285612Sdelphij shm_stat->status = BAD_MODE; 496285612Sdelphij break; 497285612Sdelphij } 498285612Sdelphij /*@-type@*/ 499285612Sdelphij 500285612Sdelphij /* 501285612Sdelphij * leap field is not a leap offset but a leap notification code. 502285612Sdelphij * The values are magic numbers used by NTP and set by GPSD, if at all, in 503285612Sdelphij * the subframe code. 504285612Sdelphij */ 505285612Sdelphij shm_stat->leap = shmcopy.leap; 506285612Sdelphij shm_stat->precision = shmcopy.precision; 507285612Sdelphij 508285612Sdelphij return shm_stat->status; 509285612Sdelphij} 510285612Sdelphij 511285612Sdelphij/* 512285612Sdelphij * shm_timer - called once every second. 513285612Sdelphij * 514285612Sdelphij * This tries to grab a sample from the SHM segment, filtering bad ones 515285612Sdelphij */ 516285612Sdelphijstatic void 517285612Sdelphijshm_timer( 518285612Sdelphij int unit, 519285612Sdelphij struct peer *peer 520285612Sdelphij ) 521285612Sdelphij{ 522285612Sdelphij struct refclockproc * const pp = peer->procptr; 523285612Sdelphij struct shmunit * const up = pp->unitptr; 524285612Sdelphij 525285612Sdelphij volatile struct shmTime *shm; 526285612Sdelphij 527285612Sdelphij l_fp tsrcv; 528285612Sdelphij l_fp tsref; 529285612Sdelphij int c; 530285612Sdelphij 531285612Sdelphij /* for formatting 'a_lastcode': */ 532285612Sdelphij struct calendar cd; 533285612Sdelphij time_t tt; 534285612Sdelphij vint64 ts; 535285612Sdelphij 536285612Sdelphij enum segstat_t status; 537285612Sdelphij struct shm_stat_t shm_stat; 538285612Sdelphij 539285612Sdelphij up->ticks++; 540285612Sdelphij if ((shm = up->shm) == NULL) { 541285612Sdelphij /* try to map again - this may succeed if meanwhile some- 542285612Sdelphij body has ipcrm'ed the old (unaccessible) shared mem segment */ 543285612Sdelphij shm = up->shm = getShmTime(unit, up->forall); 544285612Sdelphij if (shm == NULL) { 545285612Sdelphij DPRINTF(1, ("%s: no SHM segment\n", 546285612Sdelphij refnumtoa(&peer->srcadr))); 54754359Sroberto return; 54854359Sroberto } 54954359Sroberto } 550285612Sdelphij 551285612Sdelphij /* query the segment, atomically */ 552285612Sdelphij status = shm_query(shm, &shm_stat); 553285612Sdelphij 554285612Sdelphij switch (status) { 555285612Sdelphij case OK: 556285612Sdelphij DPRINTF(2, ("%s: SHM type %d sample\n", 557285612Sdelphij refnumtoa(&peer->srcadr), shm_stat.mode)); 558285612Sdelphij break; 559285612Sdelphij case NO_SEGMENT: 560285612Sdelphij /* should never happen, but is harmless */ 561285612Sdelphij return; 562285612Sdelphij case NOT_READY: 563285612Sdelphij DPRINTF(1, ("%s: SHM not ready\n",refnumtoa(&peer->srcadr))); 564285612Sdelphij up->notready++; 565285612Sdelphij return; 566285612Sdelphij case BAD_MODE: 567285612Sdelphij DPRINTF(1, ("%s: SHM type blooper, mode=%d\n", 568285612Sdelphij refnumtoa(&peer->srcadr), shm->mode)); 569285612Sdelphij up->bad++; 570285612Sdelphij msyslog (LOG_ERR, "SHM: bad mode found in shared memory: %d", 571285612Sdelphij shm->mode); 572285612Sdelphij return; 573285612Sdelphij case CLASH: 574285612Sdelphij DPRINTF(1, ("%s: type 1 access clash\n", 575285612Sdelphij refnumtoa(&peer->srcadr))); 576285612Sdelphij msyslog (LOG_NOTICE, "SHM: access clash in shared memory"); 577285612Sdelphij up->clash++; 578285612Sdelphij return; 579285612Sdelphij default: 580285612Sdelphij DPRINTF(1, ("%s: internal error, unknown SHM fetch status\n", 581285612Sdelphij refnumtoa(&peer->srcadr))); 582285612Sdelphij msyslog (LOG_NOTICE, "internal error, unknown SHM fetch status"); 583285612Sdelphij up->bad++; 584285612Sdelphij return; 585285612Sdelphij } 586285612Sdelphij 587285612Sdelphij 588285612Sdelphij /* format the last time code in human-readable form into 589285612Sdelphij * 'pp->a_lastcode'. Someone claimed: "NetBSD has incompatible 590285612Sdelphij * tv_sec". I can't find a base for this claim, but we can work 591285612Sdelphij * around that potential problem. BTW, simply casting a pointer 592285612Sdelphij * is a receipe for disaster on some architectures. 593285612Sdelphij */ 594285612Sdelphij tt = (time_t)shm_stat.tvt.tv_sec; 595285612Sdelphij ts = time_to_vint64(&tt); 596285612Sdelphij ntpcal_time_to_date(&cd, &ts); 597285612Sdelphij 598285612Sdelphij /* add ntpq -c cv timecode in ISO 8601 format */ 599285612Sdelphij c = snprintf(pp->a_lastcode, sizeof(pp->a_lastcode), 600285612Sdelphij "%04u-%02u-%02uT%02u:%02u:%02u.%09ldZ", 601285612Sdelphij cd.year, cd.month, cd.monthday, 602285612Sdelphij cd.hour, cd.minute, cd.second, 603285612Sdelphij (long)shm_stat.tvt.tv_nsec); 604294569Sdelphij pp->lencode = (c > 0 && (size_t)c < sizeof(pp->a_lastcode)) ? c : 0; 605285612Sdelphij 606285612Sdelphij /* check 1: age control of local time stamp */ 607285612Sdelphij tt = shm_stat.tvc.tv_sec - shm_stat.tvr.tv_sec; 608285612Sdelphij if (tt < 0 || tt > up->max_delay) { 609285612Sdelphij DPRINTF(1, ("%s:SHM stale/bad receive time, delay=%llds\n", 610285612Sdelphij refnumtoa(&peer->srcadr), (long long)tt)); 611285612Sdelphij up->bad++; 612285612Sdelphij msyslog (LOG_ERR, "SHM: stale/bad receive time, delay=%llds", 613285612Sdelphij (long long)tt); 61454359Sroberto return; 61554359Sroberto } 616285612Sdelphij 617285612Sdelphij /* check 2: delta check */ 618285612Sdelphij tt = shm_stat.tvr.tv_sec - shm_stat.tvt.tv_sec - (shm_stat.tvr.tv_nsec < shm_stat.tvt.tv_nsec); 619285612Sdelphij if (tt < 0) 620285612Sdelphij tt = -tt; 621285612Sdelphij if (up->max_delta > 0 && tt > up->max_delta) { 622285612Sdelphij DPRINTF(1, ("%s: SHM diff limit exceeded, delta=%llds\n", 623285612Sdelphij refnumtoa(&peer->srcadr), (long long)tt)); 624285612Sdelphij up->bad++; 625285612Sdelphij msyslog (LOG_ERR, "SHM: difference limit exceeded, delta=%llds\n", 626285612Sdelphij (long long)tt); 62754359Sroberto return; 62854359Sroberto } 629285612Sdelphij 630285612Sdelphij /* if we really made it to this point... we're winners! */ 631285612Sdelphij DPRINTF(2, ("%s: SHM feeding data\n", 632285612Sdelphij refnumtoa(&peer->srcadr))); 633285612Sdelphij tsrcv = tspec_stamp_to_lfp(shm_stat.tvr); 634285612Sdelphij tsref = tspec_stamp_to_lfp(shm_stat.tvt); 635285612Sdelphij pp->leap = shm_stat.leap; 636285612Sdelphij peer->precision = shm_stat.precision; 637285612Sdelphij refclock_process_offset(pp, tsref, tsrcv, pp->fudgetime1); 638285612Sdelphij up->good++; 63954359Sroberto} 64054359Sroberto 641285612Sdelphij/* 642285612Sdelphij * shm_clockstats - dump and reset counters 643285612Sdelphij */ 644285612Sdelphijstatic void shm_clockstats( 645285612Sdelphij int unit, 646285612Sdelphij struct peer *peer 647285612Sdelphij ) 648285612Sdelphij{ 649285612Sdelphij struct refclockproc * const pp = peer->procptr; 650285612Sdelphij struct shmunit * const up = pp->unitptr; 651285612Sdelphij 652285612Sdelphij UNUSED_ARG(unit); 653285612Sdelphij if (pp->sloppyclockflag & CLK_FLAG4) { 654285612Sdelphij mprintf_clock_stats( 655285612Sdelphij &peer->srcadr, "%3d %3d %3d %3d %3d", 656285612Sdelphij up->ticks, up->good, up->notready, 657285612Sdelphij up->bad, up->clash); 658285612Sdelphij } 659285612Sdelphij up->ticks = up->good = up->notready = up->bad = up->clash = 0; 660285612Sdelphij} 661285612Sdelphij 66254359Sroberto#else 663285612SdelphijNONEMPTY_TRANSLATION_UNIT 66454359Sroberto#endif /* REFCLOCK */ 665