Path: blob/main/system/lib/libcxx/src/chrono.cpp
6175 views
//===----------------------------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#if defined(__MVS__)9// As part of monotonic clock support on z/OS we need macro _LARGE_TIME_API10// to be defined before any system header to include definition of struct timespec64.11# define _LARGE_TIME_API12#endif1314#include <__system_error/throw_system_error.h>15#include <cerrno> // errno16#include <chrono>1718#if defined(__MVS__)19# include <__support/ibm/gettod_zos.h> // gettimeofdayMonotonic20#endif2122#include "include/apple_availability.h"23#include <time.h> // clock_gettime and CLOCK_{MONOTONIC,REALTIME,MONOTONIC_RAW}2425#if __has_include(<unistd.h>)26# include <unistd.h> // _POSIX_TIMERS27#endif2829#if __has_include(<sys/time.h>)30# include <sys/time.h> // for gettimeofday and timeval31#endif3233#if defined(__LLVM_LIBC__)34# define _LIBCPP_HAS_TIMESPEC_GET35#endif3637// OpenBSD and GPU do not have a fully conformant suite of POSIX timers, but38// it does have clock_gettime and CLOCK_MONOTONIC which is all we need.39#if defined(__APPLE__) || defined(__gnu_hurd__) || defined(__OpenBSD__) || defined(__AMDGPU__) || \40defined(__NVPTX__) || (defined(_POSIX_TIMERS) && _POSIX_TIMERS > 0)41# define _LIBCPP_HAS_CLOCK_GETTIME42#endif4344#if defined(_LIBCPP_WIN32API)45# define WIN32_LEAN_AND_MEAN46# define VC_EXTRA_LEAN47# include <windows.h>48# if _WIN32_WINNT >= _WIN32_WINNT_WIN849# include <winapifamily.h>50# endif51#endif // defined(_LIBCPP_WIN32API)5253#if defined(__Fuchsia__)54# include <zircon/syscalls.h>55#endif5657#if __has_include(<mach/mach_time.h>)58# include <mach/mach_time.h>59#endif6061#if defined(__ELF__) && defined(_LIBCPP_LINK_RT_LIB)62# pragma comment(lib, "rt")63#endif6465_LIBCPP_BEGIN_NAMESPACE_STD6667namespace chrono {6869//70// system_clock71//7273#if defined(_LIBCPP_WIN32API)7475# if _WIN32_WINNT < _WIN32_WINNT_WIN87677namespace {7879typedef void(WINAPI* GetSystemTimeAsFileTimePtr)(LPFILETIME);8081class GetSystemTimeInit {82public:83GetSystemTimeInit() {84fp = (GetSystemTimeAsFileTimePtr)(void*)GetProcAddress(85GetModuleHandleW(L"kernel32.dll"), "GetSystemTimePreciseAsFileTime");86if (fp == nullptr)87fp = GetSystemTimeAsFileTime;88}89GetSystemTimeAsFileTimePtr fp;90};9192// Pretend we're inside a system header so the compiler doesn't flag the use of the init_priority93// attribute with a value that's reserved for the implementation (we're the implementation).94# include "chrono_system_time_init.h"95} // namespace9697# endif9899static system_clock::time_point __libcpp_system_clock_now() {100// FILETIME is in 100ns units101using filetime_duration =102std::chrono::duration<__int64, std::ratio_multiply<std::ratio<100, 1>, nanoseconds::period>>;103104// The Windows epoch is Jan 1 1601, the Unix epoch Jan 1 1970.105static constexpr const seconds nt_to_unix_epoch{11644473600};106107FILETIME ft;108# if (_WIN32_WINNT >= _WIN32_WINNT_WIN8 && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)) || \109(_WIN32_WINNT >= _WIN32_WINNT_WIN10)110GetSystemTimePreciseAsFileTime(&ft);111# elif !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)112GetSystemTimeAsFileTime(&ft);113# else114GetSystemTimeAsFileTimeFunc.fp(&ft);115# endif116117filetime_duration d{(static_cast<__int64>(ft.dwHighDateTime) << 32) | static_cast<__int64>(ft.dwLowDateTime)};118return system_clock::time_point(duration_cast<system_clock::duration>(d - nt_to_unix_epoch));119}120121#elif defined(_LIBCPP_HAS_TIMESPEC_GET)122123static system_clock::time_point __libcpp_system_clock_now() {124struct timespec ts;125if (timespec_get(&ts, TIME_UTC) != TIME_UTC)126std::__throw_system_error(errno, "timespec_get(TIME_UTC) failed");127return system_clock::time_point(seconds(ts.tv_sec) + microseconds(ts.tv_nsec / 1000));128}129130#elif defined(_LIBCPP_HAS_CLOCK_GETTIME)131132static system_clock::time_point __libcpp_system_clock_now() {133struct timespec tp;134if (0 != clock_gettime(CLOCK_REALTIME, &tp))135std::__throw_system_error(errno, "clock_gettime(CLOCK_REALTIME) failed");136return system_clock::time_point(seconds(tp.tv_sec) + microseconds(tp.tv_nsec / 1000));137}138139#else140141static system_clock::time_point __libcpp_system_clock_now() {142timeval tv;143gettimeofday(&tv, 0);144return system_clock::time_point(seconds(tv.tv_sec) + microseconds(tv.tv_usec));145}146147#endif148149_LIBCPP_DIAGNOSTIC_PUSH150_LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wdeprecated")151const bool system_clock::is_steady;152_LIBCPP_DIAGNOSTIC_POP153154system_clock::time_point system_clock::now() noexcept { return __libcpp_system_clock_now(); }155156time_t system_clock::to_time_t(const time_point& t) noexcept {157return time_t(duration_cast<seconds>(t.time_since_epoch()).count());158}159160system_clock::time_point system_clock::from_time_t(time_t t) noexcept { return system_clock::time_point(seconds(t)); }161162//163// steady_clock164//165// Warning: If this is not truly steady, then it is non-conforming. It is166// better for it to not exist and have the rest of libc++ use system_clock167// instead.168//169170#if _LIBCPP_HAS_MONOTONIC_CLOCK171172# if defined(__APPLE__)173174// On Apple platforms, only CLOCK_UPTIME_RAW, CLOCK_MONOTONIC_RAW or175// mach_absolute_time are able to time functions in the nanosecond range.176// Furthermore, only CLOCK_MONOTONIC_RAW is truly monotonic, because it177// also counts cycles when the system is asleep. Thus, it is the only178// acceptable implementation of steady_clock.179static steady_clock::time_point __libcpp_steady_clock_now() {180struct timespec tp;181if (0 != clock_gettime(CLOCK_MONOTONIC_RAW, &tp))182std::__throw_system_error(errno, "clock_gettime(CLOCK_MONOTONIC_RAW) failed");183return steady_clock::time_point(seconds(tp.tv_sec) + nanoseconds(tp.tv_nsec));184}185186# elif defined(_LIBCPP_WIN32API)187188// https://msdn.microsoft.com/en-us/library/windows/desktop/ms644905(v=vs.85).aspx says:189// If the function fails, the return value is zero. <snip>190// On systems that run Windows XP or later, the function will always succeed191// and will thus never return zero.192193static LARGE_INTEGER __QueryPerformanceFrequency() {194LARGE_INTEGER val;195(void)QueryPerformanceFrequency(&val);196return val;197}198199static steady_clock::time_point __libcpp_steady_clock_now() {200static const LARGE_INTEGER freq = __QueryPerformanceFrequency();201202LARGE_INTEGER counter;203(void)QueryPerformanceCounter(&counter);204auto seconds = counter.QuadPart / freq.QuadPart;205auto fractions = counter.QuadPart % freq.QuadPart;206auto dur = seconds * nano::den + fractions * nano::den / freq.QuadPart;207return steady_clock::time_point(steady_clock::duration(dur));208}209210# elif defined(__MVS__)211212static steady_clock::time_point __libcpp_steady_clock_now() {213struct timespec64 ts;214if (0 != gettimeofdayMonotonic(&ts))215std::__throw_system_error(errno, "failed to obtain time of day");216217return steady_clock::time_point(seconds(ts.tv_sec) + nanoseconds(ts.tv_nsec));218}219220# elif defined(__Fuchsia__)221222static steady_clock::time_point __libcpp_steady_clock_now() noexcept {223// Implicitly link against the vDSO system call ABI without224// requiring the final link to specify -lzircon explicitly when225// statically linking libc++.226# pragma comment(lib, "zircon")227228return steady_clock::time_point(nanoseconds(_zx_clock_get_monotonic()));229}230231# elif defined(_LIBCPP_HAS_TIMESPEC_GET)232233static steady_clock::time_point __libcpp_steady_clock_now() {234struct timespec ts;235if (timespec_get(&ts, TIME_MONOTONIC) != TIME_MONOTONIC)236std::__throw_system_error(errno, "timespec_get(TIME_MONOTONIC) failed");237return steady_clock::time_point(seconds(ts.tv_sec) + microseconds(ts.tv_nsec / 1000));238}239240# elif defined(_LIBCPP_HAS_CLOCK_GETTIME)241242static steady_clock::time_point __libcpp_steady_clock_now() {243struct timespec tp;244if (0 != clock_gettime(CLOCK_MONOTONIC, &tp))245std::__throw_system_error(errno, "clock_gettime(CLOCK_MONOTONIC) failed");246return steady_clock::time_point(seconds(tp.tv_sec) + nanoseconds(tp.tv_nsec));247}248249# else250# error "Monotonic clock not implemented on this platform"251# endif252253_LIBCPP_DIAGNOSTIC_PUSH254_LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wdeprecated")255const bool steady_clock::is_steady;256_LIBCPP_DIAGNOSTIC_POP257258steady_clock::time_point steady_clock::now() noexcept { return __libcpp_steady_clock_now(); }259260#endif // _LIBCPP_HAS_MONOTONIC_CLOCK261262} // namespace chrono263264_LIBCPP_END_NAMESPACE_STD265266267