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 "partition_alloc/partition_alloc_base/time/time.h" 6 7#import <Foundation/Foundation.h> 8#include <mach/mach.h> 9#include <mach/mach_time.h> 10#include <sys/sysctl.h> 11#include <sys/time.h> 12#include <sys/types.h> 13 14#include <cstddef> 15#include <cstdint> 16#include <ctime> 17 18#if BUILDFLAG(IS_IOS) 19#include <cerrno> 20#endif 21 22#include "build/build_config.h" 23#include "partition_alloc/partition_alloc_base/check.h" 24#include "partition_alloc/partition_alloc_base/logging.h" 25#include "partition_alloc/partition_alloc_base/numerics/safe_conversions.h" 26#include "partition_alloc/partition_alloc_base/time/time_override.h" 27 28namespace partition_alloc::internal::base { 29 30namespace { 31 32// Returns a pointer to the initialized Mach timebase info struct. 33mach_timebase_info_data_t* MachTimebaseInfo() { 34 static mach_timebase_info_data_t timebase_info = []() { 35 mach_timebase_info_data_t info; 36 kern_return_t kr = mach_timebase_info(&info); 37 PA_BASE_DCHECK(kr == KERN_SUCCESS) << "mach_timebase_info"; 38 PA_BASE_DCHECK(info.numer); 39 PA_BASE_DCHECK(info.denom); 40 return info; 41 }(); 42 return &timebase_info; 43} 44 45int64_t MachTimeToMicroseconds(uint64_t mach_time) { 46 // timebase_info gives us the conversion factor between absolute time tick 47 // units and nanoseconds. 48 mach_timebase_info_data_t* timebase_info = MachTimebaseInfo(); 49 50 // Take the fast path when the conversion is 1:1. The result will for sure fit 51 // into an int_64 because we're going from nanoseconds to microseconds. 52 if (timebase_info->numer == timebase_info->denom) { 53 return static_cast<int64_t>(mach_time / Time::kNanosecondsPerMicrosecond); 54 } 55 56 uint64_t microseconds = 0; 57 const uint64_t divisor = 58 timebase_info->denom * Time::kNanosecondsPerMicrosecond; 59 60 // Microseconds is mach_time * timebase.numer / 61 // (timebase.denom * kNanosecondsPerMicrosecond). Divide first to reduce 62 // the chance of overflow. Also stash the remainder right now, a likely 63 // byproduct of the division. 64 microseconds = mach_time / divisor; 65 const uint64_t mach_time_remainder = mach_time % divisor; 66 67 // Now multiply, keeping an eye out for overflow. 68 PA_BASE_CHECK(!__builtin_umulll_overflow(microseconds, timebase_info->numer, 69 µseconds)); 70 71 // By dividing first we lose precision. Regain it by adding back the 72 // microseconds from the remainder, with an eye out for overflow. 73 uint64_t least_significant_microseconds = 74 (mach_time_remainder * timebase_info->numer) / divisor; 75 PA_BASE_CHECK(!__builtin_uaddll_overflow( 76 microseconds, least_significant_microseconds, µseconds)); 77 78 // Don't bother with the rollover handling that the Windows version does. 79 // The returned time in microseconds is enough for 292,277 years (starting 80 // from 2^63 because the returned int64_t is signed, 81 // 9223372036854775807 / (1e6 * 60 * 60 * 24 * 365.2425) = 292,277). 82 return checked_cast<int64_t>(microseconds); 83} 84 85// Returns monotonically growing number of ticks in microseconds since some 86// unspecified starting point. 87int64_t ComputeCurrentTicks() { 88 // mach_absolute_time is it when it comes to ticks on the Mac. Other calls 89 // with less precision (such as TickCount) just call through to 90 // mach_absolute_time. 91 return MachTimeToMicroseconds(mach_absolute_time()); 92} 93 94int64_t ComputeThreadTicks() { 95 // The pthreads library keeps a cached reference to the thread port, which 96 // does not have to be released like mach_thread_self() does. 97 mach_port_t thread_port = pthread_mach_thread_np(pthread_self()); 98 if (thread_port == MACH_PORT_NULL) { 99 PA_DLOG(ERROR) << "Failed to get pthread_mach_thread_np()"; 100 return 0; 101 } 102 103 mach_msg_type_number_t thread_info_count = THREAD_BASIC_INFO_COUNT; 104 thread_basic_info_data_t thread_info_data; 105 106 kern_return_t kr = thread_info( 107 thread_port, THREAD_BASIC_INFO, 108 reinterpret_cast<thread_info_t>(&thread_info_data), &thread_info_count); 109 PA_BASE_DCHECK(kr == KERN_SUCCESS) << "thread_info"; 110 111 CheckedNumeric<int64_t> absolute_micros(thread_info_data.user_time.seconds + 112 thread_info_data.system_time.seconds); 113 absolute_micros *= Time::kMicrosecondsPerSecond; 114 absolute_micros += (thread_info_data.user_time.microseconds + 115 thread_info_data.system_time.microseconds); 116 return absolute_micros.ValueOrDie(); 117} 118 119} // namespace 120 121// The Time routines in this file use Mach and CoreFoundation APIs, since the 122// POSIX definition of time_t in Mac OS X wraps around after 2038--and 123// there are already cookie expiration dates, etc., past that time out in 124// the field. Using CFDate prevents that problem, and using mach_absolute_time 125// for TimeTicks gives us nice high-resolution interval timing. 126 127// Time ----------------------------------------------------------------------- 128 129namespace subtle { 130Time TimeNowIgnoringOverride() { 131 return Time::FromCFAbsoluteTime(CFAbsoluteTimeGetCurrent()); 132} 133 134Time TimeNowFromSystemTimeIgnoringOverride() { 135 // Just use TimeNowIgnoringOverride() because it returns the system time. 136 return TimeNowIgnoringOverride(); 137} 138} // namespace subtle 139 140// static 141Time Time::FromCFAbsoluteTime(CFAbsoluteTime t) { 142 static_assert(std::numeric_limits<CFAbsoluteTime>::has_infinity, 143 "CFAbsoluteTime must have an infinity value"); 144 if (t == 0) { 145 return Time(); // Consider 0 as a null Time. 146 } 147 return (t == std::numeric_limits<CFAbsoluteTime>::infinity()) 148 ? Max() 149 : (UnixEpoch() + 150 Seconds(double{t + kCFAbsoluteTimeIntervalSince1970})); 151} 152 153CFAbsoluteTime Time::ToCFAbsoluteTime() const { 154 static_assert(std::numeric_limits<CFAbsoluteTime>::has_infinity, 155 "CFAbsoluteTime must have an infinity value"); 156 if (is_null()) { 157 return 0; // Consider 0 as a null Time. 158 } 159 return is_max() ? std::numeric_limits<CFAbsoluteTime>::infinity() 160 : (CFAbsoluteTime{(*this - UnixEpoch()).InSecondsF()} - 161 kCFAbsoluteTimeIntervalSince1970); 162} 163 164// static 165Time Time::FromNSDate(NSDate* date) { 166 PA_BASE_DCHECK(date); 167 return FromCFAbsoluteTime(date.timeIntervalSinceReferenceDate); 168} 169 170NSDate* Time::ToNSDate() const { 171 return [NSDate dateWithTimeIntervalSinceReferenceDate:ToCFAbsoluteTime()]; 172} 173 174// TimeDelta ------------------------------------------------------------------ 175 176// static 177TimeDelta TimeDelta::FromMachTime(uint64_t mach_time) { 178 return Microseconds(MachTimeToMicroseconds(mach_time)); 179} 180 181// TimeTicks ------------------------------------------------------------------ 182 183namespace subtle { 184TimeTicks TimeTicksNowIgnoringOverride() { 185 return TimeTicks() + Microseconds(ComputeCurrentTicks()); 186} 187} // namespace subtle 188 189// static 190bool TimeTicks::IsHighResolution() { 191 return true; 192} 193 194// static 195bool TimeTicks::IsConsistentAcrossProcesses() { 196 return true; 197} 198 199// static 200TimeTicks TimeTicks::FromMachAbsoluteTime(uint64_t mach_absolute_time) { 201 return TimeTicks(MachTimeToMicroseconds(mach_absolute_time)); 202} 203 204// static 205mach_timebase_info_data_t TimeTicks::SetMachTimebaseInfoForTesting( 206 mach_timebase_info_data_t timebase) { 207 mach_timebase_info_data_t orig_timebase = *MachTimebaseInfo(); 208 209 *MachTimebaseInfo() = timebase; 210 211 return orig_timebase; 212} 213 214// static 215TimeTicks::Clock TimeTicks::GetClock() { 216 return Clock::MAC_MACH_ABSOLUTE_TIME; 217} 218 219// ThreadTicks ---------------------------------------------------------------- 220 221namespace subtle { 222ThreadTicks ThreadTicksNowIgnoringOverride() { 223 return ThreadTicks() + Microseconds(ComputeThreadTicks()); 224} 225} // namespace subtle 226 227} // namespace partition_alloc::internal::base 228