From: Harlan Stenn Date: Fri, 23 Sep 2005 02:07:15 +0000 (-0400) Subject: [Bug 496]: Updated adjtime for QNX from Miroslaw Pabich X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c570e1911eb66063f24dd31d33dbcadb56b9ff22;p=thirdparty%2Fntp.git [Bug 496]: Updated adjtime for QNX from Miroslaw Pabich bk: 43336353du_0DjTG96zXeIKQfHXN_A --- diff --git a/libntp/adjtime.c b/libntp/adjtime.c index f04145010c..a8e65808bf 100644 --- a/libntp/adjtime.c +++ b/libntp/adjtime.c @@ -249,19 +249,32 @@ _adjtime( /* * Emulate adjtime() using QNX ClockAdjust(). * Chris Burghart , 11/2001 + * Miroslaw Pabich , 09/2005 * - * This is a *very* simple implementation of adjtime() for QNX. - * ClockAdjust() is used to tweak the system clock by about +- 1/10 - * of its current clock period per tick until the desired delta is - * achieved. + * This is an implementation of adjtime() for QNX. + * ClockAdjust() is used to tweak the system clock for about + * 1 second period until the desired delta is achieved. + * Time correction slew is limited to reasonable value. + * Internal rounding and relative errors are reduced. */ -# include -# include # include # include # include +/* + * Time correction slew limit. QNX is a hard real-time system, + * so don't adjust system clock too fast. + */ +#define CORR_SLEW_LIMIT 0.02 /* [s/s] */ + +/* + * Period of system clock adjustment. It should be equal to adjtime + * execution period (1s). If slightly less than 1s (0.95-0.99), then olddelta + * residual error (introduced by execution period jitter) will be reduced. + */ +#define ADJUST_PERIOD 0.97 /* [s] */ + int adjtime (struct timeval *delta, struct timeval *olddelta) { @@ -269,10 +282,15 @@ adjtime (struct timeval *delta, struct timeval *olddelta) double delta_nsec_old; struct _clockadjust adj; struct _clockadjust oldadj; + /* * How many nanoseconds are we adjusting? */ - delta_nsec = delta->tv_sec * 1e9 + delta->tv_usec * 1000; + if (delta != NULL) + delta_nsec = 1e9 * (long)delta->tv_sec + 1e3 * delta->tv_usec; + else + delta_nsec = 0; + /* * Build the adjust structure and call ClockAdjust() */ @@ -281,6 +299,17 @@ adjtime (struct timeval *delta, struct timeval *olddelta) struct _clockperiod period; long count; long increment; + long increment_limit; + int isneg = 0; + + /* + * Convert to absolute value for future processing + */ + if (delta_nsec < 0) + { + isneg = 1; + delta_nsec = -delta_nsec; + } /* * Get the current clock period (nanoseconds) @@ -289,13 +318,34 @@ adjtime (struct timeval *delta, struct timeval *olddelta) return -1; /* - * Set the adjust increment to approximately 1/10 timer period per - * clock tick. + * Compute count and nanoseconds increment + */ + count = 1e9 * ADJUST_PERIOD / period.nsec; + increment = delta_nsec / count + .5; + /* Reduce relative error */ + if (count > increment + 1) + { + increment = 1 + (long)((delta_nsec - 1) / count); + count = delta_nsec / increment + .5; + } + + /* + * Limit the adjust increment to appropriate value */ - count = 1 + (long)(fabs(10 * delta_nsec / period.nsec)); - increment = (long)(delta_nsec / count); + increment_limit = CORR_SLEW_LIMIT * period.nsec; + if (increment > increment_limit) + { + increment = increment_limit; + count = delta_nsec / increment + .5; + /* Reduce relative error */ + if (increment > count + 1) + { + count = 1 + (long)((delta_nsec - 1) / increment); + increment = delta_nsec / count + .5; + } + } - adj.tick_nsec_inc = increment; + adj.tick_nsec_inc = isneg ? -increment : increment; adj.tick_count = count; } else @@ -310,11 +360,24 @@ adjtime (struct timeval *delta, struct timeval *olddelta) /* * Build olddelta */ - delta_nsec_old = oldadj.tick_count * oldadj.tick_nsec_inc; - olddelta->tv_sec = (int)(delta_nsec_old / 1e9); - olddelta->tv_usec = (int)((delta_nsec_old - 1.0e9 * olddelta->tv_sec) / - 1000); - + delta_nsec_old = (double)oldadj.tick_count * oldadj.tick_nsec_inc; + if (olddelta != NULL) + { + if (delta_nsec_old != 0) + { + /* Reduce rounding error */ + delta_nsec_old += (delta_nsec_old < 0) ? -500 : 500; + olddelta->tv_sec = delta_nsec_old / 1e9; + olddelta->tv_usec = (long)(delta_nsec_old - 1e9 + * (long)olddelta->tv_sec) / 1000; + } + else + { + olddelta->tv_sec = 0; + olddelta->tv_usec = 0; + } + } + return 0; } # else /* no special adjtime() needed */