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