📄 timesync.c
字号:
uchar ub[3*8], *p; char b[2*24+1]; switch(ifc){ case Ibintime: n = sizeof(vlong); if(hz != nil) n = 3*sizeof(vlong); if(ticks != nil) n = 2*sizeof(vlong); i = read(bintimefd, ub, n); if(i != n) break; p = ub; if(nsec != nil) be2vlong(nsec, ub); p += sizeof(vlong); if(ticks != nil) be2vlong((vlong*)ticks, p); p += sizeof(vlong); if(hz != nil) be2vlong((vlong*)hz, p); return 0; case Itiming: n = sizeof(vlong); if(ticks != nil) n = 2*sizeof(vlong); i = read(timingfd, ub, n); if(i != n) break; p = ub; if(nsec != nil) be2vlong(nsec, ub); p += sizeof(vlong); if(ticks != nil) be2vlong((vlong*)ticks, p); if(hz != nil){ seek(fastclockfd, 0, 0); n = read(fastclockfd, b, sizeof(b)-1); if(n <= 0) break; b[n] = 0; *hz = strtoll(b+24, 0, 0); } return 0; case Insec: if(nsec != nil){ seek(nsecfd, 0, 0); n = read(nsecfd, b, sizeof(b)-1); if(n <= 0) break; b[n] = 0; *nsec = strtoll(b, 0, 0); } if(ticks != nil){ seek(fastclockfd, 0, 0); n = read(fastclockfd, b, sizeof(b)-1); if(n <= 0) break; b[n] = 0; *ticks = strtoll(b, 0, 0); } if(hz != nil){ seek(fastclockfd, 0, 0); n = read(fastclockfd, b, sizeof(b)-1); if(n <= 24) break; b[n] = 0; *hz = strtoll(b+24, 0, 0); } return 0; } return -1;}static voidsettime(vlong now, uvlong hz, vlong delta, int n){ uchar b[1+sizeof(vlong)+sizeof(long)], *p; if(debug) fprint(2, "settime(now=%lld, hz=%llud, delta=%lld, period=%d)\n", now, hz, delta, n); if(impotent) return; switch(ifc){ case Ibintime: if(now >= 0){ p = b; *p++ = 'n'; p = vlong2be(p, now); if(write(bintimefd, b, p-b) < 0) sysfatal("writing /dev/bintime: %r"); } if(delta != 0){ p = b; *p++ = 'd'; p = vlong2be(p, delta); p = long2be(p, n); if(write(bintimefd, b, p-b) < 0) sysfatal("writing /dev/bintime: %r"); } if(hz != 0){ p = b; *p++ = 'f'; p = vlong2be(p, hz); if(write(bintimefd, b, p-b) < 0) sysfatal("writing /dev/bintime: %r"); } break; case Itiming: case Insec: seek(nsecfd, 0, 0); if(now >= 0 || delta != 0){ if(fprint(nsecfd, "%lld %lld %d", now, delta, n) < 0) sysfatal("writing /dev/nsec: %r"); } if(hz > 0){ seek(fastclockfd, 0, 0); if(fprint(fastclockfd, "%lld", hz) < 0) sysfatal("writing /dev/fastclock: %r"); } }}//// set priority high and wire process to a processor//static voidsetpriority(void){ int fd; char buf[32]; sprint(buf, "/proc/%d/ctl", getpid()); fd = open(buf, ORDWR); if(fd < 0){ fprint(2, "can't set priority\n"); return; } if(fprint(fd, "pri 100") < 0) fprint(2, "can't set priority\n"); if(fprint(fd, "wired 2") < 0) fprint(2, "can't wire process\n"); close(fd);}// convert to ntp timestampsstatic voidhnputts(void *p, vlong nsec){ uchar *a; ulong tsh; ulong tsl; a = p; // zero is a special case if(nsec == 0) return; tsh = (nsec/SEC); nsec -= tsh*SEC; tsl = (nsec<<32)/SEC; hnputl(a, tsh+EPOCHDIFF); hnputl(a+4, tsl);}// convert from ntp timestampsstatic vlongnhgetts(void *p){ uchar *a; ulong tsh, tsl; vlong nsec; a = p; tsh = nhgetl(a); tsl = nhgetl(a+4); nsec = tsl*SEC; nsec >>= 32; nsec += (tsh - EPOCHDIFF)*SEC; return nsec;}// convert to ntp 32 bit fixed pointstatic voidhnputfp(void *p, vlong nsec){ uchar *a; ulong fp; a = p; fp = nsec/(SEC/((vlong)(1<<16))); hnputl(a, fp);}// convert from ntp fixed point to nanosecsstatic vlongnhgetfp(void *p){ uchar *a; ulong fp; vlong nsec; a = p; fp = nhgetl(a); nsec = ((vlong)fp)*(SEC/((vlong)(1<<16))); return nsec;}// get network address of the serverstatic voidsetrootid(char *d){ char buf[128]; int fd, n; char *p; snprint(buf, sizeof(buf), "%s/remote", d); fd = open(buf, OREAD); if(fd < 0) return; n = read(fd, buf, sizeof buf); close(fd); if(n <= 0) return; p = strchr(buf, '!'); if(p != nil) *p = 0; v4parseip(rootid, buf);}static voidding(void*, char *s){ if(strstr(s, "alarm") != nil) noted(NCONT); noted(NDFLT);}static voidaddntpserver(char *name){ NTPserver *ns, **l; ns = mallocz(sizeof(NTPserver), 1); if(ns == nil) sysfatal("addntpserver: %r"); timeserver = strdup(name); ns->name = name; for(l = &ntpservers; *l != nil; l = &(*l)->next) ; *l = ns;}//// sntp client, we keep calling if the delay seems// unusually high, i.e., 30% longer than avg.//static intntptimediff(NTPserver *ns){ int fd, tries, n; NTPpkt ntpin, ntpout; vlong dt, recvts, origts, xmitts, destts, x; char dir[64]; fd = dial(netmkaddr(ns->name, "udp", "ntp"), 0, dir, 0); if(fd < 0){ syslog(0, logfile, "can't reach %s: %r", ns->name); return -1; } setrootid(dir); notify(ding); memset(&ntpout, 0, sizeof(ntpout)); ntpout.mode = 3 | (3 << 3); for(tries = 0; tries < 3; tries++){ alarm(2*1000); gettime(&x, 0, 0); hnputts(ntpout.xmitts, x); if(write(fd, &ntpout, NTPSIZE) < 0){ alarm(0); continue; } n = read(fd, &ntpin, sizeof(ntpin)); alarm(0); gettime(&destts, 0, 0); if(n >= NTPSIZE){ close(fd); // we got one, use it recvts = nhgetts(ntpin.recvts); origts = nhgetts(ntpin.origts); xmitts = nhgetts(ntpin.xmitts); dt = ((recvts - origts) + (xmitts - destts))/2; // save results ns->rtt = ((destts - origts) - (xmitts - recvts))/2; ns->dt = dt; ns->stratum = ntpin.stratum; ns->precision = ntpin.precision; ns->rootdelay = nhgetfp(ntpin.rootdelay); ns->rootdisp = nhgetfp(ntpin.rootdisp); if(debug) fprint(2, "ntp %s stratum %d ntpdelay(%lld)\n", ns->name, ntpin.stratum, ns->rtt); return 0; } // try again sleep(250); } close(fd); return -1;}static vlonggpssample(void){ vlong l, g, d; int i, n; char *v[4], buf[128]; d = -1000000000000000000LL; for(i = 0; i < 5; i++){ sleep(1100); seek(gpsfil, 0, 0); n = read(gpsfil, buf, sizeof buf - 1); if (n <= 0) return(0LL); buf[n] = 0; n = tokenize(buf, v, nelem(v)); if(n != 4) return(0LL); if(strcmp(v[3], "A") != 0) return(0LL); g = atoll(v[1]); l = atoll(v[2]); if(g-l > d) d = g-l; } return(d);}static vlongntpsample(void){ NTPserver *tns, *ns; vlong metric, x; metric = 1000LL*SEC; ns = nil; for(tns = ntpservers; tns != nil; tns = tns->next){ if(ntptimediff(tns) < 0) continue; x = vabs(tns->rootdisp) + (vabs(tns->rtt+tns->rootdelay)>>1); if(debug) fprint(2, "ntp %s rootdelay %lld rootdisp %lld metric %lld\n", tns->name, tns->rootdelay, tns->rootdisp, x); if(x < metric){ metric = x; ns = tns; } } if(ns == nil) return 0LL; // save data for our server rootdisp = ns->rootdisp; rootdelay = ns->rootdelay; mydelay = ns->rtt; mydisp = avgerr; if(ns->stratum == 0) stratum = 0; else stratum = ns->stratum + 1; ε = abs(ns->rtt/2); return ns->dt;}//// sample the utc file//static vlongutcsample(void){ vlong s; int n; char *v[2], buf[128]; s = 0; seek(utcfil, 0, 0); n = read(utcfil, buf, sizeof buf - 1); if (n <= 0) return(0LL); buf[n] = 0; n = tokenize(buf, v, nelem(v)); if (strcmp(v[0], "0") == 0) return(0LL); if (n == 2) { gettime(&s, nil, nil); s -= atoll(v[1]); } lastutc = atoll(v[0]) + s; return(lastutc);}//// sntp server//static intopenlisten(char *net){ int fd, cfd; char data[128]; char devdir[40]; sprint(data, "%s/udp!*!ntp", net); cfd = announce(data, devdir); if(cfd < 0) sysfatal("can't announce"); if(fprint(cfd, "headers") < 0) sysfatal("can't set header mode"); fprint(cfd, "oldheaders"); sprint(data, "%s/data", devdir); fd = open(data, ORDWR); if(fd < 0) sysfatal("open udp data"); return fd;}static voidntpserver(char *servenet){ int fd, n; NTPpkt *ntp; char buf[512]; int vers, mode; vlong recvts, x; fd = openlisten(servenet); if (Rootid == nil) switch(type){ case Fs: Rootid = "WWV"; break; case Rtc: Rootid = "LOCL"; break; case Utc: Rootid = "UTC"; break; case Ntp: /* set by the ntp client */ break; } if (Rootid != nil) memmove(rootid, Rootid, strlen(Rootid) > 4 ? 4 : strlen(Rootid)); for(;;){ n = read(fd, buf, sizeof(buf)); gettime(&recvts, 0, 0); if(n < 0) return; if(n < OUdphdrsize + NTPSIZE) continue; ntp = (NTPpkt*)(buf+OUdphdrsize); mode = ntp->mode & 7; vers = (ntp->mode>>3) & 7; if(mode != 3) continue; ntp->mode = (vers<<3)|4; ntp->stratum = stratum; ntp->precision = myprec; hnputfp(ntp->rootdelay, rootdelay + mydelay); hnputfp(ntp->rootdisp, rootdisp + mydisp); hnputts(ntp->refts, lastutc); memmove(ntp->origts, ntp->xmitts, sizeof(ntp->origts)); hnputts(ntp->recvts, recvts); memmove(ntp->rootid, rootid, sizeof(ntp->rootid)); gettime(&x, 0, 0); hnputts(ntp->xmitts, x); write(fd, buf, NTPSIZE+OUdphdrsize); }}//// get the current time from the file system//static longfstime(void){ Dir *d; ulong t; d = dirstat("/n/boot"); if(d != nil){ t = d->atime; free(d); } else t = 0; return t;}//// get the current time from the real time clock//static longrtctime(void){ char b[20]; static int f = -1; int i, retries; memset(b, 0, sizeof(b)); for(retries = 0; retries < 100; retries++){ if(f < 0) f = open("/dev/rtc", OREAD|OCEXEC); if(f < 0) break; if(seek(f, 0, 0) < 0 || (i = read(f, b, sizeof(b))) < 0){ close(f); f = -1; } else { if(i != 0) break; } } return strtoul(b, 0, 10)+gmtdelta;}//// Sample a clock. We wait for the clock to always// be at the leading edge of a clock period.//static vlongsample(long (*get)(void)){ long this, last; vlong start, end; /* * wait for the second to change */ last = (*get)(); for(;;){ gettime(&start, 0, 0); this = (*get)(); gettime(&end, 0, 0); if(this != last) break; last = this; } return SEC*this - (end-start)/2;}//// the name of the frequency file has the method and possibly the// server name encoded in it.//static intopenfreqfile(void){ char *p; int fd; if(sysid == nil) return -1; switch(type){ case Ntp: p = smprint("%s/ts.%s.%d.%s", dir, sysid, type, timeserver); break; default: p = smprint("%s/ts.%s.%d", dir, sysid, type); break; } fd = open(p, ORDWR); if(fd < 0) fd = create(p, ORDWR, 0666); free(p); if(fd < 0) return -1; return fd;}//// the file contains the last known frequency and the// number of seconds it was sampled over//static vlongreadfreqfile(int fd, vlong ohz, vlong minhz, vlong maxhz){ int n; char buf[128]; vlong hz; n = read(fd, buf, sizeof(buf)-1); if(n <= 0) return ohz; buf[n] = 0; hz = strtoll(buf, nil, 0); if(hz > maxhz || hz < minhz) return ohz; settime(-1, hz, 0, 0); return hz;}//// remember hz and averaging period//static voidwritefreqfile(int fd, vlong hz, int secs, vlong diff){ long now; static long last; if(fd < 0) return; now = time(0); if(now - last < 10*60) return; last = now; if(seek(fd, 0, 0) < 0) return; fprint(fd, "%lld %d %d %lld\n", hz, secs, type, diff);}static uvlongvabs(vlong x){ if(x < 0LL) return (uvlong)-x; else return (uvlong)x;}static voidbackground(void){ static int inbackground; if(inbackground) return; if(!debug) { switch(rfork(RFPROC|RFFDG|RFNAMEG|RFNOTEG|RFNOWAIT)){ case -1: sysfatal("forking: %r"); break; case 0: break; default: exits(0); } } inbackground = 1;}static intgetclockprecision(vlong hz){ int i; i = 8; while(hz > 0){ i--; hz >>= 1; } return i;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -