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