xref: /freebsd/contrib/ntp/libntp/adjtime.c (revision f5f40dd63bc7acbb5312b26ac1ea1103c12352a6)
1c0b746e5SOllivier Robert #ifdef HAVE_CONFIG_H
2c0b746e5SOllivier Robert # include <config.h>
3c0b746e5SOllivier Robert #endif
4c0b746e5SOllivier Robert 
5ce265a54SOllivier Robert #ifdef MPE
6ce265a54SOllivier Robert /*
7ce265a54SOllivier Robert  * MPE lacks adjtime(), so we define our own.  But note that time slewing has
8ce265a54SOllivier Robert  * a sub-second accuracy bug documented in SR 5003462838 which prevents ntpd
9ce265a54SOllivier Robert  * from being able to maintain clock synch.  Because of the bug, this adjtime()
10ce265a54SOllivier Robert  * implementation as used by ntpd has a side-effect of screwing up the hardware
11ce265a54SOllivier Robert  * PDC clock, which will need to be reset with a reboot.
12ce265a54SOllivier Robert  *
13ce265a54SOllivier Robert  * This problem affects all versions of MPE at the time of this writing (when
14ce265a54SOllivier Robert  * MPE/iX 7.0 is the most current).  It only causes bad things to happen when
15ce265a54SOllivier Robert  * doing continuous clock synchronization with ntpd; note that you CAN run ntpd
16ce265a54SOllivier Robert  * with "disable ntp" in ntp.conf if you wish to provide a time server.
17ce265a54SOllivier Robert  *
18ce265a54SOllivier Robert  * The one-time clock adjustment functionality of ntpdate and ntp_timeset can
19ce265a54SOllivier Robert  * be used without screwing up the PDC clock.
20ce265a54SOllivier Robert  *
21ce265a54SOllivier Robert  */
22ce265a54SOllivier Robert #include <time.h>
23ce265a54SOllivier Robert 
24ce265a54SOllivier Robert int adjtime(struct timeval *delta, struct timeval *olddelta);
25ce265a54SOllivier Robert 
26ce265a54SOllivier Robert int adjtime(struct timeval *delta, struct timeval *olddelta)
27ce265a54SOllivier Robert 
28ce265a54SOllivier Robert {
29ce265a54SOllivier Robert /* Documented, supported MPE system intrinsics. */
30ce265a54SOllivier Robert 
31ce265a54SOllivier Robert extern void GETPRIVMODE(void);
32ce265a54SOllivier Robert extern void GETUSERMODE(void);
33ce265a54SOllivier Robert 
34ce265a54SOllivier Robert /* Undocumented, unsupported MPE internal functions. */
35ce265a54SOllivier Robert 
36ce265a54SOllivier Robert extern long long current_correction_usecs(void);
37ce265a54SOllivier Robert extern long long get_time(void);
38ce265a54SOllivier Robert extern void get_time_change_info(long long *, char *, char *);
39ce265a54SOllivier Robert extern long long pdc_time(int *);
40ce265a54SOllivier Robert extern void set_time_correction(long long, int, int);
41ce265a54SOllivier Robert extern long long ticks_to_micro(long long);
42ce265a54SOllivier Robert 
43ce265a54SOllivier Robert long long big_sec, big_usec, new_correction = 0LL;
44ce265a54SOllivier Robert long long prev_correction;
45ce265a54SOllivier Robert 
46ce265a54SOllivier Robert if (delta != NULL) {
47ce265a54SOllivier Robert   /* Adjustment required.  Convert delta to 64-bit microseconds. */
48ce265a54SOllivier Robert   big_sec = (long)delta->tv_sec;
49ce265a54SOllivier Robert   big_usec = delta->tv_usec;
50ce265a54SOllivier Robert   new_correction = (big_sec * 1000000LL) + big_usec;
51ce265a54SOllivier Robert }
52ce265a54SOllivier Robert 
53ce265a54SOllivier Robert GETPRIVMODE();
54ce265a54SOllivier Robert 
55ce265a54SOllivier Robert /* Determine how much of a previous correction (if any) we're interrupting. */
56ce265a54SOllivier Robert prev_correction = current_correction_usecs();
57ce265a54SOllivier Robert 
58ce265a54SOllivier Robert if (delta != NULL) {
59ce265a54SOllivier Robert   /* Adjustment required. */
60ce265a54SOllivier Robert 
61ce265a54SOllivier Robert #if 0
62ce265a54SOllivier Robert   /* Speculative code disabled until bug SR 5003462838 is fixed.  This bug
63ce265a54SOllivier Robert      prevents accurate time slewing, and indeed renders ntpd inoperable. */
64ce265a54SOllivier Robert 
65ce265a54SOllivier Robert   if (prev_correction != 0LL) {
66ce265a54SOllivier Robert     /* A previous adjustment did not complete.  Since the PDC UTC clock was
67ce265a54SOllivier Robert     immediately jumped at the start of the previous adjustment, we must
68ce265a54SOllivier Robert     explicitly reset it to the value of the MPE local time clock minus the
69ce265a54SOllivier Robert     time zone offset. */
70ce265a54SOllivier Robert 
71ce265a54SOllivier Robert     char pwf_since_boot, recover_pwf_time;
72ce265a54SOllivier Robert     long long offset_ticks, offset_usecs, pdc_usecs_current, pdc_usecs_wanted;
73ce265a54SOllivier Robert     int hpe_status;
74ce265a54SOllivier Robert 
75ce265a54SOllivier Robert     get_time_change_info(&offset_ticks, &pwf_since_boot, &recover_pwf_time);
76ce265a54SOllivier Robert     offset_usecs = ticks_to_micro(offset_ticks);
77ce265a54SOllivier Robert     pdc_usecs_wanted = get_time() - offset_usecs;
78ce265a54SOllivier Robert     pdc_usecs_current = pdc_time(&hpe_status);
79ce265a54SOllivier Robert     if (hpe_status == 0)
80ce265a54SOllivier Robert       /* Force new PDC time by starting an extra correction. */
81ce265a54SOllivier Robert       set_time_correction(pdc_usecs_wanted - pdc_usecs_current,0,1);
82ce265a54SOllivier Robert   }
839c2daa00SOllivier Robert #endif /* 0 */
84ce265a54SOllivier Robert 
85ce265a54SOllivier Robert   /* Immediately jump the PDC time to the new value, and then initiate a
86ce265a54SOllivier Robert      gradual MPE time correction slew. */
87ce265a54SOllivier Robert   set_time_correction(new_correction,0,1);
88ce265a54SOllivier Robert }
89ce265a54SOllivier Robert 
90ce265a54SOllivier Robert GETUSERMODE();
91ce265a54SOllivier Robert 
92ce265a54SOllivier Robert if (olddelta != NULL) {
93ce265a54SOllivier Robert   /* Caller wants to know remaining amount of previous correction. */
94ce265a54SOllivier Robert   (long)olddelta->tv_sec = prev_correction / 1000000LL;
95ce265a54SOllivier Robert   olddelta->tv_usec = prev_correction % 1000000LL;
96ce265a54SOllivier Robert }
97ce265a54SOllivier Robert 
98ce265a54SOllivier Robert return 0;
99ce265a54SOllivier Robert }
100ce265a54SOllivier Robert #endif /* MPE */
101ce265a54SOllivier Robert 
102c0b746e5SOllivier Robert #ifdef NEED_HPUX_ADJTIME
103c0b746e5SOllivier Robert /*************************************************************************/
104c0b746e5SOllivier Robert /* (c) Copyright Tai Jin, 1988.  All Rights Reserved.                    */
105c0b746e5SOllivier Robert /*     Hewlett-Packard Laboratories.                                     */
106c0b746e5SOllivier Robert /*                                                                       */
107c0b746e5SOllivier Robert /* Permission is hereby granted for unlimited modification, use, and     */
108c0b746e5SOllivier Robert /* distribution.  This software is made available with no warranty of    */
109c0b746e5SOllivier Robert /* any kind, express or implied.  This copyright notice must remain      */
110c0b746e5SOllivier Robert /* intact in all versions of this software.                              */
111c0b746e5SOllivier Robert /*                                                                       */
112c0b746e5SOllivier Robert /* The author would appreciate it if any bug fixes and enhancements were */
113c0b746e5SOllivier Robert /* to be sent back to him for incorporation into future versions of this */
114c0b746e5SOllivier Robert /* software.  Please send changes to tai@iag.hp.com or ken@sdd.hp.com.   */
115c0b746e5SOllivier Robert /*************************************************************************/
116c0b746e5SOllivier Robert 
117c0b746e5SOllivier Robert /*
118c0b746e5SOllivier Robert  * Revision history
119c0b746e5SOllivier Robert  *
120c0b746e5SOllivier Robert  * 9 Jul 94	David L. Mills, Unibergity of Delabunch
121c0b746e5SOllivier Robert  *		Implemented variable threshold to limit age of
122c0b746e5SOllivier Robert  *		corrections; reformatted code for readability.
123c0b746e5SOllivier Robert  */
124c0b746e5SOllivier Robert 
125c0b746e5SOllivier Robert #ifndef lint
126c0b746e5SOllivier Robert static char RCSid[] = "adjtime.c,v 3.1 1993/07/06 01:04:42 jbj Exp";
127c0b746e5SOllivier Robert #endif
128c0b746e5SOllivier Robert 
129c0b746e5SOllivier Robert #include <sys/types.h>
130c0b746e5SOllivier Robert #include <sys/ipc.h>
131c0b746e5SOllivier Robert #include <sys/msg.h>
132c0b746e5SOllivier Robert #include <time.h>
133c0b746e5SOllivier Robert #include <signal.h>
134c0b746e5SOllivier Robert #include "adjtime.h"
135c0b746e5SOllivier Robert 
136c0b746e5SOllivier Robert #define abs(x)  ((x) < 0 ? -(x) : (x))
137c0b746e5SOllivier Robert 
138c0b746e5SOllivier Robert /*
139c0b746e5SOllivier Robert  * The following paramters are appropriate for an NTP adjustment
140c0b746e5SOllivier Robert  * interval of one second.
141c0b746e5SOllivier Robert  */
142c0b746e5SOllivier Robert #define ADJ_THRESH 200		/* initial threshold */
143c0b746e5SOllivier Robert #define ADJ_DELTA 4		/* threshold decrement */
144c0b746e5SOllivier Robert 
145c0b746e5SOllivier Robert static long adjthresh;		/* adjustment threshold */
146c0b746e5SOllivier Robert static long saveup;		/* corrections accumulator */
147c0b746e5SOllivier Robert 
148c0b746e5SOllivier Robert /*
149c0b746e5SOllivier Robert  * clear_adjtime - reset accumulator and threshold variables
150c0b746e5SOllivier Robert  */
151c0b746e5SOllivier Robert void
152c0b746e5SOllivier Robert _clear_adjtime(void)
153c0b746e5SOllivier Robert {
154c0b746e5SOllivier Robert 	saveup = 0;
155c0b746e5SOllivier Robert 	adjthresh = ADJ_THRESH;
156c0b746e5SOllivier Robert }
157c0b746e5SOllivier Robert 
158c0b746e5SOllivier Robert /*
159c0b746e5SOllivier Robert  * adjtime - hp-ux copout of the standard Unix adjtime() system call
160c0b746e5SOllivier Robert  */
161c0b746e5SOllivier Robert int
162c0b746e5SOllivier Robert adjtime(
163c0b746e5SOllivier Robert 	register struct timeval *delta,
164c0b746e5SOllivier Robert 	register struct timeval *olddelta
165c0b746e5SOllivier Robert 	)
166c0b746e5SOllivier Robert {
167c0b746e5SOllivier Robert 	struct timeval newdelta;
168c0b746e5SOllivier Robert 
169c0b746e5SOllivier Robert 	/*
170c0b746e5SOllivier Robert 	 * Corrections greater than one second are done immediately.
171c0b746e5SOllivier Robert 	 */
172c0b746e5SOllivier Robert 	if (delta->tv_sec) {
173c0b746e5SOllivier Robert 		adjthresh = ADJ_THRESH;
174c0b746e5SOllivier Robert 		saveup = 0;
175c0b746e5SOllivier Robert 		return(_adjtime(delta, olddelta));
176c0b746e5SOllivier Robert 	}
177c0b746e5SOllivier Robert 
178c0b746e5SOllivier Robert 	/*
179c0b746e5SOllivier Robert 	 * Corrections less than one second are accumulated until
180c0b746e5SOllivier Robert 	 * tripping a threshold, which is initially set at ADJ_THESH and
181c0b746e5SOllivier Robert 	 * reduced in ADJ_DELTA steps to zero. The idea here is to
182c0b746e5SOllivier Robert 	 * introduce large corrections quickly, while making sure that
183c0b746e5SOllivier Robert 	 * small corrections are introduced without excessive delay. The
184c0b746e5SOllivier Robert 	 * idea comes from the ARPAnet routing update algorithm.
185c0b746e5SOllivier Robert 	 */
186c0b746e5SOllivier Robert 	saveup += delta->tv_usec;
187c0b746e5SOllivier Robert 	if (abs(saveup) >= adjthresh) {
188c0b746e5SOllivier Robert 		adjthresh = ADJ_THRESH;
189c0b746e5SOllivier Robert 		newdelta.tv_sec = 0;
190c0b746e5SOllivier Robert 		newdelta.tv_usec = saveup;
191c0b746e5SOllivier Robert 		saveup = 0;
192c0b746e5SOllivier Robert 		return(_adjtime(&newdelta, olddelta));
193c0b746e5SOllivier Robert 	} else {
194c0b746e5SOllivier Robert 		adjthresh -= ADJ_DELTA;
195c0b746e5SOllivier Robert 	}
196c0b746e5SOllivier Robert 
197c0b746e5SOllivier Robert 	/*
198c0b746e5SOllivier Robert 	 * While nobody uses it, return the residual before correction,
199c0b746e5SOllivier Robert 	 * as per Unix convention.
200c0b746e5SOllivier Robert 	 */
201c0b746e5SOllivier Robert 	if (olddelta)
202c0b746e5SOllivier Robert 	    olddelta->tv_sec = olddelta->tv_usec = 0;
203c0b746e5SOllivier Robert 	return(0);
204c0b746e5SOllivier Robert }
205c0b746e5SOllivier Robert 
206c0b746e5SOllivier Robert /*
207c0b746e5SOllivier Robert  * _adjtime - does the actual work
208c0b746e5SOllivier Robert  */
209c0b746e5SOllivier Robert int
210c0b746e5SOllivier Robert _adjtime(
211c0b746e5SOllivier Robert 	register struct timeval *delta,
212c0b746e5SOllivier Robert 	register struct timeval *olddelta
213c0b746e5SOllivier Robert 	)
214c0b746e5SOllivier Robert {
215c0b746e5SOllivier Robert 	register int mqid;
216c0b746e5SOllivier Robert 	MsgBuf msg;
217c0b746e5SOllivier Robert 	register MsgBuf *msgp = &msg;
218c0b746e5SOllivier Robert 
219c0b746e5SOllivier Robert 	/*
220c0b746e5SOllivier Robert 	 * Get the key to the adjtime message queue (note that we must
221c0b746e5SOllivier Robert 	 * get it every time because the queue might have been removed
222c0b746e5SOllivier Robert 	 * and recreated)
223c0b746e5SOllivier Robert 	 */
224c0b746e5SOllivier Robert 	if ((mqid = msgget(KEY, 0)) == -1)
225c0b746e5SOllivier Robert 	    return (-1);
226c0b746e5SOllivier Robert 	msgp->msgb.mtype = CLIENT;
227c0b746e5SOllivier Robert 	msgp->msgb.tv = *delta;
228c0b746e5SOllivier Robert 	if (olddelta)
229c0b746e5SOllivier Robert 	    msgp->msgb.code = DELTA2;
230c0b746e5SOllivier Robert 	else
231c0b746e5SOllivier Robert 	    msgp->msgb.code = DELTA1;
232c0b746e5SOllivier Robert 
233c0b746e5SOllivier Robert 	/*
234c0b746e5SOllivier Robert 	 * Tickle adjtimed and snatch residual, if indicated. Lots of
235c0b746e5SOllivier Robert 	 * fanatic error checking here.
236c0b746e5SOllivier Robert 	 */
237c0b746e5SOllivier Robert 	if (msgsnd(mqid, &msgp->msgp, MSGSIZE, 0) == -1)
238c0b746e5SOllivier Robert 	    return (-1);
239c0b746e5SOllivier Robert 	if (olddelta) {
240c0b746e5SOllivier Robert 		if (msgrcv(mqid, &msgp->msgp, MSGSIZE, SERVER, 0) == -1)
241c0b746e5SOllivier Robert 		    return (-1);
242c0b746e5SOllivier Robert 		*olddelta = msgp->msgb.tv;
243c0b746e5SOllivier Robert 	}
244c0b746e5SOllivier Robert 	return (0);
245c0b746e5SOllivier Robert }
246c0b746e5SOllivier Robert 
2479c2daa00SOllivier Robert #else
2489c2daa00SOllivier Robert # if NEED_QNX_ADJTIME
2499c2daa00SOllivier Robert /*
2509c2daa00SOllivier Robert  * Emulate adjtime() using QNX ClockAdjust().
2519c2daa00SOllivier Robert  * Chris Burghart <burghart@atd.ucar.edu>, 11/2001
252ea906c41SOllivier Robert  * Miroslaw Pabich <miroslaw_pabich@o2.pl>, 09/2005
2539c2daa00SOllivier Robert  *
254ea906c41SOllivier Robert  * This is an implementation of adjtime() for QNX.
255ea906c41SOllivier Robert  * ClockAdjust() is used to tweak the system clock for about
256ea906c41SOllivier Robert  * 1 second period until the desired delta is achieved.
257ea906c41SOllivier Robert  * Time correction slew is limited to reasonable value.
258ea906c41SOllivier Robert  * Internal rounding and relative errors are reduced.
2599c2daa00SOllivier Robert  */
2609c2daa00SOllivier Robert # include <sys/neutrino.h>
2619c2daa00SOllivier Robert # include <sys/time.h>
2629c2daa00SOllivier Robert 
2639c2daa00SOllivier Robert # include <ntp_stdlib.h>
2649c2daa00SOllivier Robert 
265ea906c41SOllivier Robert /*
266ea906c41SOllivier Robert  * Time correction slew limit. QNX is a hard real-time system,
267ea906c41SOllivier Robert  * so don't adjust system clock too fast.
268ea906c41SOllivier Robert  */
269ea906c41SOllivier Robert #define CORR_SLEW_LIMIT     0.02  /* [s/s] */
270ea906c41SOllivier Robert 
271ea906c41SOllivier Robert /*
272ea906c41SOllivier Robert  * Period of system clock adjustment. It should be equal to adjtime
273ea906c41SOllivier Robert  * execution period (1s). If slightly less than 1s (0.95-0.99), then olddelta
274ea906c41SOllivier Robert  * residual error (introduced by execution period jitter) will be reduced.
275ea906c41SOllivier Robert  */
276ea906c41SOllivier Robert #define ADJUST_PERIOD       0.97  /* [s] */
277ea906c41SOllivier Robert 
2789c2daa00SOllivier Robert int
2799c2daa00SOllivier Robert adjtime (struct timeval *delta, struct timeval *olddelta)
2809c2daa00SOllivier Robert {
2819c2daa00SOllivier Robert     double delta_nsec;
2829c2daa00SOllivier Robert     double delta_nsec_old;
2839c2daa00SOllivier Robert     struct _clockadjust adj;
2849c2daa00SOllivier Robert     struct _clockadjust oldadj;
285ea906c41SOllivier Robert 
2869c2daa00SOllivier Robert     /*
2879c2daa00SOllivier Robert      * How many nanoseconds are we adjusting?
2889c2daa00SOllivier Robert      */
289ea906c41SOllivier Robert     if (delta != NULL)
290ea906c41SOllivier Robert 	delta_nsec = 1e9 * (long)delta->tv_sec + 1e3 * delta->tv_usec;
291ea906c41SOllivier Robert     else
292ea906c41SOllivier Robert 	delta_nsec = 0;
293ea906c41SOllivier Robert 
2949c2daa00SOllivier Robert     /*
2959c2daa00SOllivier Robert      * Build the adjust structure and call ClockAdjust()
2969c2daa00SOllivier Robert      */
2979c2daa00SOllivier Robert     if (delta_nsec != 0)
2989c2daa00SOllivier Robert     {
2999c2daa00SOllivier Robert 	struct _clockperiod period;
3009c2daa00SOllivier Robert 	long count;
3019c2daa00SOllivier Robert 	long increment;
302ea906c41SOllivier Robert 	long increment_limit;
303ea906c41SOllivier Robert 	int isneg = 0;
304ea906c41SOllivier Robert 
305ea906c41SOllivier Robert 	/*
306ea906c41SOllivier Robert 	 * Convert to absolute value for future processing
307ea906c41SOllivier Robert 	 */
308ea906c41SOllivier Robert 	if (delta_nsec < 0)
309ea906c41SOllivier Robert 	{
310ea906c41SOllivier Robert 	    isneg = 1;
311ea906c41SOllivier Robert 	    delta_nsec = -delta_nsec;
312ea906c41SOllivier Robert 	}
3139c2daa00SOllivier Robert 
3149c2daa00SOllivier Robert 	/*
3159c2daa00SOllivier Robert 	 * Get the current clock period (nanoseconds)
3169c2daa00SOllivier Robert 	 */
31709100258SXin LI 	if (ClockPeriod (CLOCK_REALTIME, 0, &period, 0) == -1)
3189c2daa00SOllivier Robert 	    return -1;
3199c2daa00SOllivier Robert 
3209c2daa00SOllivier Robert 	/*
321ea906c41SOllivier Robert 	 * Compute count and nanoseconds increment
3229c2daa00SOllivier Robert 	 */
323ea906c41SOllivier Robert 	count = 1e9 * ADJUST_PERIOD / period.nsec;
324ea906c41SOllivier Robert 	increment = delta_nsec / count + .5;
325ea906c41SOllivier Robert 	/* Reduce relative error */
326ea906c41SOllivier Robert 	if (count > increment + 1)
327ea906c41SOllivier Robert 	{
328ea906c41SOllivier Robert 	    increment = 1 + (long)((delta_nsec - 1) / count);
329ea906c41SOllivier Robert 	    count = delta_nsec / increment + .5;
330ea906c41SOllivier Robert 	}
3319c2daa00SOllivier Robert 
332ea906c41SOllivier Robert 	/*
333ea906c41SOllivier Robert 	 * Limit the adjust increment to appropriate value
334ea906c41SOllivier Robert 	 */
335ea906c41SOllivier Robert 	increment_limit = CORR_SLEW_LIMIT * period.nsec;
336ea906c41SOllivier Robert 	if (increment > increment_limit)
337ea906c41SOllivier Robert 	{
338ea906c41SOllivier Robert 	    increment = increment_limit;
339ea906c41SOllivier Robert 	    count = delta_nsec / increment + .5;
340ea906c41SOllivier Robert 	    /* Reduce relative error */
341ea906c41SOllivier Robert 	    if (increment > count + 1)
342ea906c41SOllivier Robert 	    {
343ea906c41SOllivier Robert 		count =  1 + (long)((delta_nsec - 1) / increment);
344ea906c41SOllivier Robert 		increment = delta_nsec / count + .5;
345ea906c41SOllivier Robert 	    }
346ea906c41SOllivier Robert 	}
347ea906c41SOllivier Robert 
348ea906c41SOllivier Robert 	adj.tick_nsec_inc = isneg ? -increment : increment;
3499c2daa00SOllivier Robert 	adj.tick_count = count;
3509c2daa00SOllivier Robert     }
3519c2daa00SOllivier Robert     else
3529c2daa00SOllivier Robert     {
3539c2daa00SOllivier Robert 	adj.tick_nsec_inc = 0;
3549c2daa00SOllivier Robert 	adj.tick_count = 0;
3559c2daa00SOllivier Robert     }
3569c2daa00SOllivier Robert 
35709100258SXin LI     if (ClockAdjust (CLOCK_REALTIME, &adj, &oldadj) == -1)
3589c2daa00SOllivier Robert 	return -1;
3599c2daa00SOllivier Robert 
3609c2daa00SOllivier Robert     /*
3619c2daa00SOllivier Robert      * Build olddelta
3629c2daa00SOllivier Robert      */
363ea906c41SOllivier Robert     delta_nsec_old = (double)oldadj.tick_count * oldadj.tick_nsec_inc;
364ea906c41SOllivier Robert     if (olddelta != NULL)
365ea906c41SOllivier Robert     {
366ea906c41SOllivier Robert 	if (delta_nsec_old != 0)
367ea906c41SOllivier Robert 	{
368ea906c41SOllivier Robert 	    /* Reduce rounding error */
369ea906c41SOllivier Robert 	    delta_nsec_old += (delta_nsec_old < 0) ? -500 : 500;
370ea906c41SOllivier Robert 	    olddelta->tv_sec = delta_nsec_old / 1e9;
371ea906c41SOllivier Robert 	    olddelta->tv_usec = (long)(delta_nsec_old - 1e9
372ea906c41SOllivier Robert 				 * (long)olddelta->tv_sec) / 1000;
373ea906c41SOllivier Robert 	}
374ea906c41SOllivier Robert 	else
375ea906c41SOllivier Robert 	{
376ea906c41SOllivier Robert 	    olddelta->tv_sec = 0;
377ea906c41SOllivier Robert 	    olddelta->tv_usec = 0;
378ea906c41SOllivier Robert 	}
379ea906c41SOllivier Robert     }
3809c2daa00SOllivier Robert 
3819c2daa00SOllivier Robert     return 0;
3829c2daa00SOllivier Robert }
3839c2daa00SOllivier Robert # else /* no special adjtime() needed */
384*f5f40dd6SCy Schubert NONEMPTY_TRANSLATION_UNIT
3859c2daa00SOllivier Robert # endif
3869c2daa00SOllivier Robert #endif
387