time_mac.mm 9.1 KB

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