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