diff options
Diffstat (limited to 'usr.sbin/xntpd/kernel/README.kern')
-rw-r--r-- | usr.sbin/xntpd/kernel/README.kern | 596 |
1 files changed, 0 insertions, 596 deletions
diff --git a/usr.sbin/xntpd/kernel/README.kern b/usr.sbin/xntpd/kernel/README.kern deleted file mode 100644 index 64ba9c5bf379..000000000000 --- a/usr.sbin/xntpd/kernel/README.kern +++ /dev/null @@ -1,596 +0,0 @@ -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 |