1/*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@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 27struct 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 51struct 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 92struct 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 120struct 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 137struct 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 */ 164timediff_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 */ 178timediff_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