1 /*- 2 * Copyright (c) 1985, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 static char sccsid[] = "@(#)correct.c 8.1 (Berkeley) 06/06/93"; 10 #endif /* not lint */ 11 12 #ifdef sgi 13 #ident "$Revision: 1.16 $" 14 #endif 15 16 #include "globals.h" 17 #include <math.h> 18 #include <sys/types.h> 19 #include <sys/times.h> 20 #ifdef sgi 21 #include <sys/syssgi.h> 22 #endif /* sgi */ 23 24 static void adjclock __P((struct timeval *)); 25 26 /* 27 * sends to the slaves the corrections for their clocks after fixing our 28 * own 29 */ 30 void 31 correct(avdelta) 32 long avdelta; 33 { 34 struct hosttbl *htp; 35 int corr; 36 struct timeval adjlocal; 37 struct tsp to; 38 struct tsp *answer; 39 40 mstotvround(&adjlocal, avdelta); 41 42 for (htp = self.l_fwd; htp != &self; htp = htp->l_fwd) { 43 if (htp->delta != HOSTDOWN) { 44 corr = avdelta - htp->delta; 45 /* If the other machine is off in the weeds, set its time directly. 46 * If a slave gets the wrong day, the original code would simply 47 * fix the minutes. If you fix a network partition, you can get 48 * into such situations. 49 */ 50 if (htp->need_set 51 || corr >= MAXADJ*1000 52 || corr <= -MAXADJ*1000) { 53 htp->need_set = 0; 54 (void)gettimeofday(&to.tsp_time,0); 55 timevaladd(&to.tsp_time, &adjlocal); 56 to.tsp_type = TSP_SETTIME; 57 } else { 58 mstotvround(&to.tsp_time, corr); 59 to.tsp_type = TSP_ADJTIME; 60 } 61 (void)strcpy(to.tsp_name, hostname); 62 answer = acksend(&to, &htp->addr, htp->name, 63 TSP_ACK, 0, 0); 64 if (!answer) { 65 htp->delta = HOSTDOWN; 66 syslog(LOG_WARNING, 67 "no reply to time correction from %s", 68 htp->name); 69 if (++htp->noanswer >= LOSTHOST) { 70 if (trace) { 71 fprintf(fd, 72 "purging %s for not answering\n", 73 htp->name); 74 (void)fflush(fd); 75 } 76 htp = remmach(htp); 77 } 78 } 79 } 80 } 81 82 /* 83 * adjust our own clock now that we are not sending it out 84 */ 85 adjclock(&adjlocal); 86 } 87 88 89 static void 90 adjclock(corr) 91 struct timeval *corr; 92 { 93 static int passes = 0; 94 static int smoother = 0; 95 long delta; /* adjustment in usec */ 96 long ndelta; 97 struct timeval now; 98 struct timeval adj; 99 100 if (!timerisset(corr)) 101 return; 102 103 adj = *corr; 104 if (adj.tv_sec < MAXADJ && adj.tv_sec > - MAXADJ) { 105 delta = adj.tv_sec*1000000 + adj.tv_usec; 106 /* If the correction is less than the minimum round 107 * trip time for an ICMP packet, and thus 108 * less than the likely error in the measurement, 109 * do not do the entire correction. Do half 110 * or a quarter of it. 111 */ 112 113 if (delta > -MIN_ROUND*1000 114 && delta < MIN_ROUND*1000) { 115 if (smoother <= 4) 116 smoother++; 117 ndelta = delta >> smoother; 118 if (trace) 119 fprintf(fd, 120 "trimming delta %ld usec to %ld\n", 121 delta, ndelta); 122 adj.tv_usec = ndelta; 123 adj.tv_sec = 0; 124 } else if (smoother > 0) { 125 smoother--; 126 } 127 if (0 > adjtime(corr, 0)) { 128 syslog(LOG_ERR, "adjtime: %m"); 129 } 130 if (passes > 1 131 && (delta < -BIG_ADJ || delta > BIG_ADJ)) { 132 smoother = 0; 133 passes = 0; 134 syslog(LOG_WARNING, 135 "large time adjustment of %+.3f sec", 136 delta/1000000.0); 137 } 138 } else { 139 syslog(LOG_WARNING, 140 "clock correction %d sec too large to adjust", 141 adj.tv_sec); 142 (void) gettimeofday(&now, 0); 143 timevaladd(&now, corr); 144 if (settimeofday(&now, 0) < 0) 145 syslog(LOG_ERR, "settimeofday: %m"); 146 } 147 148 #ifdef sgi 149 /* Accumulate the total change, and use it to adjust the basic 150 * clock rate. 151 */ 152 if (++passes > 2) { 153 #define F_USEC_PER_SEC (1000000*1.0) /* reduce typos */ 154 #define F_NSEC_PER_SEC (F_USEC_PER_SEC*1000.0) 155 156 extern char *timetrim_fn; 157 extern char *timetrim_wpat; 158 extern long timetrim; 159 extern double tot_adj, hr_adj; /* totals in nsec */ 160 extern double tot_ticks, hr_ticks; 161 162 static double nag_tick; 163 double cur_ticks, hr_delta_ticks, tot_delta_ticks; 164 double tru_tot_adj, tru_hr_adj; /* nsecs of adjustment */ 165 double tot_trim, hr_trim; /* nsec/sec */ 166 struct tms tm; 167 FILE *timetrim_st; 168 169 cur_ticks = times(&tm); 170 tot_adj += delta*1000.0; 171 hr_adj += delta*1000.0; 172 173 tot_delta_ticks = cur_ticks-tot_ticks; 174 if (tot_delta_ticks >= 16*SECDAY*CLK_TCK) { 175 tot_adj -= rint(tot_adj/16); 176 tot_ticks += rint(tot_delta_ticks/16); 177 tot_delta_ticks = cur_ticks-tot_ticks; 178 } 179 hr_delta_ticks = cur_ticks-hr_ticks; 180 181 tru_hr_adj = hr_adj + timetrim*rint(hr_delta_ticks/CLK_TCK); 182 tru_tot_adj = (tot_adj 183 + timetrim*rint(tot_delta_ticks/CLK_TCK)); 184 185 if (hr_delta_ticks >= SECDAY*CLK_TCK 186 || (tot_delta_ticks < 4*SECDAY*CLK_TCK 187 && hr_delta_ticks >= SECHR*CLK_TCK) 188 || (trace && hr_delta_ticks >= (SECHR/10)*CLK_TCK)) { 189 190 tot_trim = rint(tru_tot_adj*CLK_TCK/tot_delta_ticks); 191 hr_trim = rint(tru_hr_adj*CLK_TCK/hr_delta_ticks); 192 193 if (trace 194 || (abs(timetrim - hr_trim) > 100000.0 195 && 0 == timetrim_fn 196 && ((cur_ticks - nag_tick) 197 >= 24*SECDAY*CLK_TCK))) { 198 nag_tick = cur_ticks; 199 syslog(LOG_NOTICE, 200 "%+.3f/%.2f or %+.3f/%.2f sec/hr; timetrim=%+.0f or %+.0f", 201 tru_tot_adj/F_NSEC_PER_SEC, 202 tot_delta_ticks/(SECHR*CLK_TCK*1.0), 203 tru_hr_adj/F_NSEC_PER_SEC, 204 hr_delta_ticks/(SECHR*CLK_TCK*1.0), 205 tot_trim, 206 hr_trim); 207 } 208 209 if (tot_trim < -MAX_TRIM || tot_trim > MAX_TRIM) { 210 tot_ticks = hr_ticks; 211 tot_adj = hr_adj; 212 } else if (0 > syssgi(SGI_SETTIMETRIM, 213 (long)tot_trim)) { 214 syslog(LOG_ERR, "SETTIMETRIM(%d): %m", 215 (long)tot_trim); 216 } else { 217 if (0 != timetrim_fn) { 218 timetrim_st = fopen(timetrim_fn, "w"); 219 if (0 == timetrim_st) { 220 syslog(LOG_ERR, "fopen(%s): %m", 221 timetrim_fn); 222 } else { 223 if (0 > fprintf(timetrim_st, 224 timetrim_wpat, 225 (long)tot_trim, 226 tru_tot_adj, 227 tot_delta_ticks)) { 228 syslog(LOG_ERR, 229 "fprintf(%s): %m", 230 timetrim_fn); 231 } 232 (void)fclose(timetrim_st); 233 } 234 } 235 236 tot_adj -= ((tot_trim - timetrim) 237 * rint(tot_delta_ticks/CLK_TCK)); 238 timetrim = tot_trim; 239 } 240 241 hr_ticks = cur_ticks; 242 hr_adj = 0; 243 } 244 } 245 #endif /* sgi */ 246 } 247 248 249 /* adjust the time in a message by the time it 250 * spent in the queue 251 */ 252 void 253 adj_msg_time(msg, now) 254 struct tsp *msg; 255 struct timeval *now; 256 { 257 msg->tsp_time.tv_sec += (now->tv_sec - from_when.tv_sec); 258 msg->tsp_time.tv_usec += (now->tv_usec - from_when.tv_usec); 259 260 while (msg->tsp_time.tv_usec < 0) { 261 msg->tsp_time.tv_sec--; 262 msg->tsp_time.tv_usec += 1000000; 263 } 264 while (msg->tsp_time.tv_usec >= 1000000) { 265 msg->tsp_time.tv_sec++; 266 msg->tsp_time.tv_usec -= 1000000; 267 } 268 } 269