[git commit master] ntpd: better selection of initial sync; fewer gettimeofday calls

Denys Vlasenko vda.linux at googlemail.com
Sun Jan 3 07:59:59 UTC 2010


commit: http://git.busybox.net/busybox/commit/?id=0b002812a8c2a95ab18374452fd0ab2065ed4029
branch: http://git.busybox.net/busybox/commit/?id=refs/heads/master

Signed-off-by: Denys Vlasenko <vda.linux at googlemail.com>
---
 networking/ntpd.c |  252 ++++++++++++++++++++++++++--------------------------
 1 files changed, 126 insertions(+), 126 deletions(-)

diff --git a/networking/ntpd.c b/networking/ntpd.c
index 92e2723..520dcd1 100644
--- a/networking/ntpd.c
+++ b/networking/ntpd.c
@@ -47,9 +47,10 @@
 
 
 #define RETRY_INTERVAL  5       /* on error, retry in N secs */
-#define QUERYTIME_MAX   15      /* wait for reply up to N secs */
+#define RESPONSE_INTERVAL 15    /* wait for reply up to N secs */
 
 #define FREQ_TOLERANCE  0.000015 /* % frequency tolerance (15 PPM) */
+#define BURSTPOLL       0
 #define MINPOLL         4       /* % minimum poll interval (6: 64 s) */
 #define MAXPOLL         12      /* % maximum poll interval (12: 1.1h, 17: 36.4h) (was 17) */
 #define MINDISP         0.01    /* % minimum dispersion (s) */
@@ -162,13 +163,13 @@ typedef struct {
 	char             *p_dotted;
 	/* when to send new query (if p_fd == -1)
 	 * or when receive times out (if p_fd >= 0): */
-	time_t           next_action_time;
 	int              p_fd;
 	int              datapoint_idx;
 	uint32_t         lastpkt_refid;
 	uint8_t          lastpkt_status;
 	uint8_t          lastpkt_stratum;
-	uint8_t          p_reachable_bits;
+	uint8_t          reachable_bits;
+	double           next_action_time;
 	double           p_xmttime;
 	double           lastpkt_recv_time;
 	double           lastpkt_delay;
@@ -196,6 +197,7 @@ enum {
 };
 
 struct globals {
+	double   cur_time;
 	/* total round trip delay to currently selected reference clock */
 	double   rootdelay;
 	/* reference timestamp: time when the system clock was last set or corrected */
@@ -245,7 +247,8 @@ struct globals {
 #define G_precision_sec  (1.0 / (1 << (- G_precision_exp)))
 	uint8_t  stratum;
 	/* Bool. After set to 1, never goes back to 0: */
-	uint8_t  adjtimex_was_done;
+	smallint adjtimex_was_done;
+	smallint initial_poll_complete;
 
 	uint8_t  discipline_state;      // doc calls it c.state
 	uint8_t  poll_exp;              // s.poll
@@ -303,7 +306,8 @@ gettime1900d(void)
 {
 	struct timeval tv;
 	gettimeofday(&tv, NULL); /* never fails */
-	return (tv.tv_sec + 1.0e-6 * tv.tv_usec + OFFSET_1900_1970);
+	G.cur_time = tv.tv_sec + (1.0e-6 * tv.tv_usec) + OFFSET_1900_1970;
+	return G.cur_time;
 }
 
 static void
@@ -355,13 +359,13 @@ d_to_sfp(double d)
 #endif
 
 static double
-dispersion(const datapoint_t *dp, double t)
+dispersion(const datapoint_t *dp)
 {
-	return dp->d_dispersion + FREQ_TOLERANCE * (t - dp->d_recv_time);
+	return dp->d_dispersion + FREQ_TOLERANCE * (G.cur_time - dp->d_recv_time);
 }
 
 static double
-root_distance(peer_t *p, double t)
+root_distance(peer_t *p)
 {
 	/* The root synchronization distance is the maximum error due to
 	 * all causes of the local clock relative to the primary server.
@@ -371,21 +375,21 @@ root_distance(peer_t *p, double t)
 	return MAXD(MINDISP, p->lastpkt_rootdelay + p->lastpkt_delay) / 2
 		+ p->lastpkt_rootdisp
 		+ p->filter_dispersion
-		+ FREQ_TOLERANCE * (t - p->lastpkt_recv_time)
+		+ FREQ_TOLERANCE * (G.cur_time - p->lastpkt_recv_time)
 		+ p->filter_jitter;
 }
 
 static void
 set_next(peer_t *p, unsigned t)
 {
-	p->next_action_time = time(NULL) + t;
+	p->next_action_time = G.cur_time + t;
 }
 
 /*
  * Peer clock filter and its helpers
  */
 static void
-filter_datapoints(peer_t *p, double t)
+filter_datapoints(peer_t *p)
 {
 	int i, idx;
 	int got_newest;
@@ -427,14 +431,14 @@ filter_datapoints(peer_t *p, double t)
 			bb_error_msg("datapoint[%d]: off:%f disp:%f(%f) age:%f%s",
 				i,
 				p->filter_datapoint[idx].d_offset,
-				p->filter_datapoint[idx].d_dispersion, dispersion(&p->filter_datapoint[idx], t),
-				t - p->filter_datapoint[idx].d_recv_time,
+				p->filter_datapoint[idx].d_dispersion, dispersion(&p->filter_datapoint[idx]),
+				G.cur_time - p->filter_datapoint[idx].d_recv_time,
 				(minoff == p->filter_datapoint[idx].d_offset || maxoff == p->filter_datapoint[idx].d_offset)
 					? " (outlier by offset)" : ""
 			);
 		}
 
-		sum += dispersion(&p->filter_datapoint[idx], t) / (2 << i);
+		sum += dispersion(&p->filter_datapoint[idx]) / (2 << i);
 
 		if (minoff == p->filter_datapoint[idx].d_offset) {
 			minoff -= 1; /* so that we don't match it ever again */
@@ -443,7 +447,7 @@ filter_datapoints(peer_t *p, double t)
 			maxoff += 1;
 		} else {
 			oldest_off = p->filter_datapoint[idx].d_offset;
-			oldest_age = t - p->filter_datapoint[idx].d_recv_time;
+			oldest_age = G.cur_time - p->filter_datapoint[idx].d_recv_time;
 			if (!got_newest) {
 				got_newest = 1;
 				newest_off = oldest_off;
@@ -466,10 +470,13 @@ filter_datapoints(peer_t *p, double t)
 	 * and then we have this estimation, ~25% off from 0.7:
 	 * 0.1/32 + 0.2/32 + 0.3/16 + 0.4/8 + 0.5/4 + 0.6/2 = 0.503125
 	 */
-	x = newest_age / (oldest_age - newest_age); /* in above example, 100 / (600 - 100) */
-	if (x < 1) {
-		x = (newest_off - oldest_off) * x; /* 0.5 * 100/500 = 0.1 */
-		wavg += x;
+	x = oldest_age - newest_age;
+	if (x != 0) {
+		x = newest_age / x; /* in above example, 100 / (600 - 100) */
+		if (x < 1) { /* paranoia check */
+			x = (newest_off - oldest_off) * x; /* 0.5 * 100/500 = 0.1 */
+			wavg += x;
+		}
 	}
 	p->filter_offset = wavg;
 
@@ -499,7 +506,7 @@ filter_datapoints(peer_t *p, double t)
 }
 
 static void
-reset_peer_stats(peer_t *p, double t, double offset)
+reset_peer_stats(peer_t *p, double offset)
 {
 	int i;
 	for (i = 0; i < NUM_DATAPOINTS; i++) {
@@ -509,7 +516,7 @@ reset_peer_stats(peer_t *p, double t, double offset)
 				p->filter_datapoint[i].d_offset -= offset;
 			}
 		} else {
-			p->filter_datapoint[i].d_recv_time  = t;
+			p->filter_datapoint[i].d_recv_time  = G.cur_time;
 			p->filter_datapoint[i].d_offset     = 0;
 			p->filter_datapoint[i].d_dispersion = MAXDISP;
 		}
@@ -517,11 +524,11 @@ reset_peer_stats(peer_t *p, double t, double offset)
 	if (offset < 16 * STEP_THRESHOLD) {
 		p->lastpkt_recv_time -= offset;
 	} else {
-		p->p_reachable_bits = 0;
-		p->lastpkt_recv_time = t;
+		p->reachable_bits = 0;
+		p->lastpkt_recv_time = G.cur_time;
 	}
-	filter_datapoints(p, t); /* recalc p->filter_xxx */
-	p->next_action_time -= (time_t)offset;
+	filter_datapoints(p); /* recalc p->filter_xxx */
+	p->next_action_time -= offset;
 	VERB5 bb_error_msg("%s->lastpkt_recv_time=%f", p->p_dotted, p->lastpkt_recv_time);
 }
 
@@ -535,8 +542,8 @@ add_peers(char *s)
 	p->p_dotted = xmalloc_sockaddr2dotted_noport(&p->p_lsa->u.sa);
 	p->p_fd = -1;
 	p->p_xmt_msg.m_status = MODE_CLIENT | (NTP_VERSION << 3);
-	p->next_action_time = time(NULL); /* = set_next(p, 0); */
-	reset_peer_stats(p, gettime1900d(), 16 * STEP_THRESHOLD);
+	p->next_action_time = G.cur_time; /* = set_next(p, 0); */
+	reset_peer_stats(p, 16 * STEP_THRESHOLD);
 	/* Speed up initial sync: with small offsets from peers,
 	 * 3 samples will sync
 	 */
@@ -567,7 +574,7 @@ do_sendto(int fd,
 	return 0;
 }
 
-static int
+static void
 send_query_to_peer(peer_t *p)
 {
 	/* Why do we need to bind()?
@@ -632,20 +639,19 @@ send_query_to_peer(peer_t *p)
 		close(p->p_fd);
 		p->p_fd = -1;
 		set_next(p, RETRY_INTERVAL);
-		return -1;
+		return;
 	}
 
-	p->p_reachable_bits <<= 1;
+	p->reachable_bits <<= 1;
 	VERB1 bb_error_msg("sent query to %s", p->p_dotted);
-	set_next(p, QUERYTIME_MAX);
-
-	return 0;
+	set_next(p, RESPONSE_INTERVAL);
 }
 
 
-static void
+static NOINLINE void
 step_time(double offset)
 {
+	llist_t *item;
 	double dtime;
 	struct timeval tv;
 	char buf[80];
@@ -663,6 +669,17 @@ step_time(double offset)
 	strftime(buf, sizeof(buf), "%a %b %e %H:%M:%S %Z %Y", localtime(&tval));
 
 	bb_error_msg("setting clock to %s (offset %fs)", buf, offset);
+
+	/* Correct various fields which contain time-relative values: */
+
+	/* p->lastpkt_recv_time, p->next_action_time and such: */
+	for (item = G.ntp_peers; item != NULL; item = item->link) {
+		peer_t *pp = (peer_t *) item->data;
+		reset_peer_stats(pp, offset);
+	}
+	/* Globals: */
+	G.cur_time -= offset;
+	G.last_update_recv_time -= offset;
 }
 
 
@@ -700,7 +717,8 @@ compare_survivor_metric(const void *aa, const void *bb)
 static int
 fit(peer_t *p, double rd)
 {
-	if (p->p_reachable_bits == 0) {
+	if ((p->reachable_bits & (p->reachable_bits-1)) == 0) {
+		/* One or zero bits in reachable_bits */
 		VERB3 bb_error_msg("peer %s unfit for selection: unreachable", p->p_dotted);
 		return 0;
 	}
@@ -712,7 +730,7 @@ fit(peer_t *p, double rd)
 		return 0;
 	}
 #endif
-	/* rd is root_distance(p, t) */
+	/* rd is root_distance(p) */
 	if (rd > MAXDIST + FREQ_TOLERANCE * (1 << G.poll_exp)) {
 		VERB3 bb_error_msg("peer %s unfit for selection: root distance too high", p->p_dotted);
 		return 0;
@@ -724,7 +742,7 @@ fit(peer_t *p, double rd)
         return 1;
 }
 static peer_t*
-select_and_cluster(double t)
+select_and_cluster(void)
 {
 	llist_t    *item;
 	int        i, j;
@@ -742,9 +760,9 @@ select_and_cluster(double t)
 
 	num_points = 0;
 	item = G.ntp_peers;
-	while (item != NULL) {
+	if (G.initial_poll_complete) while (item != NULL) {
 		peer_t *p = (peer_t *) item->data;
-		double rd = root_distance(p, t);
+		double rd = root_distance(p);
 		double offset = p->filter_offset;
 
 		if (!fit(p, rd)) {
@@ -775,7 +793,7 @@ select_and_cluster(double t)
 	num_candidates = num_points / 3;
 	if (num_candidates == 0) {
 		VERB3 bb_error_msg("no valid datapoints, no peer selected");
-		return NULL; /* never happers? */
+		return NULL;
 	}
 //TODO: sorting does not seem to be done in reference code
 	qsort(point, num_points, sizeof(point[0]), compare_point_edge);
@@ -856,7 +874,7 @@ select_and_cluster(double t)
 		p = point[i].p;
 		survivor[num_survivors].p = p;
 //TODO: save root_distance in point_t and reuse here?
-		survivor[num_survivors].metric = MAXDIST * p->lastpkt_stratum + root_distance(p, t);
+		survivor[num_survivors].metric = MAXDIST * p->lastpkt_stratum + root_distance(p);
 		VERB4 bb_error_msg("survivor[%d] metric:%f peer:%s",
 			num_survivors, survivor[num_survivors].metric, p->p_dotted);
 		num_survivors++;
@@ -952,7 +970,7 @@ select_and_cluster(double t)
 	VERB3 bb_error_msg("selected peer %s filter_offset:%f age:%f",
 			survivor[0].p->p_dotted,
 			survivor[0].p->filter_offset,
-			t - survivor[0].p->lastpkt_recv_time
+			G.cur_time - survivor[0].p->lastpkt_recv_time
 	);
 	return survivor[0].p;
 }
@@ -981,8 +999,8 @@ set_new_values(int disc_state, double offset, double recv_time)
 #define STATE_FREQ      3       /* initial frequency */
 #define STATE_SYNC      4       /* clock synchronized (normal operation) */
 /* Return: -1: decrease poll interval, 0: leave as is, 1: increase */
-static int
-update_local_clock(peer_t *p, double t)
+static NOINLINE int
+update_local_clock(peer_t *p)
 {
 	int rc;
 	long old_tmx_offset;
@@ -1037,8 +1055,6 @@ update_local_clock(peer_t *p, double t)
 	 * offset exceeds the step threshold and when it does not.
 	 */
 	if (abs_offset > STEP_THRESHOLD) {
-		llist_t *item;
-
 		switch (G.discipline_state) {
 		case STATE_SYNC:
 			/* The first outlyer: ignore it, switch to SPIK state */
@@ -1089,10 +1105,6 @@ update_local_clock(peer_t *p, double t)
 		G.polladj_count = 0;
 		G.poll_exp = MINPOLL;
 		G.stratum = MAXSTRAT;
-		for (item = G.ntp_peers; item != NULL; item = item->link) {
-			peer_t *pp = (peer_t *) item->data;
-			reset_peer_stats(pp, t, offset);
-		}
 		if (G.discipline_state == STATE_NSET) {
 			set_new_values(STATE_FREQ, /*offset:*/ 0, recv_time);
 			return 1; /* "ok to increase poll interval" */
@@ -1101,8 +1113,9 @@ update_local_clock(peer_t *p, double t)
 
 	} else { /* abs_offset <= STEP_THRESHOLD */
 
-		if (G.poll_exp < MINPOLL) {
-			VERB3 bb_error_msg("saw small offset %f, disabling burst mode", offset);
+		if (G.poll_exp < MINPOLL && G.initial_poll_complete) {
+			VERB3 bb_error_msg("small offset:%f, disabling burst mode", offset);
+			G.polladj_count = 0;
 			G.poll_exp = MINPOLL;
 		}
 
@@ -1128,7 +1141,7 @@ update_local_clock(peer_t *p, double t)
 			 */
 			set_new_values(STATE_FREQ, offset, recv_time);
 			VERB3 bb_error_msg("transitioning to FREQ, datapoint ignored");
-			return -1; /* "decrease poll interval" */
+			return 0; /* "leave poll interval as is" */
 
 #if 0 /* this is dead code for now */
 		case STATE_FSET:
@@ -1180,12 +1193,12 @@ update_local_clock(peer_t *p, double t)
 		G.stratum = p->lastpkt_stratum + 1;
 	}
 
-	G.reftime = t;
+	G.reftime = G.cur_time;
 	G.ntp_status = p->lastpkt_status;
 	G.refid = p->lastpkt_refid;
 	G.rootdelay = p->lastpkt_rootdelay + p->lastpkt_delay;
 	dtemp = p->filter_jitter; // SQRT(SQUARE(p->filter_jitter) + SQUARE(s.jitter));
-	dtemp += MAXD(p->filter_dispersion + FREQ_TOLERANCE * (t - p->lastpkt_recv_time) + abs_offset, MINDISP);
+	dtemp += MAXD(p->filter_dispersion + FREQ_TOLERANCE * (G.cur_time - p->lastpkt_recv_time) + abs_offset, MINDISP);
 	G.rootdisp = p->lastpkt_rootdisp + dtemp;
 	VERB3 bb_error_msg("updating leap/refid/reftime/rootdisp from peer %s", p->p_dotted);
 
@@ -1318,19 +1331,20 @@ retry_interval(void)
 	return interval;
 }
 static unsigned
-poll_interval(int exponent) /* exp is always -1 or 0 */
+poll_interval(int exponent)
 {
 	/* Want to send next packet at (1 << G.poll_exp) + small random value */
 	unsigned interval, r;
-	exponent += G.poll_exp; /* G.poll_exp is always > 0 */
-	/* never true: if (exp < 0) exp = 0; */
+	exponent = G.poll_exp + exponent;
+	if (exponent < 0)
+		exponent = 0;
 	interval = 1 << exponent;
 	r = random();
 	interval += ((r & (interval-1)) >> 4) + ((r >> 8) & 1); /* + 1/16 of interval, max */
 	VERB3 bb_error_msg("chose poll interval:%u (poll_exp:%d exp:%d)", interval, G.poll_exp, exponent);
 	return interval;
 }
-static void
+static NOINLINE void
 recv_and_process_peer_pkt(peer_t *p)
 {
 	int         rc;
@@ -1410,12 +1424,12 @@ recv_and_process_peer_pkt(peer_t *p)
 	T1 = p->p_xmttime;
 	T2 = lfp_to_d(msg.m_rectime);
 	T3 = lfp_to_d(msg.m_xmttime);
-	T4 = gettime1900d();
+	T4 = G.cur_time;
 
 	p->lastpkt_recv_time = T4;
 
 	VERB5 bb_error_msg("%s->lastpkt_recv_time=%f", p->p_dotted, p->lastpkt_recv_time);
-	p->datapoint_idx = p->p_reachable_bits ? (p->datapoint_idx + 1) % NUM_DATAPOINTS : 0;
+	p->datapoint_idx = p->reachable_bits ? (p->datapoint_idx + 1) % NUM_DATAPOINTS : 0;
 	datapoint = &p->filter_datapoint[p->datapoint_idx];
 	datapoint->d_recv_time = T4;
 	datapoint->d_offset    = ((T2 - T1) + (T3 - T4)) / 2;
@@ -1429,7 +1443,7 @@ recv_and_process_peer_pkt(peer_t *p)
 	if (p->lastpkt_delay < G_precision_sec)
 		p->lastpkt_delay = G_precision_sec;
 	datapoint->d_dispersion = LOG2D(msg.m_precision_exp) + G_precision_sec;
-	if (!p->p_reachable_bits) {
+	if (!p->reachable_bits) {
 		/* 1st datapoint ever - replicate offset in every element */
 		int i;
 		for (i = 1; i < NUM_DATAPOINTS; i++) {
@@ -1437,20 +1451,20 @@ recv_and_process_peer_pkt(peer_t *p)
 		}
 	}
 
-	p->p_reachable_bits |= 1;
+	p->reachable_bits |= 1;
 	VERB1 {
 		bb_error_msg("reply from %s: reach 0x%02x offset %f delay %f",
 			p->p_dotted,
-			p->p_reachable_bits,
+			p->reachable_bits,
 			datapoint->d_offset, p->lastpkt_delay);
 	}
 
 	/* Muck with statictics and update the clock */
-	filter_datapoints(p, T4);
-	q = select_and_cluster(T4);
+	filter_datapoints(p);
+	q = select_and_cluster();
 	rc = -1;
 	if (q)
-		rc = update_local_clock(q, T4);
+		rc = update_local_clock(q);
 
 	if (rc != 0) {
 		/* Adjust the poll interval by comparing the current offset
@@ -1524,12 +1538,11 @@ recv_and_process_peer_pkt(peer_t *p)
 }
 
 #if ENABLE_FEATURE_NTPD_SERVER
-static void
+static NOINLINE void
 recv_and_process_client_pkt(void /*int fd*/)
 {
 	ssize_t          size;
 	uint8_t          version;
-	double           rectime;
 	len_and_sockaddr *to;
 	struct sockaddr  *from;
 	msg_t            msg;
@@ -1565,8 +1578,9 @@ recv_and_process_client_pkt(void /*int fd*/)
 	msg.m_stratum = G.stratum;
 	msg.m_ppoll = G.poll_exp;
 	msg.m_precision_exp = G_precision_exp;
-	rectime = gettime1900d();
-	msg.m_xmttime = msg.m_rectime = d_to_lfp(rectime);
+	/* this time was obtained between poll() and recv() */
+	msg.m_rectime = d_to_lfp(G.cur_time);
+	msg.m_xmttime = d_to_lfp(gettime1900d()); /* this instant */
 	msg.m_reftime = d_to_lfp(G.reftime);
 	msg.m_orgtime = query_xmttime;
 	msg.m_rootdelay = d_to_sfp(G.rootdelay);
@@ -1686,33 +1700,10 @@ static NOINLINE void ntp_init(char **argv)
 		bb_error_msg_and_die(bb_msg_you_must_be_root);
 
 	/* Set some globals */
-#if 0
-	/* With constant b = 100, G.precision_exp is also constant -6.
-	 * Uncomment this to verify.
-	 */
-	{
-		int prec = 0;
-		int b;
-# if 0
-		struct timespec	tp;
-		/* We can use sys_clock_getres but assuming 10ms tick should be fine */
-		clock_getres(CLOCK_REALTIME, &tp);
-		tp.tv_sec = 0;
-		tp.tv_nsec = 10000000;
-		b = 1000000000 / tp.tv_nsec;  /* convert to Hz */
-# else
-		b = 100; /* b = 1000000000/10000000 = 100 */
-# endif
-		while (b > 1)
-			prec--, b >>= 1;
-		/*G.precision_exp = prec;*/
-		/*G.precision_sec = (1.0 / (1 << (- prec)));*/
-		bb_error_msg("G.precision_exp:%d sec:%f", prec, G_precision_sec); /* -6 */
-	}
-#endif
 	G.stratum = MAXSTRAT;
-	G.poll_exp = 1; /* should use MINPOLL, but 1 speeds up initial sync */
-	G.reftime = G.last_update_recv_time = gettime1900d();
+	if (BURSTPOLL != 0)
+		G.poll_exp = BURSTPOLL; /* speeds up initial sync */
+	G.reftime = G.last_update_recv_time = gettime1900d(); /* sets G.cur_time too */
 
 	/* Parse options */
 	peers = NULL;
@@ -1752,61 +1743,66 @@ static NOINLINE void ntp_init(char **argv)
 int ntpd_main(int argc UNUSED_PARAM, char **argv) MAIN_EXTERNALLY_VISIBLE;
 int ntpd_main(int argc UNUSED_PARAM, char **argv)
 {
-	struct globals g;
+#undef G
+	struct globals G;
 	struct pollfd *pfd;
 	peer_t **idx2peer;
+	unsigned cnt;
 
-	memset(&g, 0, sizeof(g));
-	SET_PTR_TO_GLOBALS(&g);
+	memset(&G, 0, sizeof(G));
+	SET_PTR_TO_GLOBALS(&G);
 
 	ntp_init(argv);
 
-	{
-		/* if ENABLE_FEATURE_NTPD_SERVER, + 1 for listen_fd: */
-		unsigned cnt = g.peer_cnt + ENABLE_FEATURE_NTPD_SERVER;
-		idx2peer = xzalloc(sizeof(idx2peer[0]) * cnt);
-		pfd = xzalloc(sizeof(pfd[0]) * cnt);
-	}
+	/* If ENABLE_FEATURE_NTPD_SERVER, + 1 for listen_fd: */
+	cnt = G.peer_cnt + ENABLE_FEATURE_NTPD_SERVER;
+	idx2peer = xzalloc(sizeof(idx2peer[0]) * cnt);
+	pfd = xzalloc(sizeof(pfd[0]) * cnt);
+
+	/* Countdown: we never sync before we sent 5 packets to each peer
+	 * NB: if some peer is not responding, we may end up sending
+	 * fewer packets to it and more to other peers.
+	 * NB2: sync usually happens using 5-1=4 packets, since last reply
+	 * does not come back instantaneously.
+	 */
+	cnt = G.peer_cnt * 5;
 
 	while (!bb_got_signal) {
 		llist_t *item;
 		unsigned i, j;
-		unsigned sent_cnt, trial_cnt;
 		int nfds, timeout;
-		time_t cur_time, nextaction;
+		double nextaction;
 
 		/* Nothing between here and poll() blocks for any significant time */
 
-		cur_time = time(NULL);
-		nextaction = cur_time + 3600;
+		nextaction = G.cur_time + 3600;
 
 		i = 0;
 #if ENABLE_FEATURE_NTPD_SERVER
-		if (g.listen_fd != -1) {
-			pfd[0].fd = g.listen_fd;
+		if (G.listen_fd != -1) {
+			pfd[0].fd = G.listen_fd;
 			pfd[0].events = POLLIN;
 			i++;
 		}
 #endif
 		/* Pass over peer list, send requests, time out on receives */
-		sent_cnt = trial_cnt = 0;
-		for (item = g.ntp_peers; item != NULL; item = item->link) {
+		for (item = G.ntp_peers; item != NULL; item = item->link) {
 			peer_t *p = (peer_t *) item->data;
 
-			/* Overflow-safe "if (p->next_action_time <= cur_time) ..." */
-			if ((int)(cur_time - p->next_action_time) >= 0) {
+			if (p->next_action_time <= G.cur_time) {
 				if (p->p_fd == -1) {
 					/* Time to send new req */
-					trial_cnt++;
-					if (send_query_to_peer(p) == 0)
-						sent_cnt++;
+					if (--cnt == 0) {
+						G.initial_poll_complete = 1;
+					}
+					send_query_to_peer(p);
 				} else {
 					/* Timed out waiting for reply */
 					close(p->p_fd);
 					p->p_fd = -1;
-					timeout = poll_interval(-1); /* try a bit faster */
+					timeout = poll_interval(-2); /* -2: try a bit sooner */
 					bb_error_msg("timed out waiting for %s, reach 0x%02x, next query in %us",
-							p->p_dotted, p->p_reachable_bits, timeout);
+							p->p_dotted, p->reachable_bits, timeout);
 					set_next(p, timeout);
 				}
 			}
@@ -1823,23 +1819,26 @@ int ntpd_main(int argc UNUSED_PARAM, char **argv)
 			}
 		}
 
-		timeout = nextaction - cur_time;
-		if (timeout < 1)
-			timeout = 1;
+		timeout = nextaction - G.cur_time;
+		if (timeout < 0)
+			timeout = 0;
+		timeout++; /* (nextaction - G.cur_time) rounds down, compensating */
 
 		/* Here we may block */
 		VERB2 bb_error_msg("poll %us, sockets:%u", timeout, i);
 		nfds = poll(pfd, i, timeout * 1000);
+		gettime1900d(); /* sets G.cur_time */
 		if (nfds <= 0)
 			continue;
 
 		/* Process any received packets */
 		j = 0;
 #if ENABLE_FEATURE_NTPD_SERVER
-		if (g.listen_fd != -1) {
+		if (G.listen_fd != -1) {
 			if (pfd[0].revents /* & (POLLIN|POLLERR)*/) {
 				nfds--;
-				recv_and_process_client_pkt(/*g.listen_fd*/);
+				recv_and_process_client_pkt(/*G.listen_fd*/);
+				gettime1900d(); /* sets G.cur_time */
 			}
 			j = 1;
 		}
@@ -1848,6 +1847,7 @@ int ntpd_main(int argc UNUSED_PARAM, char **argv)
 			if (pfd[j].revents /* & (POLLIN|POLLERR)*/) {
 				nfds--;
 				recv_and_process_peer_pkt(idx2peer[j]);
+				gettime1900d(); /* sets G.cur_time */
 			}
 		}
 	} /* while (!bb_got_signal) */
-- 
1.6.3.3



More information about the busybox-cvs mailing list