From: Dave Hart Date: Sun, 9 Oct 2011 05:08:21 +0000 (+0000) Subject: [Bug 2025] Switching between daemon and kernel loops can doubly- X-Git-Tag: NTP_4_2_7P221~4 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=48ecc007aeac93e6b4c06a8a088d76962d8a7b99;p=thirdparty%2Fntp.git [Bug 2025] Switching between daemon and kernel loops can doubly- correct drift bk: 4e912c45P5V56N19P49dz8jneoJszA --- diff --git a/ChangeLog b/ChangeLog index 10dc67f95..8e56a9386 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,5 @@ +* [Bug 2025] Switching between daemon and kernel loops can doubly- + correct drift (4.2.7p220) 2011/10/05 Released by Harlan Stenn * [Bug 1945] mbg_gps166.h use of _TM_DEFINED conflicts with MS VC. * [Bug 1946] parse_start uses open; does not work on Windows. diff --git a/include/ntp_stdlib.h b/include/ntp_stdlib.h index 390eefc1a..7669e298f 100644 --- a/include/ntp_stdlib.h +++ b/include/ntp_stdlib.h @@ -152,7 +152,9 @@ extern char * mfptoms (u_long, u_long, short); extern const char * modetoa (int); extern const char * eventstr (int); extern const char * ceventstr (int); +#ifdef KERNEL_PLL extern const char * k_st_flags (u_int32); +#endif extern char * statustoa (int, int); extern sockaddr_u * netof (sockaddr_u *); extern char * numtoa (u_int32); diff --git a/include/ntpd.h b/include/ntpd.h index dfd74bdcc..72211c7d9 100644 --- a/include/ntpd.h +++ b/include/ntpd.h @@ -148,6 +148,7 @@ extern void init_loopfilter(void); extern int local_clock(struct peer *, double); extern void adj_host_clock(void); extern void loop_config(int, double); +extern void select_loop(int); extern void huffpuff(void); extern u_long sys_clocktime; extern u_int sys_tai; diff --git a/include/refclock_atom.h b/include/refclock_atom.h index 7d83a0a0b..452e933a8 100644 --- a/include/refclock_atom.h +++ b/include/refclock_atom.h @@ -1,6 +1,7 @@ /* * Definitions for the atom driver and its friends */ +#undef NANOSECOND /* some systems define it differently */ #define NANOSECOND 1000000000 /* one second (ns) */ struct refclock_atom { diff --git a/libntp/statestr.c b/libntp/statestr.c index 50b02c2bd..19df9907b 100644 --- a/libntp/statestr.c +++ b/libntp/statestr.c @@ -316,7 +316,9 @@ decode_bitflags( char * lim; size_t b; int rc; + int saved_errno; /* for use in DPRINTF with %m */ + saved_errno = errno; LIB_GETBUF(buf); pch = buf; lim = buf + LIB_BUFLENGTH; @@ -350,6 +352,7 @@ decode_bitflags( #endif "", bits, (int)LIB_BUFLENGTH); + errno = saved_errno; return buf; } diff --git a/ntpd/cmd_args.c b/ntpd/cmd_args.c index 0b54d5b2b..5357ace9c 100644 --- a/ntpd/cmd_args.c +++ b/ntpd/cmd_args.c @@ -167,10 +167,8 @@ getCmdOpts( } while (--ct > 0); } - if (HAVE_OPT( SLEW )) { - clock_max = 600; - kern_enable = 0; - } + if (HAVE_OPT( SLEW )) + loop_config(LOOP_MAX, 600); if (HAVE_OPT( UPDATEINTERVAL )) { long val = OPT_VALUE_UPDATEINTERVAL; diff --git a/ntpd/ntp_loopfilter.c b/ntpd/ntp_loopfilter.c index 9237b5e17..641d85ad1 100644 --- a/ntpd/ntp_loopfilter.c +++ b/ntpd/ntp_loopfilter.c @@ -121,6 +121,7 @@ double clock_stability; /* frequency stability (wander) (s/s) */ double clock_codec; /* audio codec frequency (samples/s) */ static u_long clock_epoch; /* last update */ u_int sys_tai; /* TAI offset from UTC */ +static int loop_started; /* TRUE after LOOP_DRIFTINIT */ static void rstclock (int, double); /* transition function */ static double direct_freq(double); /* direct set frequency */ static void set_freq(double); /* set frequency */ @@ -131,6 +132,8 @@ int pll_status; /* last kernel status bits */ #if defined(STA_NANO) && NTP_API == 4 static u_int loop_tai; /* last TAI offset */ #endif /* STA_NANO */ +static void start_kern_loop(void); +static void stop_kern_loop(void); #endif /* KERNEL_PLL */ /* @@ -504,7 +507,7 @@ local_clock( * frequency offsets for jitter and stability values and * to update the frequency file. */ - memset(&ntv, 0, sizeof(ntv)); + ZERO(ntv); if (ext_enable) { ntv.modes = MOD_STATUS; } else { @@ -558,9 +561,11 @@ local_clock( * frequency and jitter. */ if (ntp_adjtime(&ntv) == TIME_ERROR) { - if (!(ntv.status & STA_PPSSIGNAL)) + if (pps_enable && !(ntv.status & STA_PPSSIGNAL)) report_event(EVNT_KERN, NULL, "PPS no signal"); + DPRINTF(1, ("kernel loop status (%s) %d %m\n", + k_st_flags(ntv.status), errno)); } pll_status = ntv.status; #ifdef STA_NANO @@ -771,6 +776,7 @@ rstclock( clock_epoch = current_time; } + /* * calc_freq - calculate frequency directly * @@ -794,7 +800,16 @@ direct_freq( /* - * set_freq - set clock frequency + * set_freq - set clock frequency correction + * + * Used to step the frequency correction at startup, possibly again once + * the frequency is measured (that is, transitioning from EVNT_NSET to + * EVNT_FSET), and finally to switch between daemon and kernel loop + * discipline at runtime. + * + * When the kernel loop discipline is available but the daemon loop is + * in use, the kernel frequency correction is disabled (set to 0) to + * ensure drift_comp is applied by only one of the loops. */ static void set_freq( @@ -806,11 +821,13 @@ set_freq( drift_comp = freq; loop_desc = "ntpd"; #ifdef KERNEL_PLL - if (pll_control && kern_enable) { - loop_desc = "kernel"; + if (pll_control) { ZERO(ntv); ntv.modes = MOD_FREQUENCY; - ntv.freq = DTOFREQ(drift_comp); + if (kern_enable) { + loop_desc = "kernel"; + ntv.freq = DTOFREQ(drift_comp); + } ntp_adjtime(&ntv); } #endif /* KERNEL_PLL */ @@ -818,6 +835,112 @@ set_freq( drift_comp * 1e6); } + +#ifdef KERNEL_PLL +static void +start_kern_loop(void) +{ + static int atexit_done; + + pll_control = TRUE; + ZERO(ntv); + ntv.modes = MOD_BITS; + ntv.status = STA_PLL; + ntv.maxerror = MAXDISPERSE; + ntv.esterror = MAXDISPERSE; + ntv.constant = sys_poll; +#ifdef SIGSYS + /* + * Use sigsetjmp() to save state and then call ntp_adjtime(); if + * it fails, then pll_trap() will set pll_control FALSE before + * returning control using siglogjmp(). + */ + newsigsys.sa_handler = pll_trap; + newsigsys.sa_flags = 0; + if (sigaction(SIGSYS, &newsigsys, &sigsys)) { + msyslog(LOG_ERR, "sigaction() trap SIGSYS: %m"); + pll_control = FALSE; + } else { + if (sigsetjmp(env, 1) == 0) + ntp_adjtime(&ntv); + if (sigaction(SIGSYS, &sigsys, NULL)) { + msyslog(LOG_ERR, + "sigaction() restore SIGSYS: %m"); + pll_control = FALSE; + } + } +#else /* SIGSYS */ + ntp_adjtime(&ntv); +#endif /* SIGSYS */ + + /* + * Save the result status and light up an external clock + * if available. + */ + pll_status = ntv.status; + if (pll_control) { + if (!atexit_done) { + atexit_done = TRUE; + atexit(&stop_kern_loop); + } +#ifdef STA_NANO + if (pll_status & STA_CLK) + ext_enable = TRUE; +#endif /* STA_NANO */ + report_event(EVNT_KERN, NULL, + "kernel time sync enabled"); + } +} +#endif /* KERNEL_PLL */ + + +#ifdef KERNEL_PLL +static void +stop_kern_loop(void) +{ + if (pll_control && kern_enable) { + ZERO(ntv); + ntv.modes = MOD_STATUS; + ntv.status = STA_UNSYNC; + ntp_adjtime(&ntv); + report_event(EVNT_KERN, NULL, + "kernel time sync disabled"); + } +} +#endif /* KERNEL_PLL */ + + +/* + * select_loop() - choose kernel or daemon loop discipline. + */ +void +select_loop( + int use_kern_loop + ) +{ + if (kern_enable == use_kern_loop) + return; +#ifdef KERNEL_PLL + if (pll_control && !use_kern_loop) + stop_kern_loop(); +#endif + kern_enable = use_kern_loop; +#ifdef KERNEL_PLL + if (pll_control && use_kern_loop) + start_kern_loop(); +#endif + /* + * If this loop selection change occurs after initial startup, + * call set_freq() to switch the frequency compensation to or + * from the kernel loop. + */ +#ifdef KERNEL_PLL + if (pll_control && loop_started) + set_freq(drift_comp); +#endif +} + + /* * huff-n'-puff filter */ @@ -870,51 +993,7 @@ loop_config( if (mode_ntpdate) break; - pll_control = 1; - memset(&ntv, 0, sizeof(ntv)); - ntv.modes = MOD_BITS; - ntv.status = STA_PLL; - ntv.maxerror = MAXDISPERSE; - ntv.esterror = MAXDISPERSE; - ntv.constant = sys_poll; -#ifdef SIGSYS - /* - * Use sigsetjmp() to save state and then call - * ntp_adjtime(); if it fails, then siglongjmp() is used - * to return control - */ - newsigsys.sa_handler = pll_trap; - newsigsys.sa_flags = 0; - if (sigaction(SIGSYS, &newsigsys, &sigsys)) { - msyslog(LOG_ERR, - "sigaction() fails to save SIGSYS trap: %m"); - pll_control = 0; - } - if (sigsetjmp(env, 1) == 0) - ntp_adjtime(&ntv); - if ((sigaction(SIGSYS, &sigsys, - (struct sigaction *)NULL))) { - msyslog(LOG_ERR, - "sigaction() fails to restore SIGSYS trap: %m"); - pll_control = 0; - } -#else /* SIGSYS */ - ntp_adjtime(&ntv); -#endif /* SIGSYS */ - - /* - * Save the result status and light up an external clock - * if available. - */ - pll_status = ntv.status; - if (pll_control) { -#ifdef STA_NANO - if (pll_status & STA_CLK) - ext_enable = 1; -#endif /* STA_NANO */ - report_event(EVNT_KERN, NULL, - "kernel time sync enabled"); - } + start_kern_loop(); #endif /* KERNEL_PLL */ /* @@ -931,6 +1010,7 @@ loop_config( rstclock(EVNT_FSET, 0); else rstclock(EVNT_NSET, 0); + loop_started = TRUE; #endif /* LOCKCLOCK */ break; @@ -943,14 +1023,7 @@ loop_config( case LOOP_KERN_CLEAR: #ifndef LOCKCLOCK #ifdef KERNEL_PLL - if (pll_control && kern_enable) { - memset((char *)&ntv, 0, sizeof(ntv)); - ntv.modes = MOD_STATUS; - ntv.status = STA_UNSYNC; - ntp_adjtime(&ntv); - report_event(EVNT_KERN, NULL, - "kernel time sync disabled"); - } + stop_kern_loop(); #endif /* KERNEL_PLL */ #endif /* LOCKCLOCK */ break; @@ -979,7 +1052,7 @@ loop_config( if (freq < HUFFPUFF) freq = HUFFPUFF; sys_hufflen = (int)(freq / HUFFPUFF); - sys_huffpuff = (double *)emalloc(sizeof(double) * + sys_huffpuff = emalloc(sizeof(sys_huffpuff[0]) * sys_hufflen); for (i = 0; i < sys_hufflen; i++) sys_huffpuff[i] = 1e9; @@ -993,7 +1066,7 @@ loop_config( case LOOP_MAX: /* step threshold (step) */ clock_max = freq; if (clock_max == 0 || clock_max > 0.5) - kern_enable = 0; + select_loop(FALSE); break; case LOOP_MINSTEP: /* stepout threshold (stepout) */ @@ -1025,7 +1098,7 @@ pll_trap( int arg ) { - pll_control = 0; + pll_control = FALSE; siglongjmp(env, 1); } #endif /* KERNEL_PLL && SIGSYS */ diff --git a/ntpd/ntp_proto.c b/ntpd/ntp_proto.c index d75312b0d..6fbf67c6a 100644 --- a/ntpd/ntp_proto.c +++ b/ntpd/ntp_proto.c @@ -3866,7 +3866,7 @@ proto_config( #endif /* REFCLOCK */ case PROTO_KERNEL: /* kernel discipline (kernel) */ - kern_enable = value; + select_loop(value); break; case PROTO_MONITOR: /* monitoring (monitor) */