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