libcxx

libcxx mirror with random patches
git clone https://git.neptards.moe/neptards/libcxx.git
Log | Files | Refs

chrono.cpp (6830B)


      1 //===------------------------- chrono.cpp ---------------------------------===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is dual licensed under the MIT and the University of Illinois Open
      6 // Source Licenses. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 
     10 #include "chrono"
     11 #include "cerrno"        // errno
     12 #include "system_error"  // __throw_system_error
     13 #include <time.h>        // clock_gettime, CLOCK_MONOTONIC and CLOCK_REALTIME
     14 #include "include/apple_availability.h"
     15 
     16 #if !defined(__APPLE__)
     17 #define _LIBCPP_USE_CLOCK_GETTIME
     18 #endif // __APPLE__
     19 
     20 #if defined(_LIBCPP_WIN32API)
     21 #define WIN32_LEAN_AND_MEAN
     22 #define VC_EXTRA_LEAN
     23 #include <windows.h>
     24 #if _WIN32_WINNT >= _WIN32_WINNT_WIN8
     25 #include <winapifamily.h>
     26 #endif
     27 #else
     28 #if !defined(CLOCK_REALTIME) || !defined(_LIBCPP_USE_CLOCK_GETTIME)
     29 #include <sys/time.h>        // for gettimeofday and timeval
     30 #endif // !defined(CLOCK_REALTIME)
     31 #endif // defined(_LIBCPP_WIN32API)
     32 
     33 #if !defined(_LIBCPP_HAS_NO_MONOTONIC_CLOCK)
     34 #if __APPLE__
     35 #include <mach/mach_time.h>  // mach_absolute_time, mach_timebase_info_data_t
     36 #elif defined(__vita__)
     37 #include <psp2/rtc.h>
     38 #include <psp2/kernel/processmgr.h>
     39 #elif !defined(_LIBCPP_WIN32API) && !defined(CLOCK_MONOTONIC)
     40 #error "Monotonic clock not implemented"
     41 #endif
     42 #endif
     43 
     44 _LIBCPP_BEGIN_NAMESPACE_STD
     45 
     46 namespace chrono
     47 {
     48 
     49 // system_clock
     50 
     51 const bool system_clock::is_steady;
     52 
     53 system_clock::time_point
     54 system_clock::now() _NOEXCEPT
     55 {
     56 #if defined(_LIBCPP_WIN32API)
     57   // FILETIME is in 100ns units
     58   using filetime_duration =
     59       _VSTD::chrono::duration<__int64,
     60                               _VSTD::ratio_multiply<_VSTD::ratio<100, 1>,
     61                                                     nanoseconds::period>>;
     62 
     63   // The Windows epoch is Jan 1 1601, the Unix epoch Jan 1 1970.
     64   static _LIBCPP_CONSTEXPR const seconds nt_to_unix_epoch{11644473600};
     65 
     66   FILETIME ft;
     67 #if _WIN32_WINNT >= _WIN32_WINNT_WIN8
     68 #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
     69   GetSystemTimePreciseAsFileTime(&ft);
     70 #else
     71   GetSystemTimeAsFileTime(&ft);
     72 #endif
     73 #else
     74   GetSystemTimeAsFileTime(&ft);
     75 #endif
     76 
     77   filetime_duration d{(static_cast<__int64>(ft.dwHighDateTime) << 32) |
     78                        static_cast<__int64>(ft.dwLowDateTime)};
     79   return time_point(duration_cast<duration>(d - nt_to_unix_epoch));
     80 #else
     81 #if defined(__vita__)
     82   // Vita epoch = 0001-01-01 00:00:00
     83   static _LIBCPP_CONSTEXPR const seconds vita_to_unix_epoch{62135596800};
     84 
     85   SceRtcTick tick;
     86   if (int err = sceRtcGetCurrentTick(&tick))
     87     __throw_system_error(err & 0xff, "sceRtcGetCurrentTick() failed");
     88   return time_point(microseconds(tick.tick) - vita_to_unix_epoch);
     89 #elif defined(_LIBCPP_USE_CLOCK_GETTIME) && defined(CLOCK_REALTIME)
     90   struct timespec tp;
     91   if (0 != clock_gettime(CLOCK_REALTIME, &tp))
     92     __throw_system_error(errno, "clock_gettime(CLOCK_REALTIME) failed");
     93   return time_point(seconds(tp.tv_sec) + microseconds(tp.tv_nsec / 1000));
     94 #else
     95     timeval tv;
     96     gettimeofday(&tv, 0);
     97     return time_point(seconds(tv.tv_sec) + microseconds(tv.tv_usec));
     98 #endif // _LIBCPP_USE_CLOCK_GETTIME && CLOCK_REALTIME
     99 #endif
    100 }
    101 
    102 time_t
    103 system_clock::to_time_t(const time_point& t) _NOEXCEPT
    104 {
    105     return time_t(duration_cast<seconds>(t.time_since_epoch()).count());
    106 }
    107 
    108 system_clock::time_point
    109 system_clock::from_time_t(time_t t) _NOEXCEPT
    110 {
    111     return system_clock::time_point(seconds(t));
    112 }
    113 
    114 #ifndef _LIBCPP_HAS_NO_MONOTONIC_CLOCK
    115 // steady_clock
    116 //
    117 // Warning:  If this is not truly steady, then it is non-conforming.  It is
    118 //  better for it to not exist and have the rest of libc++ use system_clock
    119 //  instead.
    120 
    121 const bool steady_clock::is_steady;
    122 
    123 #if defined(__APPLE__)
    124 
    125 // Darwin libc versions >= 1133 provide ns precision via CLOCK_UPTIME_RAW
    126 #if defined(_LIBCPP_USE_CLOCK_GETTIME) && defined(CLOCK_UPTIME_RAW)
    127 steady_clock::time_point
    128 steady_clock::now() _NOEXCEPT
    129 {
    130     struct timespec tp;
    131     if (0 != clock_gettime(CLOCK_UPTIME_RAW, &tp))
    132         __throw_system_error(errno, "clock_gettime(CLOCK_UPTIME_RAW) failed");
    133     return time_point(seconds(tp.tv_sec) + nanoseconds(tp.tv_nsec));
    134 }
    135 
    136 #else
    137 //   mach_absolute_time() * MachInfo.numer / MachInfo.denom is the number of
    138 //   nanoseconds since the computer booted up.  MachInfo.numer and MachInfo.denom
    139 //   are run time constants supplied by the OS.  This clock has no relationship
    140 //   to the Gregorian calendar.  It's main use is as a high resolution timer.
    141 
    142 // MachInfo.numer / MachInfo.denom is often 1 on the latest equipment.  Specialize
    143 //   for that case as an optimization.
    144 
    145 static
    146 steady_clock::rep
    147 steady_simplified()
    148 {
    149     return static_cast<steady_clock::rep>(mach_absolute_time());
    150 }
    151 
    152 static
    153 double
    154 compute_steady_factor()
    155 {
    156     mach_timebase_info_data_t MachInfo;
    157     mach_timebase_info(&MachInfo);
    158     return static_cast<double>(MachInfo.numer) / MachInfo.denom;
    159 }
    160 
    161 static
    162 steady_clock::rep
    163 steady_full()
    164 {
    165     static const double factor = compute_steady_factor();
    166     return static_cast<steady_clock::rep>(mach_absolute_time() * factor);
    167 }
    168 
    169 typedef steady_clock::rep (*FP)();
    170 
    171 static
    172 FP
    173 init_steady_clock()
    174 {
    175     mach_timebase_info_data_t MachInfo;
    176     mach_timebase_info(&MachInfo);
    177     if (MachInfo.numer == MachInfo.denom)
    178         return &steady_simplified;
    179     return &steady_full;
    180 }
    181 
    182 steady_clock::time_point
    183 steady_clock::now() _NOEXCEPT
    184 {
    185     static FP fp = init_steady_clock();
    186     return time_point(duration(fp()));
    187 }
    188 #endif // defined(_LIBCPP_USE_CLOCK_GETTIME) && defined(CLOCK_UPTIME_RAW)
    189 
    190 #elif defined(_LIBCPP_WIN32API)
    191 
    192 steady_clock::time_point
    193 steady_clock::now() _NOEXCEPT
    194 {
    195   static LARGE_INTEGER freq;
    196   static BOOL initialized = FALSE;
    197   if (!initialized)
    198     initialized = QueryPerformanceFrequency(&freq); // always succceeds
    199 
    200   LARGE_INTEGER counter;
    201   QueryPerformanceCounter(&counter);
    202   return time_point(duration(counter.QuadPart * nano::den / freq.QuadPart));
    203 }
    204 
    205 #elif defined(CLOCK_MONOTONIC)
    206 
    207 // On Apple platforms only CLOCK_UPTIME_RAW or mach_absolute_time are able to
    208 // time functions in the nanosecond range. Thus, they are the only acceptable
    209 // implementations of steady_clock.
    210 #ifdef __APPLE__
    211 #error "Never use CLOCK_MONOTONIC for steady_clock::now on Apple platforms"
    212 #endif
    213 
    214 steady_clock::time_point
    215 steady_clock::now() _NOEXCEPT
    216 {
    217     struct timespec tp;
    218     if (0 != clock_gettime(CLOCK_MONOTONIC, &tp))
    219         __throw_system_error(errno, "clock_gettime(CLOCK_MONOTONIC) failed");
    220     return time_point(seconds(tp.tv_sec) + nanoseconds(tp.tv_nsec));
    221 }
    222 
    223 #elif defined(__vita__)
    224 
    225 steady_clock::time_point
    226 steady_clock::now() _NOEXCEPT
    227 {
    228   return time_point(microseconds(sceKernelGetProcessTimeWide()));
    229 }
    230 
    231 #else
    232 #error "Monotonic clock not implemented"
    233 #endif
    234 
    235 #endif // !_LIBCPP_HAS_NO_MONOTONIC_CLOCK
    236 
    237 }
    238 
    239 _LIBCPP_END_NAMESPACE_STD