GNU libmicrohttpd 0.9.77
Loading...
Searching...
No Matches
mhd_mono_clock.c
Go to the documentation of this file.
1/*
2 This file is part of libmicrohttpd
3 Copyright (C) 2015 Karlson2k (Evgeny Grin)
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18*/
19
26#include "mhd_mono_clock.h"
27
28#if defined(_WIN32) && ! defined(__CYGWIN__)
29/* Prefer native clock source over wrappers */
30#ifdef HAVE_CLOCK_GETTIME
31#undef HAVE_CLOCK_GETTIME
32#endif /* HAVE_CLOCK_GETTIME */
33#ifdef HAVE_GETTIMEOFDAY
34#undef HAVE_GETTIMEOFDAY
35#endif /* HAVE_GETTIMEOFDAY */
36#endif /* _WIN32 && ! __CYGWIN__ */
37
38#ifdef HAVE_TIME_H
39#include <time.h>
40#endif /* HAVE_TIME_H */
41#ifdef HAVE_SYS_TIME_H
42#include <sys/time.h>
43#endif /* HAVE_SYS_TIME_H */
44
45#ifdef HAVE_CLOCK_GET_TIME
46#include <mach/mach.h>
47/* for host_get_clock_service(), mach_host_self(), mach_task_self() */
48#include <mach/clock.h>
49/* for clock_get_time() */
50
51#define _MHD_INVALID_CLOCK_SERV ((clock_serv_t) -2)
52
53static clock_serv_t mono_clock_service = _MHD_INVALID_CLOCK_SERV;
54#endif /* HAVE_CLOCK_GET_TIME */
55
56#ifdef _WIN32
57#ifndef WIN32_LEAN_AND_MEAN
58/* Do not include unneeded parts of W32 headers. */
59#define WIN32_LEAN_AND_MEAN 1
60#endif /* !WIN32_LEAN_AND_MEAN */
61#include <windows.h>
62#include <stdint.h>
63#endif /* _WIN32 */
64
65#ifndef NULL
66#define NULL ((void*)0)
67#endif /* ! NULL */
68
69#ifdef HAVE_CLOCK_GETTIME
70#ifdef CLOCK_REALTIME
71#define _MHD_UNWANTED_CLOCK CLOCK_REALTIME
72#else /* !CLOCK_REALTIME */
73#define _MHD_UNWANTED_CLOCK ((clockid_t) -2)
74#endif /* !CLOCK_REALTIME */
75
76static clockid_t mono_clock_id = _MHD_UNWANTED_CLOCK;
77#endif /* HAVE_CLOCK_GETTIME */
78
79/* sync clocks; reduce chance of value wrap */
80#if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_CLOCK_GET_TIME) || \
81 defined(HAVE_GETHRTIME)
82static time_t mono_clock_start;
83#endif /* HAVE_CLOCK_GETTIME || HAVE_CLOCK_GET_TIME || HAVE_GETHRTIME */
84#if defined(HAVE_TIMESPEC_GET) || defined(HAVE_GETTIMEOFDAY)
85/* The start value shared for timespec_get() and gettimeofday () */
86static time_t gettime_start;
87#endif /* HAVE_TIMESPEC_GET || HAVE_GETTIMEOFDAY */
88static time_t sys_clock_start;
89#ifdef HAVE_GETHRTIME
90static hrtime_t hrtime_start;
91#endif /* HAVE_GETHRTIME */
92#ifdef _WIN32
93#if _WIN32_WINNT >= 0x0600
94static uint64_t tick_start;
95#else /* _WIN32_WINNT < 0x0600 */
96static uint64_t perf_freq;
97static uint64_t perf_start;
98#endif /* _WIN32_WINNT < 0x0600 */
99#endif /* _WIN32 */
100
101
106{
111
116
121
126
131
137
138
142void
144{
145#ifdef HAVE_CLOCK_GET_TIME
146 mach_timespec_t cur_time;
147#endif /* HAVE_CLOCK_GET_TIME */
148 enum _MHD_mono_clock_source mono_clock_source = _MHD_CLOCK_NO_SOURCE;
149#ifdef HAVE_CLOCK_GETTIME
150 struct timespec ts;
151
152 mono_clock_id = _MHD_UNWANTED_CLOCK;
153#endif /* HAVE_CLOCK_GETTIME */
154#ifdef HAVE_CLOCK_GET_TIME
155 mono_clock_service = _MHD_INVALID_CLOCK_SERV;
156#endif /* HAVE_CLOCK_GET_TIME */
157
158 /* just a little syntactic trick to get the
159 various following ifdef's to work out nicely */
160 if (0)
161 {
162 (void) 0; /* Mute possible compiler warning */
163 }
164 else
165#ifdef HAVE_CLOCK_GETTIME
166#ifdef CLOCK_MONOTONIC_COARSE
167 /* Linux-specific fast value-getting clock */
168 /* Can be affected by frequency adjustment and don't count time in suspend, */
169 /* but preferred since it's fast */
170 if (0 == clock_gettime (CLOCK_MONOTONIC_COARSE,
171 &ts))
172 {
173 mono_clock_id = CLOCK_MONOTONIC_COARSE;
174 mono_clock_start = ts.tv_sec;
175 mono_clock_source = _MHD_CLOCK_GETTIME;
176 }
177 else
178#endif /* CLOCK_MONOTONIC_COARSE */
179#ifdef CLOCK_MONOTONIC_FAST
180 /* FreeBSD/DragonFly fast value-getting clock */
181 /* Can be affected by frequency adjustment, but preferred since it's fast */
182 if (0 == clock_gettime (CLOCK_MONOTONIC_FAST,
183 &ts))
184 {
185 mono_clock_id = CLOCK_MONOTONIC_FAST;
186 mono_clock_start = ts.tv_sec;
187 mono_clock_source = _MHD_CLOCK_GETTIME;
188 }
189 else
190#endif /* CLOCK_MONOTONIC_COARSE */
191#ifdef CLOCK_MONOTONIC_RAW_APPROX
192 /* Darwin-specific clock */
193 /* Not affected by frequency adjustment, returns clock value cached at
194 * context switch. Can be "milliseconds old", but it's fast. */
195 if (0 == clock_gettime (CLOCK_MONOTONIC_RAW_APPROX,
196 &ts))
197 {
198 mono_clock_id = CLOCK_MONOTONIC_RAW_APPROX;
199 mono_clock_start = ts.tv_sec;
200 mono_clock_source = _MHD_CLOCK_GETTIME;
201 }
202 else
203#endif /* CLOCK_MONOTONIC_RAW */
204#ifdef CLOCK_MONOTONIC_RAW
205 /* Linux and Darwin clock */
206 /* Not affected by frequency adjustment,
207 * on Linux don't count time in suspend */
208 if (0 == clock_gettime (CLOCK_MONOTONIC_RAW,
209 &ts))
210 {
211 mono_clock_id = CLOCK_MONOTONIC_RAW;
212 mono_clock_start = ts.tv_sec;
213 mono_clock_source = _MHD_CLOCK_GETTIME;
214 }
215 else
216#endif /* CLOCK_MONOTONIC_RAW */
217#ifdef CLOCK_BOOTTIME
218 /* Count time in suspend on Linux so it's real monotonic, */
219 /* but can be slower value-getting than other clocks */
220 if (0 == clock_gettime (CLOCK_BOOTTIME,
221 &ts))
222 {
223 mono_clock_id = CLOCK_BOOTTIME;
224 mono_clock_start = ts.tv_sec;
225 mono_clock_source = _MHD_CLOCK_GETTIME;
226 }
227 else
228#endif /* CLOCK_BOOTTIME */
229#ifdef CLOCK_MONOTONIC
230 /* Monotonic clock */
231 /* Widely supported, may be affected by frequency adjustment */
232 /* On Linux it's not truly monotonic as it doesn't count time in suspend */
233 if (0 == clock_gettime (CLOCK_MONOTONIC,
234 &ts))
235 {
236 mono_clock_id = CLOCK_MONOTONIC;
237 mono_clock_start = ts.tv_sec;
238 mono_clock_source = _MHD_CLOCK_GETTIME;
239 }
240 else
241#endif /* CLOCK_MONOTONIC */
242#ifdef CLOCK_UPTIME
243 /* non-Linux clock */
244 /* Doesn't count time in suspend */
245 if (0 == clock_gettime (CLOCK_UPTIME,
246 &ts))
247 {
248 mono_clock_id = CLOCK_UPTIME;
249 mono_clock_start = ts.tv_sec;
250 mono_clock_source = _MHD_CLOCK_GETTIME;
251 }
252 else
253#endif /* CLOCK_BOOTTIME */
254#endif /* HAVE_CLOCK_GETTIME */
255#ifdef HAVE_CLOCK_GET_TIME
256 /* Darwin-specific monotonic clock */
257 /* Should be monotonic as clock_set_time function always unconditionally */
258 /* failed on latest kernels */
259 if ( (KERN_SUCCESS == host_get_clock_service (mach_host_self (),
260 SYSTEM_CLOCK,
261 &mono_clock_service)) &&
262 (KERN_SUCCESS == clock_get_time (mono_clock_service,
263 &cur_time)) )
264 {
265 mono_clock_start = cur_time.tv_sec;
266 mono_clock_source = _MHD_CLOCK_GET_TIME;
267 }
268 else
269#endif /* HAVE_CLOCK_GET_TIME */
270#ifdef _WIN32
271#if _WIN32_WINNT >= 0x0600
272 /* W32 Vista or later specific monotonic clock */
273 /* Available since Vista, ~15ms accuracy */
274 if (1)
275 {
276 tick_start = GetTickCount64 ();
277 mono_clock_source = _MHD_CLOCK_GETTICKCOUNT64;
278 }
279 else
280#else /* _WIN32_WINNT < 0x0600 */
281 /* W32 specific monotonic clock */
282 /* Available on Windows 2000 and later */
283 if (1)
284 {
285 LARGE_INTEGER freq;
286 LARGE_INTEGER perf_counter;
287
288 QueryPerformanceFrequency (&freq); /* never fail on XP and later */
289 QueryPerformanceCounter (&perf_counter); /* never fail on XP and later */
290 perf_freq = (uint64_t) freq.QuadPart;
291 perf_start = (uint64_t) perf_counter.QuadPart;
292 mono_clock_source = _MHD_CLOCK_PERFCOUNTER;
293 }
294 else
295#endif /* _WIN32_WINNT < 0x0600 */
296#endif /* _WIN32 */
297#ifdef HAVE_CLOCK_GETTIME
298#ifdef CLOCK_HIGHRES
299 /* Solaris-specific monotonic high-resolution clock */
300 /* Not preferred due to be potentially resource-hungry */
301 if (0 == clock_gettime (CLOCK_HIGHRES,
302 &ts))
303 {
304 mono_clock_id = CLOCK_HIGHRES;
305 mono_clock_start = ts.tv_sec;
306 mono_clock_source = _MHD_CLOCK_GETTIME;
307 }
308 else
309#endif /* CLOCK_HIGHRES */
310#endif /* HAVE_CLOCK_GETTIME */
311#ifdef HAVE_GETHRTIME
312 /* HP-UX and Solaris monotonic clock */
313 /* Not preferred due to be potentially resource-hungry */
314 if (1)
315 {
316 hrtime_start = gethrtime ();
317 mono_clock_source = _MHD_CLOCK_GETHRTIME;
318 }
319 else
320#endif /* HAVE_GETHRTIME */
321 {
322 /* no suitable clock source was found */
323 mono_clock_source = _MHD_CLOCK_NO_SOURCE;
324 }
325
326#ifdef HAVE_CLOCK_GET_TIME
327 if ( (_MHD_CLOCK_GET_TIME != mono_clock_source) &&
328 (_MHD_INVALID_CLOCK_SERV != mono_clock_service) )
329 {
330 /* clock service was initialised but clock_get_time failed */
331 mach_port_deallocate (mach_task_self (),
332 mono_clock_service);
333 mono_clock_service = _MHD_INVALID_CLOCK_SERV;
334 }
335#else
336 (void) mono_clock_source; /* avoid compiler warning */
337#endif /* HAVE_CLOCK_GET_TIME */
338
339#ifdef HAVE_TIMESPEC_GET
340 if (1)
341 {
342 struct timespec tsg;
343 if (TIME_UTC == timespec_get (&tsg, TIME_UTC))
344 gettime_start = tsg.tv_sec;
345 else
346 gettime_start = 0;
347 }
348#elif defined(HAVE_GETTIMEOFDAY)
349 if (1)
350 {
351 struct timeval tv;
352 if (0 == gettimeofday (&tv, NULL))
353 gettime_start = tv.tv_sec;
354 else
355 gettime_start = 0;
356 }
357#endif /* HAVE_GETTIMEOFDAY */
358 sys_clock_start = time (NULL);
359}
360
361
366void
368{
369#ifdef HAVE_CLOCK_GET_TIME
370 if (_MHD_INVALID_CLOCK_SERV != mono_clock_service)
371 {
372 mach_port_deallocate (mach_task_self (),
373 mono_clock_service);
374 mono_clock_service = _MHD_INVALID_CLOCK_SERV;
375 }
376#endif /* HAVE_CLOCK_GET_TIME */
377}
378
379
387time_t
389{
390#ifdef HAVE_CLOCK_GETTIME
391 struct timespec ts;
392
393 if ( (_MHD_UNWANTED_CLOCK != mono_clock_id) &&
394 (0 == clock_gettime (mono_clock_id,
395 &ts)) )
396 return ts.tv_sec - mono_clock_start;
397#endif /* HAVE_CLOCK_GETTIME */
398#ifdef HAVE_CLOCK_GET_TIME
399 if (_MHD_INVALID_CLOCK_SERV != mono_clock_service)
400 {
401 mach_timespec_t cur_time;
402
403 if (KERN_SUCCESS == clock_get_time (mono_clock_service,
404 &cur_time))
405 return cur_time.tv_sec - mono_clock_start;
406 }
407#endif /* HAVE_CLOCK_GET_TIME */
408#if defined(_WIN32)
409#if _WIN32_WINNT >= 0x0600
410 if (1)
411 return (time_t) (((uint64_t) (GetTickCount64 () - tick_start)) / 1000);
412#else /* _WIN32_WINNT < 0x0600 */
413 if (0 != perf_freq)
414 {
415 LARGE_INTEGER perf_counter;
416
417 QueryPerformanceCounter (&perf_counter); /* never fail on XP and later */
418 return (time_t) (((uint64_t) perf_counter.QuadPart - perf_start)
419 / perf_freq);
420 }
421#endif /* _WIN32_WINNT < 0x0600 */
422#endif /* _WIN32 */
423#ifdef HAVE_GETHRTIME
424 if (1)
425 return (time_t) (((uint64_t) (gethrtime () - hrtime_start)) / 1000000000);
426#endif /* HAVE_GETHRTIME */
427
428 return time (NULL) - sys_clock_start;
429}
430
431
439uint64_t
441{
442#if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_TIMESPEC_GET)
443 struct timespec ts;
444#endif /* HAVE_CLOCK_GETTIME || HAVE_TIMESPEC_GET */
445
446#ifdef HAVE_CLOCK_GETTIME
447 if ( (_MHD_UNWANTED_CLOCK != mono_clock_id) &&
448 (0 == clock_gettime (mono_clock_id,
449 &ts)) )
450 return (uint64_t) (((uint64_t) (ts.tv_sec - mono_clock_start)) * 1000
451 + (ts.tv_nsec / 1000000));
452#endif /* HAVE_CLOCK_GETTIME */
453#ifdef HAVE_CLOCK_GET_TIME
454 if (_MHD_INVALID_CLOCK_SERV != mono_clock_service)
455 {
456 mach_timespec_t cur_time;
457
458 if (KERN_SUCCESS == clock_get_time (mono_clock_service,
459 &cur_time))
460 return (uint64_t) (((uint64_t) (cur_time.tv_sec - mono_clock_start))
461 * 1000 + (cur_time.tv_nsec / 1000000));
462 }
463#endif /* HAVE_CLOCK_GET_TIME */
464#if defined(_WIN32)
465#if _WIN32_WINNT >= 0x0600
466 if (1)
467 return (uint64_t) (GetTickCount64 () - tick_start);
468#else /* _WIN32_WINNT < 0x0600 */
469 if (0 != perf_freq)
470 {
471 LARGE_INTEGER perf_counter;
472 uint64_t num_ticks;
473
474 QueryPerformanceCounter (&perf_counter); /* never fail on XP and later */
475 num_ticks = (uint64_t) (perf_counter.QuadPart - perf_start);
476 return ((num_ticks / perf_freq) * 1000)
477 + ((num_ticks % perf_freq) / (perf_freq / 1000));
478 }
479#endif /* _WIN32_WINNT < 0x0600 */
480#endif /* _WIN32 */
481#ifdef HAVE_GETHRTIME
482 if (1)
483 return ((uint64_t) (gethrtime () - hrtime_start)) / 1000000;
484#endif /* HAVE_GETHRTIME */
485
486 /* Fallbacks, affected by system time change */
487#ifdef HAVE_TIMESPEC_GET
488 if (TIME_UTC == timespec_get (&ts, TIME_UTC))
489 return (uint64_t) (((uint64_t) (ts.tv_sec - gettime_start)) * 1000
490 + (ts.tv_nsec / 1000000));
491#elif defined(HAVE_GETTIMEOFDAY)
492 if (1)
493 {
494 struct timeval tv;
495 if (0 == gettimeofday (&tv, NULL))
496 return (uint64_t) (((uint64_t) (tv.tv_sec - gettime_start)) * 1000
497 + (tv.tv_usec / 1000));
498 }
499#endif /* HAVE_GETTIMEOFDAY */
500
501 /* The last resort fallback with very low resolution */
502 return (uint64_t) (time (NULL) - sys_clock_start) * 1000;
503}
static time_t sys_clock_start
void MHD_monotonic_sec_counter_finish(void)
time_t MHD_monotonic_sec_counter(void)
void MHD_monotonic_sec_counter_init(void)
_MHD_mono_clock_source
@ _MHD_CLOCK_GET_TIME
@ _MHD_CLOCK_PERFCOUNTER
@ _MHD_CLOCK_GETTIME
@ _MHD_CLOCK_GETHRTIME
@ _MHD_CLOCK_GETTICKCOUNT64
@ _MHD_CLOCK_NO_SOURCE
#define NULL
uint64_t MHD_monotonic_msec_counter(void)
internal monotonic clock functions implementations