~ubuntu-branches/ubuntu/trusty/mit-scheme/trusty-proposed

« back to all changes in this revision

Viewing changes to src/microcode/uxenv.c

  • Committer: Package Import Robot
  • Author(s): Chris Hanson
  • Date: 2011-10-15 03:08:33 UTC
  • mfrom: (1.1.8) (3.1.7 sid)
  • Revision ID: package-import@ubuntu.com-20111015030833-x7qc6yxuulvxbafv
Tags: 9.1-1
* New upstream.
* debian/control, debian/copyright, debian/mit-scheme-doc.*,
  debian/mit-scheme.install, debian/rules, Upstream has removed cover
  texts from documentation licenses, so merge packages mit-scheme and
  mit-scheme-doc back together.
* debian/compat: Bump to current version.
* debian/control: Bump standards-version to current and make
  necessary changes.
* debian/rules: Fix lintian warnings.

Show diffs side-by-side

added added

removed removed

Lines of Context:
2
2
 
3
3
Copyright (C) 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994,
4
4
    1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
5
 
    2006, 2007, 2008, 2009, 2010 Massachusetts Institute of Technology
 
5
    2006, 2007, 2008, 2009, 2010, 2011 Massachusetts Institute of
 
6
    Technology
6
7
 
7
8
This file is part of MIT/GNU Scheme.
8
9
 
28
29
#include "ux.h"
29
30
#include "osenv.h"
30
31
 
 
32
/* Seconds since the UTC Epoch */
 
33
 
 
34
/* This is a disaster, thanks to the mind-boggling brain damage of
 
35
   POSIX.  At any time t, the POSIX time P(t) is the number of SI
 
36
   seconds, S(t), since the UTC epoch (1972-01-01T00:00:00Z), plus
 
37
   63072000 (= 2*365*86400, to adjust for the Unix epoch, which would
 
38
   be `1970-01-01T00:00:00Z' if modern UTC hadn't begun only in 1972),
 
39
   *minus* the number L(t) of those seconds that were leap seconds in
 
40
   UTC.  That is, P(t) = S(t) + 63072000 - L(t).
 
41
 
 
42
   Problem (in the sense of problem set): Find S given P.
 
43
   Problem (in the sense of disaster): POSIX doesn't tell us S or L.
 
44
 
 
45
   So what do we do?  Fortunately, many popular Unix systems set their
 
46
   clocks using the Network Time Protocol with the NTP Project's ntpd.
 
47
   In order to support this, they provide a couple of extra-POSIX
 
48
   routines, ntp_gettime and ntp_adjtime, giving the TAI - UTC offset.
 
49
 
 
50
   What if we don't have ntp_gettime or ntp_adjtime, or if the kernel
 
51
   doesn't know the TAI - UTC offset?  We're screwed.  We could guess
 
52
   that there have been 24 leap seconds, which is true at the time of
 
53
   writing (2010-12-09).  But this is wrong if the clock is set to TAI,
 
54
   and this causes the Scheme clock to misbehave if the kernel assumes
 
55
   the TAI - UTC offset to be zero and then increments it when an NTP
 
56
   server tells it of a new leap second: at this point Scheme would
 
57
   switch from assuming a TAI - UTC offset of 24 seconds to assuming a
 
58
   TAI - UTC offset of 1 second, and rewind the clock by 23 seconds --
 
59
   it would behave even worse than a POSIX clock.
 
60
 
 
61
   So instead, if the kernel reports a TAI - UTC offset of under ten,
 
62
   we take that to be the number of leap seconds, so that at least when
 
63
   it is incremented and the system clock is rewound by a second, we
 
64
   can show a smoothly advancing clock.  If the kernel reports a TAI -
 
65
   UTC offset of at least ten, we subtract ten from it to compute the
 
66
   number of leap seconds (because 1972-01-01T00:00:00Z is 1972-01-01
 
67
   at 00:00:10 in TAI).
 
68
 
 
69
   Why a threshold of ten?  Since modern UTC began, the TAI - UTC
 
70
   offset has never been under ten.  So if you represent times during
 
71
   the entire existence of modern UTC so far, this heuristic will
 
72
   work.  */
 
73
 
 
74
/* Summary of scenarios:
 
75
 
 
76
   (a) If your system lacks ntp_gettime/ntp_adjtime, and its clock is
 
77
       set to POSIX time, then you lose exactly as badly as any POSIX
 
78
       program does.  (The clock is wrong by 24 at the time of writing,
 
79
       and it misbehaves during a leap second.)
 
80
 
 
81
   (b) If your system lacks ntp_gettime/ntp_adjtime, and its clock is
 
82
       set to TAI, then you win.  (The clock is correct and behaves
 
83
       well.)
 
84
 
 
85
   (c) If your system has ntp_gettime/ntp_adjtime, its clock is set to
 
86
       POSIX time, and its TAI - UTC offset is initialized to 0 but is
 
87
       incremented at the same time the POSIX clock is rewound, then
 
88
 
 
89
       . you will have time stamps that are off by 24 seconds at the
 
90
         time of writing, but
 
91
 
 
92
       . your clock will behave well,
 
93
 
 
94
       at least for the next net of nine positive leap seconds during
 
95
       continuous operation of your system, which should cover a good
 
96
       decade or so.
 
97
 
 
98
   (d) If your system has ntp_gettime/ntp_adjtime, and its clock is set
 
99
       to POSIX time with the correct TAI - UTC offset, then you win,
 
100
       at least for the next net of fourteen negative leap seconds, but
 
101
       there never has been a negative leap second and probably never
 
102
       will be.
 
103
 
 
104
   (e) If your system has ntp_gettime/ntp_adjtime, and its clock is set
 
105
       to TAI with a constant TAI - UTC offset of 0, then you win.
 
106
 
 
107
   Scenario (c) is the case for most modern Unix systems that I know.
 
108
   Scenario (d) is easily configured for most such Unix systems.
 
109
   Scenarios (b) and (e) are the case for any system administered by
 
110
   users of djbware (see <http://cr.yp.to/proto/utctai.html>).
 
111
 
 
112
   What about time zones?  I will think about them some other time.  */
 
113
 
 
114
static intmax_t utc_epoch_minus_unix_epoch = 63072000L;
 
115
 
 
116
static long
 
117
guess_n_leap_seconds (long tai)
 
118
{
 
119
  return ((tai < 10) ? tai : (tai - 10));
 
120
}
 
121
 
 
122
static intmax_t
 
123
guess_time_from_posix (intmax_t posix, long tai)
 
124
{
 
125
  /* This is to be used only for querying the current clock -- it
 
126
     assumes tai is the current TAI - UTC offset.  To find the (best
 
127
     approximation of) the seconds since an epoch from POSIX time
 
128
     requires consulting a leap second table.  */
 
129
  /* FIXME: There is a minor danger of arithmetic overflow here -- but
 
130
     only on broken operating systems with wildly bogus values for
 
131
     POSIX time and the TAI - UTC offset, or near 2038 on archaic
 
132
     systems with no 64-bit integer type.  */
 
133
  return (posix - utc_epoch_minus_unix_epoch + (guess_n_leap_seconds (tai)));
 
134
}
 
135
 
 
136
/* The following routines may lose information -- namely, the
 
137
   information that the system's clock is bogus.  But if this is so,
 
138
   you'll probably notice the fact anyway, and this paranoia prevents
 
139
   bad values from making Scheme crash.  These are macros because the
 
140
   signedness of the types defined in struct timeval and struct
 
141
   timespec is pretty random.  */
 
142
 
 
143
#define SANITIZE_NSEC(NSEC)                                             \
 
144
  (((NSEC) < 0)                                 ? 0                     \
 
145
   : (((uintmax_t) (NSEC)) < 1000000000UL)      ? ((uint32_t) (NSEC))   \
 
146
   :                                              999999999UL)
 
147
 
 
148
#define SANITIZE_USEC(USEC)                                             \
 
149
  (((USEC) < 0)                         ? 0                             \
 
150
   : (((uintmax_t) (USEC)) < 1000000UL) ? (1000UL * ((uint32_t) (USEC))) \
 
151
   :                                      999999UL)
 
152
 
 
153
#if defined(HAVE_BSD_NTP)
 
154
 
 
155
void
 
156
OS_nanotime_since_utc_epoch (struct scheme_nanotime *t)
 
157
{
 
158
  struct ntptimeval ntv;
 
159
  STD_VOID_SYSTEM_CALL (syscall_ntp_gettime, (UX_ntp_gettime (&ntv)));
 
160
  (t->seconds)
 
161
    = (guess_time_from_posix (((intmax_t) (ntv.time.tv_sec)), (ntv.tai)));
 
162
  (t->nanoseconds) = (SANITIZE_NSEC (ntv.time.tv_nsec));
 
163
}
 
164
 
 
165
#elif defined(HAVE_LINUX_NTP)
 
166
 
 
167
void
 
168
OS_nanotime_since_utc_epoch (struct scheme_nanotime *t)
 
169
{
 
170
  static const struct timex zero_tx;
 
171
  struct timex tx = zero_tx;
 
172
  /* This doesn't actually adjust the time, because we have set
 
173
     tx.modes to zero, meaning no modifications.  It does, however,
 
174
     return some useful information in tx, which Linux's ntp_gettime
 
175
     failed to return until recent versions.  */
 
176
  STD_VOID_SYSTEM_CALL (syscall_ntp_adjtime, (UX_ntp_adjtime (&tx)));
 
177
  (t->seconds)
 
178
    = (guess_time_from_posix (((intmax_t) (tx.time.tv_sec)), (tx.tai)));
 
179
  (t->nanoseconds) = (SANITIZE_USEC (tx.time.tv_usec));
 
180
}
 
181
 
 
182
#elif defined(HAVE_CLOCK_GETTIME)
 
183
 
 
184
void
 
185
OS_nanotime_since_utc_epoch (struct scheme_nanotime t)
 
186
{
 
187
  struct timespec ts;
 
188
  STD_VOID_SYSTEM_CALL
 
189
    (syscall_clock_gettime, (UX_clock_gettime (CLOCK_REALTIME, (&ts))));
 
190
  (t->seconds) = (guess_time_from_posix (((intmax_t) (ts.tv_sec)), 0));
 
191
  (t->nanoseconds) = (SANITIZE_NSEC (ts.tv_nsec));
 
192
}
 
193
 
 
194
#elif defined(HAVE_GETTIMEOFDAY)
 
195
 
 
196
void
 
197
OS_nanotime_since_utc_epoch (struct scheme_nanotime *t)
 
198
{
 
199
  struct timeval tv;
 
200
  STD_VOID_SYSTEM_CALL (syscall_gettimeofday, (UX_gettimeofday ((&tv), 0)));
 
201
  (t->seconds) = (guess_time_from_posix (((intmax_t) (tv.tv_sec)), 0));
 
202
  (t->nanoseconds) = (SANITIZE_USEC (tv.tv_usec));
 
203
}
 
204
 
 
205
#else  /* You are a sad, strange little Unix.  */
 
206
 
 
207
void
 
208
OS_nanotime_since_utc_epoch (struct scheme_nanotime *t)
 
209
{
 
210
  intmax_t posix_time;
 
211
  STD_UINT_SYSTEM_CALL (syscall_time, posix_time, (UX_time (0)));
 
212
  (t->seconds) = (guess_time_from_posix (posix_time, 0));
 
213
  (t->nanoseconds) = 0;
 
214
}
 
215
 
 
216
#endif
 
217
 
31
218
time_t
32
219
OS_encoded_time (void)
33
220
{