GNU libmicrohttpd 1.0.0
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-2022 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
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
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)
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 () */
87#endif /* HAVE_TIMESPEC_GET || HAVE_GETTIMEOFDAY */
89#ifdef HAVE_GETHRTIME
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
137
138
142void
144{
145#ifdef HAVE_CLOCK_GET_TIME
147#endif /* HAVE_CLOCK_GET_TIME */
149#ifdef HAVE_CLOCK_GETTIME
150 struct timespec ts;
151
153#endif /* HAVE_CLOCK_GETTIME */
154#ifdef HAVE_CLOCK_GET_TIME
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 */
171 &ts))
172 {
174 mono_clock_start = ts.tv_sec;
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 */
183 &ts))
184 {
186 mono_clock_start = ts.tv_sec;
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. */
196 &ts))
197 {
199 mono_clock_start = ts.tv_sec;
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 */
209 &ts))
210 {
212 mono_clock_start = ts.tv_sec;
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 */
221 &ts))
222 {
224 mono_clock_start = ts.tv_sec;
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 */
234 &ts))
235 {
237 mono_clock_start = ts.tv_sec;
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 {
249 mono_clock_start = ts.tv_sec;
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 */
263 &cur_time)) )
264 {
265 mono_clock_start = cur_time.tv_sec;
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 {
278 }
279 else
280#else /* _WIN32_WINNT < 0x0600 */
281 /* W32 specific monotonic clock */
282 /* Available on Windows 2000 and later */
283 if (1)
284 {
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;
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 */
302 &ts))
303 {
305 mono_clock_start = ts.tv_sec;
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 {
318 }
319 else
320#endif /* HAVE_GETHRTIME */
321 {
322 /* no suitable clock source was found */
324 }
325
326#ifdef HAVE_CLOCK_GET_TIME
329 {
330 /* clock service was initialised but clock_get_time failed */
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;
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 */
359}
360
361
366void
368{
369#ifdef HAVE_CLOCK_GET_TIME
371 {
375 }
376#endif /* HAVE_CLOCK_GET_TIME */
377}
378
379
387time_t
389{
390#ifdef HAVE_CLOCK_GETTIME
391 struct timespec ts;
392
395 &ts)) )
396 return ts.tv_sec - mono_clock_start;
397#endif /* HAVE_CLOCK_GETTIME */
398#ifdef HAVE_CLOCK_GET_TIME
400 {
402
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 {
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
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
449 &ts)) )
450 return (uint64_t) (((uint64_t) (ts.tv_sec - mono_clock_start)) * 1000
451 + (uint64_t) (ts.tv_nsec / 1000000));
452#endif /* HAVE_CLOCK_GETTIME */
453#ifdef HAVE_CLOCK_GET_TIME
455 {
457
459 &cur_time))
460 return (uint64_t) (((uint64_t) (cur_time.tv_sec - mono_clock_start))
461 * 1000 + (uint64_t) (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 {
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 + (uint64_t) (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 + (uint64_t) (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}
#define MHD_HTTP_OK
Definition microhttpd.h:344
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