Patrick Welche <prlw1@cam.ac.uk>
[netbsd-mini2440.git] / external / bsd / ntp / dist / ntpd / refclock_shm.c
blob4edafcf66da16eb4ad3a52ee07f8654b91fd6b73
1 /* $NetBSD$ */
3 /*
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
9 * PB 18.3.97
12 #ifdef HAVE_CONFIG_H
13 # include <config.h>
14 #endif
16 #if defined(REFCLOCK) && defined(CLOCK_SHM)
18 #include "ntpd.h"
19 #undef fileno
20 #include "ntp_io.h"
21 #undef fileno
22 #include "ntp_refclock.h"
23 #undef fileno
24 #include "ntp_unixtime.h"
25 #undef fileno
26 #include "ntp_stdlib.h"
28 #undef fileno
29 #include <ctype.h>
30 #undef fileno
32 #ifndef SYS_WINNT
33 # include <sys/ipc.h>
34 # include <sys/shm.h>
35 # include <assert.h>
36 # include <unistd.h>
37 # include <stdio.h>
38 #endif
41 * This driver supports a reference clock attached thru shared memory
42 */
44 /* Temp hack to simplify testing of the old mode. */
45 #define OLDWAY 0
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 */
57 * Function prototypes
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);
67 * Transfer vector
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 */
79 struct shmTime {
80 int mode; /* 0 - if valid set
81 * use values,
82 * clear valid
83 * 1 - if valid set
84 * if count before and after read of values is equal,
85 * use values
86 * clear valid
88 int count;
89 time_t clockTimeStampSec;
90 int clockTimeStampUSec;
91 time_t receiveTimeStampSec;
92 int receiveTimeStampUSec;
93 int leap;
94 int precision;
95 int nsamples;
96 int valid;
97 int dummy[10];
100 struct shmunit {
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) {
115 #ifndef SYS_WINNT
116 int shmid=0;
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));
126 return 0;
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));
132 return 0;
134 return p;
136 #else
137 char buf[10];
138 LPSECURITY_ATTRIBUTES psec=0;
139 HANDLE shmid=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);
146 return 0;
148 if (!SetSecurityDescriptorDacl(&sd,1,0,0)) {
149 msyslog(LOG_ERR,"SHM SetSecurityDescriptorDacl (unit %d): %m",unit);
150 return 0;
152 sa.nLength=sizeof (SECURITY_ATTRIBUTES);
153 sa.lpSecurityDescriptor=&sd;
154 sa.bInheritHandle=0;
155 psec=&sa;
157 shmid=CreateFileMapping ((HANDLE)0xffffffff, psec, PAGE_READWRITE,
158 0, sizeof (struct shmTime),buf);
159 if (!shmid) { /*error*/
160 char buf[1000];
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);
164 return 0;
166 else {
167 struct shmTime *p=(struct shmTime *) MapViewOfFile (shmid,
168 FILE_MAP_WRITE, 0, 0, sizeof (struct shmTime));
169 if (p==0) { /*error*/
170 char buf[1000];
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);
174 return 0;
176 return p;
178 #endif
181 * shm_start - attach to shared memory
183 static int
184 shm_start(
185 int unit,
186 struct peer *peer
189 struct refclockproc *pp;
190 struct shmunit *up;
192 pp = peer->procptr;
193 pp->io.clock_recv = noentry;
194 pp->io.srcclock = (caddr_t)peer;
195 pp->io.datalen = 0;
196 pp->io.fd = -1;
198 up = (struct shmunit *) emalloc(sizeof(*up));
199 if (up == NULL)
200 return (FALSE);
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);
210 if (up->shm != 0) {
211 up->shm->precision = PRECISION;
212 peer->precision = up->shm->precision;
213 up->shm->valid=0;
214 up->shm->nsamples=NSAMPLES;
215 pp->clockdesc = DESCRIPTION;
216 return (1);
218 else {
219 return 0;
225 * shm_shutdown - shut down the clock
227 static void
228 shm_shutdown(
229 int unit,
230 struct peer *peer
233 struct refclockproc *pp;
234 struct shmunit *up;
236 pp = peer->procptr;
237 up = (struct shmunit *)pp->unitptr;
238 #ifndef SYS_WINNT
239 /* HMS: shmdt()wants char* or const void * */
240 (void) shmdt ((char *)up->shm);
241 #else
242 UnmapViewOfFile (up->shm);
243 #endif
248 * shm_timer - called every second
250 static void
251 shm_timer(int unit, struct peer *peer)
253 if (OLDWAY)
254 return;
256 shm_peek(unit, peer);
261 * shm_poll - called by the transmit procedure
263 static void
264 shm_poll(
265 int unit,
266 struct peer *peer
269 struct refclockproc *pp;
270 int ok;
272 pp = peer->procptr;
274 if (OLDWAY) {
275 ok = shm_peek(unit, peer);
276 if (!ok) return;
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);
286 return;
288 pp->lastref = pp->lastrec;
289 refclock_receive(peer);
290 shm_clockstats(unit, peer);
294 * shm_peek - try to grab a sample
296 int shm_peek(
297 int unit,
298 struct peer *peer
301 struct refclockproc *pp;
302 struct shmunit *up;
303 struct shmTime *shm;
306 * This is the main routine. It snatches the time from the shm
307 * board and tacks on a local timestamp.
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);
317 shm = up->shm;
318 if (shm == 0) {
319 refclock_report(peer, CEVNT_FAULT);
320 return(0);
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;
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);
347 break;
348 default:
349 msyslog (LOG_ERR, "SHM: bad mode found in shared memory: %d",shm->mode);
351 shm->valid=0;
352 if (ok) {
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; */
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;
369 else {
370 refclock_report(peer, CEVNT_FAULT);
371 msyslog (LOG_NOTICE, "SHM: access clash in shared memory");
372 up->clash++;
373 return(0);
376 else {
377 refclock_report(peer, CEVNT_TIMEOUT);
378 up->notready++;
379 return(0);
381 if (!refclock_process(pp)) {
382 refclock_report(peer, CEVNT_BADTIME);
383 up->bad++;
384 return(0);
386 up->good++;
387 return(1);
391 * shm_clockstats - dump and reset counters
393 void shm_clockstats(
394 int unit,
395 struct peer *peer
398 struct refclockproc *pp;
399 struct shmunit *up;
400 char logbuf[256];
402 pp = peer->procptr;
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;
415 #else
416 int refclock_shm_bs;
417 #endif /* REFCLOCK */