1/*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) 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.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 * SPDX-License-Identifier: curl 22 * 23 ***************************************************************************/ 24 25#include "timeval.h" 26 27#if defined(_WIN32) 28 29#include <curl/curl.h> 30#include "system_win32.h" 31 32/* In case of bug fix this function has a counterpart in tool_util.c */ 33struct curltime Curl_now(void) 34{ 35 struct curltime now; 36 if(Curl_isVistaOrGreater) { /* QPC timer might have issues pre-Vista */ 37 LARGE_INTEGER count; 38 QueryPerformanceCounter(&count); 39 now.tv_sec = (time_t)(count.QuadPart / Curl_freq.QuadPart); 40 now.tv_usec = (int)((count.QuadPart % Curl_freq.QuadPart) * 1000000 / 41 Curl_freq.QuadPart); 42 } 43 else { 44 /* Disable /analyze warning that GetTickCount64 is preferred */ 45#if defined(_MSC_VER) 46#pragma warning(push) 47#pragma warning(disable:28159) 48#endif 49 DWORD milliseconds = GetTickCount(); 50#if defined(_MSC_VER) 51#pragma warning(pop) 52#endif 53 54 now.tv_sec = milliseconds / 1000; 55 now.tv_usec = (milliseconds % 1000) * 1000; 56 } 57 return now; 58} 59 60#elif defined(HAVE_CLOCK_GETTIME_MONOTONIC) || \ 61 defined(HAVE_CLOCK_GETTIME_MONOTONIC_RAW) 62 63struct curltime Curl_now(void) 64{ 65 /* 66 ** clock_gettime() is granted to be increased monotonically when the 67 ** monotonic clock is queried. Time starting point is unspecified, it 68 ** could be the system start-up time, the Epoch, or something else, 69 ** in any case the time starting point does not change once that the 70 ** system has started up. 71 */ 72#ifdef HAVE_GETTIMEOFDAY 73 struct timeval now; 74#endif 75 struct curltime cnow; 76 struct timespec tsnow; 77 78 /* 79 ** clock_gettime() may be defined by Apple's SDK as weak symbol thus 80 ** code compiles but fails during run-time if clock_gettime() is 81 ** called on unsupported OS version. 82 */ 83#if defined(__APPLE__) && defined(HAVE_BUILTIN_AVAILABLE) && \ 84 (HAVE_BUILTIN_AVAILABLE == 1) 85 bool have_clock_gettime = FALSE; 86 if(__builtin_available(macOS 10.12, iOS 10, tvOS 10, watchOS 3, *)) 87 have_clock_gettime = TRUE; 88#endif 89 90#ifdef HAVE_CLOCK_GETTIME_MONOTONIC_RAW 91 if( 92#if defined(__APPLE__) && defined(HAVE_BUILTIN_AVAILABLE) && \ 93 (HAVE_BUILTIN_AVAILABLE == 1) 94 have_clock_gettime && 95#endif 96 (0 == clock_gettime(CLOCK_MONOTONIC_RAW, &tsnow))) { 97 cnow.tv_sec = tsnow.tv_sec; 98 cnow.tv_usec = (unsigned int)(tsnow.tv_nsec / 1000); 99 } 100 else 101#endif 102 103 if( 104#if defined(__APPLE__) && defined(HAVE_BUILTIN_AVAILABLE) && \ 105 (HAVE_BUILTIN_AVAILABLE == 1) 106 have_clock_gettime && 107#endif 108 (0 == clock_gettime(CLOCK_MONOTONIC, &tsnow))) { 109 cnow.tv_sec = tsnow.tv_sec; 110 cnow.tv_usec = (unsigned int)(tsnow.tv_nsec / 1000); 111 } 112 /* 113 ** Even when the configure process has truly detected monotonic clock 114 ** availability, it might happen that it is not actually available at 115 ** run-time. When this occurs simply fallback to other time source. 116 */ 117#ifdef HAVE_GETTIMEOFDAY 118 else { 119 (void)gettimeofday(&now, NULL); 120 cnow.tv_sec = now.tv_sec; 121 cnow.tv_usec = (unsigned int)now.tv_usec; 122 } 123#else 124 else { 125 cnow.tv_sec = time(NULL); 126 cnow.tv_usec = 0; 127 } 128#endif 129 return cnow; 130} 131 132#elif defined(HAVE_MACH_ABSOLUTE_TIME) 133 134#include <stdint.h> 135#include <mach/mach_time.h> 136 137struct curltime Curl_now(void) 138{ 139 /* 140 ** Monotonic timer on Mac OS is provided by mach_absolute_time(), which 141 ** returns time in Mach "absolute time units," which are platform-dependent. 142 ** To convert to nanoseconds, one must use conversion factors specified by 143 ** mach_timebase_info(). 144 */ 145 static mach_timebase_info_data_t timebase; 146 struct curltime cnow; 147 uint64_t usecs; 148 149 if(0 == timebase.denom) 150 (void) mach_timebase_info(&timebase); 151 152 usecs = mach_absolute_time(); 153 usecs *= timebase.numer; 154 usecs /= timebase.denom; 155 usecs /= 1000; 156 157 cnow.tv_sec = usecs / 1000000; 158 cnow.tv_usec = (int)(usecs % 1000000); 159 160 return cnow; 161} 162 163#elif defined(HAVE_GETTIMEOFDAY) 164 165struct curltime Curl_now(void) 166{ 167 /* 168 ** gettimeofday() is not granted to be increased monotonically, due to 169 ** clock drifting and external source time synchronization it can jump 170 ** forward or backward in time. 171 */ 172 struct timeval now; 173 struct curltime ret; 174 (void)gettimeofday(&now, NULL); 175 ret.tv_sec = now.tv_sec; 176 ret.tv_usec = (int)now.tv_usec; 177 return ret; 178} 179 180#else 181 182struct curltime Curl_now(void) 183{ 184 /* 185 ** time() returns the value of time in seconds since the Epoch. 186 */ 187 struct curltime now; 188 now.tv_sec = time(NULL); 189 now.tv_usec = 0; 190 return now; 191} 192 193#endif 194 195/* 196 * Returns: time difference in number of milliseconds. For too large diffs it 197 * returns max value. 198 * 199 * @unittest: 1323 200 */ 201timediff_t Curl_timediff(struct curltime newer, struct curltime older) 202{ 203 timediff_t diff = (timediff_t)newer.tv_sec-older.tv_sec; 204 if(diff >= (TIMEDIFF_T_MAX/1000)) 205 return TIMEDIFF_T_MAX; 206 else if(diff <= (TIMEDIFF_T_MIN/1000)) 207 return TIMEDIFF_T_MIN; 208 return diff * 1000 + (newer.tv_usec-older.tv_usec)/1000; 209} 210 211/* 212 * Returns: time difference in number of milliseconds, rounded up. 213 * For too large diffs it returns max value. 214 */ 215timediff_t Curl_timediff_ceil(struct curltime newer, struct curltime older) 216{ 217 timediff_t diff = (timediff_t)newer.tv_sec-older.tv_sec; 218 if(diff >= (TIMEDIFF_T_MAX/1000)) 219 return TIMEDIFF_T_MAX; 220 else if(diff <= (TIMEDIFF_T_MIN/1000)) 221 return TIMEDIFF_T_MIN; 222 return diff * 1000 + (newer.tv_usec - older.tv_usec + 999)/1000; 223} 224 225/* 226 * Returns: time difference in number of microseconds. For too large diffs it 227 * returns max value. 228 */ 229timediff_t Curl_timediff_us(struct curltime newer, struct curltime older) 230{ 231 timediff_t diff = (timediff_t)newer.tv_sec-older.tv_sec; 232 if(diff >= (TIMEDIFF_T_MAX/1000000)) 233 return TIMEDIFF_T_MAX; 234 else if(diff <= (TIMEDIFF_T_MIN/1000000)) 235 return TIMEDIFF_T_MIN; 236 return diff * 1000000 + newer.tv_usec-older.tv_usec; 237} 238