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
5#include "base/time/time.h"
6
7#include <CoreFoundation/CFDate.h>
8#include <CoreFoundation/CFTimeZone.h>
9#include <mach/mach.h>
10#include <mach/mach_time.h>
11#include <sys/sysctl.h>
12#include <sys/time.h>
13#include <sys/types.h>
14#include <time.h>
15
16#include "base/basictypes.h"
17#include "base/logging.h"
18#include "base/mac/mach_logging.h"
19#include "base/mac/scoped_cftyperef.h"
20#include "base/mac/scoped_mach_port.h"
21
22namespace {
23
24uint64_t ComputeCurrentTicks() {
25#if defined(OS_IOS)
26  // On iOS mach_absolute_time stops while the device is sleeping. Instead use
27  // now - KERN_BOOTTIME to get a time difference that is not impacted by clock
28  // changes. KERN_BOOTTIME will be updated by the system whenever the system
29  // clock change.
30  struct timeval boottime;
31  int mib[2] = {CTL_KERN, KERN_BOOTTIME};
32  size_t size = sizeof(boottime);
33  int kr = sysctl(mib, arraysize(mib), &boottime, &size, NULL, 0);
34  DCHECK_EQ(KERN_SUCCESS, kr);
35  base::TimeDelta time_difference = base::Time::Now() -
36      (base::Time::FromTimeT(boottime.tv_sec) +
37       base::TimeDelta::FromMicroseconds(boottime.tv_usec));
38  return time_difference.InMicroseconds();
39#else
40  uint64_t absolute_micro;
41
42  static mach_timebase_info_data_t timebase_info;
43  if (timebase_info.denom == 0) {
44    // Zero-initialization of statics guarantees that denom will be 0 before
45    // calling mach_timebase_info.  mach_timebase_info will never set denom to
46    // 0 as that would be invalid, so the zero-check can be used to determine
47    // whether mach_timebase_info has already been called.  This is
48    // recommended by Apple's QA1398.
49    kern_return_t kr = mach_timebase_info(&timebase_info);
50    MACH_DCHECK(kr == KERN_SUCCESS, kr) << "mach_timebase_info";
51  }
52
53  // mach_absolute_time is it when it comes to ticks on the Mac.  Other calls
54  // with less precision (such as TickCount) just call through to
55  // mach_absolute_time.
56
57  // timebase_info converts absolute time tick units into nanoseconds.  Convert
58  // to microseconds up front to stave off overflows.
59  absolute_micro =
60      mach_absolute_time() / base::Time::kNanosecondsPerMicrosecond *
61      timebase_info.numer / timebase_info.denom;
62
63  // Don't bother with the rollover handling that the Windows version does.
64  // With numer and denom = 1 (the expected case), the 64-bit absolute time
65  // reported in nanoseconds is enough to last nearly 585 years.
66  return absolute_micro;
67#endif  // defined(OS_IOS)
68}
69
70uint64_t ComputeThreadTicks() {
71#if defined(OS_IOS)
72  NOTREACHED();
73  return 0;
74#else
75  base::mac::ScopedMachSendRight thread(mach_thread_self());
76  mach_msg_type_number_t thread_info_count = THREAD_BASIC_INFO_COUNT;
77  thread_basic_info_data_t thread_info_data;
78
79  if (thread.get() == MACH_PORT_NULL) {
80    DLOG(ERROR) << "Failed to get mach_thread_self()";
81    return 0;
82  }
83
84  kern_return_t kr = thread_info(
85      thread,
86      THREAD_BASIC_INFO,
87      reinterpret_cast<thread_info_t>(&thread_info_data),
88      &thread_info_count);
89  MACH_DCHECK(kr == KERN_SUCCESS, kr) << "thread_info";
90
91  return (thread_info_data.user_time.seconds *
92              base::Time::kMicrosecondsPerSecond) +
93         thread_info_data.user_time.microseconds;
94#endif  // defined(OS_IOS)
95}
96
97}  // namespace
98
99namespace base {
100
101// The Time routines in this file use Mach and CoreFoundation APIs, since the
102// POSIX definition of time_t in Mac OS X wraps around after 2038--and
103// there are already cookie expiration dates, etc., past that time out in
104// the field.  Using CFDate prevents that problem, and using mach_absolute_time
105// for TimeTicks gives us nice high-resolution interval timing.
106
107// Time -----------------------------------------------------------------------
108
109// Core Foundation uses a double second count since 2001-01-01 00:00:00 UTC.
110// The UNIX epoch is 1970-01-01 00:00:00 UTC.
111// Windows uses a Gregorian epoch of 1601.  We need to match this internally
112// so that our time representations match across all platforms.  See bug 14734.
113//   irb(main):010:0> Time.at(0).getutc()
114//   => Thu Jan 01 00:00:00 UTC 1970
115//   irb(main):011:0> Time.at(-11644473600).getutc()
116//   => Mon Jan 01 00:00:00 UTC 1601
117static const int64 kWindowsEpochDeltaSeconds = GG_INT64_C(11644473600);
118
119// static
120const int64 Time::kWindowsEpochDeltaMicroseconds =
121    kWindowsEpochDeltaSeconds * Time::kMicrosecondsPerSecond;
122
123// Some functions in time.cc use time_t directly, so we provide an offset
124// to convert from time_t (Unix epoch) and internal (Windows epoch).
125// static
126const int64 Time::kTimeTToMicrosecondsOffset = kWindowsEpochDeltaMicroseconds;
127
128// static
129Time Time::Now() {
130  return FromCFAbsoluteTime(CFAbsoluteTimeGetCurrent());
131}
132
133// static
134Time Time::FromCFAbsoluteTime(CFAbsoluteTime t) {
135  COMPILE_ASSERT(std::numeric_limits<CFAbsoluteTime>::has_infinity,
136                 numeric_limits_infinity_is_undefined_when_not_has_infinity);
137  if (t == 0)
138    return Time();  // Consider 0 as a null Time.
139  if (t == std::numeric_limits<CFAbsoluteTime>::infinity())
140    return Max();
141  return Time(static_cast<int64>(
142      (t + kCFAbsoluteTimeIntervalSince1970) * kMicrosecondsPerSecond) +
143      kWindowsEpochDeltaMicroseconds);
144}
145
146CFAbsoluteTime Time::ToCFAbsoluteTime() const {
147  COMPILE_ASSERT(std::numeric_limits<CFAbsoluteTime>::has_infinity,
148                 numeric_limits_infinity_is_undefined_when_not_has_infinity);
149  if (is_null())
150    return 0;  // Consider 0 as a null Time.
151  if (is_max())
152    return std::numeric_limits<CFAbsoluteTime>::infinity();
153  return (static_cast<CFAbsoluteTime>(us_ - kWindowsEpochDeltaMicroseconds) /
154      kMicrosecondsPerSecond) - kCFAbsoluteTimeIntervalSince1970;
155}
156
157// static
158Time Time::NowFromSystemTime() {
159  // Just use Now() because Now() returns the system time.
160  return Now();
161}
162
163// static
164Time Time::FromExploded(bool is_local, const Exploded& exploded) {
165  CFGregorianDate date;
166  date.second = exploded.second +
167      exploded.millisecond / static_cast<double>(kMillisecondsPerSecond);
168  date.minute = exploded.minute;
169  date.hour = exploded.hour;
170  date.day = exploded.day_of_month;
171  date.month = exploded.month;
172  date.year = exploded.year;
173
174  base::ScopedCFTypeRef<CFTimeZoneRef> time_zone(
175      is_local ? CFTimeZoneCopySystem() : NULL);
176  CFAbsoluteTime seconds = CFGregorianDateGetAbsoluteTime(date, time_zone) +
177      kCFAbsoluteTimeIntervalSince1970;
178  return Time(static_cast<int64>(seconds * kMicrosecondsPerSecond) +
179      kWindowsEpochDeltaMicroseconds);
180}
181
182void Time::Explode(bool is_local, Exploded* exploded) const {
183  // Avoid rounding issues, by only putting the integral number of seconds
184  // (rounded towards -infinity) into a |CFAbsoluteTime| (which is a |double|).
185  int64 microsecond = us_ % kMicrosecondsPerSecond;
186  if (microsecond < 0)
187    microsecond += kMicrosecondsPerSecond;
188  CFAbsoluteTime seconds = ((us_ - microsecond) / kMicrosecondsPerSecond) -
189                           kWindowsEpochDeltaSeconds -
190                           kCFAbsoluteTimeIntervalSince1970;
191
192  base::ScopedCFTypeRef<CFTimeZoneRef> time_zone(
193      is_local ? CFTimeZoneCopySystem() : NULL);
194  CFGregorianDate date = CFAbsoluteTimeGetGregorianDate(seconds, time_zone);
195  // 1 = Monday, ..., 7 = Sunday.
196  int cf_day_of_week = CFAbsoluteTimeGetDayOfWeek(seconds, time_zone);
197
198  exploded->year = date.year;
199  exploded->month = date.month;
200  exploded->day_of_week = cf_day_of_week % 7;
201  exploded->day_of_month = date.day;
202  exploded->hour = date.hour;
203  exploded->minute = date.minute;
204  // Make sure seconds are rounded down towards -infinity.
205  exploded->second = floor(date.second);
206  // Calculate milliseconds ourselves, since we rounded the |seconds|, making
207  // sure to round towards -infinity.
208  exploded->millisecond =
209      (microsecond >= 0) ? microsecond / kMicrosecondsPerMillisecond :
210                           (microsecond - kMicrosecondsPerMillisecond + 1) /
211                               kMicrosecondsPerMillisecond;
212}
213
214// TimeTicks ------------------------------------------------------------------
215
216// static
217TimeTicks TimeTicks::Now() {
218  return TimeTicks(ComputeCurrentTicks());
219}
220
221// static
222TimeTicks TimeTicks::HighResNow() {
223  return Now();
224}
225
226// static
227bool TimeTicks::IsHighResNowFastAndReliable() {
228  return true;
229}
230
231// static
232TimeTicks TimeTicks::ThreadNow() {
233  return TimeTicks(ComputeThreadTicks());
234}
235
236// static
237TimeTicks TimeTicks::NowFromSystemTraceTime() {
238  return HighResNow();
239}
240
241}  // namespace base
242