GNU libmicrohttpd  0.9.59
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) || defined(HAVE_GETHRTIME)
80 static time_t mono_clock_start;
81 #endif /* HAVE_CLOCK_GETTIME || HAVE_CLOCK_GET_TIME || HAVE_GETHRTIME */
82 static time_t sys_clock_start;
83 #ifdef HAVE_GETHRTIME
84 static hrtime_t hrtime_start;
85 #endif /* HAVE_GETHRTIME */
86 #ifdef _WIN32
87 #if _WIN32_WINNT >= 0x0600
88 static uint64_t tick_start;
89 #else /* _WIN32_WINNT < 0x0600 */
90 static int64_t perf_freq;
91 static int64_t perf_start;
92 #endif /* _WIN32_WINNT < 0x0600 */
93 #endif /* _WIN32 */
94 
95 
96 
101 {
106 
111 
116 
121 
126 
131 };
132 
133 
137 void
139 {
140 #ifdef HAVE_CLOCK_GET_TIME
141  mach_timespec_t cur_time;
142 #endif /* HAVE_CLOCK_GET_TIME */
143  enum _MHD_mono_clock_source mono_clock_source = _MHD_CLOCK_NO_SOURCE;
144 #ifdef HAVE_CLOCK_GETTIME
145  struct timespec ts;
146 
147  mono_clock_id = _MHD_UNWANTED_CLOCK;
148 #endif /* HAVE_CLOCK_GETTIME */
149 #ifdef HAVE_CLOCK_GET_TIME
150  mono_clock_service = _MHD_INVALID_CLOCK_SERV;
151 #endif /* HAVE_CLOCK_GET_TIME */
152 
153  /* just a little syntactic trick to get the
154  various following ifdef's to work out nicely */
155  if (0)
156  {
157  }
158  else
159 #ifdef HAVE_CLOCK_GETTIME
160 #ifdef CLOCK_MONOTONIC_COARSE
161  /* Linux-specific fast value-getting clock */
162  /* Can be affected by frequency adjustment and don't count time in suspend, */
163  /* but preferred since it's fast */
164  if (0 == clock_gettime (CLOCK_MONOTONIC_COARSE,
165  &ts))
166  {
167  mono_clock_id = CLOCK_MONOTONIC_COARSE;
168  mono_clock_start = ts.tv_sec;
169  mono_clock_source = _MHD_CLOCK_GETTIME;
170  }
171  else
172 #endif /* CLOCK_MONOTONIC_COARSE */
173 #ifdef CLOCK_MONOTONIC_FAST
174  /* FreeBSD/DragonFly fast value-getting clock */
175  /* Can be affected by frequency adjustment, but preferred since it's fast */
176  if (0 == clock_gettime (CLOCK_MONOTONIC_FAST,
177  &ts))
178  {
179  mono_clock_id = CLOCK_MONOTONIC_FAST;
180  mono_clock_start = ts.tv_sec;
181  mono_clock_source = _MHD_CLOCK_GETTIME;
182  }
183  else
184 #endif /* CLOCK_MONOTONIC_COARSE */
185 #ifdef CLOCK_MONOTONIC_RAW
186  /* Linux-specific clock */
187  /* Not affected by frequency adjustment, but don't count time in suspend */
188  if (0 == clock_gettime (CLOCK_MONOTONIC_RAW,
189  &ts))
190  {
191  mono_clock_id = CLOCK_MONOTONIC_RAW;
192  mono_clock_start = ts.tv_sec;
193  mono_clock_source = _MHD_CLOCK_GETTIME;
194  }
195  else
196 #endif /* CLOCK_MONOTONIC_RAW */
197 #ifdef CLOCK_BOOTTIME
198  /* Linux-specific clock */
199  /* Count time in suspend so it's real monotonic on Linux, */
200  /* but can be slower value-getting than other clocks */
201  if (0 == clock_gettime (CLOCK_BOOTTIME,
202  &ts))
203  {
204  mono_clock_id = CLOCK_BOOTTIME;
205  mono_clock_start = ts.tv_sec;
206  mono_clock_source = _MHD_CLOCK_GETTIME;
207  }
208  else
209 #endif /* CLOCK_BOOTTIME */
210 #ifdef CLOCK_MONOTONIC
211  /* Monotonic clock */
212  /* Widely supported, may be affected by frequency adjustment */
213  /* On Linux it's not truly monotonic as it doesn't count time in suspend */
214  if (0 == clock_gettime (CLOCK_MONOTONIC,
215  &ts))
216  {
217  mono_clock_id = CLOCK_MONOTONIC;
218  mono_clock_start = ts.tv_sec;
219  mono_clock_source = _MHD_CLOCK_GETTIME;
220  }
221  else
222 #endif /* CLOCK_BOOTTIME */
223 #endif /* HAVE_CLOCK_GETTIME */
224 #ifdef HAVE_CLOCK_GET_TIME
225  /* Darwin-specific monotonic clock */
226  /* Should be monotonic as clock_set_time function always unconditionally */
227  /* failed on latest kernels */
228  if ( (KERN_SUCCESS == host_get_clock_service (mach_host_self(),
229  SYSTEM_CLOCK,
230  &mono_clock_service)) &&
231  (KERN_SUCCESS == clock_get_time (mono_clock_service,
232  &cur_time)) )
233  {
234  mono_clock_start = cur_time.tv_sec;
235  mono_clock_source = _MHD_CLOCK_GET_TIME;
236  }
237  else
238 #endif /* HAVE_CLOCK_GET_TIME */
239 #ifdef _WIN32
240 #if _WIN32_WINNT >= 0x0600
241  /* W32 Vista or later specific monotonic clock */
242  /* Available since Vista, ~15ms accuracy */
243  if (1)
244  {
245  tick_start = GetTickCount64 ();
246  mono_clock_source = _MHD_CLOCK_GETTICKCOUNT64;
247  }
248  else
249 #else /* _WIN32_WINNT < 0x0600 */
250  /* W32 specific monotonic clock */
251  /* Available on Windows 2000 and later */
252  if (1)
253  {
254  LARGE_INTEGER freq;
255  LARGE_INTEGER perf_counter;
256 
257  QueryPerformanceFrequency (&freq); /* never fail on XP and later */
258  QueryPerformanceCounter (&perf_counter); /* never fail on XP and later */
259  perf_freq = freq.QuadPart;
260  perf_start = perf_counter.QuadPart;
261  mono_clock_source = _MHD_CLOCK_PERFCOUNTER;
262  }
263  else
264 #endif /* _WIN32_WINNT < 0x0600 */
265 #endif /* _WIN32 */
266 #ifdef HAVE_CLOCK_GETTIME
267 #ifdef CLOCK_HIGHRES
268  /* Solaris-specific monotonic high-resolution clock */
269  /* Not preferred due to be potentially resource-hungry */
270  if (0 == clock_gettime (CLOCK_HIGHRES,
271  &ts))
272  {
273  mono_clock_id = CLOCK_HIGHRES;
274  mono_clock_start = ts.tv_sec;
275  mono_clock_source = _MHD_CLOCK_GETTIME;
276  }
277  else
278 #endif /* CLOCK_HIGHRES */
279 #endif /* HAVE_CLOCK_GETTIME */
280 #ifdef HAVE_GETHRTIME
281  /* HP-UX and Solaris monotonic clock */
282  /* Not preferred due to be potentially resource-hungry */
283  if (1)
284  {
285  hrtime_start = gethrtime ();
286  mono_clock_source = _MHD_CLOCK_GETHRTIME;
287  }
288  else
289 #endif /* HAVE_GETHRTIME */
290  {
291  /* no suitable clock source was found */
292  mono_clock_source = _MHD_CLOCK_NO_SOURCE;
293  }
294 
295 #ifdef HAVE_CLOCK_GET_TIME
296  if ( (_MHD_CLOCK_GET_TIME != mono_clock_source) &&
297  (_MHD_INVALID_CLOCK_SERV != mono_clock_service) )
298  {
299  /* clock service was initialised but clock_get_time failed */
300  mach_port_deallocate (mach_task_self(),
301  mono_clock_service);
302  mono_clock_service = _MHD_INVALID_CLOCK_SERV;
303  }
304 #else
305  (void) mono_clock_source; /* avoid compiler warning */
306 #endif /* HAVE_CLOCK_GET_TIME */
307 
308  sys_clock_start = time (NULL);
309 }
310 
311 
315 void
317 {
318 #ifdef HAVE_CLOCK_GET_TIME
319  if (_MHD_INVALID_CLOCK_SERV != mono_clock_service)
320  {
321  mach_port_deallocate (mach_task_self(),
322  mono_clock_service);
323  mono_clock_service = _MHD_INVALID_CLOCK_SERV;
324  }
325 #endif /* HAVE_CLOCK_GET_TIME */
326 }
327 
328 
336 time_t
338 {
339 #ifdef HAVE_CLOCK_GETTIME
340  struct timespec ts;
341 
342  if ( (_MHD_UNWANTED_CLOCK != mono_clock_id) &&
343  (0 == clock_gettime (mono_clock_id ,
344  &ts)) )
345  return ts.tv_sec - mono_clock_start;
346 #endif /* HAVE_CLOCK_GETTIME */
347 #ifdef HAVE_CLOCK_GET_TIME
348  if (_MHD_INVALID_CLOCK_SERV != mono_clock_service)
349  {
350  mach_timespec_t cur_time;
351 
352  if (KERN_SUCCESS == clock_get_time(mono_clock_service,
353  &cur_time))
354  return cur_time.tv_sec - mono_clock_start;
355  }
356 #endif /* HAVE_CLOCK_GET_TIME */
357 #if defined(_WIN32)
358 #if _WIN32_WINNT >= 0x0600
359  if (1)
360  return (time_t)(((uint64_t)(GetTickCount64() - tick_start)) / 1000);
361 #else /* _WIN32_WINNT < 0x0600 */
362  if (0 != perf_freq)
363  {
364  LARGE_INTEGER perf_counter;
365 
366  QueryPerformanceCounter (&perf_counter); /* never fail on XP and later */
367  return (time_t)(((uint64_t)(perf_counter.QuadPart - perf_start)) / perf_freq);
368  }
369 #endif /* _WIN32_WINNT < 0x0600 */
370 #endif /* _WIN32 */
371 #ifdef HAVE_GETHRTIME
372  if (1)
373  return (time_t)(((uint64_t) (gethrtime () - hrtime_start)) / 1000000000);
374 #endif /* HAVE_GETHRTIME */
375 
376  return time (NULL) - sys_clock_start;
377 }
#define NULL
Definition: reason_phrase.c:31
static time_t sys_clock_start
void MHD_monotonic_sec_counter_init(void)
internal monotonic clock functions implementations
time_t MHD_monotonic_sec_counter(void)
_MHD_mono_clock_source
void MHD_monotonic_sec_counter_finish(void)