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