| Index: base/time/time_posix.cc
|
| diff --git a/base/time/time_posix.cc b/base/time/time_posix.cc
|
| index 4aadee618a0fb3a452edf945ab4b7e9fc3ac8a14..caa7ea9927a3cd65984529181d60be0bb0ffe80c 100644
|
| --- a/base/time/time_posix.cc
|
| +++ b/base/time/time_posix.cc
|
| @@ -15,23 +15,25 @@
|
| #include <limits>
|
| #include <ostream>
|
|
|
| +#include "base/lazy_instance.h"
|
| #include "base/logging.h"
|
| +#include "base/synchronization/lock.h"
|
| #include "build/build_config.h"
|
|
|
| #if defined(OS_ANDROID)
|
| #include "base/os_compat_android.h"
|
| #elif defined(OS_NACL)
|
| #include "base/os_compat_nacl.h"
|
| -#endif
|
| -
|
| -#if !defined(OS_MACOSX)
|
| -#include "base/lazy_instance.h"
|
| -#include "base/synchronization/lock.h"
|
| +#elif defined(OS_MACOSX)
|
| +#include <mach/mach.h>
|
| +#include <mach/mach_time.h>
|
| +#include <sys/sysctl.h>
|
| +#include "base/mac/mach_logging.h"
|
| +#include "base/mac/scoped_mach_port.h"
|
| #endif
|
|
|
| namespace {
|
|
|
| -#if !defined(OS_MACOSX)
|
| // This prevents a crash on traversing the environment global and looking up
|
| // the 'TZ' variable in libc. See: crbug.com/390567.
|
| base::LazyInstance<base::Lock>::Leaky
|
| @@ -79,6 +81,7 @@ void SysTimeToTimeStruct(SysTime t, struct tm* timestruct, bool is_local) {
|
| }
|
| #endif // OS_ANDROID
|
|
|
| +#if !defined(OS_MACOSX)
|
| int64_t ConvertTimespecToMicros(const struct timespec& ts) {
|
| base::CheckedNumeric<int64_t> result(ts.tv_sec);
|
| result *= base::Time::kMicrosecondsPerSecond;
|
| @@ -104,7 +107,89 @@ int64_t ClockNow(clockid_t clk_id) {
|
| #else // _POSIX_MONOTONIC_CLOCK
|
| #error No usable tick clock function on this platform.
|
| #endif // _POSIX_MONOTONIC_CLOCK
|
| -#endif // !defined(OS_MACOSX)
|
| +#endif
|
| +
|
| +int64_t ComputeCurrentTicks() {
|
| +#if defined(OS_IOS)
|
| + // On iOS mach_absolute_time stops while the device is sleeping. Instead use
|
| + // now - KERN_BOOTTIME to get a time difference that is not impacted by clock
|
| + // changes. KERN_BOOTTIME will be updated by the system whenever the system
|
| + // clock change.
|
| + struct timeval boottime;
|
| + int mib[2] = {CTL_KERN, KERN_BOOTTIME};
|
| + size_t size = sizeof(boottime);
|
| + int kr = sysctl(mib, arraysize(mib), &boottime, &size, NULL, 0);
|
| + DCHECK_EQ(KERN_SUCCESS, kr);
|
| + base::TimeDelta time_difference = base::Time::Now() -
|
| + (base::Time::FromTimeT(boottime.tv_sec) +
|
| + base::TimeDelta::FromMicroseconds(boottime.tv_usec));
|
| + return time_difference.InMicroseconds();
|
| +#elif defined(OS_MACOSX)
|
| + static mach_timebase_info_data_t timebase_info;
|
| + if (timebase_info.denom == 0) {
|
| + // Zero-initialization of statics guarantees that denom will be 0 before
|
| + // calling mach_timebase_info. mach_timebase_info will never set denom to
|
| + // 0 as that would be invalid, so the zero-check can be used to determine
|
| + // whether mach_timebase_info has already been called. This is
|
| + // recommended by Apple's QA1398.
|
| + kern_return_t kr = mach_timebase_info(&timebase_info);
|
| + MACH_DCHECK(kr == KERN_SUCCESS, kr) << "mach_timebase_info";
|
| + }
|
| +
|
| + // mach_absolute_time is it when it comes to ticks on the Mac. Other calls
|
| + // with less precision (such as TickCount) just call through to
|
| + // mach_absolute_time.
|
| +
|
| + // timebase_info converts absolute time tick units into nanoseconds. Convert
|
| + // to microseconds up front to stave off overflows.
|
| + base::CheckedNumeric<uint64_t> result(
|
| + mach_absolute_time() / base::Time::kNanosecondsPerMicrosecond);
|
| + result *= timebase_info.numer;
|
| + result /= timebase_info.denom;
|
| +
|
| + // Don't bother with the rollover handling that the Windows version does.
|
| + // With numer and denom = 1 (the expected case), the 64-bit absolute time
|
| + // reported in nanoseconds is enough to last nearly 585 years.
|
| + return base::checked_cast<int64_t>(result.ValueOrDie());
|
| +#else
|
| + return ClockNow(CLOCK_MONOTONIC);
|
| +#endif
|
| +}
|
| +
|
| +int64_t ComputeThreadTicks() {
|
| +#if defined(OS_IOS)
|
| + NOTREACHED();
|
| + return 0;
|
| +#elif defined(OS_MACOSX)
|
| + base::mac::ScopedMachSendRight thread(mach_thread_self());
|
| + mach_msg_type_number_t thread_info_count = THREAD_BASIC_INFO_COUNT;
|
| + thread_basic_info_data_t thread_info_data;
|
| +
|
| + if (thread.get() == MACH_PORT_NULL) {
|
| + DLOG(ERROR) << "Failed to get mach_thread_self()";
|
| + return 0;
|
| + }
|
| +
|
| + kern_return_t kr = thread_info(
|
| + thread.get(),
|
| + THREAD_BASIC_INFO,
|
| + reinterpret_cast<thread_info_t>(&thread_info_data),
|
| + &thread_info_count);
|
| + MACH_DCHECK(kr == KERN_SUCCESS, kr) << "thread_info";
|
| +
|
| + base::CheckedNumeric<int64_t> absolute_micros(
|
| + thread_info_data.user_time.seconds);
|
| + absolute_micros *= base::Time::kMicrosecondsPerSecond;
|
| + absolute_micros += thread_info_data.user_time.microseconds;
|
| + return absolute_micros.ValueOrDie();
|
| +#elif (defined(_POSIX_THREAD_CPUTIME) && (_POSIX_THREAD_CPUTIME >= 0)) || \
|
| + defined(OS_ANDROID)
|
| + return ThreadTicks(ClockNow(CLOCK_THREAD_CPUTIME_ID));
|
| +#else
|
| + NOTREACHED();
|
| + return 0;
|
| +#endif
|
| +}
|
|
|
| } // namespace
|
|
|
| @@ -123,7 +208,6 @@ struct timespec TimeDelta::ToTimeSpec() const {
|
| return result;
|
| }
|
|
|
| -#if !defined(OS_MACOSX)
|
| // The Time routines in this file use standard POSIX routines, or almost-
|
| // standard routines in the case of timegm. We need to use a Mach-specific
|
| // function for TimeTicks::Now() on Mac OS X.
|
| @@ -308,7 +392,7 @@ Time Time::FromExploded(bool is_local, const Exploded& exploded) {
|
| // TimeTicks ------------------------------------------------------------------
|
| // static
|
| TimeTicks TimeTicks::Now() {
|
| - return TimeTicks(ClockNow(CLOCK_MONOTONIC));
|
| + return TimeTicks(ComputeCurrentTicks());
|
| }
|
|
|
| // static
|
| @@ -318,17 +402,9 @@ bool TimeTicks::IsHighResolution() {
|
|
|
| // static
|
| ThreadTicks ThreadTicks::Now() {
|
| -#if (defined(_POSIX_THREAD_CPUTIME) && (_POSIX_THREAD_CPUTIME >= 0)) || \
|
| - defined(OS_ANDROID)
|
| - return ThreadTicks(ClockNow(CLOCK_THREAD_CPUTIME_ID));
|
| -#else
|
| - NOTREACHED();
|
| - return ThreadTicks();
|
| -#endif
|
| + return ThreadTicks(ComputeThreadTicks());
|
| }
|
|
|
| -#endif // !OS_MACOSX
|
| -
|
| // static
|
| Time Time::FromTimeVal(struct timeval t) {
|
| DCHECK_LT(t.tv_usec, static_cast<int>(Time::kMicrosecondsPerSecond));
|
| @@ -360,4 +436,30 @@ struct timeval Time::ToTimeVal() const {
|
| return result;
|
| }
|
|
|
| +#if defined(OS_MACOSX)
|
| +// static
|
| +Time Time::FromCFAbsoluteTime(CFAbsoluteTime t) {
|
| + static_assert(std::numeric_limits<CFAbsoluteTime>::has_infinity,
|
| + "CFAbsoluteTime must have an infinity value");
|
| + if (t == 0)
|
| + return Time(); // Consider 0 as a null Time.
|
| + if (t == std::numeric_limits<CFAbsoluteTime>::infinity())
|
| + return Max();
|
| + return Time(static_cast<int64_t>((t + kCFAbsoluteTimeIntervalSince1970) *
|
| + kMicrosecondsPerSecond) +
|
| + kWindowsEpochDeltaMicroseconds);
|
| +}
|
| +
|
| +CFAbsoluteTime Time::ToCFAbsoluteTime() const {
|
| + static_assert(std::numeric_limits<CFAbsoluteTime>::has_infinity,
|
| + "CFAbsoluteTime must have an infinity value");
|
| + if (is_null())
|
| + return 0; // Consider 0 as a null Time.
|
| + if (is_max())
|
| + return std::numeric_limits<CFAbsoluteTime>::infinity();
|
| + return (static_cast<CFAbsoluteTime>(us_ - kWindowsEpochDeltaMicroseconds) /
|
| + kMicrosecondsPerSecond) - kCFAbsoluteTimeIntervalSince1970;
|
| +}
|
| +#endif // OS_MACOSX
|
| +
|
| } // namespace base
|
|
|