struct shmunit *up;
struct shmTime *shm;
+ struct timespec tvr;
+ struct timespec tvt;
+ unsigned int c;
+ int ok = 1;
+ unsigned cns_new, rns_new;
+ int cnt;
+
+ /* for formatting 'a_lastcode': */
+ struct calendar cd;
+ time_t tt;
+ vint64 ts;
+
/*
* This is the main routine. It snatches the time from the shm
* board and tacks on a local timestamp.
refclock_report(peer, CEVNT_FAULT);
return 0;
}
- if (shm->valid) {
- struct timespec tvr;
- struct timespec tvt;
- struct tm *t;
- char timestr[20]; /* "%Y-%m-%dT%H:%M:%S" + 1 */
- int c;
- int ok = 1;
- unsigned cns_new, rns_new;
- int cnt;
-
- tvr.tv_sec = 0;
- tvr.tv_nsec = 0;
- tvt.tv_sec = 0;
- tvt.tv_nsec = 0;
- switch (shm->mode) {
- case 0:
- tvr.tv_sec = shm->receiveTimeStampSec;
- tvr.tv_nsec = shm->receiveTimeStampUSec * 1000;
- rns_new = shm->receiveTimeStampNSec;
- tvt.tv_sec = shm->clockTimeStampSec;
- tvt.tv_nsec = shm->clockTimeStampUSec * 1000;
- cns_new = shm->clockTimeStampNSec;
-
- /* Since these comparisons are between unsigned
- ** variables they are always well defined, and any
- ** (signed) underflow will turn into very large
- ** unsigned values, well above the 1000 cutoff
- */
- if ( ((cns_new - (unsigned)tvt.tv_nsec) < 1000)
- && ((rns_new - (unsigned)tvr.tv_nsec) < 1000)) {
- tvt.tv_nsec = cns_new;
- tvr.tv_nsec = rns_new;
- }
- // At this point tvr and tvt contains valid ns-level
- // timestamps, possibly generated by extending the
- // old us-level timestamps
-
- break;
-
- case 1:
- cnt = shm->count;
-
- tvr.tv_sec = shm->receiveTimeStampSec;
- tvr.tv_nsec = shm->receiveTimeStampUSec * 1000;
- rns_new = shm->receiveTimeStampNSec;
- tvt.tv_sec = shm->clockTimeStampSec;
- tvt.tv_nsec = shm->clockTimeStampUSec * 1000;
- cns_new = shm->clockTimeStampNSec;
- ok = (cnt == shm->count);
-
- /* Since these comparisons are between unsigned
- ** variables they are always well defined, and any
- ** (signed) underflow will turn into very large
- ** unsigned values, well above the 1000 cutoff
- */
- if ( ((cns_new - (unsigned)tvt.tv_nsec) < 1000)
- && ((rns_new - (unsigned)tvr.tv_nsec) < 1000)) {
- tvt.tv_nsec = cns_new;
- tvr.tv_nsec = rns_new;
- }
- // At this point tvr and tvt contains valid ns-level
- // timestamps, possibly generated by extending the
- // old us-level timestamps
-
- break;
-
- default:
- msyslog (LOG_ERR, "SHM: bad mode found in shared memory: %d",shm->mode);
- return 0;
- }
-
- /* XXX NetBSD has incompatible tv_sec */
- t = gmtime((const time_t *)&tvt.tv_sec);
-
- /* add ntpq -c cv timecode in ISO 8601 format */
- strftime(timestr, sizeof(timestr), "%Y-%m-%dT%H:%M:%S", t);
- c = snprintf(pp->a_lastcode, sizeof(pp->a_lastcode),
- "%s.%09ldZ", timestr, (long)tvt.tv_nsec);
- pp->lencode = (c < sizeof(pp->a_lastcode))
- ? c
- : 0;
-
- shm->valid = 0;
- if (ok) {
- pp->lastrec = tspec_stamp_to_lfp(tvr);
- pp->polls++;
- pp->day = t->tm_yday+1;
- pp->hour = t->tm_hour;
- pp->minute = t->tm_min;
- pp->second = t->tm_sec;
- pp->nsec = tvt.tv_nsec;
- peer->precision = shm->precision;
- pp->leap = shm->leap;
- } else {
- refclock_report(peer, CEVNT_FAULT);
- msyslog (LOG_NOTICE, "SHM: access clash in shared memory");
- up->clash++;
- return 0;
- }
- } else {
- refclock_report(peer, CEVNT_TIMEOUT);
+ if ( ! shm->valid) {
up->notready++;
return 0;
}
- if (!refclock_process(pp)) {
- refclock_report(peer, CEVNT_BADTIME);
+
+ switch (shm->mode) {
+ case 0:
+ tvr.tv_sec = shm->receiveTimeStampSec;
+ tvr.tv_nsec = shm->receiveTimeStampUSec * 1000;
+ rns_new = shm->receiveTimeStampNSec;
+ tvt.tv_sec = shm->clockTimeStampSec;
+ tvt.tv_nsec = shm->clockTimeStampUSec * 1000;
+ cns_new = shm->clockTimeStampNSec;
+
+ /* Since the following comparisons are between unsigned
+ ** variables they are always well defined, and any
+ ** (signed) underflow will turn into very large unsigned
+ ** values, well above the 1000 cutoff.
+ **
+ ** Note: The usecs *must* be a *truncated*
+ ** representation of the nsecs. This code will fail for
+ ** *rounded* usecs, and the logic to deal with
+ ** wrap-arounds in the presence of rounded values is
+ ** much more convoluted.
+ */
+ if ( ((cns_new - (unsigned)tvt.tv_nsec) < 1000)
+ && ((rns_new - (unsigned)tvr.tv_nsec) < 1000)) {
+ tvt.tv_nsec = cns_new;
+ tvr.tv_nsec = rns_new;
+ }
+ /* At this point tvr and tvt contains valid ns-level
+ ** timestamps, possibly generated by extending the old
+ ** us-level timestamps
+ */
+ break;
+
+ case 1:
+ cnt = shm->count;
+
+ tvr.tv_sec = shm->receiveTimeStampSec;
+ tvr.tv_nsec = shm->receiveTimeStampUSec * 1000;
+ rns_new = shm->receiveTimeStampNSec;
+ tvt.tv_sec = shm->clockTimeStampSec;
+ tvt.tv_nsec = shm->clockTimeStampUSec * 1000;
+ cns_new = shm->clockTimeStampNSec;
+ ok = (cnt == shm->count);
+
+ /* See the case above for an explanation of the
+ ** following test.
+ */
+ if ( ((cns_new - (unsigned)tvt.tv_nsec) < 1000)
+ && ((rns_new - (unsigned)tvr.tv_nsec) < 1000)) {
+ tvt.tv_nsec = cns_new;
+ tvr.tv_nsec = rns_new;
+ }
+ /* At this point tvr and tvt contains valid ns-level
+ ** timestamps, possibly generated by extending the old
+ ** us-level timestamps
+ */
+ break;
+
+ default:
up->bad++;
+ msyslog (LOG_ERR, "SHM: bad mode found in shared memory: %d",
+ shm->mode);
+ return 0;
+ }
+
+ /* format the last time code in human-readable form into
+ * 'pp->a_lastcode'. Someone claimed: "NetBSD has incompatible
+ * tv_sec". I can't find a base for this claim, but we can work
+ * around that potential problem. BTW, simply casting a pointer
+ * is a receipe for desaster on some architectures.
+ */
+ tt = (time_t)tvt.tv_sec;
+ ts = time_to_vint64(&tt);
+ ntpcal_time_to_date(&cd, &ts);
+
+ /* add ntpq -c cv timecode in ISO 8601 format */
+ c = snprintf(pp->a_lastcode, sizeof(pp->a_lastcode),
+ "%04u-%02u-%02uT%02u:%02u:%02u.%09ldZ",
+ cd.year, cd.month, cd.monthday,
+ cd.hour, cd.minute, cd.second,
+ (long)tvt.tv_nsec);
+ pp->lencode = (c < sizeof(pp->a_lastcode)) ? c : 0;
+
+ shm->valid = 0;
+ if (ok) {
+ l_fp tsrcv = tspec_stamp_to_lfp(tvr);
+ l_fp tsref = tspec_stamp_to_lfp(tvt);
+ pp->polls++;
+ pp->leap = shm->leap;
+ peer->precision = shm->precision;
+ refclock_process_offset(pp, tsref, tsrcv, pp->fudgetime1);
+ } else {
+ refclock_report(peer, CEVNT_FAULT);
+ msyslog (LOG_NOTICE, "SHM: access clash in shared memory");
+ up->clash++;
return 0;
}
up->good++;