correct.c revision 30642
1/*- 2 * Copyright (c) 1985, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34#ifndef lint 35#if 0 36static char sccsid[] = "@(#)correct.c 8.1 (Berkeley) 6/6/93"; 37#endif 38static const char rcsid[] = 39 "$Id$"; 40#endif /* not lint */ 41 42#include "globals.h" 43#include <math.h> 44#include <sys/types.h> 45#include <sys/times.h> 46#ifdef sgi 47#include <sys/syssgi.h> 48#endif /* sgi */ 49 50static void adjclock __P((struct timeval *)); 51 52/* 53 * sends to the slaves the corrections for their clocks after fixing our 54 * own 55 */ 56void 57correct(avdelta) 58 long avdelta; 59{ 60 struct hosttbl *htp; 61 int corr; 62 struct timeval adjlocal; 63 struct tsp to; 64 struct tsp *answer; 65 66 mstotvround(&adjlocal, avdelta); 67 68 for (htp = self.l_fwd; htp != &self; htp = htp->l_fwd) { 69 if (htp->delta != HOSTDOWN) { 70 corr = avdelta - htp->delta; 71/* If the other machine is off in the weeds, set its time directly. 72 * If a slave gets the wrong day, the original code would simply 73 * fix the minutes. If you fix a network partition, you can get 74 * into such situations. 75 */ 76 if (htp->need_set 77 || corr >= MAXADJ*1000 78 || corr <= -MAXADJ*1000) { 79 htp->need_set = 0; 80 (void)gettimeofday(&to.tsp_time,0); 81 timevaladd(&to.tsp_time, &adjlocal); 82 to.tsp_type = TSP_SETTIME; 83 } else { 84 mstotvround(&to.tsp_time, corr); 85 to.tsp_type = TSP_ADJTIME; 86 } 87 (void)strncpy(to.tsp_name, hostname, 88 sizeof to.tsp_name-1); 89 to.tsp_name[sizeof to.tsp_name-1] = '\0'; 90 answer = acksend(&to, &htp->addr, htp->name, 91 TSP_ACK, 0, 0); 92 if (!answer) { 93 htp->delta = HOSTDOWN; 94 syslog(LOG_WARNING, 95 "no reply to time correction from %s", 96 htp->name); 97 if (++htp->noanswer >= LOSTHOST) { 98 if (trace) { 99 fprintf(fd, 100 "purging %s for not answering\n", 101 htp->name); 102 (void)fflush(fd); 103 } 104 htp = remmach(htp); 105 } 106 } 107 } 108 } 109 110 /* 111 * adjust our own clock now that we are not sending it out 112 */ 113 adjclock(&adjlocal); 114} 115 116 117static void 118adjclock(corr) 119 struct timeval *corr; 120{ 121 static int passes = 0; 122 static int smoother = 0; 123 long delta; /* adjustment in usec */ 124 long ndelta; 125 struct timeval now; 126 struct timeval adj; 127 128 if (!timerisset(corr)) 129 return; 130 131 adj = *corr; 132 if (adj.tv_sec < MAXADJ && adj.tv_sec > - MAXADJ) { 133 delta = adj.tv_sec*1000000 + adj.tv_usec; 134 /* If the correction is less than the minimum round 135 * trip time for an ICMP packet, and thus 136 * less than the likely error in the measurement, 137 * do not do the entire correction. Do half 138 * or a quarter of it. 139 */ 140 141 if (delta > -MIN_ROUND*1000 142 && delta < MIN_ROUND*1000) { 143 if (smoother <= 4) 144 smoother++; 145 ndelta = delta >> smoother; 146 if (trace) 147 fprintf(fd, 148 "trimming delta %ld usec to %ld\n", 149 delta, ndelta); 150 adj.tv_usec = ndelta; 151 adj.tv_sec = 0; 152 } else if (smoother > 0) { 153 smoother--; 154 } 155 if (0 > adjtime(corr, 0)) { 156 syslog(LOG_ERR, "adjtime: %m"); 157 } 158 if (passes > 1 159 && (delta < -BIG_ADJ || delta > BIG_ADJ)) { 160 smoother = 0; 161 passes = 0; 162 syslog(LOG_WARNING, 163 "large time adjustment of %+.3f sec", 164 delta/1000000.0); 165 } 166 } else { 167 syslog(LOG_WARNING, 168 "clock correction %d sec too large to adjust", 169 adj.tv_sec); 170 (void) gettimeofday(&now, 0); 171 timevaladd(&now, corr); 172 if (settimeofday(&now, 0) < 0) 173 syslog(LOG_ERR, "settimeofday: %m"); 174 } 175 176#ifdef sgi 177 /* Accumulate the total change, and use it to adjust the basic 178 * clock rate. 179 */ 180 if (++passes > 2) { 181#define F_USEC_PER_SEC (1000000*1.0) /* reduce typos */ 182#define F_NSEC_PER_SEC (F_USEC_PER_SEC*1000.0) 183 184 extern char *timetrim_fn; 185 extern char *timetrim_wpat; 186 extern long timetrim; 187 extern double tot_adj, hr_adj; /* totals in nsec */ 188 extern double tot_ticks, hr_ticks; 189 190 static double nag_tick; 191 double cur_ticks, hr_delta_ticks, tot_delta_ticks; 192 double tru_tot_adj, tru_hr_adj; /* nsecs of adjustment */ 193 double tot_trim, hr_trim; /* nsec/sec */ 194 struct tms tm; 195 FILE *timetrim_st; 196 197 cur_ticks = times(&tm); 198 tot_adj += delta*1000.0; 199 hr_adj += delta*1000.0; 200 201 tot_delta_ticks = cur_ticks-tot_ticks; 202 if (tot_delta_ticks >= 16*SECDAY*CLK_TCK) { 203 tot_adj -= rint(tot_adj/16); 204 tot_ticks += rint(tot_delta_ticks/16); 205 tot_delta_ticks = cur_ticks-tot_ticks; 206 } 207 hr_delta_ticks = cur_ticks-hr_ticks; 208 209 tru_hr_adj = hr_adj + timetrim*rint(hr_delta_ticks/CLK_TCK); 210 tru_tot_adj = (tot_adj 211 + timetrim*rint(tot_delta_ticks/CLK_TCK)); 212 213 if (hr_delta_ticks >= SECDAY*CLK_TCK 214 || (tot_delta_ticks < 4*SECDAY*CLK_TCK 215 && hr_delta_ticks >= SECHR*CLK_TCK) 216 || (trace && hr_delta_ticks >= (SECHR/10)*CLK_TCK)) { 217 218 tot_trim = rint(tru_tot_adj*CLK_TCK/tot_delta_ticks); 219 hr_trim = rint(tru_hr_adj*CLK_TCK/hr_delta_ticks); 220 221 if (trace 222 || (abs(timetrim - hr_trim) > 100000.0 223 && 0 == timetrim_fn 224 && ((cur_ticks - nag_tick) 225 >= 24*SECDAY*CLK_TCK))) { 226 nag_tick = cur_ticks; 227 syslog(LOG_NOTICE, 228 "%+.3f/%.2f or %+.3f/%.2f sec/hr; timetrim=%+.0f or %+.0f", 229 tru_tot_adj/F_NSEC_PER_SEC, 230 tot_delta_ticks/(SECHR*CLK_TCK*1.0), 231 tru_hr_adj/F_NSEC_PER_SEC, 232 hr_delta_ticks/(SECHR*CLK_TCK*1.0), 233 tot_trim, 234 hr_trim); 235 } 236 237 if (tot_trim < -MAX_TRIM || tot_trim > MAX_TRIM) { 238 tot_ticks = hr_ticks; 239 tot_adj = hr_adj; 240 } else if (0 > syssgi(SGI_SETTIMETRIM, 241 (long)tot_trim)) { 242 syslog(LOG_ERR, "SETTIMETRIM(%d): %m", 243 (long)tot_trim); 244 } else { 245 if (0 != timetrim_fn) { 246 timetrim_st = fopen(timetrim_fn, "w"); 247 if (0 == timetrim_st) { 248 syslog(LOG_ERR, "fopen(%s): %m", 249 timetrim_fn); 250 } else { 251 if (0 > fprintf(timetrim_st, 252 timetrim_wpat, 253 (long)tot_trim, 254 tru_tot_adj, 255 tot_delta_ticks)) { 256 syslog(LOG_ERR, 257 "fprintf(%s): %m", 258 timetrim_fn); 259 } 260 (void)fclose(timetrim_st); 261 } 262 } 263 264 tot_adj -= ((tot_trim - timetrim) 265 * rint(tot_delta_ticks/CLK_TCK)); 266 timetrim = tot_trim; 267 } 268 269 hr_ticks = cur_ticks; 270 hr_adj = 0; 271 } 272 } 273#endif /* sgi */ 274} 275 276 277/* adjust the time in a message by the time it 278 * spent in the queue 279 */ 280void 281adj_msg_time(msg, now) 282 struct tsp *msg; 283 struct timeval *now; 284{ 285 msg->tsp_time.tv_sec += (now->tv_sec - from_when.tv_sec); 286 msg->tsp_time.tv_usec += (now->tv_usec - from_when.tv_usec); 287 288 while (msg->tsp_time.tv_usec < 0) { 289 msg->tsp_time.tv_sec--; 290 msg->tsp_time.tv_usec += 1000000; 291 } 292 while (msg->tsp_time.tv_usec >= 1000000) { 293 msg->tsp_time.tv_sec++; 294 msg->tsp_time.tv_usec -= 1000000; 295 } 296} 297