libmicrohttpd2

HTTP server C library (MHD 2.x, alpha)
Log | Files | Refs | README | LICENSE

mhd_mono_clock.c (22470B)


      1 /* SPDX-License-Identifier: LGPL-2.1-or-later OR (GPL-2.0-or-later WITH eCos-exception-2.0) */
      2 /*
      3   This file is part of GNU libmicrohttpd.
      4   Copyright (C) 2015-2024 Karlson2k (Evgeny Grin)
      5 
      6   GNU libmicrohttpd is free software; you can redistribute it and/or
      7   modify it under the terms of the GNU Lesser General Public
      8   License as published by the Free Software Foundation; either
      9   version 2.1 of the License, or (at your option) any later version.
     10 
     11   GNU libmicrohttpd is distributed in the hope that it will be useful,
     12   but WITHOUT ANY WARRANTY; without even the implied warranty of
     13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     14   Lesser General Public License for more details.
     15 
     16   Alternatively, you can redistribute GNU libmicrohttpd and/or
     17   modify it under the terms of the GNU General Public License as
     18   published by the Free Software Foundation; either version 2 of
     19   the License, or (at your option) any later version, together
     20   with the eCos exception, as follows:
     21 
     22     As a special exception, if other files instantiate templates or
     23     use macros or inline functions from this file, or you compile this
     24     file and link it with other works to produce a work based on this
     25     file, this file does not by itself cause the resulting work to be
     26     covered by the GNU General Public License. However the source code
     27     for this file must still be made available in accordance with
     28     section (3) of the GNU General Public License v2.
     29 
     30     This exception does not invalidate any other reasons why a work
     31     based on this file might be covered by the GNU General Public
     32     License.
     33 
     34   You should have received copies of the GNU Lesser General Public
     35   License and the GNU General Public License along with this library;
     36   if not, see <https://www.gnu.org/licenses/>.
     37 */
     38 
     39 /**
     40  * @file src/mhd2/mhd_mono_clock.h
     41  * @brief  monotonic clock functions implementations
     42  * @author Karlson2k (Evgeny Grin)
     43  */
     44 
     45 #include "mhd_sys_options.h"
     46 
     47 #include "mhd_mono_clock.h"
     48 
     49 #if defined(_WIN32) && ! defined(__CYGWIN__)
     50 /* Prefer native clock source over wrappers */
     51 #  ifdef HAVE_CLOCK_GETTIME
     52 #    undef HAVE_CLOCK_GETTIME
     53 #  endif /* HAVE_CLOCK_GETTIME */
     54 #  ifdef HAVE_GETTIMEOFDAY
     55 #    undef HAVE_GETTIMEOFDAY
     56 #  endif /* HAVE_GETTIMEOFDAY */
     57 #endif /* _WIN32 && ! __CYGWIN__ */
     58 
     59 #if defined(HAVE_MACH_CONTINUOUS_APPROXIMATE_TIME) || \
     60   defined(HAVE_MACH_APPROXIMATE_TIME)
     61 /* Use mach_*_time() functions family */
     62 #  define mhd_USE_MACH_TIME     1
     63 #endif
     64 
     65 #ifdef HAVE_TIME_H
     66 #  include <time.h>
     67 #endif /* HAVE_TIME_H */
     68 #ifdef HAVE_SYS_TIME_H
     69 #  include <sys/time.h>
     70 #endif /* HAVE_SYS_TIME_H */
     71 
     72 #if defined(HAVE_CLOCK_GET_TIME) || \
     73   defined(mhd_USE_MACH_TIME)
     74 /* for host_get_clock_service(), mach_host_self(), mach_task_self() */
     75 /* also for compatibility with old headers structure */
     76 #  include <mach/mach.h>
     77 #endif
     78 
     79 #ifdef HAVE_CLOCK_GET_TIME
     80 /* for clock_get_time() */
     81 #  include <mach/clock.h>
     82 #endif /* HAVE_CLOCK_GET_TIME */
     83 
     84 #if defined(mhd_USE_MACH_TIME)
     85 #  include <mach/mach_time.h>
     86 #endif
     87 
     88 #ifdef _WIN32
     89 #  include <windows.h>
     90 #endif /* _WIN32 */
     91 
     92 #include "mhd_assert.h"
     93 #include "mhd_unreachable.h"
     94 
     95 
     96 #ifdef HAVE_CLOCK_GETTIME
     97 #  ifdef CLOCK_REALTIME
     98 #    define mhd_CLOCK_ID_UNWANTED CLOCK_REALTIME
     99 #  else  /* !CLOCK_REALTIME */
    100 #    define mhd_CLOCK_ID_UNWANTED ((clockid_t) -2)
    101 #  endif /* !CLOCK_REALTIME */
    102 
    103 static clockid_t mono_clock_id = mhd_CLOCK_ID_UNWANTED;
    104 #endif /* HAVE_CLOCK_GETTIME */
    105 
    106 /* sync clocks; reduce chance of value wrap */
    107 #if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_CLOCK_GET_TIME) || \
    108   defined(HAVE_GETHRTIME)
    109 static time_t mono_clock_start;
    110 #endif /* HAVE_CLOCK_GETTIME || HAVE_CLOCK_GET_TIME || HAVE_GETHRTIME */
    111 
    112 #ifdef HAVE_CLOCK_GET_TIME
    113 #  if ! defined(SYSTEM_CLOCK) && defined(REALTIME_CLOCK)
    114 #    define SYSTEM_CLOCK REALTIME_CLOCK
    115 #  endif
    116 #  define mhd_CLOCK_SERV_INVALID ((clock_serv_t) -2)
    117 
    118 static clock_serv_t mono_clock_service = mhd_CLOCK_SERV_INVALID;
    119 #endif /* HAVE_CLOCK_GET_TIME */
    120 
    121 #if defined(mhd_USE_MACH_TIME)
    122 
    123 /* The numerator to calculate milliseconds */
    124 static uint_fast32_t mach_time_mls_numer = 0;
    125 /* The denominator to calculate milliseconds */
    126 static uint_fast64_t mach_time_mls_denom = 0;
    127 /* The starting value. Used to lower chance of the final value wrap. */
    128 static uint64_t mach_time_start; /* uint64_t is always available with mach */
    129 #endif
    130 
    131 #ifdef HAVE_GETHRTIME
    132 static hrtime_t hrtime_start;
    133 #endif /* HAVE_GETHRTIME */
    134 
    135 #ifdef _WIN32
    136 #  if _WIN32_WINNT >= 0x0600
    137 static uint64_t tick_start;     /* 'uint64_t' is available on W32 always */
    138 #  else  /* _WIN32_WINNT < 0x0600 */
    139 static uint64_t perf_freq;      /* 'uint64_t' is available on W32 always */
    140 static uint64_t perf_start;     /* 'uint64_t' is available on W32 always */
    141 #  endif /* _WIN32_WINNT < 0x0600 */
    142 #endif /* _WIN32 */
    143 
    144 /* Start values for fallback sources */
    145 #if defined(HAVE_TIMESPEC_GET) || defined(HAVE_GETTIMEOFDAY)
    146 /* The start value shared for timespec_get() and gettimeofday () */
    147 static time_t gettime_start;
    148 #define mhd_HAVE_GETTIME_START_VAR      1
    149 #endif /* HAVE_TIMESPEC_GET || HAVE_GETTIMEOFDAY */
    150 static time_t sys_clock_start;
    151 
    152 
    153 #ifdef HAVE_CLOCK_GET_TIME
    154 /**
    155  * Initialise Darwin-specific resources for 'clock_get_time()'
    156  * @param[out] cur_time the optional pointer to get the current time value,
    157  *                      can be NULL
    158  * @return 'true' if succeed,
    159  *         'false' if failed
    160  */
    161 static MHD_FN_PAR_OUT_ (1) MHD_FN_MUST_CHECK_RESULT_ bool
    162 mclock_init_clock_get_time (mach_timespec_t *cur_time)
    163 {
    164   mhd_assert (mhd_CLOCK_SERV_INVALID == mono_clock_service);
    165 
    166   if (KERN_SUCCESS == host_get_clock_service (mach_host_self (),
    167                                               SYSTEM_CLOCK,
    168                                               &mono_clock_service))
    169     return false;
    170 
    171   if (NULL != cur_time)
    172   {
    173     if (KERN_SUCCESS != clock_get_time (mono_clock_service,
    174                                         cur_time))
    175     {
    176       (void) mach_port_deallocate (mach_task_self (),
    177                                    mono_clock_service);
    178       mono_clock_service = mhd_CLOCK_SERV_INVALID;
    179       return false;
    180     }
    181   }
    182 
    183   return true;
    184 }
    185 
    186 
    187 /**
    188  * De-initialise Darwin-specific resources for 'clock_get_time()'
    189  */
    190 static void
    191 mclock_deinit_clock_get_time (void)
    192 {
    193   mhd_assert (mhd_CLOCK_SERV_INVALID != mono_clock_service);
    194   (void) mach_port_deallocate (mach_task_self (),
    195                                mono_clock_service);
    196   mono_clock_service = mhd_CLOCK_SERV_INVALID;
    197 }
    198 
    199 
    200 #else  /* HAVE_CLOCK_GET_TIME */
    201 /* No-op implementation */
    202 #  define mclock_init_clock_get_time(ptr) ((void) ptr, false)
    203 #  define mclock_deinit_clock_get_time() ((void) 0)
    204 #endif /* HAVE_CLOCK_GET_TIME */
    205 
    206 #if defined(mhd_USE_MACH_TIME)
    207 
    208 /**
    209  * Calculate greatest common divisor.
    210  * Based on Euclidean algorithm as it is fast enough and more compact then
    211  * binary GCD algorithm.
    212  * @param a the first value
    213  * @param b the second value
    214  * @return the greatest common divisor,
    215  *         if either of the input values is zero, the other input value
    216  *         returned
    217  */
    218 mhd_static_inline uint_fast32_t
    219 mclock_gcd (uint_fast32_t a, uint_fast32_t b)
    220 {
    221   if (0 == b)
    222     return a;
    223 
    224   while (1)
    225   {
    226     a %= b;
    227     if (0 == a)
    228       return b;
    229     b %= a;
    230     if (0 == b)
    231       break;
    232   }
    233   return a;
    234 }
    235 
    236 
    237 /**
    238  * Initialise data for mach_time functions
    239  * @return 'true' if succeed,
    240  *         'false' if failed
    241  */
    242 static bool
    243 mclock_init_mach_time (void)
    244 {
    245   struct mach_timebase_info mach_tb_info;
    246   uint_fast32_t comm_div;
    247   static const uint_fast32_t nanosec_in_milisec = 1000u * 1000u;
    248 
    249   mhd_assert ((0 != mach_time_mls_denom) || (0 == mach_time_mls_numer));
    250 
    251   if (KERN_SUCCESS != mach_timebase_info (&mach_tb_info))
    252     return false;
    253 
    254   mhd_assert (0 != mach_tb_info.numer); /* Help code analysers */
    255   mhd_assert (0 != mach_tb_info.denom); /* Help code analysers */
    256 
    257   comm_div = mclock_gcd (mach_tb_info.numer, nanosec_in_milisec);
    258   mach_time_mls_numer = mach_tb_info.numer / comm_div;
    259   mach_time_mls_denom =
    260     ((uint_fast64_t) mach_tb_info.denom) * (nanosec_in_milisec / comm_div);
    261 
    262   return true;
    263 }
    264 
    265 
    266 #else  /* ! mhd_USE_MACH_TIME */
    267 #  define mclock_init_mach_time()     (true)
    268 #endif /* ! mhd_USE_MACH_TIME */
    269 
    270 /**
    271  * Type of monotonic clock source
    272  */
    273 enum mhd_mono_clock_source
    274 {
    275   /**
    276    * No monotonic clock source.
    277    */
    278   mhd_MCLOCK_SOUCE_NO_SOURCE = 0
    279 
    280 #ifdef HAVE_CLOCK_GETTIME
    281   ,
    282   /**
    283    * clock_gettime() with specific clock.
    284    * Generic standard source.
    285    */
    286   mhd_MCLOCK_SOUCE_GETTIME
    287 #endif /* HAVE_CLOCK_GETTIME */
    288 
    289 #if defined(mhd_USE_MACH_TIME)
    290   ,
    291   /**
    292    * mach_continuous_approximate_time() or mach_approximate_time()
    293    * with coefficient.
    294    * Darwin-specific clock source.
    295    */
    296   mhd_MCLOCK_SOUCE_MACH_TIME
    297 #endif /* mhd_USE_MACH_TIME */
    298 
    299 #ifdef HAVE_CLOCK_GET_TIME
    300   ,
    301   /**
    302    * clock_get_time() with specific clock service.
    303    * Darwin-specific clock source.
    304    */
    305   mhd_MCLOCK_SOUCE_GET_TIME
    306 #endif /* HAVE_CLOCK_GET_TIME */
    307 
    308 #ifdef HAVE_GETHRTIME
    309   ,
    310   /**
    311    * gethrtime() / 1000000
    312    * HP-UX and Solaris monotonic clock source.
    313    */
    314   mhd_MCLOCK_SOUCE_GETHRTIME
    315 #endif /* HAVE_GETHRTIME */
    316 
    317 #ifdef _WIN32
    318 #if _WIN32_WINNT >= 0x0600
    319   ,
    320   /**
    321    * GetTickCount64()
    322    * W32 tick counter source.
    323    */
    324   mhd_MCLOCK_SOUCE_GETTICKCOUNT64
    325 #else  /* _WIN32_WINNT < 0x0600 */
    326 
    327   ,
    328   /**
    329    * QueryPerformanceCounter() / QueryPerformanceFrequency()
    330    * Older W32 monotonic time source.
    331    */
    332   mhd_MCLOCK_SOUCE_PERFCOUNTER
    333 #endif /* _WIN32_WINNT < 0x0600 */
    334 #endif /* _WIN32 */
    335 };
    336 
    337 /**
    338  * The active source of the monotonic time
    339  */
    340 static enum mhd_mono_clock_source mono_clock_source =
    341   mhd_MCLOCK_SOUCE_NO_SOURCE;
    342 
    343 /**
    344  * Initialise milliseconds counters.
    345  */
    346 MHD_INTERNAL void
    347 mhd_mclock_init_once (void)
    348 {
    349 #ifdef HAVE_CLOCK_GET_TIME
    350   mach_timespec_t cur_time;
    351 #endif /* HAVE_CLOCK_GET_TIME */
    352 #ifdef HAVE_CLOCK_GETTIME
    353   struct timespec ts;
    354 
    355   mono_clock_id = mhd_CLOCK_ID_UNWANTED;
    356 #endif /* HAVE_CLOCK_GETTIME */
    357 #ifdef HAVE_CLOCK_GET_TIME
    358   mono_clock_service = mhd_CLOCK_SERV_INVALID;
    359 #endif /* HAVE_CLOCK_GET_TIME */
    360 
    361   mono_clock_source = mhd_MCLOCK_SOUCE_NO_SOURCE;
    362 
    363   /* Try specialised fast sources */
    364 #ifdef _WIN32
    365 #if _WIN32_WINNT >= 0x0600
    366   /* W32 Vista or later specific monotonic clock */
    367   /* Available since Vista, ~15ms accuracy */
    368   if (1)
    369   {
    370     tick_start = GetTickCount64 ();
    371     mono_clock_source = mhd_MCLOCK_SOUCE_GETTICKCOUNT64;
    372   }
    373   else
    374 #else  /* _WIN32_WINNT < 0x0600 */
    375   /* W32 specific monotonic clock */
    376   /* Available on Windows 2000 and later */
    377   if (1)
    378   {
    379     LARGE_INTEGER freq;
    380     LARGE_INTEGER perf_counter;
    381 
    382     (void) QueryPerformanceFrequency (&freq);       /* never fail on XP and later */
    383     (void) QueryPerformanceCounter (&perf_counter); /* never fail on XP and later */
    384     perf_freq = (uint64_t) freq.QuadPart;
    385     perf_start = (uint64_t) perf_counter.QuadPart;
    386     mono_clock_source = mhd_MCLOCK_SOUCE_PERFCOUNTER;
    387   }
    388   else
    389 #endif /* _WIN32_WINNT < 0x0600 */
    390 #endif /* _WIN32 */
    391 #if defined(mhd_USE_MACH_TIME)
    392   /* Mach (Darwin) specific monotonic clock */
    393   /* mach_continuous_approximate_time() counts time in suspend,
    394      mach_approximate_time() does not count time in suspend.
    395      Both function are fast and used as a basis for universal portable functions
    396      on Darwin. */
    397   if (mclock_init_mach_time ())
    398   {
    399 #  ifdef HAVE_MACH_CONTINUOUS_APPROXIMATE_TIME
    400     mach_time_start = mach_continuous_approximate_time ();
    401 #  else  /* HAVE_MACH_APPROXIMATE_TIME */
    402     mach_time_start = mach_approximate_time ();
    403 #  endif
    404     mono_clock_source = mhd_MCLOCK_SOUCE_MACH_TIME;
    405   }
    406   else
    407 #endif /* mhd_USE_MACH_TIME */
    408 
    409   /* Try universally available sources */
    410 #ifdef HAVE_CLOCK_GETTIME
    411 #ifdef CLOCK_MONOTONIC_COARSE
    412   /* Linux-specific fast value-getting clock */
    413   /* Can be affected by frequency adjustment and doesn't count time
    414    * in suspend, but preferred since it's fast */
    415   if (0 == clock_gettime (CLOCK_MONOTONIC_COARSE,
    416                           &ts))
    417   {
    418     mono_clock_id = CLOCK_MONOTONIC_COARSE;
    419     mono_clock_start = ts.tv_sec;
    420     mono_clock_source = mhd_MCLOCK_SOUCE_GETTIME;
    421   }
    422   else
    423 #endif /* CLOCK_MONOTONIC_COARSE */
    424 #ifdef CLOCK_MONOTONIC_FAST
    425   /* FreeBSD/DragonFly fast value-getting clock */
    426   /* Can be affected by frequency adjustment, but preferred since it's fast */
    427   if (0 == clock_gettime (CLOCK_MONOTONIC_FAST,
    428                           &ts))
    429   {
    430     mono_clock_id = CLOCK_MONOTONIC_FAST;
    431     mono_clock_start = ts.tv_sec;
    432     mono_clock_source = mhd_MCLOCK_SOUCE_GETTIME;
    433   }
    434   else
    435 #endif /* CLOCK_MONOTONIC_COARSE */
    436 #ifdef CLOCK_UPTIME_FAST
    437   /* FreeBSD/DragonFly fast value-getting clock */
    438   /* Can be affected by frequency adjustment and doesn't count time
    439    * in suspend, but preferred since it's fast */
    440   if (0 == clock_gettime (CLOCK_UPTIME_FAST,
    441                           &ts))
    442   {
    443     mono_clock_id = CLOCK_MONOTONIC_FAST;
    444     mono_clock_start = ts.tv_sec;
    445     mono_clock_source = mhd_MCLOCK_SOUCE_GETTIME;
    446   }
    447   else
    448 #endif /* CLOCK_UPTIME_FAST */
    449 #ifdef CLOCK_MONOTONIC_RAW_APPROX
    450   /* Darwin-specific clock */
    451   /* Not affected by frequency adjustment, returns clock value cached at
    452    * context switch. Can be "milliseconds old", but it's fast. */
    453   if (0 == clock_gettime (CLOCK_MONOTONIC_RAW_APPROX,
    454                           &ts))
    455   {
    456     mono_clock_id = CLOCK_MONOTONIC_RAW_APPROX;
    457     mono_clock_start = ts.tv_sec;
    458     mono_clock_source = mhd_MCLOCK_SOUCE_GETTIME;
    459   }
    460   else
    461 #endif /* CLOCK_MONOTONIC_RAW */
    462 #ifdef CLOCK_UPTIME_RAW_APPROX
    463   /* Darwin-specific clock */
    464   /* Not affected by frequency adjustment, but doesn't count time in suspend.
    465    * Returns clock value cached at context switch.
    466    * Can be "milliseconds old", but it's fast. */
    467   if (0 == clock_gettime (CLOCK_UPTIME_RAW_APPROX,
    468                           &ts))
    469   {
    470     mono_clock_id = CLOCK_UPTIME_RAW_APPROX;
    471     mono_clock_start = ts.tv_sec;
    472     mono_clock_source = mhd_MCLOCK_SOUCE_GETTIME;
    473   }
    474   else
    475 #endif /* CLOCK_UPTIME_RAW_APPROX */
    476 #ifdef CLOCK_MONOTONIC_RAW
    477   /* Linux and Darwin clock */
    478   /* Not affected by frequency adjustment,
    479    * on Linux doesn't count time in suspend */
    480   if (0 == clock_gettime (CLOCK_MONOTONIC_RAW,
    481                           &ts))
    482   {
    483     mono_clock_id = CLOCK_MONOTONIC_RAW;
    484     mono_clock_start = ts.tv_sec;
    485     mono_clock_source = mhd_MCLOCK_SOUCE_GETTIME;
    486   }
    487   else
    488 #endif /* CLOCK_MONOTONIC_RAW */
    489 #ifdef CLOCK_BOOTTIME
    490   /* Counts time in suspend on Linux so it's real monotonic, */
    491   /* but can be slower value-getting than other clocks */
    492   if (0 == clock_gettime (CLOCK_BOOTTIME,
    493                           &ts))
    494   {
    495     mono_clock_id = CLOCK_BOOTTIME;
    496     mono_clock_start = ts.tv_sec;
    497     mono_clock_source = mhd_MCLOCK_SOUCE_GETTIME;
    498   }
    499   else
    500 #endif /* CLOCK_BOOTTIME */
    501 #ifdef CLOCK_MONOTONIC
    502   /* Monotonic clock */
    503   /* Widely supported, may be affected by frequency adjustment */
    504   /* On Linux it's not truly monotonic as it doesn't count time in suspend */
    505   if (0 == clock_gettime (CLOCK_MONOTONIC,
    506                           &ts))
    507   {
    508     mono_clock_id = CLOCK_MONOTONIC;
    509     mono_clock_start = ts.tv_sec;
    510     mono_clock_source = mhd_MCLOCK_SOUCE_GETTIME;
    511   }
    512   else
    513 #endif /* CLOCK_MONOTONIC */
    514 #ifdef CLOCK_UPTIME
    515   /* non-Linux clock */
    516   /* Doesn't count time in suspend */
    517   if (0 == clock_gettime (CLOCK_UPTIME,
    518                           &ts))
    519   {
    520     mono_clock_id = CLOCK_UPTIME;
    521     mono_clock_start = ts.tv_sec;
    522     mono_clock_source = mhd_MCLOCK_SOUCE_GETTIME;
    523   }
    524   else
    525 #endif /* CLOCK_BOOTTIME */
    526 #endif /* HAVE_CLOCK_GETTIME */
    527 #ifdef HAVE_CLOCK_GET_TIME
    528   /* Darwin-specific monotonic clock source */
    529   /* Should be monotonic as clock_set_time function always unconditionally */
    530   /* failed on modern kernels */
    531   if (mclock_init_clock_get_time (&cur_time))
    532   {
    533     mono_clock_start = cur_time.tv_sec;
    534     mono_clock_source = mhd_MCLOCK_SOUCE_GET_TIME;
    535   }
    536   else
    537 #endif /* HAVE_CLOCK_GET_TIME */
    538 #ifdef HAVE_CLOCK_GETTIME
    539 #ifdef CLOCK_HIGHRES
    540   /* Solaris-specific monotonic high-resolution clock */
    541   /* Not preferred due to be potentially resource-hungry */
    542   if (0 == clock_gettime (CLOCK_HIGHRES,
    543                           &ts))
    544   {
    545     mono_clock_id = CLOCK_HIGHRES;
    546     mono_clock_start = ts.tv_sec;
    547     mono_clock_source = mhd_MCLOCK_SOUCE_GETTIME;
    548   }
    549   else
    550 #endif /* CLOCK_HIGHRES */
    551 #endif /* HAVE_CLOCK_GETTIME */
    552 #ifdef HAVE_GETHRTIME
    553   /* HP-UX and Solaris monotonic clock */
    554   /* Not preferred due to be potentially resource-hungry */
    555   if (1)
    556   {
    557     hrtime_start = gethrtime ();
    558     mono_clock_source = mhd_MCLOCK_SOUCE_GETHRTIME;
    559   }
    560   else
    561 #endif /* HAVE_GETHRTIME */
    562   (void) 0; /* The end of if-else chain */
    563 
    564   /* Initialise start values for fallbacks */
    565 #ifdef HAVE_TIMESPEC_GET
    566   if (1)
    567   {
    568     struct timespec tsg;
    569     if (TIME_UTC == timespec_get (&tsg, TIME_UTC))
    570       gettime_start = tsg.tv_sec;
    571     else
    572       gettime_start = 0;
    573   }
    574 #elif defined(HAVE_GETTIMEOFDAY)
    575   if (1)
    576   {
    577     struct timeval tv;
    578     if (0 == gettimeofday (&tv, NULL))
    579       gettime_start = tv.tv_sec;
    580     else
    581       gettime_start = 0;
    582   }
    583 #endif /* HAVE_GETTIMEOFDAY */
    584 
    585   sys_clock_start = time (NULL);
    586 #ifdef mhd_HAVE_GETTIME_START_VAR
    587   if (((time_t) -1) == sys_clock_start)
    588     sys_clock_start = gettime_start;
    589 #endif /* mhd_HAVE_GETTIME_START_VAR */
    590 }
    591 
    592 
    593 #ifdef HAVE_CLOCK_GET_TIME
    594 /* Resources may be allocated only for Darwin clock_get_time() */
    595 
    596 MHD_INTERNAL void
    597 mhd_mclock_deinit (void)
    598 {
    599   if (mhd_MCLOCK_SOUCE_GET_TIME == mono_clock_source)
    600     mclock_deinit_clock_get_time ();
    601 }
    602 
    603 
    604 MHD_INTERNAL void
    605 mhd_mclock_re_init (void)
    606 {
    607   if (mhd_MCLOCK_SOUCE_GET_TIME == mono_clock_source)
    608   {
    609     if (! mclock_init_clock_get_time (NULL))
    610       /* Fallback to full initialisation */
    611       mhd_mclock_init_once ();
    612   }
    613 }
    614 
    615 
    616 #endif /* HAVE_CLOCK_GET_TIME */
    617 
    618 /**
    619  * Monotonic milliseconds counter, useful for timeout calculation.
    620  * Tries to be not affected by manually setting the system real time
    621  * clock or adjustments by NTP synchronization.
    622  *
    623  * @return number of microseconds from some fixed moment
    624  */
    625 MHD_INTERNAL uint_fast64_t
    626 mhd_monotonic_msec_counter (void)
    627 {
    628   enum mhd_mono_clock_source source_to_use;
    629 
    630   /* Optimise binary if the source is fixed */
    631 #if defined(_WIN32) && _WIN32_WINNT >= 0x0600
    632   if (1)
    633     source_to_use = mhd_MCLOCK_SOUCE_GETTICKCOUNT64;
    634   else
    635 #endif /* _WIN32 && _WIN32_WINNT >= 0x0600 */
    636   source_to_use = mono_clock_source;
    637 
    638   mhd_assert (mono_clock_source == source_to_use);
    639 
    640   switch (source_to_use)
    641   {
    642   case mhd_MCLOCK_SOUCE_NO_SOURCE:
    643     break; /* Use fallbacks */
    644 #ifdef HAVE_CLOCK_GETTIME
    645   case mhd_MCLOCK_SOUCE_GETTIME:
    646     mhd_assert (mhd_CLOCK_ID_UNWANTED != mono_clock_id);
    647     if (1)
    648     {
    649       struct timespec ts;
    650       if (0 == clock_gettime (mono_clock_id,
    651                               &ts))
    652         return (uint_fast64_t)
    653                (((uint_fast64_t) (ts.tv_sec - mono_clock_start)) * 1000
    654                 + (uint_fast64_t) (ts.tv_nsec / 1000000));
    655     }
    656     break;
    657 #endif /* HAVE_CLOCK_GETTIME */
    658 
    659 #if defined(mhd_USE_MACH_TIME)
    660   case mhd_MCLOCK_SOUCE_MACH_TIME:
    661     mhd_assert (0 != mach_time_mls_numer);
    662     mhd_assert (0 != mach_time_mls_denom);
    663     if (1)
    664     {
    665       uint64_t t;
    666 #  ifdef HAVE_MACH_CONTINUOUS_APPROXIMATE_TIME
    667       t = mach_continuous_approximate_time () - mach_time_start;
    668 #  else  /* HAVE_MACH_APPROXIMATE_TIME */
    669       t = mach_approximate_time () - mach_time_start;
    670 #  endif
    671 #  ifndef MHD_FAVOR_SMALL_CODE
    672       if (1 == mach_time_mls_numer) /* Shortcut for the most common situation */
    673         return (uint_fast64_t) t / mach_time_mls_denom;
    674 #  endif /* MHD_FAVOR_SMALL_CODE */
    675 
    676       /* Avoid float point arithmetic as it lower precision on higher values.
    677          Two stages calculations to avoid overflow of integer values and keep
    678          precision high enough. */
    679       return (((uint_fast64_t) t) / mach_time_mls_denom) * mach_time_mls_numer
    680              + ((((uint_fast64_t) t) % mach_time_mls_denom)
    681                 * mach_time_mls_numer) / mach_time_mls_denom;
    682     }
    683     break;
    684 #endif /* mhd_USE_MACH_TIME */
    685 
    686 #ifdef HAVE_CLOCK_GET_TIME
    687   case mhd_MCLOCK_SOUCE_GET_TIME:
    688     mhd_assert (mhd_CLOCK_SERV_INVALID != mono_clock_service);
    689     if (1)
    690     {
    691       mach_timespec_t cur_time;
    692 
    693       if (KERN_SUCCESS == clock_get_time (mono_clock_service,
    694                                           &cur_time))
    695         return (uint_fast64_t)
    696                (((uint_fast64_t) (cur_time.tv_sec - mono_clock_start)) * 1000
    697                 + (uint_fast64_t) (cur_time.tv_nsec / 1000000));
    698     }
    699     break;
    700 #endif /* HAVE_CLOCK_GET_TIME */
    701 
    702 #ifdef HAVE_GETHRTIME
    703   case mhd_MCLOCK_SOUCE_GETHRTIME:
    704     return ((uint_fast64_t) (gethrtime () - hrtime_start)) / 1000000;
    705 #endif /* HAVE_GETHRTIME */
    706 
    707 #ifdef _WIN32
    708 #if _WIN32_WINNT >= 0x0600
    709   case mhd_MCLOCK_SOUCE_GETTICKCOUNT64:
    710     return (uint_fast64_t) (GetTickCount64 () - tick_start);
    711 #else  /* _WIN32_WINNT < 0x0600 */
    712   case mhd_MCLOCK_SOUCE_PERFCOUNTER:
    713     mhd_assert (0 != perf_freq);
    714     if (1)
    715     {
    716       LARGE_INTEGER perf_counter;
    717       uint_fast64_t num_ticks;
    718 
    719       (void) QueryPerformanceCounter (&perf_counter);   /* never fail on XP and later */
    720       num_ticks = (uint_fast64_t) (perf_counter.QuadPart - perf_start);
    721       return ((num_ticks / perf_freq) * 1000)
    722              + (((num_ticks % perf_freq) * 1000) / perf_freq);
    723     }
    724     break;
    725 #endif /* _WIN32_WINNT < 0x0600 */
    726 #endif /* _WIN32 */
    727   default:
    728     mhd_UNREACHABLE ();
    729     break;
    730   }
    731 
    732   /* Fallbacks, affected by system time change */
    733 #ifdef HAVE_TIMESPEC_GET
    734   if (1)
    735   {
    736     struct timespec ts;
    737     if (TIME_UTC == timespec_get (&ts, TIME_UTC))
    738       return (uint_fast64_t)
    739              (((uint_fast64_t) (ts.tv_sec - gettime_start)) * 1000
    740               + (uint_fast64_t) (ts.tv_nsec / 1000000));
    741   }
    742 #elif defined(HAVE_GETTIMEOFDAY)
    743   if (1)
    744   {
    745     struct timeval tv;
    746     if (0 == gettimeofday (&tv, NULL))
    747       return (uint_fast64_t)
    748              (((uint_fast64_t) (tv.tv_sec - gettime_start)) * 1000
    749               + (uint_fast64_t) (tv.tv_usec / 1000));
    750   }
    751 #endif /* HAVE_GETTIMEOFDAY */
    752 
    753   /* The last resort fallback with very low resolution */
    754 #ifdef mhd_HAVE_GETTIME_START_VAR
    755   if (1)
    756   {
    757     time_t time_now;
    758     time_now = time (NULL);
    759     if (((time_t) -1) != time_now)
    760       return ((uint_fast64_t) (time_now - sys_clock_start)) * 1000;
    761   }
    762   return 0; /* No time source, should not really happen */
    763 #else  /* ! mhd_HAVE_GETTIME_START_VAR */
    764   return ((uint_fast64_t) (time (NULL) - sys_clock_start)) * 1000;
    765 #endif
    766 }