Coverage Report

Created: 2024-02-25 06:14

/src/PROJ/curl/lib/timeval.c
Line
Count
Source (jump to first uncovered line)
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 */
33
struct 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
63
struct curltime Curl_now(void)
64
0
{
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
0
#ifdef HAVE_GETTIMEOFDAY
73
0
  struct timeval now;
74
0
#endif
75
0
  struct curltime cnow;
76
0
  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
0
#ifdef HAVE_CLOCK_GETTIME_MONOTONIC_RAW
91
0
  if(
92
#if defined(__APPLE__) && defined(HAVE_BUILTIN_AVAILABLE) &&    \
93
        (HAVE_BUILTIN_AVAILABLE == 1)
94
    have_clock_gettime &&
95
#endif
96
0
    (0 == clock_gettime(CLOCK_MONOTONIC_RAW, &tsnow))) {
97
0
    cnow.tv_sec = tsnow.tv_sec;
98
0
    cnow.tv_usec = (unsigned int)(tsnow.tv_nsec / 1000);
99
0
  }
100
0
  else
101
0
#endif
102
103
0
  if(
104
#if defined(__APPLE__) && defined(HAVE_BUILTIN_AVAILABLE) && \
105
        (HAVE_BUILTIN_AVAILABLE == 1)
106
    have_clock_gettime &&
107
#endif
108
0
    (0 == clock_gettime(CLOCK_MONOTONIC, &tsnow))) {
109
0
    cnow.tv_sec = tsnow.tv_sec;
110
0
    cnow.tv_usec = (unsigned int)(tsnow.tv_nsec / 1000);
111
0
  }
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
0
#ifdef HAVE_GETTIMEOFDAY
118
0
  else {
119
0
    (void)gettimeofday(&now, NULL);
120
0
    cnow.tv_sec = now.tv_sec;
121
0
    cnow.tv_usec = (unsigned int)now.tv_usec;
122
0
  }
123
#else
124
  else {
125
    cnow.tv_sec = time(NULL);
126
    cnow.tv_usec = 0;
127
  }
128
#endif
129
0
  return cnow;
130
0
}
131
132
#elif defined(HAVE_MACH_ABSOLUTE_TIME)
133
134
#include <stdint.h>
135
#include <mach/mach_time.h>
136
137
struct 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
165
struct 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
182
struct 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
 */
201
timediff_t Curl_timediff(struct curltime newer, struct curltime older)
202
0
{
203
0
  timediff_t diff = (timediff_t)newer.tv_sec-older.tv_sec;
204
0
  if(diff >= (TIMEDIFF_T_MAX/1000))
205
0
    return TIMEDIFF_T_MAX;
206
0
  else if(diff <= (TIMEDIFF_T_MIN/1000))
207
0
    return TIMEDIFF_T_MIN;
208
0
  return diff * 1000 + (newer.tv_usec-older.tv_usec)/1000;
209
0
}
210
211
/*
212
 * Returns: time difference in number of milliseconds, rounded up.
213
 * For too large diffs it returns max value.
214
 */
215
timediff_t Curl_timediff_ceil(struct curltime newer, struct curltime older)
216
0
{
217
0
  timediff_t diff = (timediff_t)newer.tv_sec-older.tv_sec;
218
0
  if(diff >= (TIMEDIFF_T_MAX/1000))
219
0
    return TIMEDIFF_T_MAX;
220
0
  else if(diff <= (TIMEDIFF_T_MIN/1000))
221
0
    return TIMEDIFF_T_MIN;
222
0
  return diff * 1000 + (newer.tv_usec - older.tv_usec + 999)/1000;
223
0
}
224
225
/*
226
 * Returns: time difference in number of microseconds. For too large diffs it
227
 * returns max value.
228
 */
229
timediff_t Curl_timediff_us(struct curltime newer, struct curltime older)
230
0
{
231
0
  timediff_t diff = (timediff_t)newer.tv_sec-older.tv_sec;
232
0
  if(diff >= (TIMEDIFF_T_MAX/1000000))
233
0
    return TIMEDIFF_T_MAX;
234
0
  else if(diff <= (TIMEDIFF_T_MIN/1000000))
235
0
    return TIMEDIFF_T_MIN;
236
0
  return diff * 1000000 + newer.tv_usec-older.tv_usec;
237
0
}