Home | History | Annotate | Download | only in lib
      1 /***************************************************************************
      2  *                                  _   _ ____  _
      3  *  Project                     ___| | | |  _ \| |
      4  *                             / __| | | | |_) | |
      5  *                            | (__| |_| |  _ <| |___
      6  *                             \___|\___/|_| \_\_____|
      7  *
      8  * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel (at) haxx.se>, et al.
      9  *
     10  * This software is licensed as described in the file COPYING, which
     11  * you should have received as part of this distribution. The terms
     12  * are also available at https://curl.haxx.se/docs/copyright.html.
     13  *
     14  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
     15  * copies of the Software, and permit persons to whom the Software is
     16  * furnished to do so, under the terms of the COPYING file.
     17  *
     18  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
     19  * KIND, either express or implied.
     20  *
     21  ***************************************************************************/
     22 
     23 #include "timeval.h"
     24 
     25 #if defined(WIN32) && !defined(MSDOS)
     26 
     27 struct curltime Curl_now(void)
     28 {
     29   /*
     30   ** GetTickCount() is available on _all_ Windows versions from W95 up
     31   ** to nowadays. Returns milliseconds elapsed since last system boot,
     32   ** increases monotonically and wraps once 49.7 days have elapsed.
     33   */
     34   struct curltime now;
     35 #if !defined(_WIN32_WINNT) || !defined(_WIN32_WINNT_VISTA) || \
     36     (_WIN32_WINNT < _WIN32_WINNT_VISTA)
     37   DWORD milliseconds = GetTickCount();
     38   now.tv_sec = milliseconds / 1000;
     39   now.tv_usec = (milliseconds % 1000) * 1000;
     40 #else
     41   ULONGLONG milliseconds = GetTickCount64();
     42   now.tv_sec = (time_t) (milliseconds / 1000);
     43   now.tv_usec = (unsigned int) (milliseconds % 1000) * 1000;
     44 #endif
     45 
     46   return now;
     47 }
     48 
     49 #elif defined(HAVE_CLOCK_GETTIME_MONOTONIC)
     50 
     51 struct curltime Curl_now(void)
     52 {
     53   /*
     54   ** clock_gettime() is granted to be increased monotonically when the
     55   ** monotonic clock is queried. Time starting point is unspecified, it
     56   ** could be the system start-up time, the Epoch, or something else,
     57   ** in any case the time starting point does not change once that the
     58   ** system has started up.
     59   */
     60   struct timeval now;
     61   struct curltime cnow;
     62   struct timespec tsnow;
     63   if(0 == clock_gettime(CLOCK_MONOTONIC, &tsnow)) {
     64     cnow.tv_sec = tsnow.tv_sec;
     65     cnow.tv_usec = (unsigned int)(tsnow.tv_nsec / 1000);
     66   }
     67   /*
     68   ** Even when the configure process has truly detected monotonic clock
     69   ** availability, it might happen that it is not actually available at
     70   ** run-time. When this occurs simply fallback to other time source.
     71   */
     72 #ifdef HAVE_GETTIMEOFDAY
     73   else {
     74     (void)gettimeofday(&now, NULL);
     75     cnow.tv_sec = now.tv_sec;
     76     cnow.tv_usec = (unsigned int)now.tv_usec;
     77   }
     78 #else
     79   else {
     80     cnow.tv_sec = time(NULL);
     81     cnow.tv_usec = 0;
     82   }
     83 #endif
     84   return cnow;
     85 }
     86 
     87 #elif defined(HAVE_MACH_ABSOLUTE_TIME)
     88 
     89 #include <stdint.h>
     90 #include <mach/mach_time.h>
     91 
     92 struct curltime Curl_now(void)
     93 {
     94   /*
     95   ** Monotonic timer on Mac OS is provided by mach_absolute_time(), which
     96   ** returns time in Mach "absolute time units," which are platform-dependent.
     97   ** To convert to nanoseconds, one must use conversion factors specified by
     98   ** mach_timebase_info().
     99   */
    100   static mach_timebase_info_data_t timebase;
    101   struct curltime cnow;
    102   uint64_t usecs;
    103 
    104   if(0 == timebase.denom)
    105     (void) mach_timebase_info(&timebase);
    106 
    107   usecs = mach_absolute_time();
    108   usecs *= timebase.numer;
    109   usecs /= timebase.denom;
    110   usecs /= 1000;
    111 
    112   cnow.tv_sec = usecs / 1000000;
    113   cnow.tv_usec = usecs % 1000000;
    114 
    115   return cnow;
    116 }
    117 
    118 #elif defined(HAVE_GETTIMEOFDAY)
    119 
    120 struct curltime Curl_now(void)
    121 {
    122   /*
    123   ** gettimeofday() is not granted to be increased monotonically, due to
    124   ** clock drifting and external source time synchronization it can jump
    125   ** forward or backward in time.
    126   */
    127   struct timeval now;
    128   struct curltime ret;
    129   (void)gettimeofday(&now, NULL);
    130   ret.tv_sec = now.tv_sec;
    131   ret.tv_usec = now.tv_usec;
    132   return ret;
    133 }
    134 
    135 #else
    136 
    137 struct curltime Curl_now(void)
    138 {
    139   /*
    140   ** time() returns the value of time in seconds since the Epoch.
    141   */
    142   struct curltime now;
    143   now.tv_sec = time(NULL);
    144   now.tv_usec = 0;
    145   return now;
    146 }
    147 
    148 #endif
    149 
    150 #if SIZEOF_TIME_T < 8
    151 #define TIME_MAX INT_MAX
    152 #define TIME_MIN INT_MIN
    153 #else
    154 #define TIME_MAX 9223372036854775807LL
    155 #define TIME_MIN -9223372036854775807LL
    156 #endif
    157 
    158 /*
    159  * Returns: time difference in number of milliseconds. For too large diffs it
    160  * returns max value.
    161  *
    162  * @unittest: 1323
    163  */
    164 timediff_t Curl_timediff(struct curltime newer, struct curltime older)
    165 {
    166   timediff_t diff = newer.tv_sec-older.tv_sec;
    167   if(diff >= (TIME_MAX/1000))
    168     return TIME_MAX;
    169   else if(diff <= (TIME_MIN/1000))
    170     return TIME_MIN;
    171   return diff * 1000 + (newer.tv_usec-older.tv_usec)/1000;
    172 }
    173 
    174 /*
    175  * Returns: time difference in number of microseconds. For too large diffs it
    176  * returns max value.
    177  */
    178 timediff_t Curl_timediff_us(struct curltime newer, struct curltime older)
    179 {
    180   timediff_t diff = newer.tv_sec-older.tv_sec;
    181   if(diff >= (TIME_MAX/1000000))
    182     return TIME_MAX;
    183   else if(diff <= (TIME_MIN/1000000))
    184     return TIME_MIN;
    185   return diff * 1000000 + newer.tv_usec-older.tv_usec;
    186 }
    187