GNU libmicrohttpd  0.9.75
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 
53 static 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 
76 static 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)
82 static 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 () */
86 static time_t gettime_start;
87 #endif /* HAVE_TIMESPEC_GET || HAVE_GETTIMEOFDAY */
88 static time_t sys_clock_start;
89 #ifdef HAVE_GETHRTIME
90 static hrtime_t hrtime_start;
91 #endif /* HAVE_GETHRTIME */
92 #ifdef _WIN32
93 #if _WIN32_WINNT >= 0x0600
94 static uint64_t tick_start;
95 #else /* _WIN32_WINNT < 0x0600 */
96 static uint64_t perf_freq;
97 static uint64_t perf_start;
98 #endif /* _WIN32_WINNT < 0x0600 */
99 #endif /* _WIN32 */
100 
101 
106 {
111 
116 
121 
126 
131 
136 };
137 
138 
142 void
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 
366 void
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 
387 time_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 
439 uint64_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 }
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
static time_t sys_clock_start
uint64_t MHD_monotonic_msec_counter(void)
internal monotonic clock functions implementations