Coverage Report

Created: 2025-10-13 06:03

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