GNU libmicrohttpd  0.9.29
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 #ifdef HAVE_CLOCK_GET_TIME
29 #include <mach/mach.h>
30 /* for host_get_clock_service(), mach_host_self(), mach_task_self() */
31 #include <mach/clock.h>
32 /* for clock_get_time() */
33 
34 #define _MHD_INVALID_CLOCK_SERV ((clock_serv_t) -2)
35 
36 static clock_serv_t mono_clock_service = _MHD_INVALID_CLOCK_SERV;
37 #endif /* HAVE_CLOCK_GET_TIME */
38 
39 #ifdef HAVE_CLOCK_GETTIME
40 #ifdef CLOCK_REALTIME
41 #define _MHD_UNWANTED_CLOCK CLOCK_REALTIME
42 #else /* !CLOCK_REALTIME */
43 #define _MHD_UNWANTED_CLOCK ((clockid_t) -2)
44 #endif /* !CLOCK_REALTIME */
45 
46 static clockid_t mono_clock_id = _MHD_UNWANTED_CLOCK;
47 #endif /* HAVE_CLOCK_GETTIME */
48 
49 /* sync clocks; reduce chance of value wrap */
50 static time_t mono_clock_start;
51 static time_t sys_clock_start;
52 #ifdef HAVE_GETHRTIME
53 static hrtime_t hrtime_start;
54 #endif /* HAVE_GETHRTIME */
55 #ifdef _WIN32
56 #if _WIN32_WINNT >= 0x0600
57 static uint64_t tick_start;
58 #else /* _WIN32_WINNT < 0x0600 */
59 static int64_t perf_freq;
60 static int64_t perf_start;
61 #endif /* _WIN32_WINNT < 0x0600 */
62 #endif /* _WIN32 */
63 
64 
65 
70 {
75 
80 
85 
90 
95 
100 };
101 
105 void
107 {
108 #ifdef HAVE_CLOCK_GET_TIME
109  mach_timespec_t cur_time;
110 #endif /* HAVE_CLOCK_GET_TIME */
111  enum _MHD_mono_clock_source mono_clock_source = _MHD_CLOCK_NO_SOURCE;
112 #ifdef HAVE_CLOCK_GETTIME
113  struct timespec ts;
114 
115  mono_clock_id = _MHD_UNWANTED_CLOCK;
116 #endif /* HAVE_CLOCK_GETTIME */
117 #ifdef HAVE_CLOCK_GET_TIME
118  mono_clock_service = _MHD_INVALID_CLOCK_SERV;
119 #endif /* HAVE_CLOCK_GET_TIME */
120 
121  if (0)
122  {
123  } else
124 #ifdef HAVE_CLOCK_GETTIME
125 #ifdef CLOCK_MONOTONIC_COARSE
126  /* Linux-specific fast value-getting clock */
127  /* Can be affected by frequency adjustment and don't count time in suspend, */
128  /* but preferred since it's fast */
129  if (0 == clock_gettime (CLOCK_MONOTONIC_COARSE, &ts))
130  {
131  mono_clock_id = CLOCK_MONOTONIC_COARSE;
132  mono_clock_start = ts.tv_sec;
133  mono_clock_source = _MHD_CLOCK_GETTIME;
134  } else
135 #endif /* CLOCK_MONOTONIC_COARSE */
136 #ifdef CLOCK_MONOTONIC_FAST
137  /* FreeBSD/DragonFly fast value-getting clock */
138  /* Can be affected by frequency adjustment, but preferred since it's fast */
139  if (0 == clock_gettime (CLOCK_MONOTONIC_FAST, &ts))
140  {
141  mono_clock_id = CLOCK_MONOTONIC_FAST;
142  mono_clock_start = ts.tv_sec;
143  mono_clock_source = _MHD_CLOCK_GETTIME;
144  } else
145 #endif /* CLOCK_MONOTONIC_COARSE */
146 #ifdef CLOCK_MONOTONIC_RAW
147  /* Linux-specific clock */
148  /* Not affected by frequency adjustment, but don't count time in suspend */
149  if (0 == clock_gettime (CLOCK_MONOTONIC_RAW , &ts))
150  {
151  mono_clock_id = CLOCK_MONOTONIC_RAW;
152  mono_clock_start = ts.tv_sec;
153  mono_clock_source = _MHD_CLOCK_GETTIME;
154  } else
155 #endif /* CLOCK_MONOTONIC_RAW */
156 #ifdef CLOCK_BOOTTIME
157  /* Linux-specific clock */
158  /* Count time in suspend so it's real monotonic on Linux, */
159  /* but can be slower value-getting than other clocks */
160  if (0 == clock_gettime(CLOCK_BOOTTIME, &ts))
161  {
162  mono_clock_id = CLOCK_BOOTTIME;
163  mono_clock_start = ts.tv_sec;
164  mono_clock_source = _MHD_CLOCK_GETTIME;
165  } else
166 #endif /* CLOCK_BOOTTIME */
167 #ifdef CLOCK_MONOTONIC
168  /* Monotonic clock */
169  /* Widely supported, may be affected by frequency adjustment */
170  /* On Linux it's not truly monotonic as it doesn't count time in suspend */
171  if (0 == clock_gettime(CLOCK_MONOTONIC, &ts))
172  {
173  mono_clock_id = CLOCK_MONOTONIC;
174  mono_clock_start = ts.tv_sec;
175  mono_clock_source = _MHD_CLOCK_GETTIME;
176  } else
177 #endif /* CLOCK_BOOTTIME */
178 #endif /* HAVE_CLOCK_GETTIME */
179 #ifdef HAVE_CLOCK_GET_TIME
180  /* Darwin-specific monotonic clock */
181  /* Should be monotonic as clock_set_time function always unconditionally */
182  /* failed on latest kernels */
183  if (KERN_SUCCESS == host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &mono_clock_service) &&
184  KERN_SUCCESS == clock_get_time(mono_clock_service, &cur_time))
185  {
186  mono_clock_start = cur_time.tv_sec;
187  mono_clock_source = _MHD_CLOCK_GET_TIME;
188  } else
189 #endif /* HAVE_CLOCK_GET_TIME */
190 #ifdef _WIN32
191 #if _WIN32_WINNT >= 0x0600
192  /* W32 Vista or later specific monotonic clock */
193  /* Available since Vista, ~15ms accuracy */
194  if (1)
195  {
196  tick_start = GetTickCount64();
197  mono_clock_source = _MHD_CLOCK_GETTICKCOUNT64;
198  } else
199 #else /* _WIN32_WINNT < 0x0600 */
200  /* W32 specific monotonic clock */
201  /* Available on Windows 2000 and later */
202  if (1)
203  {
204  LARGE_INTEGER freq, perf_counter;
205  QueryPerformanceFrequency(&freq); /* never fail on XP and later */
206  QueryPerformanceCounter(&perf_counter); /* never fail on XP and later */
207  perf_freq = freq.QuadPart;
208  perf_start = perf_counter.QuadPart;
209  mono_clock_source = _MHD_CLOCK_PERFCOUNTER;
210  } else
211 #endif /* _WIN32_WINNT < 0x0600 */
212 #endif /* _WIN32 */
213 #ifdef HAVE_CLOCK_GETTIME
214 #ifdef CLOCK_HIGHRES
215  /* Solaris-specific monotonic high-resolution clock */
216  /* Not preferred due to be potentially resource-hungry */
217  if (0 == clock_gettime (CLOCK_HIGHRES, &ts))
218  {
219  mono_clock_id = CLOCK_HIGHRES;
220  mono_clock_start = ts.tv_sec;
221  mono_clock_source = _MHD_CLOCK_GETTIME;
222  } else
223 #endif /* CLOCK_HIGHRES */
224 #endif /* HAVE_CLOCK_GETTIME */
225 #ifdef HAVE_GETHRTIME
226  /* HP-UX and Solaris monotonic clock */
227  /* Not preferred due to be potentially resource-hungry */
228  if (1)
229  {
230  hrtime_start = gethrtime();
231  mono_clock_source = _MHD_CLOCK_GETHRTIME;
232  } else
233 #endif /* HAVE_GETHRTIME */
234  {
235  /* no suitable clock source was found */
236  mono_clock_source = _MHD_CLOCK_NO_SOURCE;
237  }
238 
239 #ifdef HAVE_CLOCK_GET_TIME
240  if ( (_MHD_CLOCK_GET_TIME != mono_clock_source) &&
241  (_MHD_INVALID_CLOCK_SERV != mono_clock_service) )
242  {
243  /* clock service was initialised but clock_get_time failed */
244  mach_port_deallocate (mach_task_self(), mono_clock_service);
245  mono_clock_service = _MHD_INVALID_CLOCK_SERV;
246  }
247 #else
248  (void) mono_clock_source; /* avoid compiler warning */
249 #endif /* HAVE_CLOCK_GET_TIME */
250 
251  sys_clock_start = time (NULL);
252 }
253 
254 
258 void
260 {
261 #ifdef HAVE_CLOCK_GET_TIME
262  if (_MHD_INVALID_CLOCK_SERV != mono_clock_service)
263  {
264  mach_port_deallocate(mach_task_self(), mono_clock_service);
265  mono_clock_service = _MHD_INVALID_CLOCK_SERV;
266  }
267 #endif /* HAVE_CLOCK_GET_TIME */
268 }
269 
277 time_t
279 {
280 #ifdef HAVE_CLOCK_GETTIME
281  struct timespec ts;
282 
283  if (_MHD_UNWANTED_CLOCK != mono_clock_id &&
284  0 == clock_gettime (mono_clock_id , &ts))
285  return ts.tv_sec - mono_clock_start;
286 #endif /* HAVE_CLOCK_GETTIME */
287 #ifdef HAVE_CLOCK_GET_TIME
288  if (_MHD_INVALID_CLOCK_SERV != mono_clock_service)
289  {
290  mach_timespec_t cur_time;
291  if (KERN_SUCCESS == clock_get_time(mono_clock_service, &cur_time))
292  return cur_time.tv_sec - mono_clock_start;
293  }
294 #endif /* HAVE_CLOCK_GET_TIME */
295 #if defined(_WIN32)
296 #if _WIN32_WINNT >= 0x0600
297  if (1)
298  return (time_t)(((uint64_t)(GetTickCount64() - tick_start)) / 1000);
299 #else /* _WIN32_WINNT < 0x0600 */
300  if (0 != perf_freq)
301  {
302  LARGE_INTEGER perf_counter;
303  QueryPerformanceCounter(&perf_counter); /* never fail on XP and later */
304  return (time_t)(((uint64_t)(perf_counter.QuadPart - perf_start)) / perf_freq);
305  }
306 #endif /* _WIN32_WINNT < 0x0600 */
307 #endif /* _WIN32 */
308 #ifdef HAVE_GETHRTIME
309  if (1)
310  return (time_t)(((uint64_t)(gethrtime() - hrtime_start)) / 1000000000);
311 #endif /* HAVE_GETHRTIME */
312 
313  return time (NULL) - sys_clock_start;
314 }
#define NULL
Definition: reason_phrase.c:30
static time_t sys_clock_start
void MHD_monotonic_sec_counter_init(void)
internal monotonic clock functions implementations
static time_t mono_clock_start
time_t MHD_monotonic_sec_counter(void)
_MHD_mono_clock_source
void MHD_monotonic_sec_counter_finish(void)