#ifndef lint
static char sccsid[] = "@(#)correct.c 8.1 (Berkeley) 6/6/93";
#endif
#ifdef sgi
#ident "$Revision: 1.1 $"
#endif
#include "globals.h"
#include <math.h>
#include <sys/types.h>
#include <sys/times.h>
#ifdef sgi
#include <sys/syssgi.h>
#endif
static void adjclock __P((struct timeval *));
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 (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);
}
}
}
}
adjclock(&adjlocal);
}
static void
adjclock(corr)
struct timeval *corr;
{
static int passes = 0;
static int smoother = 0;
long delta;
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 (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
if (++passes > 2) {
#define F_USEC_PER_SEC (1000000*1.0)
#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;
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;
double tot_trim, hr_trim;
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
}
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;
}
}