1 // Copyright 2012 The Chromium Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include <sys/time.h> 6 7 #include <cstdint> 8 #include <ctime> 9 10 #include "build/build_config.h" 11 #include "partition_alloc/partition_alloc_base/time/time.h" 12 #if BUILDFLAG(IS_ANDROID) && !defined(__LP64__) 13 #include <time64.h> 14 #endif 15 #include <unistd.h> 16 17 #include "partition_alloc/partition_alloc_base/check.h" 18 #include "partition_alloc/partition_alloc_base/notreached.h" 19 #include "partition_alloc/partition_alloc_base/numerics/safe_math.h" 20 #include "partition_alloc/partition_alloc_base/time/time_override.h" 21 22 // Ensure the Fuchsia and Mac builds do not include this module. Instead, 23 // non-POSIX implementation is used for sampling the system clocks. 24 #if BUILDFLAG(IS_FUCHSIA) || BUILDFLAG(IS_APPLE) 25 #error "This implementation is for POSIX platforms other than Fuchsia or Mac." 26 #endif 27 28 namespace partition_alloc::internal::base { 29 30 namespace { 31 ConvertTimespecToMicros(const struct timespec & ts)32int64_t ConvertTimespecToMicros(const struct timespec& ts) { 33 // On 32-bit systems, the calculation cannot overflow int64_t. 34 // 2**32 * 1000000 + 2**64 / 1000 < 2**63 35 if (sizeof(ts.tv_sec) <= 4 && sizeof(ts.tv_nsec) <= 8) { 36 int64_t result = ts.tv_sec; 37 result *= Time::kMicrosecondsPerSecond; 38 result += (ts.tv_nsec / Time::kNanosecondsPerMicrosecond); 39 return result; 40 } 41 CheckedNumeric<int64_t> result(ts.tv_sec); 42 result *= Time::kMicrosecondsPerSecond; 43 result += (ts.tv_nsec / Time::kNanosecondsPerMicrosecond); 44 return result.ValueOrDie(); 45 } 46 47 // Helper function to get results from clock_gettime() and convert to a 48 // microsecond timebase. Minimum requirement is MONOTONIC_CLOCK to be supported 49 // on the system. FreeBSD 6 has CLOCK_MONOTONIC but defines 50 // _POSIX_MONOTONIC_CLOCK to -1. 51 #if (BUILDFLAG(IS_POSIX) && defined(_POSIX_MONOTONIC_CLOCK) && \ 52 _POSIX_MONOTONIC_CLOCK >= 0) || \ 53 BUILDFLAG(IS_BSD) || BUILDFLAG(IS_ANDROID) ClockNow(clockid_t clk_id)54int64_t ClockNow(clockid_t clk_id) { 55 struct timespec ts; 56 PA_BASE_CHECK(clock_gettime(clk_id, &ts) == 0); 57 return ConvertTimespecToMicros(ts); 58 } 59 #else // _POSIX_MONOTONIC_CLOCK 60 #error No usable tick clock function on this platform. 61 #endif // _POSIX_MONOTONIC_CLOCK 62 63 } // namespace 64 65 // Time ----------------------------------------------------------------------- 66 67 namespace subtle { TimeNowIgnoringOverride()68Time TimeNowIgnoringOverride() { 69 struct timeval tv; 70 struct timezone tz = {0, 0}; // UTC 71 PA_BASE_CHECK(gettimeofday(&tv, &tz) == 0); 72 // Combine seconds and microseconds in a 64-bit field containing microseconds 73 // since the epoch. That's enough for nearly 600 centuries. Adjust from 74 // Unix (1970) to Windows (1601) epoch. 75 return Time() + 76 Microseconds((tv.tv_sec * Time::kMicrosecondsPerSecond + tv.tv_usec) + 77 Time::kTimeTToMicrosecondsOffset); 78 } 79 TimeNowFromSystemTimeIgnoringOverride()80Time TimeNowFromSystemTimeIgnoringOverride() { 81 // Just use TimeNowIgnoringOverride() because it returns the system time. 82 return TimeNowIgnoringOverride(); 83 } 84 } // namespace subtle 85 86 // TimeTicks ------------------------------------------------------------------ 87 88 namespace subtle { TimeTicksNowIgnoringOverride()89TimeTicks TimeTicksNowIgnoringOverride() { 90 return TimeTicks() + Microseconds(ClockNow(CLOCK_MONOTONIC)); 91 } 92 } // namespace subtle 93 94 // static GetClock()95TimeTicks::Clock TimeTicks::GetClock() { 96 return Clock::LINUX_CLOCK_MONOTONIC; 97 } 98 99 // static IsHighResolution()100bool TimeTicks::IsHighResolution() { 101 return true; 102 } 103 104 // static IsConsistentAcrossProcesses()105bool TimeTicks::IsConsistentAcrossProcesses() { 106 return true; 107 } 108 109 // ThreadTicks ---------------------------------------------------------------- 110 111 namespace subtle { ThreadTicksNowIgnoringOverride()112ThreadTicks ThreadTicksNowIgnoringOverride() { 113 #if (defined(_POSIX_THREAD_CPUTIME) && (_POSIX_THREAD_CPUTIME >= 0)) || \ 114 BUILDFLAG(IS_ANDROID) 115 return ThreadTicks() + Microseconds(ClockNow(CLOCK_THREAD_CPUTIME_ID)); 116 #else 117 PA_NOTREACHED(); 118 #endif 119 } 120 } // namespace subtle 121 122 } // namespace partition_alloc::internal::base 123