Annotation of embedaddon/ntp/libntp/adjtime.c, revision 1.1.1.1

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>