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