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 |