diff options
| author | Ollivier Robert <roberto@FreeBSD.org> | 2008-08-18 14:26:05 +0000 | 
|---|---|---|
| committer | Ollivier Robert <roberto@FreeBSD.org> | 2008-08-18 14:26:05 +0000 | 
| commit | ff717da2cf625e3d07537a93a4c240692fa55bd6 (patch) | |
| tree | 9dcf618e4446ac2b5fca7d0afe7767382664f0d6 /libntp/adjtime.c | |
| parent | cce65f439697627afbccf5a67035a957bb4d784a (diff) | |
Diffstat (limited to 'libntp/adjtime.c')
| -rw-r--r-- | libntp/adjtime.c | 97 | 
1 files changed, 80 insertions, 17 deletions
| diff --git a/libntp/adjtime.c b/libntp/adjtime.c index f04145010ccb5..a8e65808bf291 100644 --- a/libntp/adjtime.c +++ b/libntp/adjtime.c @@ -249,19 +249,32 @@ _adjtime(  /*   * Emulate adjtime() using QNX ClockAdjust().   * Chris Burghart <burghart@atd.ucar.edu>, 11/2001 + * Miroslaw Pabich <miroslaw_pabich@o2.pl>, 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 <math.h> -# include <stdio.h>  # include <sys/neutrino.h>  # include <sys/time.h>  # include <ntp_stdlib.h> +/* + * 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 */ | 
