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