xref: /third_party/curl/lib/timeval.c (revision 13498266)
113498266Sopenharmony_ci/***************************************************************************
213498266Sopenharmony_ci *                                  _   _ ____  _
313498266Sopenharmony_ci *  Project                     ___| | | |  _ \| |
413498266Sopenharmony_ci *                             / __| | | | |_) | |
513498266Sopenharmony_ci *                            | (__| |_| |  _ <| |___
613498266Sopenharmony_ci *                             \___|\___/|_| \_\_____|
713498266Sopenharmony_ci *
813498266Sopenharmony_ci * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
913498266Sopenharmony_ci *
1013498266Sopenharmony_ci * This software is licensed as described in the file COPYING, which
1113498266Sopenharmony_ci * you should have received as part of this distribution. The terms
1213498266Sopenharmony_ci * are also available at https://curl.se/docs/copyright.html.
1313498266Sopenharmony_ci *
1413498266Sopenharmony_ci * You may opt to use, copy, modify, merge, publish, distribute and/or sell
1513498266Sopenharmony_ci * copies of the Software, and permit persons to whom the Software is
1613498266Sopenharmony_ci * furnished to do so, under the terms of the COPYING file.
1713498266Sopenharmony_ci *
1813498266Sopenharmony_ci * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
1913498266Sopenharmony_ci * KIND, either express or implied.
2013498266Sopenharmony_ci *
2113498266Sopenharmony_ci * SPDX-License-Identifier: curl
2213498266Sopenharmony_ci *
2313498266Sopenharmony_ci ***************************************************************************/
2413498266Sopenharmony_ci
2513498266Sopenharmony_ci#include "timeval.h"
2613498266Sopenharmony_ci
2713498266Sopenharmony_ci#if defined(_WIN32)
2813498266Sopenharmony_ci
2913498266Sopenharmony_ci#include <curl/curl.h>
3013498266Sopenharmony_ci#include "system_win32.h"
3113498266Sopenharmony_ci
3213498266Sopenharmony_ci/* In case of bug fix this function has a counterpart in tool_util.c */
3313498266Sopenharmony_cistruct curltime Curl_now(void)
3413498266Sopenharmony_ci{
3513498266Sopenharmony_ci  struct curltime now;
3613498266Sopenharmony_ci  if(Curl_isVistaOrGreater) { /* QPC timer might have issues pre-Vista */
3713498266Sopenharmony_ci    LARGE_INTEGER count;
3813498266Sopenharmony_ci    QueryPerformanceCounter(&count);
3913498266Sopenharmony_ci    now.tv_sec = (time_t)(count.QuadPart / Curl_freq.QuadPart);
4013498266Sopenharmony_ci    now.tv_usec = (int)((count.QuadPart % Curl_freq.QuadPart) * 1000000 /
4113498266Sopenharmony_ci                        Curl_freq.QuadPart);
4213498266Sopenharmony_ci  }
4313498266Sopenharmony_ci  else {
4413498266Sopenharmony_ci    /* Disable /analyze warning that GetTickCount64 is preferred  */
4513498266Sopenharmony_ci#if defined(_MSC_VER)
4613498266Sopenharmony_ci#pragma warning(push)
4713498266Sopenharmony_ci#pragma warning(disable:28159)
4813498266Sopenharmony_ci#endif
4913498266Sopenharmony_ci    DWORD milliseconds = GetTickCount();
5013498266Sopenharmony_ci#if defined(_MSC_VER)
5113498266Sopenharmony_ci#pragma warning(pop)
5213498266Sopenharmony_ci#endif
5313498266Sopenharmony_ci
5413498266Sopenharmony_ci    now.tv_sec = milliseconds / 1000;
5513498266Sopenharmony_ci    now.tv_usec = (milliseconds % 1000) * 1000;
5613498266Sopenharmony_ci  }
5713498266Sopenharmony_ci  return now;
5813498266Sopenharmony_ci}
5913498266Sopenharmony_ci
6013498266Sopenharmony_ci#elif defined(HAVE_CLOCK_GETTIME_MONOTONIC) ||  \
6113498266Sopenharmony_ci  defined(HAVE_CLOCK_GETTIME_MONOTONIC_RAW)
6213498266Sopenharmony_ci
6313498266Sopenharmony_cistruct curltime Curl_now(void)
6413498266Sopenharmony_ci{
6513498266Sopenharmony_ci  /*
6613498266Sopenharmony_ci  ** clock_gettime() is granted to be increased monotonically when the
6713498266Sopenharmony_ci  ** monotonic clock is queried. Time starting point is unspecified, it
6813498266Sopenharmony_ci  ** could be the system start-up time, the Epoch, or something else,
6913498266Sopenharmony_ci  ** in any case the time starting point does not change once that the
7013498266Sopenharmony_ci  ** system has started up.
7113498266Sopenharmony_ci  */
7213498266Sopenharmony_ci#ifdef HAVE_GETTIMEOFDAY
7313498266Sopenharmony_ci  struct timeval now;
7413498266Sopenharmony_ci#endif
7513498266Sopenharmony_ci  struct curltime cnow;
7613498266Sopenharmony_ci  struct timespec tsnow;
7713498266Sopenharmony_ci
7813498266Sopenharmony_ci  /*
7913498266Sopenharmony_ci  ** clock_gettime() may be defined by Apple's SDK as weak symbol thus
8013498266Sopenharmony_ci  ** code compiles but fails during run-time if clock_gettime() is
8113498266Sopenharmony_ci  ** called on unsupported OS version.
8213498266Sopenharmony_ci  */
8313498266Sopenharmony_ci#if defined(__APPLE__) && defined(HAVE_BUILTIN_AVAILABLE) && \
8413498266Sopenharmony_ci        (HAVE_BUILTIN_AVAILABLE == 1)
8513498266Sopenharmony_ci  bool have_clock_gettime = FALSE;
8613498266Sopenharmony_ci  if(__builtin_available(macOS 10.12, iOS 10, tvOS 10, watchOS 3, *))
8713498266Sopenharmony_ci    have_clock_gettime = TRUE;
8813498266Sopenharmony_ci#endif
8913498266Sopenharmony_ci
9013498266Sopenharmony_ci#ifdef HAVE_CLOCK_GETTIME_MONOTONIC_RAW
9113498266Sopenharmony_ci  if(
9213498266Sopenharmony_ci#if defined(__APPLE__) && defined(HAVE_BUILTIN_AVAILABLE) &&    \
9313498266Sopenharmony_ci        (HAVE_BUILTIN_AVAILABLE == 1)
9413498266Sopenharmony_ci    have_clock_gettime &&
9513498266Sopenharmony_ci#endif
9613498266Sopenharmony_ci    (0 == clock_gettime(CLOCK_MONOTONIC_RAW, &tsnow))) {
9713498266Sopenharmony_ci    cnow.tv_sec = tsnow.tv_sec;
9813498266Sopenharmony_ci    cnow.tv_usec = (unsigned int)(tsnow.tv_nsec / 1000);
9913498266Sopenharmony_ci  }
10013498266Sopenharmony_ci  else
10113498266Sopenharmony_ci#endif
10213498266Sopenharmony_ci
10313498266Sopenharmony_ci  if(
10413498266Sopenharmony_ci#if defined(__APPLE__) && defined(HAVE_BUILTIN_AVAILABLE) && \
10513498266Sopenharmony_ci        (HAVE_BUILTIN_AVAILABLE == 1)
10613498266Sopenharmony_ci    have_clock_gettime &&
10713498266Sopenharmony_ci#endif
10813498266Sopenharmony_ci    (0 == clock_gettime(CLOCK_MONOTONIC, &tsnow))) {
10913498266Sopenharmony_ci    cnow.tv_sec = tsnow.tv_sec;
11013498266Sopenharmony_ci    cnow.tv_usec = (unsigned int)(tsnow.tv_nsec / 1000);
11113498266Sopenharmony_ci  }
11213498266Sopenharmony_ci  /*
11313498266Sopenharmony_ci  ** Even when the configure process has truly detected monotonic clock
11413498266Sopenharmony_ci  ** availability, it might happen that it is not actually available at
11513498266Sopenharmony_ci  ** run-time. When this occurs simply fallback to other time source.
11613498266Sopenharmony_ci  */
11713498266Sopenharmony_ci#ifdef HAVE_GETTIMEOFDAY
11813498266Sopenharmony_ci  else {
11913498266Sopenharmony_ci    (void)gettimeofday(&now, NULL);
12013498266Sopenharmony_ci    cnow.tv_sec = now.tv_sec;
12113498266Sopenharmony_ci    cnow.tv_usec = (unsigned int)now.tv_usec;
12213498266Sopenharmony_ci  }
12313498266Sopenharmony_ci#else
12413498266Sopenharmony_ci  else {
12513498266Sopenharmony_ci    cnow.tv_sec = time(NULL);
12613498266Sopenharmony_ci    cnow.tv_usec = 0;
12713498266Sopenharmony_ci  }
12813498266Sopenharmony_ci#endif
12913498266Sopenharmony_ci  return cnow;
13013498266Sopenharmony_ci}
13113498266Sopenharmony_ci
13213498266Sopenharmony_ci#elif defined(HAVE_MACH_ABSOLUTE_TIME)
13313498266Sopenharmony_ci
13413498266Sopenharmony_ci#include <stdint.h>
13513498266Sopenharmony_ci#include <mach/mach_time.h>
13613498266Sopenharmony_ci
13713498266Sopenharmony_cistruct curltime Curl_now(void)
13813498266Sopenharmony_ci{
13913498266Sopenharmony_ci  /*
14013498266Sopenharmony_ci  ** Monotonic timer on Mac OS is provided by mach_absolute_time(), which
14113498266Sopenharmony_ci  ** returns time in Mach "absolute time units," which are platform-dependent.
14213498266Sopenharmony_ci  ** To convert to nanoseconds, one must use conversion factors specified by
14313498266Sopenharmony_ci  ** mach_timebase_info().
14413498266Sopenharmony_ci  */
14513498266Sopenharmony_ci  static mach_timebase_info_data_t timebase;
14613498266Sopenharmony_ci  struct curltime cnow;
14713498266Sopenharmony_ci  uint64_t usecs;
14813498266Sopenharmony_ci
14913498266Sopenharmony_ci  if(0 == timebase.denom)
15013498266Sopenharmony_ci    (void) mach_timebase_info(&timebase);
15113498266Sopenharmony_ci
15213498266Sopenharmony_ci  usecs = mach_absolute_time();
15313498266Sopenharmony_ci  usecs *= timebase.numer;
15413498266Sopenharmony_ci  usecs /= timebase.denom;
15513498266Sopenharmony_ci  usecs /= 1000;
15613498266Sopenharmony_ci
15713498266Sopenharmony_ci  cnow.tv_sec = usecs / 1000000;
15813498266Sopenharmony_ci  cnow.tv_usec = (int)(usecs % 1000000);
15913498266Sopenharmony_ci
16013498266Sopenharmony_ci  return cnow;
16113498266Sopenharmony_ci}
16213498266Sopenharmony_ci
16313498266Sopenharmony_ci#elif defined(HAVE_GETTIMEOFDAY)
16413498266Sopenharmony_ci
16513498266Sopenharmony_cistruct curltime Curl_now(void)
16613498266Sopenharmony_ci{
16713498266Sopenharmony_ci  /*
16813498266Sopenharmony_ci  ** gettimeofday() is not granted to be increased monotonically, due to
16913498266Sopenharmony_ci  ** clock drifting and external source time synchronization it can jump
17013498266Sopenharmony_ci  ** forward or backward in time.
17113498266Sopenharmony_ci  */
17213498266Sopenharmony_ci  struct timeval now;
17313498266Sopenharmony_ci  struct curltime ret;
17413498266Sopenharmony_ci  (void)gettimeofday(&now, NULL);
17513498266Sopenharmony_ci  ret.tv_sec = now.tv_sec;
17613498266Sopenharmony_ci  ret.tv_usec = (int)now.tv_usec;
17713498266Sopenharmony_ci  return ret;
17813498266Sopenharmony_ci}
17913498266Sopenharmony_ci
18013498266Sopenharmony_ci#else
18113498266Sopenharmony_ci
18213498266Sopenharmony_cistruct curltime Curl_now(void)
18313498266Sopenharmony_ci{
18413498266Sopenharmony_ci  /*
18513498266Sopenharmony_ci  ** time() returns the value of time in seconds since the Epoch.
18613498266Sopenharmony_ci  */
18713498266Sopenharmony_ci  struct curltime now;
18813498266Sopenharmony_ci  now.tv_sec = time(NULL);
18913498266Sopenharmony_ci  now.tv_usec = 0;
19013498266Sopenharmony_ci  return now;
19113498266Sopenharmony_ci}
19213498266Sopenharmony_ci
19313498266Sopenharmony_ci#endif
19413498266Sopenharmony_ci
19513498266Sopenharmony_ci/*
19613498266Sopenharmony_ci * Returns: time difference in number of milliseconds. For too large diffs it
19713498266Sopenharmony_ci * returns max value.
19813498266Sopenharmony_ci *
19913498266Sopenharmony_ci * @unittest: 1323
20013498266Sopenharmony_ci */
20113498266Sopenharmony_citimediff_t Curl_timediff(struct curltime newer, struct curltime older)
20213498266Sopenharmony_ci{
20313498266Sopenharmony_ci  timediff_t diff = (timediff_t)newer.tv_sec-older.tv_sec;
20413498266Sopenharmony_ci  if(diff >= (TIMEDIFF_T_MAX/1000))
20513498266Sopenharmony_ci    return TIMEDIFF_T_MAX;
20613498266Sopenharmony_ci  else if(diff <= (TIMEDIFF_T_MIN/1000))
20713498266Sopenharmony_ci    return TIMEDIFF_T_MIN;
20813498266Sopenharmony_ci  return diff * 1000 + (newer.tv_usec-older.tv_usec)/1000;
20913498266Sopenharmony_ci}
21013498266Sopenharmony_ci
21113498266Sopenharmony_ci/*
21213498266Sopenharmony_ci * Returns: time difference in number of milliseconds, rounded up.
21313498266Sopenharmony_ci * For too large diffs it returns max value.
21413498266Sopenharmony_ci */
21513498266Sopenharmony_citimediff_t Curl_timediff_ceil(struct curltime newer, struct curltime older)
21613498266Sopenharmony_ci{
21713498266Sopenharmony_ci  timediff_t diff = (timediff_t)newer.tv_sec-older.tv_sec;
21813498266Sopenharmony_ci  if(diff >= (TIMEDIFF_T_MAX/1000))
21913498266Sopenharmony_ci    return TIMEDIFF_T_MAX;
22013498266Sopenharmony_ci  else if(diff <= (TIMEDIFF_T_MIN/1000))
22113498266Sopenharmony_ci    return TIMEDIFF_T_MIN;
22213498266Sopenharmony_ci  return diff * 1000 + (newer.tv_usec - older.tv_usec + 999)/1000;
22313498266Sopenharmony_ci}
22413498266Sopenharmony_ci
22513498266Sopenharmony_ci/*
22613498266Sopenharmony_ci * Returns: time difference in number of microseconds. For too large diffs it
22713498266Sopenharmony_ci * returns max value.
22813498266Sopenharmony_ci */
22913498266Sopenharmony_citimediff_t Curl_timediff_us(struct curltime newer, struct curltime older)
23013498266Sopenharmony_ci{
23113498266Sopenharmony_ci  timediff_t diff = (timediff_t)newer.tv_sec-older.tv_sec;
23213498266Sopenharmony_ci  if(diff >= (TIMEDIFF_T_MAX/1000000))
23313498266Sopenharmony_ci    return TIMEDIFF_T_MAX;
23413498266Sopenharmony_ci  else if(diff <= (TIMEDIFF_T_MIN/1000000))
23513498266Sopenharmony_ci    return TIMEDIFF_T_MIN;
23613498266Sopenharmony_ci  return diff * 1000000 + newer.tv_usec-older.tv_usec;
23713498266Sopenharmony_ci}
238