summaryrefslogtreecommitdiffstats
path: root/usr.sbin/xntpd/kernel/README.kern
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/xntpd/kernel/README.kern')
-rw-r--r--usr.sbin/xntpd/kernel/README.kern596
1 files changed, 596 insertions, 0 deletions
diff --git a/usr.sbin/xntpd/kernel/README.kern b/usr.sbin/xntpd/kernel/README.kern
new file mode 100644
index 0000000..64ba9c5
--- /dev/null
+++ b/usr.sbin/xntpd/kernel/README.kern
@@ -0,0 +1,596 @@
+Precision Time and Frequency Synchronization Using Modified Kernels
+
+1. Introduction
+
+This memo describes replacements for certain SunOS and Ultrix kernel
+routines that manage the system clock and timer functions. They provide
+improved accuracy and stability through the use of a disciplined clock
+interface for use with the Network Time Protocol (NTP) or similar time-
+synchronization protocol. In addition, for certain models of the
+DECstation 5000 product line, the new routines provide improved
+precision to +-1 microsecond (us) (SunOS 4.1.1 already does provide
+precision to +-1 us). The current public NTP distribution cooperates
+with these kernel routines to provide synchronization in principle to
+within a microsecond, but in practice this is limited by the short-term
+stability of the oscillator that drives the timer interrupt.
+
+This memo describes the principles behind the design and operation of
+the software. There are two versions of the software, one that operates
+with the SunOS 4.1.1 kernel and the other that operates with the Ultrix
+4.2a kernel (and probably the 4.3 kernel, although this has not been
+tested). A detailed description of the variables and algorithms is given
+in the hope that similar improvements can be incorporated in Unix
+kernels for other machines. The software itself is not included in this
+memo, since it involves licensed code. Detailed instructions on where to
+obtain it for either SunOS or Ultrix will be given separately.
+
+The principle function added to the SunOS and Ultrix kernels is to
+change the way the system clock is controlled, in order to provide
+precision time and frequency adjustments. Another function utilizes an
+undocumented counter in the DECstation hardware to provide precise time
+to the microsecond. This function can be used only with the DECstation
+5000/240 and possibly others that use the same input/output chipset.
+
+2. Design Principles
+
+In order to understand how these routines work, it is useful to consider
+how most Unix systems maintain the system clock. In the original design
+a hardware timer interrupts the kernel at some fixed rate, such as 100
+Hz in the SunOS kernel and 256 Hz in the Ultrix kernel. Since 256 does
+not evenly divide the second in microseconds, the kernel inserts 64 us
+once each second so that the system clock stays in step with real time.
+The time returned by the gettimeofday() routine is thus characterized by
+255 advances of 3906 us plus one of 3970 us.
+
+Also in the original design it is possible to slew the system clock to a
+new offset using the adjtime() system call. To do this the clock
+frequency is changed by adding or subtracting a fixed amount (tickadj)
+at each timer interrupt (tick) for a calculated number of ticks. Since
+this calculation involves dividing the requested offset by tickadj, it
+is possible to slew to a new offset with a precision only of tickadj,
+which is usually in the neighborhood of 5 us, but sometimes much higher.
+
+In order to maintain the system clock within specified bounds with this
+scheme, it is necessary to call adjtime() on a regular basis. For
+instance, let the bound be set at 100 us, which is a reasonable value
+for NTP-synchronized hosts on a local network, and let the onboard
+oscillator tolerance be 100 ppm, which is a reasonably conservative
+assumption. This requires that adjtime() be called at intervals not
+exceeding 1 second (s), which is in fact what the unmodified NTP
+software daemon does.
+
+In the modified kernel routines this scheme is replaced by another that
+extends the low-order bits of the system clock to provide very precise
+clock adjustments. At each timer interrupt a precisely calibrated time
+adjustment is added to the composite time value and overflows handled as
+required. The quantity to add is computed from the adjtime() call and,
+in addition a frequency adjustment, which is automatically calculated
+from previous time adjustments. This implementation operates as an
+adaptive-parameter, first-order, type-II, phase-lock loop (PLL), which
+in principle provides precision control of the system clock phase to
+within +-1 us and frequency to within +-5 nanoseconds (ns) per day.
+
+This PLL model is identical to the one implemented in NTP, except that
+in NTP the software daemon has to simulate the PLL using only the
+original adjtime() system call. The daemon is considerably complicated
+by the need to parcel time adjustments at frequent intervals in order to
+maintain the accuracy to specified bounds. The kernel routines do this
+directly, allowing vast gobs of ugly daemon code to be avoided at the
+expense of only a small amount of new code in the kernel. In fact, the
+amount of code added to the kernel for the new scheme is about the
+amount removed for the old scheme. The new adjtime() routine needs to be
+called only as each new time update is determined, which in NTP occurs
+at intervals of from 64 s to 1024 s. In addition, doing the frequency
+correction in the kernel means that the system time runs true even if
+the daemon were to cease operation or the network paths to the primary
+reference source fail.
+
+Note that the degree to which the adjtime() adjustment can be made is
+limited to a specific maximum value, presently +-128 milliseconds (ms),
+in order to achieve microsecond resolution. It is the intent in the
+design that settimeofday() be used for changes in system time greater
+than +-128 ms. It has been the Internet experience that the need to
+change the system time in increments greater than +-128 milliseconds is
+extremely rare and is usually associated with a hardware or software
+malfunction. Nevertheless, the limit applies to each adjtime() call and
+it is possible, but not recommended, that this routine is called at
+intervals smaller than 64 seconds, which is the NTP lower limit.
+
+For the most accurate and stable operation, adjtime() should be called
+at specified intervals; however, the PLL is quite forgiving and neither
+moderate loss of updates nor variations in the length of the interval is
+serious. The current engineering parameters have been optimized for
+intervals not greater than about 64 s. For larger intervals the PLL time
+constant can be adjusted to optimize the dynamic response up to
+intervals of 1024 s. Normally, this is automatically done by NTP. In any
+case, if updates are suspended, the PLL coasts at the frequency last
+determinated, which usually results in errors increasing only to a few
+tens of milliseconds over a day.
+
+The new code needs to know the initial frequency offset and time
+constant for the PLL, and the daemon needs to know the current frequency
+offset computed by the kernel for monitoring purposes. This is provided
+by a small change in the second argument of the kernel adjtime() calling
+sequence, which is documented later in this memo. Ordinarily, only the
+daemon will call the adjtime() routine, so the modified calling sequence
+is easily accommodated. Other than this change, the operation of
+adjtime() is transparent to the original.
+
+In the DECstation 5000/240 and possibly other models there happens to be
+an undocumented hardware register that counts system bus cycles at a
+rate of 25 MHz. The new kernel routines test for the CPU type and, in
+the case of the '240, use this register to interpolate system time
+between hardware timer interrupts. This results in a precision of +-1 us
+for all time values obtained via the gettimeofday() system call. This
+routine calls the kernel routine microtime(), which returns the actual
+interpolated value, but does not change the kernel time variable.
+Therefore, other kernel routines that access the kernel time variable
+directly and do not call either gettimeofday() or microtime() will
+continue their present behavior.
+
+The new kernel routines include provisions for error statistics (maximum
+error and estimated error), leap seconds and system clock status. These
+are intended to support applications that need such things; however,
+there are no applications other than the time-synchronization daemon
+itself that presently use them. At issue is the manner in which these
+data can be provided to application clients, such as new system calls
+and data interfaces. While a proposed interface is described later in
+this memo, it has not yet been implemented. This is an area for further
+study.
+
+While any time-synchronization daemon can in principle be modified to
+use the new code, the most likely will be users of the xntp3
+distribution of NTP. The code in the xntp3 distribution determines
+whether the new kernel code is in use and automatically reconfigures as
+required. When the new code is in use, the daemon reads the frequency
+offset from a file and provides it and the initial time constant via
+adjtime(). In subsequent calls to adjtime(), only the time adjustment
+and time constant are affected. The daemon reads the frequency from the
+kernel (returned as the second argument of adjtime()) at intervals of
+one hour and writes it to the file.
+
+3. Technical Description
+
+Following is a technical description of how the new scheme works in
+terms of the variables and algorithms involved. These components are
+discussed as a distinct entity and do not involve coding details
+specific to the Ultrix kernel. The algorithms involve only minor changes
+to the system clock and interval timer routines, but do not in
+themselves provide a conduit for application programs to learn the
+system clock status or statistics of the time-synchronization process.
+In a later section a number of new system calls are proposed to do this,
+along with an interface specification.
+
+The new scheme works like the companion simulator called kern.c and
+included in this directory. This stand-alone simulator includes code
+fragments identical to those in the modified kernel routines and
+operates in the same way. The system clock is implemented in the kernel
+using a set of variables and algorithms defined below and in the
+simulator. The algorithms are driven by explicit calls from the
+synchronization protocol as each time update is computed. The clock is
+read and set using the gettimeofday() and settimeofday() system calls,
+which operate in the same way as the originals, but return a status word
+describing the state of the system clock.
+
+Once the system clock has been set, the adjtime() system call is used to
+provide periodic updates including the time offset and possibly
+frequency offset and time constant. With NTP this occurs at intervals of
+from 64 s to 1024 s, deending on the time constant value. The kernel
+implements an adaptive-parameter, first-order, type-II, phase-lock loop
+(PLL) in order to integrate this offset into the phase and frequency of
+the system clock. The kernel keeps track of the time of the last update
+and adjusts the maximum error to grow by an amount equal to the
+oscillator frequency tolerance times the elapsed time since the last
+update.
+
+Occasionally, it is necessary to adjust the PLL parameters in response
+to environmental conditions, such as leap-second warning and oscillator
+stability observations. While the interface to do this has not yet been
+implemented, proposals to to that are included in a later section. A
+system call (setloop()) is used on such occasions to communicate these
+data. In addition, a system call (getloop())) is used to extract these
+data from the kernel for monitoring purposes.
+
+All programs utilize the system clock status variable time_status, which
+records whether the clock is synchronized, waiting for a leap second,
+etc. The value of this variable is returned by each system call. It can
+be set explicitly by the setloop() system call and implicitly by the
+settimeofday() system call and in the timer-interrupt routine. Values
+presently defined in the header file timex.h are as follows:
+
+int time_status = TIME_BAD; /* clock synchronization status */
+
+#define TIME_UNS 0 /* unspecified or unknown */
+#define TIME_OK 1 /* operation succeeded */
+#define TIME_INS 1 /* insert leap second at end of current day */
+#define TIME_DEL 2 /* delete leap second at end of current day */
+#define TIME_OOP 3 /* leap second in progress */
+#define TIME_BAD 4 /* system clock is not synchronized */
+#define TIME_ADR -1 /* operation failed: invalid address */
+#define TIME_VAL -2 /* operation failed: invalid argument */
+#define TIME_PRV -3 /* operation failed: priviledged operation */
+
+In case of a negative result code, the operation has failed; however,
+some variables may have been modified before the error was detected.
+Note that the new system calls never return a value of zero, so it is
+possible to determine whether the old routines or the new ones are in
+use. The syntax of the modified adjtime() is as follows:
+
+/*
+ * adjtime - adjuts system time
+ */
+#include <sys/timex.h>
+
+int gettimexofday(tp, fiddle)
+
+struct timeval *tp; /* system time adjustment*/
+struct timeval *fiddle; /* sneak path */
+
+On entry the "timeval" sneak path is coded:
+
+struct timeval {
+ long tv_sec = time_constant; /* time constant */
+ long tv_usec = time_freq; /* new frequency offset */
+}
+
+However, the sneak is ignored if fiddle is the null pointer and the new
+frequency offset is ignored if zero.
+
+The value returned on exit is the system clock status defined above. The
+"timeval" sneak path is modified as follows:
+
+struct timeval {
+ long tv_sec = time_precision; /* system clock precision */
+ long tv_usec = time_freq; /* current frequency offset */
+}
+
+3.1. Kernel Variables
+
+The following variables are used by the new code:
+
+long time_offset = 0; /* time adjustment (us) */
+
+This variable is used by the PLL to adjust the system time in small
+increments. It is scaled by (1 << SHIFT_UPDATE) in binary microseconds.
+The maximum value that can be represented is about +-130 ms and the
+minimum value or precision is about one nanosecond.
+
+long time_constant = SHIFT_TAU; /* pll time constant */
+
+This variable determines the bandwidth or "stiffness" of the PLL. It is
+used as a shift, with the effective value in positive powers of two. The
+optimum value for this variable is equal to 1/64 times the update
+interval. The default value SHIFT_TAU (0) corresponds to a PLL time
+constant of about one hour or an update interval of about one minute,
+which is appropriate for typical uncompensated quartz oscillators used
+in most computing equipment. Values larger than four are not useful,
+unless the local clock timebase is derived from a precision oscillator.
+
+long time_tolerance = MAXFREQ; /* frequency tolerance (ppm) */
+
+This variable represents the maximum frequency error or tolerance of the
+particular platform and is a property of the architecture. It is
+expressed as a positive number greater than zero in parts-per-million
+(ppm). The default MAXFREQ (100) is appropriate for conventional
+workstations.
+
+long time_precision = 1000000 / HZ; /* clock precision (us) */
+
+This variable represents the maximum error in reading the system clock.
+It is expressed as a positive number greater than zero in microseconds
+and is usually based on the number of microseconds between timer
+interrupts, in the case of the Ultrix kernel, 3906. However, in cases
+where the time can be interpolated between timer interrupts with
+microsecond resolution, the precision is specified as 1. This variable
+is computed by the kernel for use by the time-synchronization daemon,
+but is otherwise not used by the kernel.
+
+struct timeval time_maxerror; /* maximum error */
+
+This variable represents the maximum error, expressed as a Unix timeval,
+of the system clock. For NTP, it is computed as the synchronization
+distance, which is equal to one-half the root delay plus the root
+dispersion. It is increased by a small amount (time_tolerance) each
+second to reflect the clock frequency tolerance. This variable is
+computed by the time-synchronization daemon and the kernel for use by
+the application program, but is otherwise not used by the kernel.
+
+struct timeval time_esterror; /* estimated error */
+
+This variable represents the best estimate of the actual error,
+expressed as a Unix timeval, of the system clock based on its past
+behavior, together with observations of multiple clocks within the peer
+group. This variable is computed by the time-synchronization daemon for
+use by the application program, but is otherwise not used by the kernel.
+
+The PLL itself is controlled by the following variables:
+
+long time_phase = 0; /* phase offset (scaled us) */
+long time_freq = 0; /* frequency offset (scaled ppm) */long
+time_adj = 0; /* tick adjust (scaled 1 / HZ) */
+
+These variables control the phase increment and the frequency increment
+of the system clock at each tick of the clock. The time_phase variable
+is scaled by (1 << SHIFT_SCALE) in binary microseconds, giving a minimum
+value (time resolution) of 9.3e-10 us. The time_freq variable is scaled
+by (1 << SHIFT_KF) in parts-per-million (ppm), giving it a maximum value
+of about +-130 ppm and a minimum value (frequency resolution) of 6e-8
+ppm. The time_adj variable is the actual phase increment in scaled
+microseconds to add to time_phase once each tick. It is computed from
+time_phase and time_freq once per second.
+
+long time_reftime = 0; /* time at last adjustment (s) */
+
+This variable is the second's portion of the system time on the last
+call to adjtime(). It is used to adjust the time_freq variable as the
+time since the last update increases.
+
+The HZ define establishes the timer interrupt frequency, 256 Hz for the
+Ultrix kernel and 100 Hz for the SunOS kernel. The SHIFT_HZ define
+expresses the same value as the nearest power of two in order to avoid
+hardware multiply operations. These are the only parameters that need to
+be changed for different timer interrupt rates.
+
+#define HZ 256 /* timer interrupt frequency (Hz) */
+#define SHIFT_HZ 8 /* log2(HZ) */
+
+The following defines establish the engineering parameters of the PLL
+model. They are chosen for an initial convergence time of about an hour,
+an overshoot of about seven percent and a final convergence time of
+several hours, depending on initial frequency error.
+
+#define SHIFT_KG 10 /* shift for phase increment */
+#define SHIFT_KF 24 /* shift for frequency increment */
+#define SHIFT_TAU 0 /* default time constant (shift) */
+
+The SHIFT_SCALE define establishes the decimal point on the time_phase
+variable which serves as a an extension to the low-order bits of the
+system clock variable. The SHIFT_UPDATE define establishes the decimal
+point of the phase portion of the adjtime() update. The FINEUSEC define
+represents 1 us in scaled units.
+
+#define SHIFT_SCALE 28 /* shift for scale factor */
+#define SHIFT_UPDATE 14 /* shift for offset scale factor */
+#define FINEUSEC (1 << SHIFT_SCALE) /* 1 us in scaled units */
+
+The FINETUNE define represents the residual, in ppm, to be added to the
+system clock variable in addition to the integral 1-us value given by
+tick. This allows a systematic frequency offset in cases where the timer
+interrupt frequency does not exactly divide the second in microseconds.
+
+#define FINETUNE (1000000 - (1000000 / HZ) * HZ) /* frequency adjustment
+ * for non-isochronous HZ (ppm) */
+
+The following four defines establish the performance envelope of the
+PLL, one to bound the maximum phase error, another to bound the maximum
+frequency error and the last two to bound the minimum and maximum time
+between updates. The intent of these bounds is to force the PLL to
+operate within predefined limits in order to conform to the correctness
+models assumed by time-synchronization protocols like NTP and DTSS. An
+excursion which exceeds these bounds is clamped to the bound and
+operation proceeds accordingly. In practice, this can occur only if
+something has failed or is operating out of tolerance, but otherwise the
+PLL continues to operate in a stable mode. Note that the MAXPHASE define
+conforms to the maximum offset allowed in NTP before the system time is
+reset, rather than incrementally adjusted.
+
+#define MAXPHASE 128000 /* max phase error (us) */
+#define MINSEC 64 /* min interval between updates (s) */
+#define MAXFREQ 100 /* max frequency error (ppm) */
+#define MAXSEC 1024 /* max interval between updates (s) */
+
+3.2. Code Segments
+
+The code segments illustrated in the simulator should make clear the
+operations at various points in the code. These segments are not derived
+from any licensed code. The hardupdate() fragment is called by adjtime()
+to update the system clock phase and frequency. This is an
+implementation of an adaptive-parameter, first-order, type-II phase-lock
+loop. Note that the time constant is in units of powers of two, so that
+multiplies can be done by simple shifts. The phase variable is computed
+as the offset multiplied by the time constant. Then, the time since the
+last update is computed and clamped to a maximum (for robustness) and to
+zero if initializing. The offset is multiplied (sorry about the ugly
+multiply) by the result and by the square of the time constant and then
+added to the frequency variable. Finally, the frequency variable is
+clamped not to exceed the tolerance. Note that all shifts are assumed to
+be positive and that a shift of a signed quantity to the right requires
+a litle dance.
+
+With the defines given, the maximum time offset is determined by the
+size in bits of the long type (32) less the SHIFT_UPDATE (14) scale
+factor or 18 bits (signed). The scale factor is chosen so that there is
+no loss of significance in later steps, which may involve a right shift
+up to 14 bits. This results in a maximum offset of about +-130 ms. Since
+the time_constant must be greater than or equal to zero, the maximum
+frequency offset is determined by the SHIFT_KF (24) scale factor, or
+about +-130 ppm. In the addition step the value of offset * mtemp is
+represented in 18 + 10 = 28 bits, which will not overflow a long add.
+There could be a loss of precision due to the right shift of up to eight
+bits, since time_constant is bounded at four. This results in a net
+worst-case frequency error of about 2^-16 us or well down into the
+oscillator phase noise. While the time_offset value is assumed checked
+before entry, the time_phase variable is an accumulator, so is clamped
+to the tolerance on every call. This helps to damp transients before the
+oscillator frequency has been determined, as well as to satisfy the
+correctness assertions if the time-synchronization protocol comes
+unstuck.
+
+The hardclock() fragment is inserted in the hardware timer interrupt
+routine at the point the system clock is to be incremented. The phase
+adjustment (time_adj) is added to the clock phase (time_phase) and
+tested for overflow of the microsecond. If an overflow occurs, the
+microsecond (tick) in incremented or decremented.
+
+The second_overflow() fragment is inserted at the point where the
+microseconds field of the system time variable is being checked for
+overflow. On rollover of the second the maximum error is increased by
+the tolerance. The time offset is divided by the phase weight (SHIFT_KG)
+and time constant. The time offset is then reduced by the result and the
+result is scaled and becomes the value of the phase adjustment. The
+phase adjustment is then corrected for the calculated frequency offset
+and a fixed offset FINETUNE which is a property of the architecture. On
+rollover of the day the leap-warning indicator is checked and the
+apparent time adjusted +-1 s accordingly. The gettimeofday() routine
+insures that the reported time is always monotonically increasing.
+
+The simulator can be used to check the loop operation over the design
+range of +-128 ms in time error and +-100 ppm in frequency error. This
+confirms that no overflows occur and that the loop initially converges
+in about 50-60 minutes for timer interrupt rates from 50 Hz to 1024 Hz.
+The loop has a normal overshoot of about seven percent and a final
+convergence time of several hours, depending on the initional frequency
+error.
+
+3.3. Leap Seconds
+
+The leap-warning condition is determined by the synchronization protocol
+(if remotely synchronized), by the timecode receiver (if available), or
+by the operator (if awake). The time_status value must be set on the day
+the leap event is to occur (30 June or 31 December) and is automatically
+reset after the event. If the value is TIME_DEL, the kernel adds one
+second to the system time immediately following second 23:59:58 and
+resets time_status to TIME_OK. If the value is TIME_INS, the kernel
+subtracts one second from the system time immediately following second
+23:59:59 and resets time_status to TIME_OOP, in effect causing system
+time to repeat second 59. Immediately following the repeated second, the
+kernel resets time_status to TIME_OK.
+
+Depending upon the system call implementation, the reported time during
+a leap second may repeat (with a return code set to advertise that fact)
+or be monotonically adjusted until system time "catches up" to reported
+time. With the latter scheme the reported time will be correct before
+and after the leap second, but freeze or slowly advance during the leap
+second itself. However, Most programs will probably use the ctime()
+library routine to convert from timeval (seconds, microseconds) format
+to tm format (seconds, minutes,...). If this routine is modified to
+inspect the return code of the gettimeofday() routine, it could simply
+report the leap second as second 60.
+
+To determine local midnight without fuss, the kernel simply finds the
+residue of the time.tv_sec value mod 86,400, but this requires a messy
+divide. Probably a better way to do this is to initialize an auxiliary
+counter in the settimeofday() routine using an ugly divide and increment
+the counter at the same time the time.tv_sec is incremented in the timer
+interrupt routine. For future embellishment.
+
+4. Proposed Application Program Interface
+
+Most programs read the system clock using the gettimeofday() system
+call, which returns the system time and time-zone data. In the modified
+5000/240 kernel, the gettimeofday() routine calls the microtime()
+routine, which interpolates between hardware timer interrupts to a
+precision of +-1 microsecond. However, the synchronization protocol
+provides additional information that will be of interest in many
+applications. For some applications it is necessary to know the maximum
+error of the reported time due to all causes, including those due to the
+system clock reading error, oscillator frequency error and accumulated
+errors due to intervening time servers on the path to a primary
+reference source. However, for those protocols that adjust the system
+clock frequency as well as the time offset, the errors expected in
+actual use will almost always be much less than the maximum error.
+Therefore, it is useful to report the estimated error, as well as the
+maximum error.
+
+It does not seem useful to provide additional details private to the
+kernel and synchronization protocol, such as stratum, reference
+identifier, reference timestamp and so forth. It would in principle be
+possible for the application to independently evaluate the quality of
+time and project into the future how long this time might be "valid."
+However, to do that properly would duplicate the functionality of the
+synchronization protocol and require knowledge of many mundane details
+of the platform architecture, such as the tick value, reachability
+status and related variables. Therefore, the application interface does
+not reveal anything except the time, timezone and error data.
+
+With respect to NTP, the data maintained by the protocol include the
+roundtrip delay and total dispersion to the source of synchronization.
+In terms of the above, the maximum error is computed as half the delay
+plus the dispersion, while the estimated error is equal to the
+dispersion. These are reported in timeval structures. A new system call
+is proposed that includes all the data in the gettimeofday() plus the
+two new timeval structures.
+
+The proposed interface involves modifications to the gettimeofday(),
+settimeofday() and adjtime() system calls, as well as new system calls
+to get and set various system parameters. In order to minimize
+confusion, by convention the new system calls are named with an "x"
+following the "time"; e.g., adjtime() becomes adjtimex(). The operation
+of the modified gettimexofday(), settimexofday() and adjtimex() system
+calls is identical to that of their prototypes, except for the error
+quantities and certain other side effects, as documented below. By
+convention, a NULL pointer can be used in place of any argument, in
+which case the argument is ignored.
+
+The synchronization protocol daemon needs to set and adjust the system
+clock and certain other kernel variables. It needs to read these
+variables for monitoring purposes as well. The present list of these
+include a subset of the variables defined previously:
+
+long time_precision
+long time_timeconstant
+long time_tolerance
+long time_freq
+long time_status
+
+/*
+ * gettimexofday, settimexofday - get/set date and time
+ */
+#include <sys/timex.h>
+
+int gettimexofday(tp, tzp, tmaxp, testp)
+
+struct timeval *tp; /* system time */
+struct timezone *tzp; /* timezone */
+struct timeval *tmaxp; /* maximum error */
+struct timeval *testp; /* estimated error */
+
+The settimeofday() syntax is identical. Note that a call to
+settimexofday() automatically results in the system being declared
+unsynchronized (TIME_BAD return code), since the synchronization
+condition can only be achieved by the synchronization daemon using an
+internal or external primary reference source and the adjtimex() system
+call.
+
+/*
+ * adjtimex - adjust system time
+ */
+#include <sys/timex.h>
+
+int adjtimex(tp, tzp, freq, tc)
+
+struct timeval *tp; /* system time */
+struct timezone *tzp; /* timezone */
+long freq; /* frequency adjustment */
+long tc; /* time constant */
+
+/*
+ * getloop, setloop - get/set kernel time variables
+ */
+#include <sys/timex.h>
+
+int getloop(code, argp)
+
+int code; /* operation code */
+long *argp; /* argument pointer */
+
+The paticular kernal variables affected by these routines are selected
+by the operation code. Values presently defined in the header file
+timex.h are as follows:
+
+#define TIME_PREC 1 /* precision (log2(sec)) */
+#define TIME_TCON 2 /* time constant (log2(sec) */
+#define TIME_FREQ 3 /* frequency tolerance */
+#define TIME_FREQ 4 /* frequency offset (scaled) */
+#define TIME_STAT 5 /* status (see return codes) */
+
+The getloop() syntax is identical.
+
+Comments welcome, but very little support is available:
+
+David L. Mills
+Electrical Engineering Department
+University of Delaware
+Newark, DE 19716
+302 831 8247 fax 302 831 4316
+mills@udel.edu
OpenPOWER on IntegriCloud