8 #define SEC 1000000000LL
10 #define HOUR (60LL*MIN)
11 #define DAY (24LL*HOUR)
20 HZAvgSecs= 3*60, /* target averaging period for frequency in seconds */
21 MinSampleSecs= 60, /* minimum sampling time in seconds */
25 char *dir = "/tmp"; /* directory sample files live in */
26 char *logfile = "timesync";
35 int gmtdelta; /* rtc+gmtdelta = gmt */
40 vlong mydisp, rootdisp;
41 vlong mydelay, rootdelay;
48 /* list of time samples */
49 typedef struct Sample Sample;
59 typedef struct NTPpkt NTPpkt;
70 uchar origts[8]; /* departed client */
71 uchar recvts[8]; /* arrived at server */
72 uchar xmitts[8]; /* departed server */
78 typedef struct NTPserver NTPserver;
91 NTPserver *ntpservers;
95 NTPSIZE= 48, /* basic ntp packet */
96 NTPDIGESTSIZE= 20, /* key and digest */
99 /* error bound of last sample */
102 static void addntpserver(char *name);
103 static int adjustperiod(vlong diff, vlong accuracy, int secs);
104 static void background(void);
105 static int caperror(vlong dhz, int tsecs, vlong taccuracy);
106 static long fstime(void);
107 static int gettime(vlong *nsec, uvlong *ticks, uvlong *hz); /* returns time, ticks, hz */
108 static int getclockprecision(vlong);
109 static vlong gpssample(void);
110 static void hnputts(void *p, vlong nsec);
111 static void hnputts(void *p, vlong nsec);
112 static void inittime(void);
113 static vlong nhgetts(void *p);
114 static vlong nhgetts(void *p);
115 static void ntpserver(char*);
116 static vlong ntpsample(void);
117 static int ntptimediff(NTPserver *ns);
118 static int openfreqfile(void);
119 static vlong readfreqfile(int fd, vlong ohz, vlong minhz, vlong maxhz);
120 static long rtctime(void);
121 static vlong sample(long (*get)(void));
122 static void setpriority(void);
123 static void setrootid(char *d);
124 static void settime(vlong now, uvlong hz, vlong delta, int n); /* set time, hz, delta, period */
125 static vlong utcsample(void);
126 static uvlong vabs(vlong);
127 static uvlong whatisthefrequencykenneth(uvlong hz, uvlong minhz, uvlong maxhz,
128 vlong dt, vlong ticks, vlong period);
129 static void writefreqfile(int fd, vlong hz, int secs, vlong diff);
131 // ((1970-1900)*365 + 17 /*leap days*/)*24*60*60
132 #define EPOCHDIFF 2208988800UL
137 fprint(2, "usage: %s [-a accuracy][-d dir][-I rootid][-s net]"
138 "[-S stratum][-DfGilLnrU] timesource ...\n", argv0);
143 main(int argc, char **argv)
145 int i, t, fd, nservenet;
146 int secs; /* sampling period */
147 int tsecs; /* temporary sampling period */
148 uvlong hz, minhz, maxhz, period, nhz;
149 vlong diff, accuracy, taccuracy;
151 Sample *s, *x, *first, **l;
154 type = Fs; /* by default, sync with the file system */
156 accuracy = 1000000LL; /* default accuracy is 1 millisecond */
158 tsecs = secs = MinSampleSecs;
163 accuracy = strtoll(EARGF(usage()), 0, 0); /* specified in ns */
165 sysfatal("bad accuracy specified");
168 dir = EARGF(usage());
185 Rootid = EARGF(usage());
192 * Assume time source in local time rather than GMT.
193 * Calculate difference so that rtctime can return GMT.
194 * This is useful with the rtc on PC's that run Windows
195 * since Windows keeps the local time in the rtc.
202 * if the years are different, we're at most a day off,
205 if(tl.year < tg.year){
207 tg.yday = tl.yday + 1;
208 }else if(tl.year > tg.year){
212 assert(tl.year == tg.year);
218 gmtdelta = tg.sec+60*(tg.min+60*(tg.hour+tg.yday*24));
220 assert(abs(gmtdelta) <= 24*60*60);
234 if(nservenet >= nelem(servenet))
235 sysfatal("too many networks to serve on");
236 servenet[nservenet++] = EARGF(usage());
239 stratum = strtoll(EARGF(usage()), 0, 0);
245 fmtinstall('E', eipfmt);
246 fmtinstall('I', eipfmt);
247 fmtinstall('V', eipfmt);
248 sysid = getenv("sysname");
250 /* detach from the current namespace */
257 timeserver = argv[0];
259 sysfatal("bad time source");
263 timeserver = argv[0];
265 timeserver = "/mnt/gps/time";
269 timeserver = argv[0];
271 timeserver = "/srv/boot";
275 for(i = 0; i < argc; i++)
276 addntpserver(argv[i]);
278 addntpserver("$ntp");
284 /* figure out our time interface and initial frequency */
289 myprec = getclockprecision(hz);
291 /* convert the accuracy from nanoseconds to ticks */
292 taccuracy = hz*accuracy/SEC;
299 fd = open(timeserver, ORDWR);
301 sysfatal("opening %s: %r", timeserver);
302 if(amount(fd, "/n/boot", MREPL, "") < 0)
303 sysfatal("mounting %s: %r", timeserver);
307 bind("#r", "/dev", MAFTER);
308 if(access("/dev/rtc", AREAD) < 0)
309 sysfatal("accessing /dev/rtc: %r");
312 fd = open(timeserver, OREAD);
314 sysfatal("opening %s: %r", timeserver);
318 fd = open(timeserver, OREAD);
320 sysfatal("opening %s: %r", timeserver);
326 * start a local ntp server(s)
328 for(i = 0; i < nservenet; i++)
329 switch(rfork(RFPROC|RFFDG|RFMEM|RFNOWAIT)){
331 sysfatal("forking: %r");
333 ntpserver(servenet[i]);
337 /* get the last known frequency from the file */
339 hz = readfreqfile(fd, hz, minhz, maxhz);
342 * this is the main loop. it gets a sample, adjusts the
343 * clock and computes a sleep period until the next loop.
344 * we balance frequency drift against the length of the
345 * period to avoid blowing the accuracy limit.
349 avgerr = accuracy >> 1;
350 for(;; background(), sleep(tsecs*1000)){
351 s = mallocz(sizeof *s, 1);
354 /* get times for this sample */
358 s->stime = sample(fstime);
361 s->stime = sample(rtctime);
364 s->stime = utcsample();
367 syslog(0, logfile, "no sample");
378 syslog(0, logfile, "no sample");
389 syslog(0, logfile, "no sample");
397 /* use fastest method to read local clock and ticks */
398 gettime(&s->ltime, &s->ticks, 0);
399 if(type == Ntp || type == Gps)
400 s->stime = s->ltime + diff;
402 /* if the sample was bad, ignore it */
408 /* reset local time */
409 diff = s->stime - s->ltime;
410 if(diff > 10*SEC || diff < -10*SEC){
411 /* we're way off, just set the time */
412 secs = MinSampleSecs;
413 settime(s->stime, 0, 0, 0);
415 /* keep a running average of the error. */
416 avgerr = (avgerr>>1) + (vabs(diff)>>1);
419 * the time to next sample depends on how good or
422 tsecs = secs = adjustperiod(diff, accuracy, secs);
425 * work off the fixed difference. This is done
426 * by adding a ramp to the clock. Each 100th of a
427 * second (or so) the kernel will add diff/(4*secs*100)
428 * to the clock. we only do 1/4 of the difference per
429 * period to dampen any measurement noise.
431 * any difference greater than ε we work off during the
436 settime(-1, 0, diff-((3*ε)/4), secs);
438 settime(-1, 0, diff+((3*ε)/4), secs);
440 settime(-1, 0, diff, 4*secs);
444 fprint(2, "δ %lld avgδ %lld f %lld\n", diff, avgerr, hz);
446 /* dump old samples (keep at least one) */
448 if(first->next == nil)
450 if(s->stime - first->next->stime < DAY)
458 * The sampling error is limited by the total error. If
459 * we make sure the sampling period is at least 16 million
460 * times the average error, we should calculate a frequency
461 * with on average a 1e-7 error.
463 * So that big hz changes don't blow our accuracy requirement,
464 * we shorten the period to make sure that δhz*secs will be
465 * greater than the accuracy limit.
467 period = avgerr << 24;
468 for(x = first; x != nil; x = x->next)
469 if(s->stime - x->stime < period ||
470 x->next == nil || s->stime - x->next->stime < period)
473 nhz = whatisthefrequencykenneth(
478 tsecs = caperror(vabs(nhz-hz), tsecs, taccuracy);
480 writefreqfile(fd, hz, (s->stime - x->stime)/SEC, diff);
483 /* add current sample to list. */
488 syslog(0, logfile, "δ %lld avgδ %lld hz %lld",
494 * adjust the sampling period with some histeresis
497 adjustperiod(vlong diff, vlong accuracy, int secs)
501 absdiff = vabs(diff);
503 if(absdiff < (accuracy>>1))
505 else if(absdiff > accuracy)
509 if(secs < MinSampleSecs)
510 secs = MinSampleSecs;
515 * adjust the frequency
518 whatisthefrequencykenneth(uvlong hz, uvlong minhz, uvlong maxhz, vlong dt,
519 vlong ticks, vlong period)
522 static mpint *mpdt, *mpticks, *mphz, *mpbillion;
525 if(dt <= 0 || ticks <= 0)
530 mpbillion = uvtomp(SEC, nil);
533 /* hz = (ticks*SEC)/dt */
534 mpdt = vtomp(dt, mpdt);
535 mpticks = vtomp(ticks, mpticks);
536 mpmul(mpticks, mpbillion, mpticks);
537 mpdiv(mpticks, mpdt, mphz, nil);
541 if(hz < minhz || hz > maxhz)
544 /* damp the change if we're shorter than the target period */
546 hz = (12ULL*ohz + 4ULL*hz)/16ULL;
548 settime(-1, hz, 0, 0);
553 * We may be changing the frequency to match a bad measurement
554 * or to match a condition no longer in effect. To make sure
555 * that this doesn't blow our error budget over the next measurement
556 * period, shorten the period to make sure that δhz*secs will be
557 * less than the accuracy limit. Here taccuracy is accuracy converted
558 * from nanoseconds to ticks.
561 caperror(vlong dhz, int tsecs, vlong taccuracy)
563 if(dhz*tsecs <= taccuracy)
567 fprint(2, "δhz %lld tsecs %d tacc %lld\n", dhz, tsecs, taccuracy);
569 tsecs = taccuracy/dhz;
570 if(tsecs < MinSampleSecs)
571 tsecs = MinSampleSecs;
588 int fastclockfd = -1;
601 if(access("/dev/time", 0) < 0)
602 bind("#c", "/dev", MAFTER);
603 if(access("/dev/rtc", 0) < 0)
604 bind("#r", "/dev", MAFTER);
606 /* figure out what interface we have */
608 bintimefd = open("/dev/bintime", mode);
612 nsecfd = open("/dev/nsec", mode);
614 sysfatal("opening /dev/nsec");
615 fastclockfd = open("/dev/fastclock", mode);
617 sysfatal("opening /dev/fastclock");
618 timingfd = open("/dev/timing", OREAD);
625 * convert binary numbers from/to kernel
627 static uvlong uvorder = 0x0001020304050607ULL;
630 be2vlong(vlong *to, uchar *f)
636 o = (uchar*)&uvorder;
637 for(i = 0; i < sizeof(vlong); i++)
639 return f+sizeof(vlong);
643 vlong2be(uchar *t, vlong from)
649 o = (uchar*)&uvorder;
650 for(i = 0; i < sizeof(vlong); i++)
652 return t+sizeof(vlong);
655 static long order = 0x00010203;
658 be2long(long *to, uchar *f)
665 for(i = 0; i < sizeof(long); i++)
667 return f+sizeof(long);
671 long2be(uchar *t, long from)
678 for(i = 0; i < sizeof(long); i++)
680 return t+sizeof(long);
684 * read ticks and local time in nanoseconds
687 gettime(vlong *nsec, uvlong *ticks, uvlong *hz)
700 i = read(bintimefd, ub, n);
708 be2vlong((vlong*)ticks, p);
711 be2vlong((vlong*)hz, p);
717 i = read(timingfd, ub, n);
725 be2vlong((vlong*)ticks, p);
727 seek(fastclockfd, 0, 0);
728 n = read(fastclockfd, b, sizeof(b)-1);
732 *hz = strtoll(b+24, 0, 0);
738 n = read(nsecfd, b, sizeof(b)-1);
742 *nsec = strtoll(b, 0, 0);
745 seek(fastclockfd, 0, 0);
746 n = read(fastclockfd, b, sizeof(b)-1);
750 *ticks = strtoll(b, 0, 0);
753 seek(fastclockfd, 0, 0);
754 n = read(fastclockfd, b, sizeof(b)-1);
758 *hz = strtoll(b+24, 0, 0);
766 settime(vlong now, uvlong hz, vlong delta, int n)
768 uchar b[1+sizeof(vlong)+sizeof(long)], *p;
771 fprint(2, "settime(now=%lld, hz=%llud, delta=%lld, period=%d)\n",
780 p = vlong2be(p, now);
781 if(write(bintimefd, b, p-b) < 0)
782 sysfatal("writing /dev/bintime: %r");
787 p = vlong2be(p, delta);
789 if(write(bintimefd, b, p-b) < 0)
790 sysfatal("writing /dev/bintime: %r");
796 if(write(bintimefd, b, p-b) < 0)
797 sysfatal("writing /dev/bintime: %r");
803 if(now >= 0 || delta != 0){
804 if(fprint(nsecfd, "%lld %lld %d", now, delta, n) < 0)
805 sysfatal("writing /dev/nsec: %r");
808 seek(fastclockfd, 0, 0);
809 if(fprint(fastclockfd, "%lld", hz) < 0)
810 sysfatal("writing /dev/fastclock: %r");
816 * set priority high and wire process to a processor
824 sprint(buf, "/proc/%d/ctl", getpid());
825 fd = open(buf, ORDWR);
827 fprint(2, "can't set priority\n");
830 if(fprint(fd, "pri 100") < 0)
831 fprint(2, "can't set priority\n");
832 if(fprint(fd, "wired 2") < 0)
833 fprint(2, "can't wire process\n");
837 /* convert to ntp timestamps */
839 hnputts(void *p, vlong nsec)
846 /* zero is a special case */
852 tsl = (nsec<<32)/SEC;
853 hnputl(a, tsh+EPOCHDIFF);
857 /* convert from ntp timestamps */
870 nsec += (tsh - EPOCHDIFF)*SEC;
874 /* convert to ntp 32 bit fixed point */
876 hnputfp(void *p, vlong nsec)
883 fp = nsec/(SEC/((vlong)(1<<16)));
887 /* convert from ntp fixed point to nanosecs */
897 nsec = ((vlong)fp)*(SEC/((vlong)(1<<16)));
901 /* get network address of the server */
909 snprint(buf, sizeof buf, "%s/remote", d);
910 fd = open(buf, OREAD);
913 n = read(fd, buf, sizeof buf);
917 p = strchr(buf, '!');
920 v4parseip(rootid, buf);
926 if(strstr(s, "alarm") != nil)
932 addntpserver(char *name)
936 ns = mallocz(sizeof(NTPserver), 1);
938 sysfatal("addntpserver: %r");
939 timeserver = strdup(name);
941 for(l = &ntpservers; *l != nil; l = &(*l)->next)
947 * sntp client, we keep calling if the delay seems
948 * unusually high, i.e., 30% longer than avg.
951 ntptimediff(NTPserver *ns)
954 NTPpkt ntpin, ntpout;
955 vlong dt, recvts, origts, xmitts, destts, x;
960 alarm(30*1000); /* don't wait forever if ns->name is unreachable */
961 fd = dial(netmkaddr(ns->name, "udp", "ntp"), 0, dir, 0);
964 syslog(0, logfile, "can't reach %s: %r", ns->name);
969 memset(&ntpout, 0, sizeof(ntpout));
970 ntpout.mode = 3 | (3 << 3);
972 for(tries = 0; tries < 3; tries++){
976 hnputts(ntpout.xmitts, x);
977 if(write(fd, &ntpout, NTPSIZE) < 0){
982 n = read(fd, &ntpin, sizeof ntpin);
984 gettime(&destts, 0, 0);
988 /* we got one, use it */
989 recvts = nhgetts(ntpin.recvts);
990 origts = nhgetts(ntpin.origts);
991 xmitts = nhgetts(ntpin.xmitts);
992 dt = ((recvts - origts) + (xmitts - destts))/2;
995 ns->rtt = ((destts - origts) - (xmitts - recvts))/2;
997 ns->stratum = ntpin.stratum;
998 ns->precision = ntpin.precision;
999 ns->rootdelay = nhgetfp(ntpin.rootdelay);
1000 ns->rootdisp = nhgetfp(ntpin.rootdisp);
1003 fprint(2, "ntp %s stratum %d ntpdelay(%lld)\n",
1004 ns->name, ntpin.stratum, ns->rtt);
1020 char *v[4], buf[128];
1022 d = -1000000000000000000LL;
1023 for(i = 0; i < 5; i++){
1026 n = read(gpsfil, buf, sizeof buf - 1);
1030 n = tokenize(buf, v, nelem(v));
1031 if(n != 4 || strcmp(v[3], "A") != 0)
1044 NTPserver *tns, *ns;
1047 metric = 1000LL*SEC;
1049 for(tns = ntpservers; tns != nil; tns = tns->next){
1050 if(ntptimediff(tns) < 0)
1052 x = vabs(tns->rootdisp) + (vabs(tns->rtt+tns->rootdelay)>>1);
1054 fprint(2, "ntp %s rootdelay %lld rootdisp %lld metric %lld\n",
1055 tns->name, tns->rootdelay, tns->rootdisp, x);
1065 /* save data for our server */
1066 rootdisp = ns->rootdisp;
1067 rootdelay = ns->rootdelay;
1070 if(ns->stratum == 0)
1073 stratum = ns->stratum + 1;
1080 * sample the utc file
1087 char *v[2], buf[128];
1091 n = read(utcfil, buf, sizeof buf - 1);
1095 n = tokenize(buf, v, nelem(v));
1096 if (strcmp(v[0], "0") == 0)
1099 gettime(&s, nil, nil);
1102 lastutc = atoll(v[0]) + s;
1110 openlisten(char *net)
1113 char data[128], devdir[40];
1115 sprint(data, "%s/udp!*!ntp", net);
1116 cfd = announce(data, devdir);
1118 sysfatal("can't announce");
1119 if(fprint(cfd, "headers") < 0)
1120 sysfatal("can't set header mode");
1122 sprint(data, "%s/data", devdir);
1123 fd = open(data, ORDWR);
1125 sysfatal("open %s: %r", data);
1130 ntpserver(char *servenet)
1132 int fd, n, vers, mode;
1137 fd = openlisten(servenet);
1154 /* set by the ntp client */
1158 memmove(rootid, Rootid, strlen(Rootid) > 4? 4: strlen(Rootid));
1161 n = read(fd, buf, sizeof buf);
1162 gettime(&recvts, 0, 0);
1164 /* don't croak on input error, but don't spin either */
1168 if(n < Udphdrsize + NTPSIZE)
1171 ntp = (NTPpkt*)(buf + Udphdrsize);
1172 mode = ntp->mode & 7;
1173 vers = (ntp->mode>>3) & 7;
1177 ntp->mode = (vers<<3)|4;
1178 ntp->stratum = stratum;
1179 ntp->precision = myprec;
1180 hnputfp(ntp->rootdelay, rootdelay + mydelay);
1181 hnputfp(ntp->rootdisp, rootdisp + mydisp);
1182 hnputts(ntp->refts, lastutc);
1183 memmove(ntp->origts, ntp->xmitts, sizeof(ntp->origts));
1184 hnputts(ntp->recvts, recvts);
1185 memmove(ntp->rootid, rootid, sizeof(ntp->rootid));
1187 hnputts(ntp->xmitts, x);
1188 write(fd, buf, NTPSIZE + Udphdrsize);
1193 * get the current time from the file system
1201 d = dirstat("/n/boot");
1211 * get the current time from the real time clock
1220 memset(b, 0, sizeof(b));
1221 for(retries = 0; retries < 100; retries++){
1223 f = open("/dev/rtc", OREAD|OCEXEC);
1226 if(seek(f, 0, 0) < 0 || (i = read(f, b, sizeof b)) < 0){
1233 return strtoul(b, 0, 10)+gmtdelta;
1238 * Sample a clock. We wait for the clock to always
1239 * be at the leading edge of a clock period.
1242 sample(long (*get)(void))
1248 * wait for the second to change
1252 gettime(&start, 0, 0);
1254 gettime(&end, 0, 0);
1259 return SEC*this - (end-start)/2;
1263 * the name of the frequency file has the method and possibly the
1264 * server name encoded in it.
1277 p = smprint("%s/ts.%s.%d.%s", dir, sysid, type, timeserver);
1280 p = smprint("%s/ts.%s.%d", dir, sysid, type);
1283 fd = open(p, ORDWR);
1285 fd = create(p, ORDWR, 0666);
1293 * the file contains the last known frequency and the
1294 * number of seconds it was sampled over
1297 readfreqfile(int fd, vlong ohz, vlong minhz, vlong maxhz)
1303 n = read(fd, buf, sizeof buf-1);
1307 hz = strtoll(buf, nil, 0);
1309 if(hz > maxhz || hz < minhz)
1312 settime(-1, hz, 0, 0);
1317 * remember hz and averaging period
1320 writefreqfile(int fd, vlong hz, int secs, vlong diff)
1328 if(now - last < 10*60)
1331 if(seek(fd, 0, 0) < 0)
1333 fprint(fd, "%lld %d %d %lld\n", hz, secs, type, diff);
1348 static int inbackground;
1354 switch(rfork(RFPROC|RFFDG|RFNAMEG|RFNOTEG|RFNOWAIT)){
1356 sysfatal("forking: %r");
1367 getclockprecision(vlong hz)