GNU libmicrohttpd  0.9.68
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__) && defined(HAVE_CLOCK_GETTIME)
29 /* Prefer native clock source over wrappers */
30 #undef HAVE_CLOCK_GETTIME
31 #endif /* _WIN32 && ! __CYGWIN__ && HAVE_CLOCK_GETTIME */
32 
33 #ifdef HAVE_CLOCK_GETTIME
34 #include <time.h>
35 #endif /* HAVE_CLOCK_GETTIME */
36 
37 #ifdef HAVE_GETHRTIME
38 #ifdef HAVE_SYS_TIME_H
39 /* Solaris defines gethrtime() in sys/time.h */
40 #include <sys/time.h>
41 #endif /* HAVE_SYS_TIME_H */
42 #ifdef HAVE_TIME_H
43 /* HP-UX defines gethrtime() in time.h */
44 #include <time.h>
45 #endif /* HAVE_TIME_H */
46 #endif /* HAVE_GETHRTIME */
47 
48 #ifdef HAVE_CLOCK_GET_TIME
49 #include <mach/mach.h>
50 /* for host_get_clock_service(), mach_host_self(), mach_task_self() */
51 #include <mach/clock.h>
52 /* for clock_get_time() */
53 
54 #define _MHD_INVALID_CLOCK_SERV ((clock_serv_t) -2)
55 
56 static clock_serv_t mono_clock_service = _MHD_INVALID_CLOCK_SERV;
57 #endif /* HAVE_CLOCK_GET_TIME */
58 
59 #ifdef _WIN32
60 #ifndef WIN32_LEAN_AND_MEAN
61 /* Do not include unneeded parts of W32 headers. */
62 #define WIN32_LEAN_AND_MEAN 1
63 #endif /* !WIN32_LEAN_AND_MEAN */
64 #include <windows.h>
65 #include <stdint.h>
66 #endif /* _WIN32 */
67 
68 #ifdef HAVE_CLOCK_GETTIME
69 #ifdef CLOCK_REALTIME
70 #define _MHD_UNWANTED_CLOCK CLOCK_REALTIME
71 #else /* !CLOCK_REALTIME */
72 #define _MHD_UNWANTED_CLOCK ((clockid_t) -2)
73 #endif /* !CLOCK_REALTIME */
74 
75 static clockid_t mono_clock_id = _MHD_UNWANTED_CLOCK;
76 #endif /* HAVE_CLOCK_GETTIME */
77 
78 /* sync clocks; reduce chance of value wrap */
79 #if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_CLOCK_GET_TIME) || \
80  defined(HAVE_GETHRTIME)
81 static time_t mono_clock_start;
82 #endif /* HAVE_CLOCK_GETTIME || HAVE_CLOCK_GET_TIME || HAVE_GETHRTIME */
83 static time_t sys_clock_start;
84 #ifdef HAVE_GETHRTIME
85 static hrtime_t hrtime_start;
86 #endif /* HAVE_GETHRTIME */
87 #ifdef _WIN32
88 #if _WIN32_WINNT >= 0x0600
89 static uint64_t tick_start;
90 #else /* _WIN32_WINNT < 0x0600 */
91 static int64_t perf_freq;
92 static int64_t perf_start;
93 #endif /* _WIN32_WINNT < 0x0600 */
94 #endif /* _WIN32 */
95 
96 
97 
102 {
107 
112 
117 
122 
127 
132 };
133 
134 
138 void
140 {
141 #ifdef HAVE_CLOCK_GET_TIME
142  mach_timespec_t cur_time;
143 #endif /* HAVE_CLOCK_GET_TIME */
144  enum _MHD_mono_clock_source mono_clock_source = _MHD_CLOCK_NO_SOURCE;
145 #ifdef HAVE_CLOCK_GETTIME
146  struct timespec ts;
147 
148  mono_clock_id = _MHD_UNWANTED_CLOCK;
149 #endif /* HAVE_CLOCK_GETTIME */
150 #ifdef HAVE_CLOCK_GET_TIME
151  mono_clock_service = _MHD_INVALID_CLOCK_SERV;
152 #endif /* HAVE_CLOCK_GET_TIME */
153 
154  /* just a little syntactic trick to get the
155  various following ifdef's to work out nicely */
156  if (0)
157  {
158  }
159  else
160 #ifdef HAVE_CLOCK_GETTIME
161 #ifdef CLOCK_MONOTONIC_COARSE
162  /* Linux-specific fast value-getting clock */
163  /* Can be affected by frequency adjustment and don't count time in suspend, */
164  /* but preferred since it's fast */
165  if (0 == clock_gettime (CLOCK_MONOTONIC_COARSE,
166  &ts))
167  {
168  mono_clock_id = CLOCK_MONOTONIC_COARSE;
169  mono_clock_start = ts.tv_sec;
170  mono_clock_source = _MHD_CLOCK_GETTIME;
171  }
172  else
173 #endif /* CLOCK_MONOTONIC_COARSE */
174 #ifdef CLOCK_MONOTONIC_FAST
175  /* FreeBSD/DragonFly fast value-getting clock */
176  /* Can be affected by frequency adjustment, but preferred since it's fast */
177  if (0 == clock_gettime (CLOCK_MONOTONIC_FAST,
178  &ts))
179  {
180  mono_clock_id = CLOCK_MONOTONIC_FAST;
181  mono_clock_start = ts.tv_sec;
182  mono_clock_source = _MHD_CLOCK_GETTIME;
183  }
184  else
185 #endif /* CLOCK_MONOTONIC_COARSE */
186 #ifdef CLOCK_MONOTONIC_RAW
187  /* Linux-specific clock */
188  /* Not affected by frequency adjustment, but don't count time in suspend */
189  if (0 == clock_gettime (CLOCK_MONOTONIC_RAW,
190  &ts))
191  {
192  mono_clock_id = CLOCK_MONOTONIC_RAW;
193  mono_clock_start = ts.tv_sec;
194  mono_clock_source = _MHD_CLOCK_GETTIME;
195  }
196  else
197 #endif /* CLOCK_MONOTONIC_RAW */
198 #ifdef CLOCK_BOOTTIME
199  /* Linux-specific clock */
200  /* Count time in suspend so it's real monotonic on Linux, */
201  /* but can be slower value-getting than other clocks */
202  if (0 == clock_gettime (CLOCK_BOOTTIME,
203  &ts))
204  {
205  mono_clock_id = CLOCK_BOOTTIME;
206  mono_clock_start = ts.tv_sec;
207  mono_clock_source = _MHD_CLOCK_GETTIME;
208  }
209  else
210 #endif /* CLOCK_BOOTTIME */
211 #ifdef CLOCK_MONOTONIC
212  /* Monotonic clock */
213  /* Widely supported, may be affected by frequency adjustment */
214  /* On Linux it's not truly monotonic as it doesn't count time in suspend */
215  if (0 == clock_gettime (CLOCK_MONOTONIC,
216  &ts))
217  {
218  mono_clock_id = CLOCK_MONOTONIC;
219  mono_clock_start = ts.tv_sec;
220  mono_clock_source = _MHD_CLOCK_GETTIME;
221  }
222  else
223 #endif /* CLOCK_BOOTTIME */
224 #endif /* HAVE_CLOCK_GETTIME */
225 #ifdef HAVE_CLOCK_GET_TIME
226  /* Darwin-specific monotonic clock */
227  /* Should be monotonic as clock_set_time function always unconditionally */
228  /* failed on latest kernels */
229  if ( (KERN_SUCCESS == host_get_clock_service (mach_host_self (),
230  SYSTEM_CLOCK,
231  &mono_clock_service)) &&
232  (KERN_SUCCESS == clock_get_time (mono_clock_service,
233  &cur_time)) )
234  {
235  mono_clock_start = cur_time.tv_sec;
236  mono_clock_source = _MHD_CLOCK_GET_TIME;
237  }
238  else
239 #endif /* HAVE_CLOCK_GET_TIME */
240 #ifdef _WIN32
241 #if _WIN32_WINNT >= 0x0600
242  /* W32 Vista or later specific monotonic clock */
243  /* Available since Vista, ~15ms accuracy */
244  if (1)
245  {
246  tick_start = GetTickCount64 ();
247  mono_clock_source = _MHD_CLOCK_GETTICKCOUNT64;
248  }
249  else
250 #else /* _WIN32_WINNT < 0x0600 */
251  /* W32 specific monotonic clock */
252  /* Available on Windows 2000 and later */
253  if (1)
254  {
255  LARGE_INTEGER freq;
256  LARGE_INTEGER perf_counter;
257 
258  QueryPerformanceFrequency (&freq); /* never fail on XP and later */
259  QueryPerformanceCounter (&perf_counter); /* never fail on XP and later */
260  perf_freq = freq.QuadPart;
261  perf_start = perf_counter.QuadPart;
262  mono_clock_source = _MHD_CLOCK_PERFCOUNTER;
263  }
264  else
265 #endif /* _WIN32_WINNT < 0x0600 */
266 #endif /* _WIN32 */
267 #ifdef HAVE_CLOCK_GETTIME
268 #ifdef CLOCK_HIGHRES
269  /* Solaris-specific monotonic high-resolution clock */
270  /* Not preferred due to be potentially resource-hungry */
271  if (0 == clock_gettime (CLOCK_HIGHRES,
272  &ts))
273  {
274  mono_clock_id = CLOCK_HIGHRES;
275  mono_clock_start = ts.tv_sec;
276  mono_clock_source = _MHD_CLOCK_GETTIME;
277  }
278  else
279 #endif /* CLOCK_HIGHRES */
280 #endif /* HAVE_CLOCK_GETTIME */
281 #ifdef HAVE_GETHRTIME
282  /* HP-UX and Solaris monotonic clock */
283  /* Not preferred due to be potentially resource-hungry */
284  if (1)
285  {
286  hrtime_start = gethrtime ();
287  mono_clock_source = _MHD_CLOCK_GETHRTIME;
288  }
289  else
290 #endif /* HAVE_GETHRTIME */
291  {
292  /* no suitable clock source was found */
293  mono_clock_source = _MHD_CLOCK_NO_SOURCE;
294  }
295 
296 #ifdef HAVE_CLOCK_GET_TIME
297  if ( (_MHD_CLOCK_GET_TIME != mono_clock_source) &&
298  (_MHD_INVALID_CLOCK_SERV != mono_clock_service) )
299  {
300  /* clock service was initialised but clock_get_time failed */
301  mach_port_deallocate (mach_task_self (),
302  mono_clock_service);
303  mono_clock_service = _MHD_INVALID_CLOCK_SERV;
304  }
305 #else
306  (void) mono_clock_source; /* avoid compiler warning */
307 #endif /* HAVE_CLOCK_GET_TIME */
308 
309  sys_clock_start = time (NULL);
310 }
311 
312 
316 void
318 {
319 #ifdef HAVE_CLOCK_GET_TIME
320  if (_MHD_INVALID_CLOCK_SERV != mono_clock_service)
321  {
322  mach_port_deallocate (mach_task_self (),
323  mono_clock_service);
324  mono_clock_service = _MHD_INVALID_CLOCK_SERV;
325  }
326 #endif /* HAVE_CLOCK_GET_TIME */
327 }
328 
329 
337 time_t
339 {
340 #ifdef HAVE_CLOCK_GETTIME
341  struct timespec ts;
342 
343  if ( (_MHD_UNWANTED_CLOCK != mono_clock_id) &&
344  (0 == clock_gettime (mono_clock_id,
345  &ts)) )
346  return ts.tv_sec - mono_clock_start;
347 #endif /* HAVE_CLOCK_GETTIME */
348 #ifdef HAVE_CLOCK_GET_TIME
349  if (_MHD_INVALID_CLOCK_SERV != mono_clock_service)
350  {
351  mach_timespec_t cur_time;
352 
353  if (KERN_SUCCESS == clock_get_time (mono_clock_service,
354  &cur_time))
355  return cur_time.tv_sec - mono_clock_start;
356  }
357 #endif /* HAVE_CLOCK_GET_TIME */
358 #if defined(_WIN32)
359 #if _WIN32_WINNT >= 0x0600
360  if (1)
361  return (time_t) (((uint64_t) (GetTickCount64 () - tick_start)) / 1000);
362 #else /* _WIN32_WINNT < 0x0600 */
363  if (0 != perf_freq)
364  {
365  LARGE_INTEGER perf_counter;
366 
367  QueryPerformanceCounter (&perf_counter); /* never fail on XP and later */
368  return (time_t) (((uint64_t) (perf_counter.QuadPart - perf_start))
369  / perf_freq);
370  }
371 #endif /* _WIN32_WINNT < 0x0600 */
372 #endif /* _WIN32 */
373 #ifdef HAVE_GETHRTIME
374  if (1)
375  return (time_t) (((uint64_t) (gethrtime () - hrtime_start)) / 1000000000);
376 #endif /* HAVE_GETHRTIME */
377 
378  return time (NULL) - sys_clock_start;
379 }
time_t MHD_monotonic_sec_counter(void)
#define NULL
Definition: reason_phrase.c:30
static time_t sys_clock_start
_MHD_mono_clock_source
void MHD_monotonic_sec_counter_finish(void)
void MHD_monotonic_sec_counter_init(void)