xref: /unit/src/nxt_time.c (revision 0:a63ceefd6ab0)
1*0Sigor@sysoev.ru 
2*0Sigor@sysoev.ru /*
3*0Sigor@sysoev.ru  * Copyright (C) Igor Sysoev
4*0Sigor@sysoev.ru  * Copyright (C) NGINX, Inc.
5*0Sigor@sysoev.ru  */
6*0Sigor@sysoev.ru 
7*0Sigor@sysoev.ru #include <nxt_main.h>
8*0Sigor@sysoev.ru 
9*0Sigor@sysoev.ru 
10*0Sigor@sysoev.ru /* OS-specific real, monotonic, and local times and timezone update. */
11*0Sigor@sysoev.ru 
12*0Sigor@sysoev.ru 
13*0Sigor@sysoev.ru /* Real time. */
14*0Sigor@sysoev.ru 
15*0Sigor@sysoev.ru #if (NXT_HAVE_CLOCK_REALTIME_COARSE)
16*0Sigor@sysoev.ru 
17*0Sigor@sysoev.ru /*
18*0Sigor@sysoev.ru  * Linux clock_gettime() resides on the vDSO page.  Linux 2.6.32
19*0Sigor@sysoev.ru  * clock_gettime(CLOCK_REALTIME_COARSE) uses only cached values and does
20*0Sigor@sysoev.ru  * not read TSC or HPET so it has the kernel jiffy precision (1ms by default)
21*0Sigor@sysoev.ru  * and it is several times faster than clock_gettime(CLOCK_REALTIME).
22*0Sigor@sysoev.ru  */
23*0Sigor@sysoev.ru 
24*0Sigor@sysoev.ru void
nxt_realtime(nxt_realtime_t * now)25*0Sigor@sysoev.ru nxt_realtime(nxt_realtime_t *now)
26*0Sigor@sysoev.ru {
27*0Sigor@sysoev.ru     struct timespec  ts;
28*0Sigor@sysoev.ru 
29*0Sigor@sysoev.ru     (void) clock_gettime(CLOCK_REALTIME_COARSE, &ts);
30*0Sigor@sysoev.ru 
31*0Sigor@sysoev.ru     now->sec = (nxt_time_t) ts.tv_sec;
32*0Sigor@sysoev.ru     now->nsec = ts.tv_nsec;
33*0Sigor@sysoev.ru }
34*0Sigor@sysoev.ru 
35*0Sigor@sysoev.ru 
36*0Sigor@sysoev.ru #elif (NXT_HAVE_CLOCK_REALTIME_FAST)
37*0Sigor@sysoev.ru 
38*0Sigor@sysoev.ru /*
39*0Sigor@sysoev.ru  * FreeBSD 7.0 specific clock_gettime(CLOCK_REALTIME_FAST) may be
40*0Sigor@sysoev.ru  * 5-30 times faster than clock_gettime(CLOCK_REALTIME) depending
41*0Sigor@sysoev.ru  * on kern.timecounter.hardware.  The clock has a precision of 1/HZ
42*0Sigor@sysoev.ru  * seconds (HZ is 1000 on modern platforms, thus 1ms precision).
43*0Sigor@sysoev.ru  * FreeBSD 9.2 clock_gettime() resides on the vDSO page and reads
44*0Sigor@sysoev.ru  * TSC.  clock_gettime(CLOCK_REALTIME_FAST) is the same as
45*0Sigor@sysoev.ru  * clock_gettime(CLOCK_REALTIME).
46*0Sigor@sysoev.ru  */
47*0Sigor@sysoev.ru 
48*0Sigor@sysoev.ru void
nxt_realtime(nxt_realtime_t * now)49*0Sigor@sysoev.ru nxt_realtime(nxt_realtime_t *now)
50*0Sigor@sysoev.ru {
51*0Sigor@sysoev.ru     struct timespec  ts;
52*0Sigor@sysoev.ru 
53*0Sigor@sysoev.ru     (void) clock_gettime(CLOCK_REALTIME_FAST, &ts);
54*0Sigor@sysoev.ru 
55*0Sigor@sysoev.ru     now->sec = (nxt_time_t) ts.tv_sec;
56*0Sigor@sysoev.ru     now->nsec = ts.tv_nsec;
57*0Sigor@sysoev.ru }
58*0Sigor@sysoev.ru 
59*0Sigor@sysoev.ru 
60*0Sigor@sysoev.ru #elif (NXT_HAVE_CLOCK_REALTIME && !(NXT_HPUX))
61*0Sigor@sysoev.ru 
62*0Sigor@sysoev.ru /*
63*0Sigor@sysoev.ru  * clock_gettime(CLOCK_REALTIME) is supported by Linux, FreeBSD 3.0,
64*0Sigor@sysoev.ru  * Solaris 8, NetBSD 1.3, and AIX.  HP-UX supports it too, however,
65*0Sigor@sysoev.ru  * it is implemented through a call to gettimeofday().  Linux
66*0Sigor@sysoev.ru  * clock_gettime(CLOCK_REALTIME) resides on the vDSO page and reads
67*0Sigor@sysoev.ru  * TSC or HPET.  FreeBSD 9.2 clock_gettime(CLOCK_REALTIME) resides
68*0Sigor@sysoev.ru  * on the vDSO page and reads TSC.
69*0Sigor@sysoev.ru  */
70*0Sigor@sysoev.ru 
71*0Sigor@sysoev.ru void
nxt_realtime(nxt_realtime_t * now)72*0Sigor@sysoev.ru nxt_realtime(nxt_realtime_t *now)
73*0Sigor@sysoev.ru {
74*0Sigor@sysoev.ru     struct timespec  ts;
75*0Sigor@sysoev.ru 
76*0Sigor@sysoev.ru     (void) clock_gettime(CLOCK_REALTIME, &ts);
77*0Sigor@sysoev.ru 
78*0Sigor@sysoev.ru     now->sec = (nxt_time_t) ts.tv_sec;
79*0Sigor@sysoev.ru     now->nsec = ts.tv_nsec;
80*0Sigor@sysoev.ru }
81*0Sigor@sysoev.ru 
82*0Sigor@sysoev.ru 
83*0Sigor@sysoev.ru #else
84*0Sigor@sysoev.ru 
85*0Sigor@sysoev.ru /* MacOSX, HP-UX. */
86*0Sigor@sysoev.ru 
87*0Sigor@sysoev.ru void
nxt_realtime(nxt_realtime_t * now)88*0Sigor@sysoev.ru nxt_realtime(nxt_realtime_t *now)
89*0Sigor@sysoev.ru {
90*0Sigor@sysoev.ru     struct timeval  tv;
91*0Sigor@sysoev.ru 
92*0Sigor@sysoev.ru     (void) gettimeofday(&tv, NULL);
93*0Sigor@sysoev.ru 
94*0Sigor@sysoev.ru     now->sec = (nxt_time_t) tv.tv_sec;
95*0Sigor@sysoev.ru     now->nsec = tv.tv_usec * 1000;
96*0Sigor@sysoev.ru }
97*0Sigor@sysoev.ru 
98*0Sigor@sysoev.ru #endif
99*0Sigor@sysoev.ru 
100*0Sigor@sysoev.ru 
101*0Sigor@sysoev.ru /* Monotonic time. */
102*0Sigor@sysoev.ru 
103*0Sigor@sysoev.ru #if (NXT_HAVE_CLOCK_MONOTONIC_COARSE)
104*0Sigor@sysoev.ru 
105*0Sigor@sysoev.ru /*
106*0Sigor@sysoev.ru  * Linux clock_gettime() resides on the vDSO page.  Linux 2.6.32
107*0Sigor@sysoev.ru  * clock_gettime(CLOCK_MONOTONIC_COARSE) uses only cached values and does
108*0Sigor@sysoev.ru  * not read TSC or HPET so it has the kernel jiffy precision (1ms by default)
109*0Sigor@sysoev.ru  * and it is several times faster than clock_gettime(CLOCK_MONOTONIC).
110*0Sigor@sysoev.ru  */
111*0Sigor@sysoev.ru 
112*0Sigor@sysoev.ru void
nxt_monotonic_time(nxt_monotonic_time_t * now)113*0Sigor@sysoev.ru nxt_monotonic_time(nxt_monotonic_time_t *now)
114*0Sigor@sysoev.ru {
115*0Sigor@sysoev.ru     struct timespec  ts;
116*0Sigor@sysoev.ru 
117*0Sigor@sysoev.ru     (void) clock_gettime(CLOCK_MONOTONIC_COARSE, &ts);
118*0Sigor@sysoev.ru 
119*0Sigor@sysoev.ru     now->monotonic = (nxt_nsec_t) ts.tv_sec * 1000000000 + ts.tv_nsec;
120*0Sigor@sysoev.ru }
121*0Sigor@sysoev.ru 
122*0Sigor@sysoev.ru 
123*0Sigor@sysoev.ru #elif (NXT_HAVE_CLOCK_MONOTONIC_FAST)
124*0Sigor@sysoev.ru 
125*0Sigor@sysoev.ru /*
126*0Sigor@sysoev.ru  * FreeBSD 7.0 specific clock_gettime(CLOCK_MONOTONIC_FAST) may be
127*0Sigor@sysoev.ru  * 5-30 times faster than clock_gettime(CLOCK_MONOTONIC) depending
128*0Sigor@sysoev.ru  * on kern.timecounter.hardware.  The clock has a precision of 1/HZ
129*0Sigor@sysoev.ru  * seconds (HZ is 1000 on modern platforms, thus 1ms precision).
130*0Sigor@sysoev.ru  * FreeBSD 9.2 clock_gettime() resides on the vDSO page and reads
131*0Sigor@sysoev.ru  * TSC.  clock_gettime(CLOCK_MONOTONIC_FAST) is the same as
132*0Sigor@sysoev.ru  * clock_gettime(CLOCK_MONOTONIC).
133*0Sigor@sysoev.ru  */
134*0Sigor@sysoev.ru 
135*0Sigor@sysoev.ru void
nxt_monotonic_time(nxt_monotonic_time_t * now)136*0Sigor@sysoev.ru nxt_monotonic_time(nxt_monotonic_time_t *now)
137*0Sigor@sysoev.ru {
138*0Sigor@sysoev.ru     struct timespec  ts;
139*0Sigor@sysoev.ru 
140*0Sigor@sysoev.ru     (void) clock_gettime(CLOCK_MONOTONIC_FAST, &ts);
141*0Sigor@sysoev.ru 
142*0Sigor@sysoev.ru     now->monotonic = (nxt_nsec_t) ts.tv_sec * 1000000000 + ts.tv_nsec;
143*0Sigor@sysoev.ru }
144*0Sigor@sysoev.ru 
145*0Sigor@sysoev.ru 
146*0Sigor@sysoev.ru #elif (NXT_HAVE_HG_GETHRTIME)
147*0Sigor@sysoev.ru 
148*0Sigor@sysoev.ru /*
149*0Sigor@sysoev.ru  * HP-UX 11.31 provides fast hg_gethrtime() which uses a chunk of memory
150*0Sigor@sysoev.ru  * shared between userspace application and the kernel, and was introduced
151*0Sigor@sysoev.ru  * by Project Mercury ("HG").
152*0Sigor@sysoev.ru  */
153*0Sigor@sysoev.ru 
154*0Sigor@sysoev.ru void
nxt_monotonic_time(nxt_monotonic_time_t * now)155*0Sigor@sysoev.ru nxt_monotonic_time(nxt_monotonic_time_t *now)
156*0Sigor@sysoev.ru {
157*0Sigor@sysoev.ru     now->monotonic = (nxt_nsec_t) hg_gethrtime();
158*0Sigor@sysoev.ru }
159*0Sigor@sysoev.ru 
160*0Sigor@sysoev.ru 
161*0Sigor@sysoev.ru #elif (NXT_SOLARIS || NXT_HPUX)
162*0Sigor@sysoev.ru 
163*0Sigor@sysoev.ru /*
164*0Sigor@sysoev.ru  * Solaris gethrtime(), clock_gettime(CLOCK_REALTIME), and gettimeofday()
165*0Sigor@sysoev.ru  * use a fast systrap whereas clock_gettime(CLOCK_MONOTONIC) and other
166*0Sigor@sysoev.ru  * clock_gettime()s use normal systrap.  However, the difference is
167*0Sigor@sysoev.ru  * negligible on x86_64.
168*0Sigor@sysoev.ru  *
169*0Sigor@sysoev.ru  * HP-UX lacks clock_gettime(CLOCK_MONOTONIC) but has lightweight
170*0Sigor@sysoev.ru  * system call gethrtime().
171*0Sigor@sysoev.ru  */
172*0Sigor@sysoev.ru 
173*0Sigor@sysoev.ru void
nxt_monotonic_time(nxt_monotonic_time_t * now)174*0Sigor@sysoev.ru nxt_monotonic_time(nxt_monotonic_time_t *now)
175*0Sigor@sysoev.ru {
176*0Sigor@sysoev.ru     now->monotonic = (nxt_nsec_t) gethrtime();
177*0Sigor@sysoev.ru }
178*0Sigor@sysoev.ru 
179*0Sigor@sysoev.ru 
180*0Sigor@sysoev.ru #elif (NXT_HAVE_CLOCK_MONOTONIC)
181*0Sigor@sysoev.ru 
182*0Sigor@sysoev.ru /*
183*0Sigor@sysoev.ru  * clock_gettime(CLOCK_MONOTONIC) is supported by Linux, FreeBSD 5.0,
184*0Sigor@sysoev.ru  * Solaris 8, NetBSD 1.6, and AIX.  Linux clock_gettime(CLOCK_MONOTONIC)
185*0Sigor@sysoev.ru  * resides on the vDSO page and reads TSC or HPET.  FreeBSD 9.2
186*0Sigor@sysoev.ru  * clock_gettime(CLOCK_MONOTONIC) resides on the vDSO page and reads TSC.
187*0Sigor@sysoev.ru  */
188*0Sigor@sysoev.ru 
189*0Sigor@sysoev.ru void
nxt_monotonic_time(nxt_monotonic_time_t * now)190*0Sigor@sysoev.ru nxt_monotonic_time(nxt_monotonic_time_t *now)
191*0Sigor@sysoev.ru {
192*0Sigor@sysoev.ru     struct timespec  ts;
193*0Sigor@sysoev.ru 
194*0Sigor@sysoev.ru     (void) clock_gettime(CLOCK_MONOTONIC, &ts);
195*0Sigor@sysoev.ru 
196*0Sigor@sysoev.ru     now->monotonic = (nxt_nsec_t) ts.tv_sec * 1000000000 + ts.tv_nsec;
197*0Sigor@sysoev.ru }
198*0Sigor@sysoev.ru 
199*0Sigor@sysoev.ru 
200*0Sigor@sysoev.ru #elif (NXT_MACOSX)
201*0Sigor@sysoev.ru 
202*0Sigor@sysoev.ru /*
203*0Sigor@sysoev.ru  * MacOSX does not support clock_gettime(), but mach_absolute_time() returns
204*0Sigor@sysoev.ru  * monotonic ticks.  To get nanoseconds the ticks should be multiplied then
205*0Sigor@sysoev.ru  * divided by numerator/denominator returned by mach_timebase_info(), however
206*0Sigor@sysoev.ru  * on modern MacOSX they are 1/1.  On PowerPC MacOSX these values were
207*0Sigor@sysoev.ru  * 1000000000/33333335 or 1000000000/25000000, on iOS 4+ they were 125/3,
208*0Sigor@sysoev.ru  * and on iOS 3 they were 1000000000/24000000.
209*0Sigor@sysoev.ru  */
210*0Sigor@sysoev.ru 
211*0Sigor@sysoev.ru void
nxt_monotonic_time(nxt_monotonic_time_t * now)212*0Sigor@sysoev.ru nxt_monotonic_time(nxt_monotonic_time_t *now)
213*0Sigor@sysoev.ru {
214*0Sigor@sysoev.ru     now->monotonic = mach_absolute_time();
215*0Sigor@sysoev.ru }
216*0Sigor@sysoev.ru 
217*0Sigor@sysoev.ru 
218*0Sigor@sysoev.ru #else
219*0Sigor@sysoev.ru 
220*0Sigor@sysoev.ru void
nxt_monotonic_time(nxt_monotonic_time_t * now)221*0Sigor@sysoev.ru nxt_monotonic_time(nxt_monotonic_time_t *now)
222*0Sigor@sysoev.ru {
223*0Sigor@sysoev.ru     nxt_nsec_t      current;
224*0Sigor@sysoev.ru     nxt_nsec_int_t  delta;
225*0Sigor@sysoev.ru     struct timeval  tv;
226*0Sigor@sysoev.ru 
227*0Sigor@sysoev.ru     (void) gettimeofday(&tv, NULL);
228*0Sigor@sysoev.ru 
229*0Sigor@sysoev.ru     now->realtime.sec = (nxt_time_t) tv.tv_sec;
230*0Sigor@sysoev.ru     now->realtime.nsec = tv.tv_usec * 1000;
231*0Sigor@sysoev.ru 
232*0Sigor@sysoev.ru     /*
233*0Sigor@sysoev.ru      * Monotonic time emulation using gettimeofday()
234*0Sigor@sysoev.ru      * for platforms which lack monotonic time.
235*0Sigor@sysoev.ru      */
236*0Sigor@sysoev.ru 
237*0Sigor@sysoev.ru     current = (nxt_nsec_t) tv.tv_sec * 1000000000 + tv.tv_usec * 1000;
238*0Sigor@sysoev.ru     delta = current - now->previous;
239*0Sigor@sysoev.ru     now->previous = current;
240*0Sigor@sysoev.ru 
241*0Sigor@sysoev.ru     if (delta > 0) {
242*0Sigor@sysoev.ru         now->monotonic += delta;
243*0Sigor@sysoev.ru 
244*0Sigor@sysoev.ru     } else {
245*0Sigor@sysoev.ru         /* The time went backward. */
246*0Sigor@sysoev.ru         now->monotonic++;
247*0Sigor@sysoev.ru     }
248*0Sigor@sysoev.ru 
249*0Sigor@sysoev.ru     /*
250*0Sigor@sysoev.ru      * Eliminate subsequent gettimeofday() call
251*0Sigor@sysoev.ru      * in nxt_thread_realtime_update().
252*0Sigor@sysoev.ru      */
253*0Sigor@sysoev.ru     now->update = now->monotonic + 1;
254*0Sigor@sysoev.ru }
255*0Sigor@sysoev.ru 
256*0Sigor@sysoev.ru #endif
257*0Sigor@sysoev.ru 
258*0Sigor@sysoev.ru 
259*0Sigor@sysoev.ru /* Local time. */
260*0Sigor@sysoev.ru 
261*0Sigor@sysoev.ru #if (NXT_HAVE_LOCALTIME_R)
262*0Sigor@sysoev.ru 
263*0Sigor@sysoev.ru void
nxt_localtime(nxt_time_t s,struct tm * tm)264*0Sigor@sysoev.ru nxt_localtime(nxt_time_t s, struct tm *tm)
265*0Sigor@sysoev.ru {
266*0Sigor@sysoev.ru     time_t  _s;
267*0Sigor@sysoev.ru 
268*0Sigor@sysoev.ru     _s = (time_t) s;
269*0Sigor@sysoev.ru     (void) localtime_r(&_s, tm);
270*0Sigor@sysoev.ru }
271*0Sigor@sysoev.ru 
272*0Sigor@sysoev.ru 
273*0Sigor@sysoev.ru #else
274*0Sigor@sysoev.ru 
275*0Sigor@sysoev.ru void
nxt_localtime(nxt_time_t s,struct tm * tm)276*0Sigor@sysoev.ru nxt_localtime(nxt_time_t s, struct tm *tm)
277*0Sigor@sysoev.ru {
278*0Sigor@sysoev.ru     time_t     _s;
279*0Sigor@sysoev.ru     struct tm  *_tm;
280*0Sigor@sysoev.ru 
281*0Sigor@sysoev.ru     _s = (time_t) s;
282*0Sigor@sysoev.ru     _tm = localtime(&_s);
283*0Sigor@sysoev.ru     *tm = *_tm;
284*0Sigor@sysoev.ru }
285*0Sigor@sysoev.ru 
286*0Sigor@sysoev.ru #endif
287*0Sigor@sysoev.ru 
288*0Sigor@sysoev.ru 
289*0Sigor@sysoev.ru /* Timezone update. */
290*0Sigor@sysoev.ru 
291*0Sigor@sysoev.ru #if (NXT_LINUX)
292*0Sigor@sysoev.ru 
293*0Sigor@sysoev.ru /*
294*0Sigor@sysoev.ru  * Linux glibc does not test /etc/localtime change
295*0Sigor@sysoev.ru  * in localtime_r(), but tests in localtime().
296*0Sigor@sysoev.ru  */
297*0Sigor@sysoev.ru 
298*0Sigor@sysoev.ru void
nxt_timezone_update(void)299*0Sigor@sysoev.ru nxt_timezone_update(void)
300*0Sigor@sysoev.ru {
301*0Sigor@sysoev.ru     time_t  s;
302*0Sigor@sysoev.ru 
303*0Sigor@sysoev.ru     s = time(NULL);
304*0Sigor@sysoev.ru     (void) localtime(&s);
305*0Sigor@sysoev.ru }
306*0Sigor@sysoev.ru 
307*0Sigor@sysoev.ru 
308*0Sigor@sysoev.ru #elif (NXT_FREEBSD)
309*0Sigor@sysoev.ru 
310*0Sigor@sysoev.ru /*
311*0Sigor@sysoev.ru  * FreeBSD libc does not test /etc/localtime change, but it can be
312*0Sigor@sysoev.ru  * worked around by calling tzset() with TZ and then without TZ
313*0Sigor@sysoev.ru  * to update timezone.  This trick should work since FreeBSD 2.1.0.
314*0Sigor@sysoev.ru  */
315*0Sigor@sysoev.ru 
316*0Sigor@sysoev.ru void
nxt_timezone_update(void)317*0Sigor@sysoev.ru nxt_timezone_update(void)
318*0Sigor@sysoev.ru {
319*0Sigor@sysoev.ru     if (getenv("TZ") != NULL) {
320*0Sigor@sysoev.ru         return;
321*0Sigor@sysoev.ru     }
322*0Sigor@sysoev.ru 
323*0Sigor@sysoev.ru     /* The libc uses /etc/localtime if TZ is not set. */
324*0Sigor@sysoev.ru 
325*0Sigor@sysoev.ru     (void) putenv((char *) "TZ=UTC");
326*0Sigor@sysoev.ru     tzset();
327*0Sigor@sysoev.ru 
328*0Sigor@sysoev.ru     (void) unsetenv("TZ");
329*0Sigor@sysoev.ru     tzset();
330*0Sigor@sysoev.ru }
331*0Sigor@sysoev.ru 
332*0Sigor@sysoev.ru 
333*0Sigor@sysoev.ru #elif (NXT_SOLARIS)
334*0Sigor@sysoev.ru 
335*0Sigor@sysoev.ru /*
336*0Sigor@sysoev.ru  * Solaris 10, patch 142909-17 introduced tzreload(8):
337*0Sigor@sysoev.ru  *
338*0Sigor@sysoev.ru  *   The tzreload command notifies active (running) processes to reread
339*0Sigor@sysoev.ru  *   timezone information.  The timezone information is cached in each
340*0Sigor@sysoev.ru  *   process, absent a tzreload command, is never reread until a process
341*0Sigor@sysoev.ru  *   is restarted.  In response to a tzreload command, active processes
342*0Sigor@sysoev.ru  *   reread the current timezone information at the next call to ctime(3C)
343*0Sigor@sysoev.ru  *   and mktime(3C).  By default, the tzreload notification is sent to
344*0Sigor@sysoev.ru  *   the processes within the current zone.
345*0Sigor@sysoev.ru  */
346*0Sigor@sysoev.ru 
347*0Sigor@sysoev.ru void
nxt_timezone_update(void)348*0Sigor@sysoev.ru nxt_timezone_update(void)
349*0Sigor@sysoev.ru {
350*0Sigor@sysoev.ru     time_t  s;
351*0Sigor@sysoev.ru 
352*0Sigor@sysoev.ru     s = time(NULL);
353*0Sigor@sysoev.ru     (void) ctime(&s);
354*0Sigor@sysoev.ru }
355*0Sigor@sysoev.ru 
356*0Sigor@sysoev.ru 
357*0Sigor@sysoev.ru #else
358*0Sigor@sysoev.ru 
359*0Sigor@sysoev.ru void
nxt_timezone_update(void)360*0Sigor@sysoev.ru nxt_timezone_update(void)
361*0Sigor@sysoev.ru {
362*0Sigor@sysoev.ru     return;
363*0Sigor@sysoev.ru }
364*0Sigor@sysoev.ru 
365*0Sigor@sysoev.ru #endif
366