Line 0
Link Here
|
|
|
1 |
/* $Id$ */ |
2 |
|
3 |
/* |
4 |
* Copyright (c) 2004 Darren Tucker <dtucker at zip com au> |
5 |
* |
6 |
* Permission to use, copy, modify, and distribute this software for any |
7 |
* purpose with or without fee is hereby granted, provided that the above |
8 |
* copyright notice and this permission notice appear in all copies. |
9 |
* |
10 |
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
11 |
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
12 |
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
13 |
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
14 |
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
15 |
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
16 |
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
17 |
*/ |
18 |
|
19 |
#include "includes.h" |
20 |
|
21 |
#ifdef USE_ADJTIMEX |
22 |
#include <sys/timex.h> |
23 |
#include <errno.h> |
24 |
#ifdef adjtime |
25 |
# undef adjtime |
26 |
#endif |
27 |
|
28 |
/* scale factor used by adjtimex freq param. 1 ppm = 65536 */ |
29 |
#define ADJTIMEX_FREQ_SCALE 65536 |
30 |
|
31 |
/* maximum change to skew per adjustment, in PPM */ |
32 |
#define MAX_SKEW_DELTA 5.0 |
33 |
|
34 |
/* |
35 |
* Prevent warnings. We can't just include ntpd.h because of conflicting |
36 |
* definitions of ntp_adjtime() |
37 |
*/ |
38 |
void log_warn(const char *, ...); |
39 |
void log_info(const char *, ...); |
40 |
void log_debug(const char *, ...); |
41 |
|
42 |
int |
43 |
_compat_adjtime(const struct timeval *delta, struct timeval *olddelta) |
44 |
{ |
45 |
static struct timeval tlast = {0,0}; |
46 |
static double tskew = 0; |
47 |
static int synced = -1; |
48 |
struct timeval tnow, tdelta; |
49 |
double skew = 0, newskew, deltaskew, adjust, interval = 0; |
50 |
struct timex tmx; |
51 |
int result, saved_errno; |
52 |
|
53 |
gettimeofday(&tnow, NULL); |
54 |
adjust = (double)delta->tv_sec; |
55 |
adjust += (double)delta->tv_usec / 1000000; |
56 |
|
57 |
/* Even if the caller doesn't care about the olddelta, we do */ |
58 |
if (olddelta == NULL) |
59 |
olddelta = &tdelta; |
60 |
|
61 |
result = adjtime(delta, olddelta); |
62 |
saved_errno = errno; |
63 |
|
64 |
if (olddelta->tv_sec == 0 && olddelta->tv_usec == 0 && |
65 |
synced != INT_MAX) |
66 |
synced++; |
67 |
else |
68 |
synced = 0; |
69 |
|
70 |
/* |
71 |
* do skew calculations if we have synced |
72 |
*/ |
73 |
if (synced == 0 ) { |
74 |
tmx.modes = 0; |
75 |
if (adjtimex(&tmx) == -1) |
76 |
log_warn("adjtimex get failed"); |
77 |
else |
78 |
tskew = (double)tmx.freq / ADJTIMEX_FREQ_SCALE; |
79 |
} else if (synced >= 1) { |
80 |
interval = (double)(tnow.tv_sec - tlast.tv_sec); |
81 |
interval += (double)(tnow.tv_usec - tlast.tv_usec) / 1000000; |
82 |
|
83 |
skew = (adjust * 1000000) / interval; |
84 |
newskew = ((tskew * synced) + skew) / synced; |
85 |
deltaskew = newskew - tskew; |
86 |
|
87 |
if (deltaskew > MAX_SKEW_DELTA) { |
88 |
log_info("skew change %0.3lf exceeds limit", deltaskew); |
89 |
tskew += MAX_SKEW_DELTA; |
90 |
} else if (deltaskew < -MAX_SKEW_DELTA) { |
91 |
log_info("skew change %0.3lf exceeds limit", deltaskew); |
92 |
tskew -= MAX_SKEW_DELTA; |
93 |
} else { |
94 |
tskew = newskew; |
95 |
} |
96 |
|
97 |
/* Adjust the kernel skew. */ |
98 |
tmx.freq = (long)(tskew * ADJTIMEX_FREQ_SCALE); |
99 |
tmx.modes = ADJ_FREQUENCY; |
100 |
if (adjtimex(&tmx) == -1) |
101 |
log_warn("adjtimex set freq failed"); |
102 |
} |
103 |
|
104 |
log_debug("interval %0.3lf skew %0.3lf total skew %0.3lf", interval, |
105 |
skew, tskew); |
106 |
|
107 |
tlast = tnow; |
108 |
errno = saved_errno; |
109 |
return result; |
110 |
} |
111 |
#endif |