| @@ -1,565 +1,564 @@ | | | @@ -1,565 +1,564 @@ |
1 | /* $NetBSD: refclock_shm.c,v 1.4 2015/04/07 17:34:19 christos Exp $ */ | | 1 | /* $NetBSD: refclock_shm.c,v 1.5 2015/04/13 17:45:19 christos Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * refclock_shm - clock driver for utc via shared memory | | 4 | * refclock_shm - clock driver for utc via shared memory |
5 | * - under construction - | | 5 | * - under construction - |
6 | * To add new modes: Extend or union the shmTime-struct. Do not | | 6 | * To add new modes: Extend or union the shmTime-struct. Do not |
7 | * extend/shrink size, because otherwise existing implementations | | 7 | * extend/shrink size, because otherwise existing implementations |
8 | * will specify wrong size of shared memory-segment | | 8 | * will specify wrong size of shared memory-segment |
9 | * PB 18.3.97 | | 9 | * PB 18.3.97 |
10 | */ | | 10 | */ |
11 | | | 11 | |
12 | #ifdef HAVE_CONFIG_H | | 12 | #ifdef HAVE_CONFIG_H |
13 | # include <config.h> | | 13 | # include <config.h> |
14 | #endif | | 14 | #endif |
15 | | | 15 | |
16 | #include "ntp_types.h" | | 16 | #include "ntp_types.h" |
17 | | | 17 | |
18 | #if defined(REFCLOCK) && defined(CLOCK_SHM) | | 18 | #if defined(REFCLOCK) && defined(CLOCK_SHM) |
19 | | | 19 | |
20 | #include "ntpd.h" | | 20 | #include "ntpd.h" |
21 | #undef fileno | | 21 | #undef fileno |
22 | #include "ntp_io.h" | | 22 | #include "ntp_io.h" |
23 | #undef fileno | | 23 | #undef fileno |
24 | #include "ntp_refclock.h" | | 24 | #include "ntp_refclock.h" |
25 | #undef fileno | | 25 | #undef fileno |
26 | #include "timespecops.h" | | 26 | #include "timespecops.h" |
27 | #undef fileno | | 27 | #undef fileno |
28 | #include "ntp_stdlib.h" | | 28 | #include "ntp_stdlib.h" |
29 | | | 29 | |
30 | #undef fileno | | 30 | #undef fileno |
31 | #include <ctype.h> | | 31 | #include <ctype.h> |
32 | #undef fileno | | 32 | #undef fileno |
33 | | | 33 | |
34 | #ifndef SYS_WINNT | | 34 | #ifndef SYS_WINNT |
35 | # include <sys/ipc.h> | | 35 | # include <sys/ipc.h> |
36 | # include <sys/shm.h> | | 36 | # include <sys/shm.h> |
37 | # include <assert.h> | | 37 | # include <assert.h> |
38 | # include <unistd.h> | | 38 | # include <unistd.h> |
39 | # include <stdio.h> | | 39 | # include <stdio.h> |
40 | #endif | | 40 | #endif |
41 | | | 41 | |
42 | /* | | 42 | /* |
43 | * This driver supports a reference clock attached thru shared memory | | 43 | * This driver supports a reference clock attached thru shared memory |
44 | */ | | 44 | */ |
45 | | | 45 | |
46 | /* | | 46 | /* |
47 | * SHM interface definitions | | 47 | * SHM interface definitions |
48 | */ | | 48 | */ |
49 | #define PRECISION (-1) /* precision assumed (0.5 s) */ | | 49 | #define PRECISION (-1) /* precision assumed (0.5 s) */ |
50 | #define REFID "SHM" /* reference ID */ | | 50 | #define REFID "SHM" /* reference ID */ |
51 | #define DESCRIPTION "SHM/Shared memory interface" | | 51 | #define DESCRIPTION "SHM/Shared memory interface" |
52 | | | 52 | |
53 | #define NSAMPLES 3 /* stages of median filter */ | | 53 | #define NSAMPLES 3 /* stages of median filter */ |
54 | | | 54 | |
55 | /* | | 55 | /* |
56 | * Mode flags | | 56 | * Mode flags |
57 | */ | | 57 | */ |
58 | #define SHM_MODE_PRIVATE 0x0001 | | 58 | #define SHM_MODE_PRIVATE 0x0001 |
59 | | | 59 | |
60 | /* | | 60 | /* |
61 | * Function prototypes | | 61 | * Function prototypes |
62 | */ | | 62 | */ |
63 | static int shm_start (int unit, struct peer *peer); | | 63 | static int shm_start (int unit, struct peer *peer); |
64 | static void shm_shutdown (int unit, struct peer *peer); | | 64 | static void shm_shutdown (int unit, struct peer *peer); |
65 | static void shm_poll (int unit, struct peer *peer); | | 65 | static void shm_poll (int unit, struct peer *peer); |
66 | static void shm_timer (int unit, struct peer *peer); | | 66 | static void shm_timer (int unit, struct peer *peer); |
67 | static void shm_clockstats (int unit, struct peer *peer); | | 67 | static void shm_clockstats (int unit, struct peer *peer); |
68 | static void shm_control (int unit, const struct refclockstat * in_st, | | 68 | static void shm_control (int unit, const struct refclockstat * in_st, |
69 | struct refclockstat * out_st, struct peer *peer); | | 69 | struct refclockstat * out_st, struct peer *peer); |
70 | | | 70 | |
71 | /* | | 71 | /* |
72 | * Transfer vector | | 72 | * Transfer vector |
73 | */ | | 73 | */ |
74 | struct refclock refclock_shm = { | | 74 | struct refclock refclock_shm = { |
75 | shm_start, /* start up driver */ | | 75 | shm_start, /* start up driver */ |
76 | shm_shutdown, /* shut down driver */ | | 76 | shm_shutdown, /* shut down driver */ |
77 | shm_poll, /* transmit poll message */ | | 77 | shm_poll, /* transmit poll message */ |
78 | shm_control, /* control settings */ | | 78 | shm_control, /* control settings */ |
79 | noentry, /* not used: init */ | | 79 | noentry, /* not used: init */ |
80 | noentry, /* not used: buginfo */ | | 80 | noentry, /* not used: buginfo */ |
81 | shm_timer, /* once per second */ | | 81 | shm_timer, /* once per second */ |
82 | }; | | 82 | }; |
83 | | | 83 | |
84 | struct shmTime { | | 84 | struct shmTime { |
85 | int mode; /* 0 - if valid is set: | | 85 | int mode; /* 0 - if valid is set: |
86 | * use values, | | 86 | * use values, |
87 | * clear valid | | 87 | * clear valid |
88 | * 1 - if valid is set: | | 88 | * 1 - if valid is set: |
89 | * if count before and after read of values is equal, | | 89 | * if count before and after read of values is equal, |
90 | * use values | | 90 | * use values |
91 | * clear valid | | 91 | * clear valid |
92 | */ | | 92 | */ |
93 | volatile int count; | | 93 | volatile int count; |
94 | time_t clockTimeStampSec; | | 94 | time_t clockTimeStampSec; |
95 | int clockTimeStampUSec; | | 95 | int clockTimeStampUSec; |
96 | time_t receiveTimeStampSec; | | 96 | time_t receiveTimeStampSec; |
97 | int receiveTimeStampUSec; | | 97 | int receiveTimeStampUSec; |
98 | int leap; | | 98 | int leap; |
99 | int precision; | | 99 | int precision; |
100 | int nsamples; | | 100 | int nsamples; |
101 | volatile int valid; | | 101 | volatile int valid; |
102 | unsigned clockTimeStampNSec; /* Unsigned ns timestamps */ | | 102 | unsigned clockTimeStampNSec; /* Unsigned ns timestamps */ |
103 | unsigned receiveTimeStampNSec; /* Unsigned ns timestamps */ | | 103 | unsigned receiveTimeStampNSec; /* Unsigned ns timestamps */ |
104 | int dummy[8]; | | 104 | int dummy[8]; |
105 | }; | | 105 | }; |
106 | | | 106 | |
107 | struct shmunit { | | 107 | struct shmunit { |
108 | struct shmTime *shm; /* pointer to shared memory segment */ | | 108 | struct shmTime *shm; /* pointer to shared memory segment */ |
109 | int forall; /* access for all UIDs? */ | | 109 | int forall; /* access for all UIDs? */ |
110 | | | 110 | |
111 | /* debugging/monitoring counters - reset when printed */ | | 111 | /* debugging/monitoring counters - reset when printed */ |
112 | int ticks; /* number of attempts to read data*/ | | 112 | int ticks; /* number of attempts to read data*/ |
113 | int good; /* number of valid samples */ | | 113 | int good; /* number of valid samples */ |
114 | int notready; /* number of peeks without data ready */ | | 114 | int notready; /* number of peeks without data ready */ |
115 | int bad; /* number of invalid samples */ | | 115 | int bad; /* number of invalid samples */ |
116 | int clash; /* number of access clashes while reading */ | | 116 | int clash; /* number of access clashes while reading */ |
117 | | | 117 | |
118 | time_t max_delta; /* difference limit */ | | 118 | time_t max_delta; /* difference limit */ |
119 | time_t max_delay; /* age/stale limit */ | | 119 | time_t max_delay; /* age/stale limit */ |
120 | }; | | 120 | }; |
121 | | | 121 | |
122 | static struct shmTime* | | 122 | static struct shmTime* |
123 | getShmTime( | | 123 | getShmTime( |
124 | int unit, | | 124 | int unit, |
125 | int/*BOOL*/ forall | | 125 | int/*BOOL*/ forall |
126 | ) | | 126 | ) |
127 | { | | 127 | { |
128 | struct shmTime *p = NULL; | | 128 | struct shmTime *p = NULL; |
129 | | | 129 | |
130 | #ifndef SYS_WINNT | | 130 | #ifndef SYS_WINNT |
131 | | | 131 | |
132 | int shmid; | | 132 | int shmid; |
133 | | | 133 | |
134 | /* 0x4e545030 is NTP0. | | 134 | /* 0x4e545030 is NTP0. |
135 | * Big units will give non-ascii but that's OK | | 135 | * Big units will give non-ascii but that's OK |
136 | * as long as everybody does it the same way. | | 136 | * as long as everybody does it the same way. |
137 | */ | | 137 | */ |
138 | shmid=shmget(0x4e545030 + unit, sizeof (struct shmTime), | | 138 | shmid=shmget(0x4e545030 + unit, sizeof (struct shmTime), |
139 | IPC_CREAT | (forall ? 0666 : 0600)); | | 139 | IPC_CREAT | (forall ? 0666 : 0600)); |
140 | if (shmid == -1) { /* error */ | | 140 | if (shmid == -1) { /* error */ |
141 | msyslog(LOG_ERR, "SHM shmget (unit %d): %m", unit); | | 141 | msyslog(LOG_ERR, "SHM shmget (unit %d): %m", unit); |
142 | return NULL; | | 142 | return NULL; |
143 | } | | 143 | } |
144 | p = (struct shmTime *)shmat (shmid, 0, 0); | | 144 | p = (struct shmTime *)shmat (shmid, 0, 0); |
145 | if (p == (struct shmTime *)-1) { /* error */ | | 145 | if (p == (struct shmTime *)-1) { /* error */ |
146 | msyslog(LOG_ERR, "SHM shmat (unit %d): %m", unit); | | 146 | msyslog(LOG_ERR, "SHM shmat (unit %d): %m", unit); |
147 | return NULL; | | 147 | return NULL; |
148 | } | | 148 | } |
149 | return p; | | 149 | return p; |
150 | | | 150 | |
151 | #else | | 151 | #else |
152 | | | 152 | |
153 | static const char * nspref[2] = { "Local", "Global" }; | | 153 | static const char * nspref[2] = { "Local", "Global" }; |
154 | char buf[20]; | | 154 | char buf[20]; |
155 | LPSECURITY_ATTRIBUTES psec = 0; | | 155 | LPSECURITY_ATTRIBUTES psec = 0; |
156 | HANDLE shmid = 0; | | 156 | HANDLE shmid = 0; |
157 | SECURITY_DESCRIPTOR sd; | | 157 | SECURITY_DESCRIPTOR sd; |
158 | SECURITY_ATTRIBUTES sa; | | 158 | SECURITY_ATTRIBUTES sa; |
159 | unsigned int numch; | | 159 | unsigned int numch; |
160 | | | 160 | |
161 | numch = snprintf(buf, sizeof(buf), "%s\\NTP%d", | | 161 | numch = snprintf(buf, sizeof(buf), "%s\\NTP%d", |
162 | nspref[forall != 0], (unit & 0xFF)); | | 162 | nspref[forall != 0], (unit & 0xFF)); |
163 | if (numch >= sizeof(buf)) { | | 163 | if (numch >= sizeof(buf)) { |
164 | msyslog(LOG_ERR, "SHM name too long (unit %d)", unit); | | 164 | msyslog(LOG_ERR, "SHM name too long (unit %d)", unit); |
165 | return NULL; | | 165 | return NULL; |
166 | } | | 166 | } |
167 | if (forall) { /* world access */ | | 167 | if (forall) { /* world access */ |
168 | if (!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION)) { | | 168 | if (!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION)) { |
169 | msyslog(LOG_ERR,"SHM InitializeSecurityDescriptor (unit %d): %m", unit); | | 169 | msyslog(LOG_ERR,"SHM InitializeSecurityDescriptor (unit %d): %m", unit); |
170 | return NULL; | | 170 | return NULL; |
171 | } | | 171 | } |
172 | if (!SetSecurityDescriptorDacl(&sd, TRUE, NULL, FALSE)) { | | 172 | if (!SetSecurityDescriptorDacl(&sd, TRUE, NULL, FALSE)) { |
173 | msyslog(LOG_ERR, "SHM SetSecurityDescriptorDacl (unit %d): %m", unit); | | 173 | msyslog(LOG_ERR, "SHM SetSecurityDescriptorDacl (unit %d): %m", unit); |
174 | return NULL; | | 174 | return NULL; |
175 | } | | 175 | } |
176 | sa.nLength = sizeof(SECURITY_ATTRIBUTES); | | 176 | sa.nLength = sizeof(SECURITY_ATTRIBUTES); |
177 | sa.lpSecurityDescriptor = &sd; | | 177 | sa.lpSecurityDescriptor = &sd; |
178 | sa.bInheritHandle = FALSE; | | 178 | sa.bInheritHandle = FALSE; |
179 | psec = &sa; | | 179 | psec = &sa; |
180 | } | | 180 | } |
181 | shmid = CreateFileMapping ((HANDLE)0xffffffff, psec, PAGE_READWRITE, | | 181 | shmid = CreateFileMapping ((HANDLE)0xffffffff, psec, PAGE_READWRITE, |
182 | 0, sizeof (struct shmTime), buf); | | 182 | 0, sizeof (struct shmTime), buf); |
183 | if (shmid == NULL) { /*error*/ | | 183 | if (shmid == NULL) { /*error*/ |
184 | char buf[1000]; | | 184 | char buf[1000]; |
185 | FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, | | 185 | FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, |
186 | 0, GetLastError (), 0, buf, sizeof (buf), 0); | | 186 | 0, GetLastError (), 0, buf, sizeof (buf), 0); |
187 | msyslog(LOG_ERR, "SHM CreateFileMapping (unit %d): %s", unit, buf); | | 187 | msyslog(LOG_ERR, "SHM CreateFileMapping (unit %d): %s", unit, buf); |
188 | return NULL; | | 188 | return NULL; |
189 | } | | 189 | } |
190 | p = (struct shmTime *)MapViewOfFile(shmid, FILE_MAP_WRITE, 0, 0, | | 190 | p = (struct shmTime *)MapViewOfFile(shmid, FILE_MAP_WRITE, 0, 0, |
191 | sizeof (struct shmTime)); | | 191 | sizeof (struct shmTime)); |
192 | if (p == NULL) { /*error*/ | | 192 | if (p == NULL) { /*error*/ |
193 | char buf[1000]; | | 193 | char buf[1000]; |
194 | FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, | | 194 | FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, |
195 | 0, GetLastError (), 0, buf, sizeof (buf), 0); | | 195 | 0, GetLastError (), 0, buf, sizeof (buf), 0); |
196 | msyslog(LOG_ERR,"SHM MapViewOfFile (unit %d): %s", unit, buf); | | 196 | msyslog(LOG_ERR,"SHM MapViewOfFile (unit %d): %s", unit, buf); |
197 | return NULL; | | 197 | return NULL; |
198 | } | | 198 | } |
199 | | | 199 | |
200 | #endif | | | |
201 | | | | |
202 | return p; | | 200 | return p; |
| | | 201 | #endif |
203 | } | | 202 | } |
204 | /* | | 203 | /* |
205 | * shm_start - attach to shared memory | | 204 | * shm_start - attach to shared memory |
206 | */ | | 205 | */ |
207 | static int | | 206 | static int |
208 | shm_start( | | 207 | shm_start( |
209 | int unit, | | 208 | int unit, |
210 | struct peer *peer | | 209 | struct peer *peer |
211 | ) | | 210 | ) |
212 | { | | 211 | { |
213 | struct refclockproc * const pp = peer->procptr; | | 212 | struct refclockproc * const pp = peer->procptr; |
214 | struct shmunit * const up = emalloc_zero(sizeof(*up)); | | 213 | struct shmunit * const up = emalloc_zero(sizeof(*up)); |
215 | | | 214 | |
216 | pp->io.clock_recv = noentry; | | 215 | pp->io.clock_recv = noentry; |
217 | pp->io.srcclock = peer; | | 216 | pp->io.srcclock = peer; |
218 | pp->io.datalen = 0; | | 217 | pp->io.datalen = 0; |
219 | pp->io.fd = -1; | | 218 | pp->io.fd = -1; |
220 | | | 219 | |
221 | up->forall = (unit >= 2) && !(peer->ttl & SHM_MODE_PRIVATE); | | 220 | up->forall = (unit >= 2) && !(peer->ttl & SHM_MODE_PRIVATE); |
222 | | | 221 | |
223 | up->shm = getShmTime(unit, up->forall); | | 222 | up->shm = getShmTime(unit, up->forall); |
224 | | | 223 | |
225 | /* | | 224 | /* |
226 | * Initialize miscellaneous peer variables | | 225 | * Initialize miscellaneous peer variables |
227 | */ | | 226 | */ |
228 | memcpy((char *)&pp->refid, REFID, 4); | | 227 | memcpy((char *)&pp->refid, REFID, 4); |
229 | if (up->shm != 0) { | | 228 | if (up->shm != 0) { |
230 | pp->unitptr = up; | | 229 | pp->unitptr = up; |
231 | up->shm->precision = PRECISION; | | 230 | up->shm->precision = PRECISION; |
232 | peer->precision = up->shm->precision; | | 231 | peer->precision = up->shm->precision; |
233 | up->shm->valid = 0; | | 232 | up->shm->valid = 0; |
234 | up->shm->nsamples = NSAMPLES; | | 233 | up->shm->nsamples = NSAMPLES; |
235 | pp->clockdesc = DESCRIPTION; | | 234 | pp->clockdesc = DESCRIPTION; |
236 | /* items to be changed later in 'shm_control()': */ | | 235 | /* items to be changed later in 'shm_control()': */ |
237 | up->max_delay = 5; | | 236 | up->max_delay = 5; |
238 | up->max_delta = 4*3600; | | 237 | up->max_delta = 4*3600; |
239 | return 1; | | 238 | return 1; |
240 | } else { | | 239 | } else { |
241 | free(up); | | 240 | free(up); |
242 | pp->unitptr = NULL; | | 241 | pp->unitptr = NULL; |
243 | return 0; | | 242 | return 0; |
244 | } | | 243 | } |
245 | } | | 244 | } |
246 | | | 245 | |
247 | | | 246 | |
248 | /* | | 247 | /* |
249 | * shm_control - configure flag1/time2 params | | 248 | * shm_control - configure flag1/time2 params |
250 | * | | 249 | * |
251 | * These are not yet available during 'shm_start', so we have to do any | | 250 | * These are not yet available during 'shm_start', so we have to do any |
252 | * pre-computations we want to avoid during regular poll/timer callbacks | | 251 | * pre-computations we want to avoid during regular poll/timer callbacks |
253 | * in this callback. | | 252 | * in this callback. |
254 | */ | | 253 | */ |
255 | static void | | 254 | static void |
256 | shm_control( | | 255 | shm_control( |
257 | int unit, | | 256 | int unit, |
258 | const struct refclockstat * in_st, | | 257 | const struct refclockstat * in_st, |
259 | struct refclockstat * out_st, | | 258 | struct refclockstat * out_st, |
260 | struct peer * peer | | 259 | struct peer * peer |
261 | ) | | 260 | ) |
262 | { | | 261 | { |
263 | struct refclockproc * const pp = peer->procptr; | | 262 | struct refclockproc * const pp = peer->procptr; |
264 | struct shmunit * const up = pp->unitptr; | | 263 | struct shmunit * const up = pp->unitptr; |
265 | | | 264 | |
266 | UNUSED_ARG(unit); | | 265 | UNUSED_ARG(unit); |
267 | UNUSED_ARG(in_st); | | 266 | UNUSED_ARG(in_st); |
268 | UNUSED_ARG(out_st); | | 267 | UNUSED_ARG(out_st); |
269 | if (NULL == up) | | 268 | if (NULL == up) |
270 | return; | | 269 | return; |
271 | if (pp->sloppyclockflag & CLK_FLAG1) | | 270 | if (pp->sloppyclockflag & CLK_FLAG1) |
272 | up->max_delta = 0; | | 271 | up->max_delta = 0; |
273 | else if (pp->fudgetime2 < 1. || pp->fudgetime2 > 86400.) | | 272 | else if (pp->fudgetime2 < 1. || pp->fudgetime2 > 86400.) |
274 | up->max_delta = 4*3600; | | 273 | up->max_delta = 4*3600; |
275 | else | | 274 | else |
276 | up->max_delta = (time_t)floor(pp->fudgetime2 + 0.5); | | 275 | up->max_delta = (time_t)floor(pp->fudgetime2 + 0.5); |
277 | } | | 276 | } |
278 | | | 277 | |
279 | | | 278 | |
280 | /* | | 279 | /* |
281 | * shm_shutdown - shut down the clock | | 280 | * shm_shutdown - shut down the clock |
282 | */ | | 281 | */ |
283 | static void | | 282 | static void |
284 | shm_shutdown( | | 283 | shm_shutdown( |
285 | int unit, | | 284 | int unit, |
286 | struct peer *peer | | 285 | struct peer *peer |
287 | ) | | 286 | ) |
288 | { | | 287 | { |
289 | struct refclockproc * const pp = peer->procptr; | | 288 | struct refclockproc * const pp = peer->procptr; |
290 | struct shmunit * const up = pp->unitptr; | | 289 | struct shmunit * const up = pp->unitptr; |
291 | | | 290 | |
292 | UNUSED_ARG(unit); | | 291 | UNUSED_ARG(unit); |
293 | if (NULL == up) | | 292 | if (NULL == up) |
294 | return; | | 293 | return; |
295 | #ifndef SYS_WINNT | | 294 | #ifndef SYS_WINNT |
296 | | | 295 | |
297 | /* HMS: shmdt() wants char* or const void * */ | | 296 | /* HMS: shmdt() wants char* or const void * */ |
298 | (void)shmdt((char *)up->shm); | | 297 | (void)shmdt((char *)up->shm); |
299 | | | 298 | |
300 | #else | | 299 | #else |
301 | | | 300 | |
302 | UnmapViewOfFile(up->shm); | | 301 | UnmapViewOfFile(up->shm); |
303 | | | 302 | |
304 | #endif | | 303 | #endif |
305 | free(up); | | 304 | free(up); |
306 | } | | 305 | } |
307 | | | 306 | |
308 | | | 307 | |
309 | /* | | 308 | /* |
310 | * shm_poll - called by the transmit procedure | | 309 | * shm_poll - called by the transmit procedure |
311 | */ | | 310 | */ |
312 | static void | | 311 | static void |
313 | shm_poll( | | 312 | shm_poll( |
314 | int unit, | | 313 | int unit, |
315 | struct peer *peer | | 314 | struct peer *peer |
316 | ) | | 315 | ) |
317 | { | | 316 | { |
318 | struct refclockproc * const pp = peer->procptr; | | 317 | struct refclockproc * const pp = peer->procptr; |
319 | struct shmunit * const up = pp->unitptr; | | 318 | struct shmunit * const up = pp->unitptr; |
320 | int major_error; | | 319 | int major_error; |
321 | | | 320 | |
322 | pp->polls++; | | 321 | pp->polls++; |
323 | | | 322 | |
324 | /* get dominant reason if we have no samples at all */ | | 323 | /* get dominant reason if we have no samples at all */ |
325 | major_error = max(up->notready, up->bad); | | 324 | major_error = max(up->notready, up->bad); |
326 | major_error = max(major_error, up->clash); | | 325 | major_error = max(major_error, up->clash); |
327 | | | 326 | |
328 | /* | | 327 | /* |
329 | * Process median filter samples. If none received, see what | | 328 | * Process median filter samples. If none received, see what |
330 | * happened, tell the core and keep going. | | 329 | * happened, tell the core and keep going. |
331 | */ | | 330 | */ |
332 | if (pp->coderecv != pp->codeproc) { | | 331 | if (pp->coderecv != pp->codeproc) { |
333 | /* have some samples, everything OK */ | | 332 | /* have some samples, everything OK */ |
334 | pp->lastref = pp->lastrec; | | 333 | pp->lastref = pp->lastrec; |
335 | refclock_receive(peer); | | 334 | refclock_receive(peer); |
336 | } else if (NULL == up->shm) { /* is this possible at all? */ | | 335 | } else if (NULL == up->shm) { /* is this possible at all? */ |
337 | /* we're out of business without SHM access */ | | 336 | /* we're out of business without SHM access */ |
338 | refclock_report(peer, CEVNT_FAULT); | | 337 | refclock_report(peer, CEVNT_FAULT); |
339 | } else if (major_error == up->clash) { | | 338 | } else if (major_error == up->clash) { |
340 | /* too many collisions is like a bad signal */ | | 339 | /* too many collisions is like a bad signal */ |
341 | refclock_report(peer, CEVNT_PROP); | | 340 | refclock_report(peer, CEVNT_PROP); |
342 | } else if (major_error == up->bad) { | | 341 | } else if (major_error == up->bad) { |
343 | /* too much stale/bad/garbled data */ | | 342 | /* too much stale/bad/garbled data */ |
344 | refclock_report(peer, CEVNT_BADREPLY); | | 343 | refclock_report(peer, CEVNT_BADREPLY); |
345 | } else { | | 344 | } else { |
346 | /* in any other case assume it's just a timeout */ | | 345 | /* in any other case assume it's just a timeout */ |
347 | refclock_report(peer, CEVNT_TIMEOUT); | | 346 | refclock_report(peer, CEVNT_TIMEOUT); |
348 | } | | 347 | } |
349 | /* shm_clockstats() clears the tallies, so it must be last... */ | | 348 | /* shm_clockstats() clears the tallies, so it must be last... */ |
350 | shm_clockstats(unit, peer); | | 349 | shm_clockstats(unit, peer); |
351 | } | | 350 | } |
352 | | | 351 | |
353 | /* | | 352 | /* |
354 | * shm_timer - called onece every second. | | 353 | * shm_timer - called onece every second. |
355 | * | | 354 | * |
356 | * This tries to grab a sample from the SHM segment | | 355 | * This tries to grab a sample from the SHM segment |
357 | */ | | 356 | */ |
358 | static void | | 357 | static void |
359 | shm_timer( | | 358 | shm_timer( |
360 | int unit, | | 359 | int unit, |
361 | struct peer *peer | | 360 | struct peer *peer |
362 | ) | | 361 | ) |
363 | { | | 362 | { |
364 | struct refclockproc * const pp = peer->procptr; | | 363 | struct refclockproc * const pp = peer->procptr; |
365 | struct shmunit * const up = pp->unitptr; | | 364 | struct shmunit * const up = pp->unitptr; |
366 | | | 365 | |
367 | /* access order is important for lock-free SHM access; we | | 366 | /* access order is important for lock-free SHM access; we |
368 | ** enforce order by treating the whole structure volatile. | | 367 | ** enforce order by treating the whole structure volatile. |
369 | ** | | 368 | ** |
370 | ** IMPORTANT NOTE: This does not protect from reordering on CPU | | 369 | ** IMPORTANT NOTE: This does not protect from reordering on CPU |
371 | ** level, and it does nothing for cache consistency and | | 370 | ** level, and it does nothing for cache consistency and |
372 | ** visibility of changes by other cores. We need atomic and/or | | 371 | ** visibility of changes by other cores. We need atomic and/or |
373 | ** fence instructions for that. | | 372 | ** fence instructions for that. |
374 | */ | | 373 | */ |
375 | volatile struct shmTime *shm; | | 374 | volatile struct shmTime *shm; |
376 | | | 375 | |
377 | struct timespec tvr; | | 376 | struct timespec tvr; |
378 | struct timespec tvt; | | 377 | struct timespec tvt; |
379 | l_fp tsrcv; | | 378 | l_fp tsrcv; |
380 | l_fp tsref; | | 379 | l_fp tsref; |
381 | unsigned int c; | | 380 | unsigned int c; |
382 | unsigned int cns_new, rns_new; | | 381 | unsigned int cns_new, rns_new; |
383 | int cnt; | | 382 | int cnt; |
384 | | | 383 | |
385 | /* for formatting 'a_lastcode': */ | | 384 | /* for formatting 'a_lastcode': */ |
386 | struct calendar cd; | | 385 | struct calendar cd; |
387 | time_t tt, now; | | 386 | time_t tt, now; |
388 | vint64 ts; | | 387 | vint64 ts; |
389 | | | 388 | |
390 | /* | | 389 | /* |
391 | * This is the main routine. It snatches the time from the shm | | 390 | * This is the main routine. It snatches the time from the shm |
392 | * board and tacks on a local timestamp. | | 391 | * board and tacks on a local timestamp. |
393 | */ | | 392 | */ |
394 | up->ticks++; | | 393 | up->ticks++; |
395 | if ((shm = up->shm) == NULL) { | | 394 | if ((shm = up->shm) == NULL) { |
396 | /* try to map again - this may succeed if meanwhile some- | | 395 | /* try to map again - this may succeed if meanwhile some- |
397 | body has ipcrm'ed the old (unaccessible) shared mem segment */ | | 396 | body has ipcrm'ed the old (unaccessible) shared mem segment */ |
398 | shm = up->shm = getShmTime(unit, up->forall); | | 397 | shm = up->shm = getShmTime(unit, up->forall); |
399 | if (shm == NULL) { | | 398 | if (shm == NULL) { |
400 | DPRINTF(1, ("%s: no SHM segment\n", | | 399 | DPRINTF(1, ("%s: no SHM segment\n", |
401 | refnumtoa(&peer->srcadr))); | | 400 | refnumtoa(&peer->srcadr))); |
402 | return; | | 401 | return; |
403 | } | | 402 | } |
404 | } | | 403 | } |
405 | if ( ! shm->valid) { | | 404 | if ( ! shm->valid) { |
406 | DPRINTF(1, ("%s: SHM not ready\n", | | 405 | DPRINTF(1, ("%s: SHM not ready\n", |
407 | refnumtoa(&peer->srcadr))); | | 406 | refnumtoa(&peer->srcadr))); |
408 | up->notready++; | | 407 | up->notready++; |
409 | return; | | 408 | return; |
410 | } | | 409 | } |
411 | | | 410 | |
412 | switch (shm->mode) { | | 411 | switch (shm->mode) { |
413 | case 0: | | 412 | case 0: |
414 | tvr.tv_sec = shm->receiveTimeStampSec; | | 413 | tvr.tv_sec = shm->receiveTimeStampSec; |
415 | tvr.tv_nsec = shm->receiveTimeStampUSec * 1000; | | 414 | tvr.tv_nsec = shm->receiveTimeStampUSec * 1000; |
416 | rns_new = shm->receiveTimeStampNSec; | | 415 | rns_new = shm->receiveTimeStampNSec; |
417 | tvt.tv_sec = shm->clockTimeStampSec; | | 416 | tvt.tv_sec = shm->clockTimeStampSec; |
418 | tvt.tv_nsec = shm->clockTimeStampUSec * 1000; | | 417 | tvt.tv_nsec = shm->clockTimeStampUSec * 1000; |
419 | cns_new = shm->clockTimeStampNSec; | | 418 | cns_new = shm->clockTimeStampNSec; |
420 | | | 419 | |
421 | /* Since the following comparisons are between unsigned | | 420 | /* Since the following comparisons are between unsigned |
422 | ** variables they are always well defined, and any | | 421 | ** variables they are always well defined, and any |
423 | ** (signed) underflow will turn into very large unsigned | | 422 | ** (signed) underflow will turn into very large unsigned |
424 | ** values, well above the 1000 cutoff. | | 423 | ** values, well above the 1000 cutoff. |
425 | ** | | 424 | ** |
426 | ** Note: The usecs *must* be a *truncated* | | 425 | ** Note: The usecs *must* be a *truncated* |
427 | ** representation of the nsecs. This code will fail for | | 426 | ** representation of the nsecs. This code will fail for |
428 | ** *rounded* usecs, and the logic to deal with | | 427 | ** *rounded* usecs, and the logic to deal with |
429 | ** wrap-arounds in the presence of rounded values is | | 428 | ** wrap-arounds in the presence of rounded values is |
430 | ** much more convoluted. | | 429 | ** much more convoluted. |
431 | */ | | 430 | */ |
432 | if ( ((cns_new - (unsigned)tvt.tv_nsec) < 1000) | | 431 | if ( ((cns_new - (unsigned)tvt.tv_nsec) < 1000) |
433 | && ((rns_new - (unsigned)tvr.tv_nsec) < 1000)) { | | 432 | && ((rns_new - (unsigned)tvr.tv_nsec) < 1000)) { |
434 | tvt.tv_nsec = cns_new; | | 433 | tvt.tv_nsec = cns_new; |
435 | tvr.tv_nsec = rns_new; | | 434 | tvr.tv_nsec = rns_new; |
436 | } | | 435 | } |
437 | /* At this point tvr and tvt contains valid ns-level | | 436 | /* At this point tvr and tvt contains valid ns-level |
438 | ** timestamps, possibly generated by extending the old | | 437 | ** timestamps, possibly generated by extending the old |
439 | ** us-level timestamps | | 438 | ** us-level timestamps |
440 | */ | | 439 | */ |
441 | DPRINTF(2, ("%s: SHM type 0 sample\n", | | 440 | DPRINTF(2, ("%s: SHM type 0 sample\n", |
442 | refnumtoa(&peer->srcadr))); | | 441 | refnumtoa(&peer->srcadr))); |
443 | break; | | 442 | break; |
444 | | | 443 | |
445 | case 1: | | 444 | case 1: |
446 | cnt = shm->count; | | 445 | cnt = shm->count; |
447 | | | 446 | |
448 | tvr.tv_sec = shm->receiveTimeStampSec; | | 447 | tvr.tv_sec = shm->receiveTimeStampSec; |
449 | tvr.tv_nsec = shm->receiveTimeStampUSec * 1000; | | 448 | tvr.tv_nsec = shm->receiveTimeStampUSec * 1000; |
450 | rns_new = shm->receiveTimeStampNSec; | | 449 | rns_new = shm->receiveTimeStampNSec; |
451 | tvt.tv_sec = shm->clockTimeStampSec; | | 450 | tvt.tv_sec = shm->clockTimeStampSec; |
452 | tvt.tv_nsec = shm->clockTimeStampUSec * 1000; | | 451 | tvt.tv_nsec = shm->clockTimeStampUSec * 1000; |
453 | cns_new = shm->clockTimeStampNSec; | | 452 | cns_new = shm->clockTimeStampNSec; |
454 | if (cnt != shm->count) { | | 453 | if (cnt != shm->count) { |
455 | DPRINTF(1, ("%s: type 1 access clash\n", | | 454 | DPRINTF(1, ("%s: type 1 access clash\n", |
456 | refnumtoa(&peer->srcadr))); | | 455 | refnumtoa(&peer->srcadr))); |
457 | msyslog (LOG_NOTICE, "SHM: access clash in shared memory"); | | 456 | msyslog (LOG_NOTICE, "SHM: access clash in shared memory"); |
458 | up->clash++; | | 457 | up->clash++; |
459 | return; | | 458 | return; |
460 | } | | 459 | } |
461 | | | 460 | |
462 | /* See the case above for an explanation of the | | 461 | /* See the case above for an explanation of the |
463 | ** following test. | | 462 | ** following test. |
464 | */ | | 463 | */ |
465 | if ( ((cns_new - (unsigned)tvt.tv_nsec) < 1000) | | 464 | if ( ((cns_new - (unsigned)tvt.tv_nsec) < 1000) |
466 | && ((rns_new - (unsigned)tvr.tv_nsec) < 1000)) { | | 465 | && ((rns_new - (unsigned)tvr.tv_nsec) < 1000)) { |
467 | tvt.tv_nsec = cns_new; | | 466 | tvt.tv_nsec = cns_new; |
468 | tvr.tv_nsec = rns_new; | | 467 | tvr.tv_nsec = rns_new; |
469 | } | | 468 | } |
470 | /* At this point tvr and tvt contains valid ns-level | | 469 | /* At this point tvr and tvt contains valid ns-level |
471 | ** timestamps, possibly generated by extending the old | | 470 | ** timestamps, possibly generated by extending the old |
472 | ** us-level timestamps | | 471 | ** us-level timestamps |
473 | */ | | 472 | */ |
474 | DPRINTF(2, ("%s: SHM type 1 sample\n", | | 473 | DPRINTF(2, ("%s: SHM type 1 sample\n", |
475 | refnumtoa(&peer->srcadr))); | | 474 | refnumtoa(&peer->srcadr))); |
476 | break; | | 475 | break; |
477 | | | 476 | |
478 | default: | | 477 | default: |
479 | DPRINTF(1, ("%s: SHM type blooper, mode=%d\n", | | 478 | DPRINTF(1, ("%s: SHM type blooper, mode=%d\n", |
480 | refnumtoa(&peer->srcadr), shm->mode)); | | 479 | refnumtoa(&peer->srcadr), shm->mode)); |
481 | up->bad++; | | 480 | up->bad++; |
482 | msyslog (LOG_ERR, "SHM: bad mode found in shared memory: %d", | | 481 | msyslog (LOG_ERR, "SHM: bad mode found in shared memory: %d", |
483 | shm->mode); | | 482 | shm->mode); |
484 | return; | | 483 | return; |
485 | } | | 484 | } |
486 | shm->valid = 0; | | 485 | shm->valid = 0; |
487 | | | 486 | |
488 | /* format the last time code in human-readable form into | | 487 | /* format the last time code in human-readable form into |
489 | * 'pp->a_lastcode'. Someone claimed: "NetBSD has incompatible | | 488 | * 'pp->a_lastcode'. Someone claimed: "NetBSD has incompatible |
490 | * tv_sec". I can't find a base for this claim, but we can work | | 489 | * tv_sec". I can't find a base for this claim, but we can work |
491 | * around that potential problem. BTW, simply casting a pointer | | 490 | * around that potential problem. BTW, simply casting a pointer |
492 | * is a receipe for disaster on some architectures. | | 491 | * is a receipe for disaster on some architectures. |
493 | */ | | 492 | */ |
494 | tt = (time_t)tvt.tv_sec; | | 493 | tt = (time_t)tvt.tv_sec; |
495 | ts = time_to_vint64(&tt); | | 494 | ts = time_to_vint64(&tt); |
496 | ntpcal_time_to_date(&cd, &ts); | | 495 | ntpcal_time_to_date(&cd, &ts); |
497 | | | 496 | |
498 | /* add ntpq -c cv timecode in ISO 8601 format */ | | 497 | /* add ntpq -c cv timecode in ISO 8601 format */ |
499 | c = snprintf(pp->a_lastcode, sizeof(pp->a_lastcode), | | 498 | c = snprintf(pp->a_lastcode, sizeof(pp->a_lastcode), |
500 | "%04u-%02u-%02uT%02u:%02u:%02u.%09ldZ", | | 499 | "%04u-%02u-%02uT%02u:%02u:%02u.%09ldZ", |
501 | cd.year, cd.month, cd.monthday, | | 500 | cd.year, cd.month, cd.monthday, |
502 | cd.hour, cd.minute, cd.second, | | 501 | cd.hour, cd.minute, cd.second, |
503 | (long)tvt.tv_nsec); | | 502 | (long)tvt.tv_nsec); |
504 | pp->lencode = (c < sizeof(pp->a_lastcode)) ? c : 0; | | 503 | pp->lencode = (c < sizeof(pp->a_lastcode)) ? c : 0; |
505 | | | 504 | |
506 | /* check 1: age control of local time stamp */ | | 505 | /* check 1: age control of local time stamp */ |
507 | time(&now); | | 506 | time(&now); |
508 | tt = now - tvr.tv_sec; | | 507 | tt = now - tvr.tv_sec; |
509 | if (tt < 0 || tt > up->max_delay) { | | 508 | if (tt < 0 || tt > up->max_delay) { |
510 | DPRINTF(1, ("%s:SHM stale/bad receive time, delay=%llds\n", | | 509 | DPRINTF(1, ("%s:SHM stale/bad receive time, delay=%llds\n", |
511 | refnumtoa(&peer->srcadr), (long long)tt)); | | 510 | refnumtoa(&peer->srcadr), (long long)tt)); |
512 | up->bad++; | | 511 | up->bad++; |
513 | msyslog (LOG_ERR, "SHM: stale/bad receive time, delay=%llds", | | 512 | msyslog (LOG_ERR, "SHM: stale/bad receive time, delay=%llds", |
514 | (long long)tt); | | 513 | (long long)tt); |
515 | return; | | 514 | return; |
516 | } | | 515 | } |
517 | | | 516 | |
518 | /* check 2: delta check */ | | 517 | /* check 2: delta check */ |
519 | tt = tvr.tv_sec - tvt.tv_sec - (tvr.tv_nsec < tvt.tv_nsec); | | 518 | tt = tvr.tv_sec - tvt.tv_sec - (tvr.tv_nsec < tvt.tv_nsec); |
520 | if (tt < 0) | | 519 | if (tt < 0) |
521 | tt = -tt; | | 520 | tt = -tt; |
522 | if (up->max_delta > 0 && tt > up->max_delta) { | | 521 | if (up->max_delta > 0 && tt > up->max_delta) { |
523 | DPRINTF(1, ("%s: SHM diff limit exceeded, delta=%llds\n", | | 522 | DPRINTF(1, ("%s: SHM diff limit exceeded, delta=%llds\n", |
524 | refnumtoa(&peer->srcadr), (long long)tt)); | | 523 | refnumtoa(&peer->srcadr), (long long)tt)); |
525 | up->bad++; | | 524 | up->bad++; |
526 | msyslog (LOG_ERR, "SHM: difference limit exceeded, delta=%llds\n", | | 525 | msyslog (LOG_ERR, "SHM: difference limit exceeded, delta=%llds\n", |
527 | (long long)tt); | | 526 | (long long)tt); |
528 | return; | | 527 | return; |
529 | } | | 528 | } |
530 | | | 529 | |
531 | /* if we really made it to this point... we're winners! */ | | 530 | /* if we really made it to this point... we're winners! */ |
532 | DPRINTF(2, ("%s: SHM feeding data\n", | | 531 | DPRINTF(2, ("%s: SHM feeding data\n", |
533 | refnumtoa(&peer->srcadr))); | | 532 | refnumtoa(&peer->srcadr))); |
534 | tsrcv = tspec_stamp_to_lfp(tvr); | | 533 | tsrcv = tspec_stamp_to_lfp(tvr); |
535 | tsref = tspec_stamp_to_lfp(tvt); | | 534 | tsref = tspec_stamp_to_lfp(tvt); |
536 | pp->leap = shm->leap; | | 535 | pp->leap = shm->leap; |
537 | peer->precision = shm->precision; | | 536 | peer->precision = shm->precision; |
538 | refclock_process_offset(pp, tsref, tsrcv, pp->fudgetime1); | | 537 | refclock_process_offset(pp, tsref, tsrcv, pp->fudgetime1); |
539 | up->good++; | | 538 | up->good++; |
540 | } | | 539 | } |
541 | | | 540 | |
542 | /* | | 541 | /* |
543 | * shm_clockstats - dump and reset counters | | 542 | * shm_clockstats - dump and reset counters |
544 | */ | | 543 | */ |
545 | static void shm_clockstats( | | 544 | static void shm_clockstats( |
546 | int unit, | | 545 | int unit, |
547 | struct peer *peer | | 546 | struct peer *peer |
548 | ) | | 547 | ) |
549 | { | | 548 | { |
550 | struct refclockproc * const pp = peer->procptr; | | 549 | struct refclockproc * const pp = peer->procptr; |
551 | struct shmunit * const up = pp->unitptr; | | 550 | struct shmunit * const up = pp->unitptr; |
552 | | | 551 | |
553 | UNUSED_ARG(unit); | | 552 | UNUSED_ARG(unit); |
554 | if (pp->sloppyclockflag & CLK_FLAG4) { | | 553 | if (pp->sloppyclockflag & CLK_FLAG4) { |
555 | mprintf_clock_stats( | | 554 | mprintf_clock_stats( |
556 | &peer->srcadr, "%3d %3d %3d %3d %3d", | | 555 | &peer->srcadr, "%3d %3d %3d %3d %3d", |
557 | up->ticks, up->good, up->notready, | | 556 | up->ticks, up->good, up->notready, |
558 | up->bad, up->clash); | | 557 | up->bad, up->clash); |
559 | } | | 558 | } |
560 | up->ticks = up->good = up->notready = up->bad = up->clash = 0; | | 559 | up->ticks = up->good = up->notready = up->bad = up->clash = 0; |
561 | } | | 560 | } |
562 | | | 561 | |
563 | #else | | 562 | #else |
564 | NONEMPTY_TRANSLATION_UNIT | | 563 | NONEMPTY_TRANSLATION_UNIT |
565 | #endif /* REFCLOCK */ | | 564 | #endif /* REFCLOCK */ |