diff options
Diffstat (limited to 'usr.sbin/timed/timed/correct.c')
-rw-r--r-- | usr.sbin/timed/timed/correct.c | 294 |
1 files changed, 294 insertions, 0 deletions
diff --git a/usr.sbin/timed/timed/correct.c b/usr.sbin/timed/timed/correct.c new file mode 100644 index 0000000..569d2e1 --- /dev/null +++ b/usr.sbin/timed/timed/correct.c @@ -0,0 +1,294 @@ +/*- + * Copyright (c) 1985, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)correct.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#ifdef sgi +#ident "$Revision: 1.16 $" +#endif + +#include "globals.h" +#include <math.h> +#include <sys/types.h> +#include <sys/times.h> +#ifdef sgi +#include <sys/syssgi.h> +#endif /* sgi */ + +static void adjclock __P((struct timeval *)); + +/* + * sends to the slaves the corrections for their clocks after fixing our + * own + */ +void +correct(avdelta) + long avdelta; +{ + struct hosttbl *htp; + int corr; + struct timeval adjlocal; + struct tsp to; + struct tsp *answer; + + mstotvround(&adjlocal, avdelta); + + for (htp = self.l_fwd; htp != &self; htp = htp->l_fwd) { + if (htp->delta != HOSTDOWN) { + corr = avdelta - htp->delta; +/* If the other machine is off in the weeds, set its time directly. + * If a slave gets the wrong day, the original code would simply + * fix the minutes. If you fix a network partition, you can get + * into such situations. + */ + if (htp->need_set + || corr >= MAXADJ*1000 + || corr <= -MAXADJ*1000) { + htp->need_set = 0; + (void)gettimeofday(&to.tsp_time,0); + timevaladd(&to.tsp_time, &adjlocal); + to.tsp_type = TSP_SETTIME; + } else { + mstotvround(&to.tsp_time, corr); + to.tsp_type = TSP_ADJTIME; + } + (void)strcpy(to.tsp_name, hostname); + answer = acksend(&to, &htp->addr, htp->name, + TSP_ACK, 0, 0); + if (!answer) { + htp->delta = HOSTDOWN; + syslog(LOG_WARNING, + "no reply to time correction from %s", + htp->name); + if (++htp->noanswer >= LOSTHOST) { + if (trace) { + fprintf(fd, + "purging %s for not answering\n", + htp->name); + (void)fflush(fd); + } + htp = remmach(htp); + } + } + } + } + + /* + * adjust our own clock now that we are not sending it out + */ + adjclock(&adjlocal); +} + + +static void +adjclock(corr) + struct timeval *corr; +{ + static int passes = 0; + static int smoother = 0; + long delta; /* adjustment in usec */ + long ndelta; + struct timeval now; + struct timeval adj; + + if (!timerisset(corr)) + return; + + adj = *corr; + if (adj.tv_sec < MAXADJ && adj.tv_sec > - MAXADJ) { + delta = adj.tv_sec*1000000 + adj.tv_usec; + /* If the correction is less than the minimum round + * trip time for an ICMP packet, and thus + * less than the likely error in the measurement, + * do not do the entire correction. Do half + * or a quarter of it. + */ + + if (delta > -MIN_ROUND*1000 + && delta < MIN_ROUND*1000) { + if (smoother <= 4) + smoother++; + ndelta = delta >> smoother; + if (trace) + fprintf(fd, + "trimming delta %ld usec to %ld\n", + delta, ndelta); + adj.tv_usec = ndelta; + adj.tv_sec = 0; + } else if (smoother > 0) { + smoother--; + } + if (0 > adjtime(corr, 0)) { + syslog(LOG_ERR, "adjtime: %m"); + } + if (passes > 1 + && (delta < -BIG_ADJ || delta > BIG_ADJ)) { + smoother = 0; + passes = 0; + syslog(LOG_WARNING, + "large time adjustment of %+.3f sec", + delta/1000000.0); + } + } else { + syslog(LOG_WARNING, + "clock correction %d sec too large to adjust", + adj.tv_sec); + (void) gettimeofday(&now, 0); + timevaladd(&now, corr); + if (settimeofday(&now, 0) < 0) + syslog(LOG_ERR, "settimeofday: %m"); + } + +#ifdef sgi + /* Accumulate the total change, and use it to adjust the basic + * clock rate. + */ + if (++passes > 2) { +#define F_USEC_PER_SEC (1000000*1.0) /* reduce typos */ +#define F_NSEC_PER_SEC (F_USEC_PER_SEC*1000.0) + + extern char *timetrim_fn; + extern char *timetrim_wpat; + extern long timetrim; + extern double tot_adj, hr_adj; /* totals in nsec */ + extern double tot_ticks, hr_ticks; + + static double nag_tick; + double cur_ticks, hr_delta_ticks, tot_delta_ticks; + double tru_tot_adj, tru_hr_adj; /* nsecs of adjustment */ + double tot_trim, hr_trim; /* nsec/sec */ + struct tms tm; + FILE *timetrim_st; + + cur_ticks = times(&tm); + tot_adj += delta*1000.0; + hr_adj += delta*1000.0; + + tot_delta_ticks = cur_ticks-tot_ticks; + if (tot_delta_ticks >= 16*SECDAY*CLK_TCK) { + tot_adj -= rint(tot_adj/16); + tot_ticks += rint(tot_delta_ticks/16); + tot_delta_ticks = cur_ticks-tot_ticks; + } + hr_delta_ticks = cur_ticks-hr_ticks; + + tru_hr_adj = hr_adj + timetrim*rint(hr_delta_ticks/CLK_TCK); + tru_tot_adj = (tot_adj + + timetrim*rint(tot_delta_ticks/CLK_TCK)); + + if (hr_delta_ticks >= SECDAY*CLK_TCK + || (tot_delta_ticks < 4*SECDAY*CLK_TCK + && hr_delta_ticks >= SECHR*CLK_TCK) + || (trace && hr_delta_ticks >= (SECHR/10)*CLK_TCK)) { + + tot_trim = rint(tru_tot_adj*CLK_TCK/tot_delta_ticks); + hr_trim = rint(tru_hr_adj*CLK_TCK/hr_delta_ticks); + + if (trace + || (abs(timetrim - hr_trim) > 100000.0 + && 0 == timetrim_fn + && ((cur_ticks - nag_tick) + >= 24*SECDAY*CLK_TCK))) { + nag_tick = cur_ticks; + syslog(LOG_NOTICE, + "%+.3f/%.2f or %+.3f/%.2f sec/hr; timetrim=%+.0f or %+.0f", + tru_tot_adj/F_NSEC_PER_SEC, + tot_delta_ticks/(SECHR*CLK_TCK*1.0), + tru_hr_adj/F_NSEC_PER_SEC, + hr_delta_ticks/(SECHR*CLK_TCK*1.0), + tot_trim, + hr_trim); + } + + if (tot_trim < -MAX_TRIM || tot_trim > MAX_TRIM) { + tot_ticks = hr_ticks; + tot_adj = hr_adj; + } else if (0 > syssgi(SGI_SETTIMETRIM, + (long)tot_trim)) { + syslog(LOG_ERR, "SETTIMETRIM(%d): %m", + (long)tot_trim); + } else { + if (0 != timetrim_fn) { + timetrim_st = fopen(timetrim_fn, "w"); + if (0 == timetrim_st) { + syslog(LOG_ERR, "fopen(%s): %m", + timetrim_fn); + } else { + if (0 > fprintf(timetrim_st, + timetrim_wpat, + (long)tot_trim, + tru_tot_adj, + tot_delta_ticks)) { + syslog(LOG_ERR, + "fprintf(%s): %m", + timetrim_fn); + } + (void)fclose(timetrim_st); + } + } + + tot_adj -= ((tot_trim - timetrim) + * rint(tot_delta_ticks/CLK_TCK)); + timetrim = tot_trim; + } + + hr_ticks = cur_ticks; + hr_adj = 0; + } + } +#endif /* sgi */ +} + + +/* adjust the time in a message by the time it + * spent in the queue + */ +void +adj_msg_time(msg, now) + struct tsp *msg; + struct timeval *now; +{ + msg->tsp_time.tv_sec += (now->tv_sec - from_when.tv_sec); + msg->tsp_time.tv_usec += (now->tv_usec - from_when.tv_usec); + + while (msg->tsp_time.tv_usec < 0) { + msg->tsp_time.tv_sec--; + msg->tsp_time.tv_usec += 1000000; + } + while (msg->tsp_time.tv_usec >= 1000000) { + msg->tsp_time.tv_sec++; + msg->tsp_time.tv_usec -= 1000000; + } +} |