4 * refclock_shm - clock driver for utc via shared memory
5 * - under construction -
6 * To add new modes: Extend or union the shmTime-struct. Do not
7 * extend/shrink size, because otherwise existing implementations
8 * will specify wrong size of shared memory-segment
16 #if defined(REFCLOCK) && defined(CLOCK_SHM)
22 #include "ntp_refclock.h"
24 #include "ntp_unixtime.h"
26 #include "ntp_stdlib.h"
41 * This driver supports a reference clock attached thru shared memory
44 /* Temp hack to simplify testing of the old mode. */
48 * SHM interface definitions
50 #define PRECISION (-1) /* precision assumed (0.5 s) */
51 #define REFID "SHM" /* reference ID */
52 #define DESCRIPTION "SHM/Shared memory interface"
54 #define NSAMPLES 3 /* stages of median filter */
59 static int shm_start (int unit
, struct peer
*peer
);
60 static void shm_shutdown (int unit
, struct peer
*peer
);
61 static void shm_poll (int unit
, struct peer
*peer
);
62 static void shm_timer (int unit
, struct peer
*peer
);
63 int shm_peek (int unit
, struct peer
*peer
);
64 void shm_clockstats (int unit
, struct peer
*peer
);
69 struct refclock refclock_shm
= {
70 shm_start
, /* start up driver */
71 shm_shutdown
, /* shut down driver */
72 shm_poll
, /* transmit poll message */
73 noentry
, /* not used: control */
74 noentry
, /* not used: init */
75 noentry
, /* not used: buginfo */
76 shm_timer
, /* once per second */
80 int mode
; /* 0 - if valid set
84 * if count before and after read of values is equal,
89 time_t clockTimeStampSec
;
90 int clockTimeStampUSec
;
91 time_t receiveTimeStampSec
;
92 int receiveTimeStampUSec
;
101 struct shmTime
*shm
; /* pointer to shared memory segment */
103 /* debugging/monitoring counters - reset when printed */
104 int ticks
; /* number of attempts to read data*/
105 int good
; /* number of valid samples */
106 int notready
; /* number of peeks without data ready */
107 int bad
; /* number of invalid samples */
108 int clash
; /* number of access clashes while reading */
112 struct shmTime
*getShmTime(int);
114 struct shmTime
*getShmTime (int unit
) {
118 /* 0x4e545030 is NTP0.
119 * Big units will give non-ascii but that's OK
120 * as long as everybody does it the same way.
122 shmid
=shmget (0x4e545030+unit
, sizeof (struct shmTime
),
123 IPC_CREAT
|(unit
<2?0600:0666));
124 if (shmid
==-1) { /*error */
125 msyslog(LOG_ERR
,"SHM shmget (unit %d): %s",unit
,strerror(errno
));
128 else { /* no error */
129 struct shmTime
*p
=(struct shmTime
*)shmat (shmid
, 0, 0);
130 if ((int)(long)p
==-1) { /* error */
131 msyslog(LOG_ERR
,"SHM shmat (unit %d): %s",unit
,strerror(errno
));
138 LPSECURITY_ATTRIBUTES psec
=0;
140 SECURITY_DESCRIPTOR sd
;
141 SECURITY_ATTRIBUTES sa
;
142 sprintf (buf
,"NTP%d",unit
);
143 if (unit
>=2) { /* world access */
144 if (!InitializeSecurityDescriptor(&sd
, SECURITY_DESCRIPTOR_REVISION
)) {
145 msyslog(LOG_ERR
,"SHM InitializeSecurityDescriptor (unit %d): %m",unit
);
148 if (!SetSecurityDescriptorDacl(&sd
,1,0,0)) {
149 msyslog(LOG_ERR
,"SHM SetSecurityDescriptorDacl (unit %d): %m",unit
);
152 sa
.nLength
=sizeof (SECURITY_ATTRIBUTES
);
153 sa
.lpSecurityDescriptor
=&sd
;
157 shmid
=CreateFileMapping ((HANDLE
)0xffffffff, psec
, PAGE_READWRITE
,
158 0, sizeof (struct shmTime
),buf
);
159 if (!shmid
) { /*error*/
161 FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM
,
162 0, GetLastError (), 0, buf
, sizeof (buf
), 0);
163 msyslog(LOG_ERR
,"SHM CreateFileMapping (unit %d): %s",unit
,buf
);
167 struct shmTime
*p
=(struct shmTime
*) MapViewOfFile (shmid
,
168 FILE_MAP_WRITE
, 0, 0, sizeof (struct shmTime
));
169 if (p
==0) { /*error*/
171 FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM
,
172 0, GetLastError (), 0, buf
, sizeof (buf
), 0);
173 msyslog(LOG_ERR
,"SHM MapViewOfFile (unit %d): %s",unit
,buf
);
181 * shm_start - attach to shared memory
189 struct refclockproc
*pp
;
193 pp
->io
.clock_recv
= noentry
;
194 pp
->io
.srcclock
= (caddr_t
)peer
;
198 up
= (struct shmunit
*) emalloc(sizeof(*up
));
201 memset((char *)up
, 0, sizeof(*up
));
202 pp
->unitptr
= (caddr_t
)up
;
204 up
->shm
= getShmTime(unit
);
207 * Initialize miscellaneous peer variables
209 memcpy((char *)&pp
->refid
, REFID
, 4);
211 up
->shm
->precision
= PRECISION
;
212 peer
->precision
= up
->shm
->precision
;
214 up
->shm
->nsamples
=NSAMPLES
;
215 pp
->clockdesc
= DESCRIPTION
;
225 * shm_shutdown - shut down the clock
233 struct refclockproc
*pp
;
237 up
= (struct shmunit
*)pp
->unitptr
;
239 /* HMS: shmdt()wants char* or const void * */
240 (void) shmdt ((char *)up
->shm
);
242 UnmapViewOfFile (up
->shm
);
248 * shm_timer - called every second
251 shm_timer(int unit
, struct peer
*peer
)
256 shm_peek(unit
, peer
);
261 * shm_poll - called by the transmit procedure
269 struct refclockproc
*pp
;
275 ok
= shm_peek(unit
, peer
);
280 * Process median filter samples. If none received, declare a
281 * timeout and keep going.
283 if (pp
->coderecv
== pp
->codeproc
) {
284 refclock_report(peer
, CEVNT_TIMEOUT
);
285 shm_clockstats(unit
, peer
);
288 pp
->lastref
= pp
->lastrec
;
289 refclock_receive(peer
);
290 shm_clockstats(unit
, peer
);
294 * shm_peek - try to grab a sample
301 struct refclockproc
*pp
;
306 * This is the main routine. It snatches the time from the shm
307 * board and tacks on a local timestamp.
310 up
= (struct shmunit
*)pp
->unitptr
;
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
);
319 refclock_report(peer
, CEVNT_FAULT
);
333 tvr
.tv_sec
=shm
->receiveTimeStampSec
;
334 tvr
.tv_usec
=shm
->receiveTimeStampUSec
;
335 tvt
.tv_sec
=shm
->clockTimeStampSec
;
336 tvt
.tv_usec
=shm
->clockTimeStampUSec
;
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
);
349 msyslog (LOG_ERR
, "SHM: bad mode found in shared memory: %d",shm
->mode
);
353 time_t help
; /* XXX NetBSD has incompatible tv_sec */
355 TVTOTS(&tvr
,&pp
->lastrec
);
356 pp
->lastrec
.l_ui
+= JAN_1970
;
357 /* pp->lasttime = current_time; */
361 pp
->day
=t
->tm_yday
+1;
363 pp
->minute
=t
->tm_min
;
364 pp
->second
=t
->tm_sec
;
365 pp
->nsec
=tvt
.tv_usec
* 1000;
366 peer
->precision
=shm
->precision
;
370 refclock_report(peer
, CEVNT_FAULT
);
371 msyslog (LOG_NOTICE
, "SHM: access clash in shared memory");
377 refclock_report(peer
, CEVNT_TIMEOUT
);
381 if (!refclock_process(pp
)) {
382 refclock_report(peer
, CEVNT_BADTIME
);
391 * shm_clockstats - dump and reset counters
398 struct refclockproc
*pp
;
403 up
= (struct shmunit
*)pp
->unitptr
;
405 if (!(pp
->sloppyclockflag
& CLK_FLAG4
)) return;
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
);
411 up
->ticks
= up
->good
= up
->notready
=up
->bad
= up
->clash
= 0;
417 #endif /* REFCLOCK */