📄 1
字号:
From tgl@sss.pgh.pa.us Sun Jun 16 03:34:01 1996To: Mills@huey.udel.educc: ken@sdd.hp.comSubject: Re: Proposed change to adjtimed for HPUX In-reply-to: Your message of Fri, 1 Mar 96 14:09:29 EST <9603011409.aa22376@huey.udel.edu> Date: Sun, 24 Mar 1996 21:14:55 -0500From: Tom Lane <tgl@sss.pgh.pa.us>I finally figured out why I was still getting occasional "Previous timeadjustment didn't complete" messages even with my revisions to theadjtimed daemon. Should've been obvious. The daemon process, of course,is subject to scheduling delays. If a near-maximum time slew is requestedat the top of the second, but the daemon is not dispatched to begin it fora few ticks, then the slew will not be complete at the top of the nextsecond.The old version of the daemon was extremely prone to this problem becauseit would always schedule the slew to occur over one full second. (Itvaried the tickadj delta rather than the time interval over which thedelta is applied.) So even a one-tick scheduling delay would trigger acomplaint.The patch attached below makes adjtimed work more like the customaryBSD-ish flavor of adjtime(2): constant slew rate of 5 microsec/tickapplied over as long a period as needed to get the requested delta.This is much less likely to trigger a didn't-complete complaint for slewsless than the maximum possible slew. Also, the patch increases theprocess priority (decreases nice setting) to reduce the chances that thedaemon will not be executed immediately when it needs to run.In addition to fixing the daemon, the attached patch changesntp_unixclock.c to reduce the maxslew value a little bit when using thisdaemon. This is the same tweak applied when SLEWALWAYS is defined, andit gives further defense against didn't-complete gripes.Although the patched code can still get the didn't-complete complaint,it is much less likely to do so than the original code. It has a coupleof other advantages, I think: it works much more like BSD adjtime than theold code, so should create fewer compatibility problems; and it workscorrectly for slews exceeding 1 second, which is not an issue for ntpd butis an issue for other applications that might like to use this emulationof adjtime(). regards, tom laneNote: these are diffs against ntpd 3.5a; haven't gotten around todownloading the newer releases yet.*** adjtime/adjtimed.c.orig Mon Oct 3 06:02:20 1994--- adjtime/adjtimed.c Sat Mar 23 15:43:08 1996****************** 18,29 **** /* * Adjust time daemon.! * This deamon adjusts the rate of the system clock a la BSD's adjtime(). * The adjtime() routine uses SYSV messages to communicate with this daemon. * * Caveat: This emulation uses an undocumented kernel variable. As such, it! * cannot be guaranteed to work in future HP-UX releases. Perhaps a real! * adjtime(2) will be supported in the future. */ #include <sys/param.h>--- 18,29 ---- /* * Adjust time daemon.! * This daemon adjusts the rate of the system clock a la BSD's adjtime(). * The adjtime() routine uses SYSV messages to communicate with this daemon. * * Caveat: This emulation uses an undocumented kernel variable. As such, it! * cannot be guaranteed to work in future HP-UX releases. Fortunately,! * it will no longer be needed in HPUX 10.01 and later. */ #include <sys/param.h>****************** 37,42 ****--- 37,43 ---- #include <fcntl.h> #include <stdio.h> #include <errno.h>+ #include <unistd.h> #include "ntp_syslog.h" #include "adjtime.h" ****************** 196,208 **** perror("adjtimed: get message queue id"); Exit(1); }! if (plock(PROCLOCK)) { syslog(LOG_ERR, "plock: %m"); perror("adjtimed: plock"); Cleanup(); } for (;;) { if (msgrcv(mqid, &msg.msgp, MSGSIZE, CLIENT, 0) == -1) { if (errno == EINTR) continue;--- 197,220 ---- perror("adjtimed: get message queue id"); Exit(1); }! ! /* Lock process in memory to improve response time */ if (plock(PROCLOCK)) { syslog(LOG_ERR, "plock: %m"); perror("adjtimed: plock"); Cleanup(); } + /* Also raise process priority.+ * If we do not get run when we want, this leads to bad timekeeping+ * and "Previous time adjustment didn't complete" gripes from xntpd.+ */+ if (nice(-10) == -1) {+ syslog(LOG_ERR, "nice: %m");+ perror("adjtimed: nice");+ Cleanup();+ }+ for (;;) { if (msgrcv(mqid, &msg.msgp, MSGSIZE, CLIENT, 0) == -1) { if (errno == EINTR) continue;****************** 252,317 **** */ #define DEFAULT_RATE (MILLION / HZ) #define UNKNOWN_RATE 0L! #define SLEW_RATE (MILLION / DEFAULT_RATE)! #define MIN_DELTA SLEW_RATE static long default_rate = DEFAULT_RATE;! static long slew_rate = SLEW_RATE; AdjustClockRate(delta, olddelta) register struct timeval *delta, *olddelta; { register long rate, dt; struct itimerval period, remains;- static long leftover = 0;- /*- * rate of change- */- dt = (delta->tv_sec * MILLION) + delta->tv_usec + leftover;- - if (dt < MIN_DELTA && dt > -MIN_DELTA) {- leftover += delta->tv_usec;- - if (olddelta) {- getitimer(ITIMER_REAL, &remains);- dt = ((remains.it_value.tv_sec * MILLION) + remains.it_value.tv_usec) *- oldrate;- olddelta->tv_sec = dt / MILLION;- olddelta->tv_usec = dt - (olddelta->tv_sec * MILLION); - } ! if (verbose > 2) printf("adjtimed: delta is too small: %dus\n", dt);! if (sysdebug > 2) syslog(LOG_INFO, "delta is too small: %dus", dt);! return (1);! }! ! leftover = dt % MIN_DELTA;! dt -= leftover; if (verbose) printf("adjtimed: new correction %.6fs\n", (double)dt / (double)MILLION); if (sysdebug) syslog(LOG_INFO, "new correction %.6fs", (double)dt / (double)MILLION);- if (verbose > 2) printf("adjtimed: leftover %dus\n", leftover);- if (sysdebug > 2) syslog(LOG_INFO, "leftover %dus", leftover);- rate = dt; /*! * The adjustment will always be a multiple of the minimum adjustment.! * So the period will always be a whole second value. */- period.it_value.tv_sec = 1l;- period.it_value.tv_usec = 0;- if (verbose > 1)! printf("adjtimed: will be complete in %ds\n", period.it_value.tv_sec); if (sysdebug > 1)! syslog(LOG_INFO, "will be complete in %ds", period.it_value.tv_sec); /* * adjust the clock rate */! if (SetClockRate((rate / slew_rate) + default_rate) == -1) {! syslog(LOG_ERR, "set clock rate: %m");! perror("adjtimed: set clock rate"); } /* * start the timer--- 264,319 ---- */ #define DEFAULT_RATE (MILLION / HZ) #define UNKNOWN_RATE 0L! #define TICK_ADJ 5 /* standard adjustment rate, microsec/tick */! static long default_rate = DEFAULT_RATE;! static long tick_rate = HZ; /* ticks per sec */! static long slew_rate = TICK_ADJ * HZ; /* in microsec/sec */ AdjustClockRate(delta, olddelta) register struct timeval *delta, *olddelta; { register long rate, dt; struct itimerval period, remains; ! dt = (delta->tv_sec * MILLION) + delta->tv_usec; if (verbose) printf("adjtimed: new correction %.6fs\n", (double)dt / (double)MILLION); if (sysdebug) syslog(LOG_INFO, "new correction %.6fs", (double)dt / (double)MILLION); /*! * Apply a slew rate of slew_rate over a period of dt/slew_rate seconds.! */! if (dt > 0) {! rate = slew_rate;! } else {! rate = -slew_rate;! dt = -dt;! }! period.it_value.tv_sec = dt / slew_rate;! period.it_value.tv_usec = (dt % slew_rate) * (MILLION / slew_rate);! /*! * Note: we assume the kernel will convert the specified period into ticks! * using the modified clock rate rather than an assumed nominal clock rate,! * and therefore will generate the timer interrupt after the specified! * number of true seconds, not skewed seconds. */ if (verbose > 1)! printf("adjtimed: will be complete in %lds %ldus\n",! period.it_value.tv_sec, period.it_value.tv_usec); if (sysdebug > 1)! syslog(LOG_INFO, "will be complete in %lds %ldus",! period.it_value.tv_sec, period.it_value.tv_usec); /* * adjust the clock rate */! if (dt) {! if (SetClockRate((rate / tick_rate) + default_rate) == -1) {! syslog(LOG_ERR, "set clock rate: %m");! perror("adjtimed: set clock rate");! } } /* * start the timer****************** 390,400 **** if (rate != default_rate) { if (verbose > 3) { printf("adjtimed: clock rate (%lu) %ldus/s\n", rate,! (rate - default_rate) * slew_rate); } if (sysdebug > 3) { syslog(LOG_INFO, "clock rate (%lu) %ldus/s", rate,! (rate - default_rate) * slew_rate); } } --- 392,402 ---- if (rate != default_rate) { if (verbose > 3) { printf("adjtimed: clock rate (%lu) %ldus/s\n", rate,! (rate - default_rate) * tick_rate); } if (sysdebug > 3) { syslog(LOG_INFO, "clock rate (%lu) %ldus/s", rate,! (rate - default_rate) * tick_rate); } } ****************** 421,427 **** */ default_rate = GetClockRate(); if (default_rate == UNKNOWN_RATE) default_rate = DEFAULT_RATE;! slew_rate = (MILLION / default_rate); return (0); } /* InitClockRate */--- 423,430 ---- */ default_rate = GetClockRate(); if (default_rate == UNKNOWN_RATE) default_rate = DEFAULT_RATE;! tick_rate = (MILLION / default_rate);! slew_rate = TICK_ADJ * tick_rate; return (0); } /* InitClockRate */*** xntpd/ntp_unixclock.c.orig Mon Feb 5 17:58:30 1996--- xntpd/ntp_unixclock.c Sun Mar 24 16:41:51 1996****************** 180,185 ****--- 180,192 ---- adj_precision = (1<<CLOCK_ADJ) * hz * 0.1; #endif /* SYS_WINNT */ #endif /* ADJTIME_IS_ACCURATE */+ #if defined(SYS_HPUX) && (SYS_HPUX < 10)+ /*+ * when using adjtimed daemon, need to allow more time+ * because daemon may not run right away+ */+ tvu_maxslew = tickadj * (hz-3) * (1<<CLOCK_ADJ);+ #else #if defined(SLEWALWAYS) && !defined(ADJTIME_IS_ACCURATE) /* * give us more time if we are always slewing... just in case****************** 192,197 ****--- 199,205 ---- tvu_maxslew = tickadj * hz * (1<<CLOCK_ADJ); #endif /* SYS_WINTNT */ #endif /* SLEWALWAYS */+ #endif /* SYS_HPUX */ if (tvu_maxslew > 999990) { /* * Don't let the maximum slew exceed 1 second in 4. This
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -