correct.c revision 86644
11553Srgrimes/*- 21553Srgrimes * Copyright (c) 1985, 1993 31553Srgrimes * The Regents of the University of California. All rights reserved. 41553Srgrimes * 51553Srgrimes * Redistribution and use in source and binary forms, with or without 61553Srgrimes * modification, are permitted provided that the following conditions 71553Srgrimes * are met: 81553Srgrimes * 1. Redistributions of source code must retain the above copyright 91553Srgrimes * notice, this list of conditions and the following disclaimer. 101553Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111553Srgrimes * notice, this list of conditions and the following disclaimer in the 121553Srgrimes * documentation and/or other materials provided with the distribution. 131553Srgrimes * 3. All advertising materials mentioning features or use of this software 141553Srgrimes * must display the following acknowledgement: 151553Srgrimes * This product includes software developed by the University of 161553Srgrimes * California, Berkeley and its contributors. 171553Srgrimes * 4. Neither the name of the University nor the names of its contributors 181553Srgrimes * may be used to endorse or promote products derived from this software 191553Srgrimes * without specific prior written permission. 201553Srgrimes * 211553Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 221553Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 231553Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 241553Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 251553Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 261553Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 271553Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 281553Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 291553Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 301553Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 311553Srgrimes * SUCH DAMAGE. 321553Srgrimes */ 331553Srgrimes 341553Srgrimes#ifndef lint 3530642Scharnier#if 0 361553Srgrimesstatic char sccsid[] = "@(#)correct.c 8.1 (Berkeley) 6/6/93"; 3730642Scharnier#endif 3830642Scharnierstatic const char rcsid[] = 3950479Speter "$FreeBSD: head/usr.sbin/timed/timed/correct.c 86644 2001-11-20 06:36:09Z jhb $"; 401553Srgrimes#endif /* not lint */ 411553Srgrimes 421553Srgrimes#include "globals.h" 431553Srgrimes#include <math.h> 441553Srgrimes#include <sys/types.h> 451553Srgrimes#include <sys/times.h> 461553Srgrimes#ifdef sgi 471553Srgrimes#include <sys/syssgi.h> 481553Srgrimes#endif /* sgi */ 491553Srgrimes 501553Srgrimesstatic void adjclock __P((struct timeval *)); 511553Srgrimes 521553Srgrimes/* 531553Srgrimes * sends to the slaves the corrections for their clocks after fixing our 541553Srgrimes * own 551553Srgrimes */ 561553Srgrimesvoid 571553Srgrimescorrect(avdelta) 581553Srgrimes long avdelta; 591553Srgrimes{ 601553Srgrimes struct hosttbl *htp; 611553Srgrimes int corr; 6286644Sjhb struct timeval adjlocal, tmptv; 631553Srgrimes struct tsp to; 641553Srgrimes struct tsp *answer; 651553Srgrimes 661553Srgrimes mstotvround(&adjlocal, avdelta); 671553Srgrimes 681553Srgrimes for (htp = self.l_fwd; htp != &self; htp = htp->l_fwd) { 691553Srgrimes if (htp->delta != HOSTDOWN) { 701553Srgrimes corr = avdelta - htp->delta; 711553Srgrimes/* If the other machine is off in the weeds, set its time directly. 721553Srgrimes * If a slave gets the wrong day, the original code would simply 731553Srgrimes * fix the minutes. If you fix a network partition, you can get 741553Srgrimes * into such situations. 751553Srgrimes */ 761553Srgrimes if (htp->need_set 771553Srgrimes || corr >= MAXADJ*1000 781553Srgrimes || corr <= -MAXADJ*1000) { 791553Srgrimes htp->need_set = 0; 8086644Sjhb (void)gettimeofday(&tmptv,0); 8186644Sjhb timevaladd(&tmptv, &adjlocal); 8286644Sjhb to.tsp_time.tv_sec = tmptv.tv_sec; 8386644Sjhb to.tsp_time.tv_usec = tmptv.tv_usec; 841553Srgrimes to.tsp_type = TSP_SETTIME; 851553Srgrimes } else { 8686644Sjhb tmptv.tv_sec = to.tsp_time.tv_sec; 8786644Sjhb tmptv.tv_usec = to.tsp_time.tv_usec; 8886644Sjhb mstotvround(&tmptv, corr); 8986644Sjhb to.tsp_time.tv_sec = tmptv.tv_sec; 9086644Sjhb to.tsp_time.tv_usec = tmptv.tv_usec; 911553Srgrimes to.tsp_type = TSP_ADJTIME; 921553Srgrimes } 9330830Scharnier (void)strcpy(to.tsp_name, hostname); 941553Srgrimes answer = acksend(&to, &htp->addr, htp->name, 951553Srgrimes TSP_ACK, 0, 0); 961553Srgrimes if (!answer) { 971553Srgrimes htp->delta = HOSTDOWN; 981553Srgrimes syslog(LOG_WARNING, 991553Srgrimes "no reply to time correction from %s", 1001553Srgrimes htp->name); 1011553Srgrimes if (++htp->noanswer >= LOSTHOST) { 1021553Srgrimes if (trace) { 1031553Srgrimes fprintf(fd, 1041553Srgrimes "purging %s for not answering\n", 1051553Srgrimes htp->name); 1061553Srgrimes (void)fflush(fd); 1071553Srgrimes } 1081553Srgrimes htp = remmach(htp); 1091553Srgrimes } 1101553Srgrimes } 1111553Srgrimes } 1121553Srgrimes } 1131553Srgrimes 1141553Srgrimes /* 1151553Srgrimes * adjust our own clock now that we are not sending it out 1161553Srgrimes */ 1171553Srgrimes adjclock(&adjlocal); 1181553Srgrimes} 1191553Srgrimes 1201553Srgrimes 1211553Srgrimesstatic void 1221553Srgrimesadjclock(corr) 1231553Srgrimes struct timeval *corr; 1241553Srgrimes{ 1251553Srgrimes static int passes = 0; 1261553Srgrimes static int smoother = 0; 1271553Srgrimes long delta; /* adjustment in usec */ 1281553Srgrimes long ndelta; 1291553Srgrimes struct timeval now; 1301553Srgrimes struct timeval adj; 1311553Srgrimes 1321553Srgrimes if (!timerisset(corr)) 1331553Srgrimes return; 1341553Srgrimes 1351553Srgrimes adj = *corr; 1361553Srgrimes if (adj.tv_sec < MAXADJ && adj.tv_sec > - MAXADJ) { 1371553Srgrimes delta = adj.tv_sec*1000000 + adj.tv_usec; 1381553Srgrimes /* If the correction is less than the minimum round 1391553Srgrimes * trip time for an ICMP packet, and thus 1401553Srgrimes * less than the likely error in the measurement, 1411553Srgrimes * do not do the entire correction. Do half 1421553Srgrimes * or a quarter of it. 1431553Srgrimes */ 1441553Srgrimes 1451553Srgrimes if (delta > -MIN_ROUND*1000 1461553Srgrimes && delta < MIN_ROUND*1000) { 1471553Srgrimes if (smoother <= 4) 1481553Srgrimes smoother++; 1491553Srgrimes ndelta = delta >> smoother; 1501553Srgrimes if (trace) 1511553Srgrimes fprintf(fd, 1521553Srgrimes "trimming delta %ld usec to %ld\n", 1531553Srgrimes delta, ndelta); 1541553Srgrimes adj.tv_usec = ndelta; 1551553Srgrimes adj.tv_sec = 0; 1561553Srgrimes } else if (smoother > 0) { 1571553Srgrimes smoother--; 1581553Srgrimes } 1591553Srgrimes if (0 > adjtime(corr, 0)) { 1601553Srgrimes syslog(LOG_ERR, "adjtime: %m"); 1611553Srgrimes } 1621553Srgrimes if (passes > 1 1631553Srgrimes && (delta < -BIG_ADJ || delta > BIG_ADJ)) { 1641553Srgrimes smoother = 0; 1651553Srgrimes passes = 0; 1661553Srgrimes syslog(LOG_WARNING, 1671553Srgrimes "large time adjustment of %+.3f sec", 1681553Srgrimes delta/1000000.0); 1691553Srgrimes } 1701553Srgrimes } else { 1711553Srgrimes syslog(LOG_WARNING, 1721553Srgrimes "clock correction %d sec too large to adjust", 1731553Srgrimes adj.tv_sec); 1741553Srgrimes (void) gettimeofday(&now, 0); 1751553Srgrimes timevaladd(&now, corr); 1761553Srgrimes if (settimeofday(&now, 0) < 0) 1771553Srgrimes syslog(LOG_ERR, "settimeofday: %m"); 1781553Srgrimes } 1791553Srgrimes 1801553Srgrimes#ifdef sgi 1811553Srgrimes /* Accumulate the total change, and use it to adjust the basic 1821553Srgrimes * clock rate. 1831553Srgrimes */ 1841553Srgrimes if (++passes > 2) { 1851553Srgrimes#define F_USEC_PER_SEC (1000000*1.0) /* reduce typos */ 1861553Srgrimes#define F_NSEC_PER_SEC (F_USEC_PER_SEC*1000.0) 1871553Srgrimes 1881553Srgrimes extern char *timetrim_fn; 1891553Srgrimes extern char *timetrim_wpat; 1901553Srgrimes extern long timetrim; 1911553Srgrimes extern double tot_adj, hr_adj; /* totals in nsec */ 1921553Srgrimes extern double tot_ticks, hr_ticks; 1931553Srgrimes 1941553Srgrimes static double nag_tick; 1951553Srgrimes double cur_ticks, hr_delta_ticks, tot_delta_ticks; 1961553Srgrimes double tru_tot_adj, tru_hr_adj; /* nsecs of adjustment */ 1971553Srgrimes double tot_trim, hr_trim; /* nsec/sec */ 1981553Srgrimes struct tms tm; 1991553Srgrimes FILE *timetrim_st; 2001553Srgrimes 2011553Srgrimes cur_ticks = times(&tm); 2021553Srgrimes tot_adj += delta*1000.0; 2031553Srgrimes hr_adj += delta*1000.0; 2041553Srgrimes 2051553Srgrimes tot_delta_ticks = cur_ticks-tot_ticks; 2061553Srgrimes if (tot_delta_ticks >= 16*SECDAY*CLK_TCK) { 2071553Srgrimes tot_adj -= rint(tot_adj/16); 2081553Srgrimes tot_ticks += rint(tot_delta_ticks/16); 2091553Srgrimes tot_delta_ticks = cur_ticks-tot_ticks; 2101553Srgrimes } 2111553Srgrimes hr_delta_ticks = cur_ticks-hr_ticks; 2121553Srgrimes 2131553Srgrimes tru_hr_adj = hr_adj + timetrim*rint(hr_delta_ticks/CLK_TCK); 2141553Srgrimes tru_tot_adj = (tot_adj 2151553Srgrimes + timetrim*rint(tot_delta_ticks/CLK_TCK)); 2161553Srgrimes 2171553Srgrimes if (hr_delta_ticks >= SECDAY*CLK_TCK 2181553Srgrimes || (tot_delta_ticks < 4*SECDAY*CLK_TCK 2191553Srgrimes && hr_delta_ticks >= SECHR*CLK_TCK) 2201553Srgrimes || (trace && hr_delta_ticks >= (SECHR/10)*CLK_TCK)) { 2211553Srgrimes 2221553Srgrimes tot_trim = rint(tru_tot_adj*CLK_TCK/tot_delta_ticks); 2231553Srgrimes hr_trim = rint(tru_hr_adj*CLK_TCK/hr_delta_ticks); 2241553Srgrimes 2251553Srgrimes if (trace 2261553Srgrimes || (abs(timetrim - hr_trim) > 100000.0 2271553Srgrimes && 0 == timetrim_fn 2281553Srgrimes && ((cur_ticks - nag_tick) 2291553Srgrimes >= 24*SECDAY*CLK_TCK))) { 2301553Srgrimes nag_tick = cur_ticks; 2311553Srgrimes syslog(LOG_NOTICE, 2321553Srgrimes "%+.3f/%.2f or %+.3f/%.2f sec/hr; timetrim=%+.0f or %+.0f", 2331553Srgrimes tru_tot_adj/F_NSEC_PER_SEC, 2341553Srgrimes tot_delta_ticks/(SECHR*CLK_TCK*1.0), 2351553Srgrimes tru_hr_adj/F_NSEC_PER_SEC, 2361553Srgrimes hr_delta_ticks/(SECHR*CLK_TCK*1.0), 2371553Srgrimes tot_trim, 2381553Srgrimes hr_trim); 2391553Srgrimes } 2401553Srgrimes 2411553Srgrimes if (tot_trim < -MAX_TRIM || tot_trim > MAX_TRIM) { 2421553Srgrimes tot_ticks = hr_ticks; 2431553Srgrimes tot_adj = hr_adj; 2441553Srgrimes } else if (0 > syssgi(SGI_SETTIMETRIM, 2451553Srgrimes (long)tot_trim)) { 2461553Srgrimes syslog(LOG_ERR, "SETTIMETRIM(%d): %m", 2471553Srgrimes (long)tot_trim); 2481553Srgrimes } else { 2491553Srgrimes if (0 != timetrim_fn) { 2501553Srgrimes timetrim_st = fopen(timetrim_fn, "w"); 2511553Srgrimes if (0 == timetrim_st) { 2521553Srgrimes syslog(LOG_ERR, "fopen(%s): %m", 2531553Srgrimes timetrim_fn); 2541553Srgrimes } else { 2551553Srgrimes if (0 > fprintf(timetrim_st, 2561553Srgrimes timetrim_wpat, 2571553Srgrimes (long)tot_trim, 2581553Srgrimes tru_tot_adj, 2591553Srgrimes tot_delta_ticks)) { 2601553Srgrimes syslog(LOG_ERR, 2611553Srgrimes "fprintf(%s): %m", 2621553Srgrimes timetrim_fn); 2631553Srgrimes } 2641553Srgrimes (void)fclose(timetrim_st); 2651553Srgrimes } 2661553Srgrimes } 2671553Srgrimes 2681553Srgrimes tot_adj -= ((tot_trim - timetrim) 2691553Srgrimes * rint(tot_delta_ticks/CLK_TCK)); 2701553Srgrimes timetrim = tot_trim; 2711553Srgrimes } 2721553Srgrimes 2731553Srgrimes hr_ticks = cur_ticks; 2741553Srgrimes hr_adj = 0; 2751553Srgrimes } 2761553Srgrimes } 2771553Srgrimes#endif /* sgi */ 2781553Srgrimes} 2791553Srgrimes 2801553Srgrimes 2811553Srgrimes/* adjust the time in a message by the time it 2821553Srgrimes * spent in the queue 2831553Srgrimes */ 2841553Srgrimesvoid 2851553Srgrimesadj_msg_time(msg, now) 2861553Srgrimes struct tsp *msg; 2871553Srgrimes struct timeval *now; 2881553Srgrimes{ 2891553Srgrimes msg->tsp_time.tv_sec += (now->tv_sec - from_when.tv_sec); 2901553Srgrimes msg->tsp_time.tv_usec += (now->tv_usec - from_when.tv_usec); 2911553Srgrimes 2921553Srgrimes while (msg->tsp_time.tv_usec < 0) { 2931553Srgrimes msg->tsp_time.tv_sec--; 2941553Srgrimes msg->tsp_time.tv_usec += 1000000; 2951553Srgrimes } 2961553Srgrimes while (msg->tsp_time.tv_usec >= 1000000) { 2971553Srgrimes msg->tsp_time.tv_sec++; 2981553Srgrimes msg->tsp_time.tv_usec -= 1000000; 2991553Srgrimes } 3001553Srgrimes} 301