Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(249)

Side by Side Diff: base/time/time_posix.cc

Issue 1569553005: Use base/time/time_posix.cc on OS X and iOS. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix compilation on Mac Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « base/time/time_mac.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "base/time/time.h" 5 #include "base/time/time.h"
6 6
7 #include <stdint.h> 7 #include <stdint.h>
8 #include <sys/time.h> 8 #include <sys/time.h>
9 #include <time.h> 9 #include <time.h>
10 #if defined(OS_ANDROID) && !defined(__LP64__) 10 #if defined(OS_ANDROID) && !defined(__LP64__)
11 #include <time64.h> 11 #include <time64.h>
12 #endif 12 #endif
13 #include <unistd.h> 13 #include <unistd.h>
14 14
15 #include <limits> 15 #include <limits>
16 #include <ostream> 16 #include <ostream>
17 17
18 #include "base/lazy_instance.h"
18 #include "base/logging.h" 19 #include "base/logging.h"
20 #include "base/synchronization/lock.h"
19 #include "build/build_config.h" 21 #include "build/build_config.h"
20 22
21 #if defined(OS_ANDROID) 23 #if defined(OS_ANDROID)
22 #include "base/os_compat_android.h" 24 #include "base/os_compat_android.h"
23 #elif defined(OS_NACL) 25 #elif defined(OS_NACL)
24 #include "base/os_compat_nacl.h" 26 #include "base/os_compat_nacl.h"
25 #endif 27 #elif defined(OS_MACOSX)
26 28 #include <mach/mach.h>
27 #if !defined(OS_MACOSX) 29 #include <mach/mach_time.h>
28 #include "base/lazy_instance.h" 30 #include <sys/sysctl.h>
29 #include "base/synchronization/lock.h" 31 #include "base/mac/mach_logging.h"
32 #include "base/mac/scoped_mach_port.h"
30 #endif 33 #endif
31 34
32 namespace { 35 namespace {
33 36
34 #if !defined(OS_MACOSX)
35 // This prevents a crash on traversing the environment global and looking up 37 // This prevents a crash on traversing the environment global and looking up
36 // the 'TZ' variable in libc. See: crbug.com/390567. 38 // the 'TZ' variable in libc. See: crbug.com/390567.
37 base::LazyInstance<base::Lock>::Leaky 39 base::LazyInstance<base::Lock>::Leaky
38 g_sys_time_to_time_struct_lock = LAZY_INSTANCE_INITIALIZER; 40 g_sys_time_to_time_struct_lock = LAZY_INSTANCE_INITIALIZER;
39 41
40 // Define a system-specific SysTime that wraps either to a time_t or 42 // Define a system-specific SysTime that wraps either to a time_t or
41 // a time64_t depending on the host system, and associated convertion. 43 // a time64_t depending on the host system, and associated convertion.
42 // See crbug.com/162007 44 // See crbug.com/162007
43 #if defined(OS_ANDROID) && !defined(__LP64__) 45 #if defined(OS_ANDROID) && !defined(__LP64__)
44 typedef time64_t SysTime; 46 typedef time64_t SysTime;
(...skipping 27 matching lines...) Expand all
72 74
73 void SysTimeToTimeStruct(SysTime t, struct tm* timestruct, bool is_local) { 75 void SysTimeToTimeStruct(SysTime t, struct tm* timestruct, bool is_local) {
74 base::AutoLock locked(g_sys_time_to_time_struct_lock.Get()); 76 base::AutoLock locked(g_sys_time_to_time_struct_lock.Get());
75 if (is_local) 77 if (is_local)
76 localtime_r(&t, timestruct); 78 localtime_r(&t, timestruct);
77 else 79 else
78 gmtime_r(&t, timestruct); 80 gmtime_r(&t, timestruct);
79 } 81 }
80 #endif // OS_ANDROID 82 #endif // OS_ANDROID
81 83
84 #if !defined(OS_MACOSX)
82 int64_t ConvertTimespecToMicros(const struct timespec& ts) { 85 int64_t ConvertTimespecToMicros(const struct timespec& ts) {
83 base::CheckedNumeric<int64_t> result(ts.tv_sec); 86 base::CheckedNumeric<int64_t> result(ts.tv_sec);
84 result *= base::Time::kMicrosecondsPerSecond; 87 result *= base::Time::kMicrosecondsPerSecond;
85 result += (ts.tv_nsec / base::Time::kNanosecondsPerMicrosecond); 88 result += (ts.tv_nsec / base::Time::kNanosecondsPerMicrosecond);
86 return result.ValueOrDie(); 89 return result.ValueOrDie();
87 } 90 }
88 91
89 // Helper function to get results from clock_gettime() and convert to a 92 // Helper function to get results from clock_gettime() and convert to a
90 // microsecond timebase. Minimum requirement is MONOTONIC_CLOCK to be supported 93 // microsecond timebase. Minimum requirement is MONOTONIC_CLOCK to be supported
91 // on the system. FreeBSD 6 has CLOCK_MONOTONIC but defines 94 // on the system. FreeBSD 6 has CLOCK_MONOTONIC but defines
92 // _POSIX_MONOTONIC_CLOCK to -1. 95 // _POSIX_MONOTONIC_CLOCK to -1.
93 #if (defined(OS_POSIX) && \ 96 #if (defined(OS_POSIX) && \
94 defined(_POSIX_MONOTONIC_CLOCK) && _POSIX_MONOTONIC_CLOCK >= 0) || \ 97 defined(_POSIX_MONOTONIC_CLOCK) && _POSIX_MONOTONIC_CLOCK >= 0) || \
95 defined(OS_BSD) || defined(OS_ANDROID) 98 defined(OS_BSD) || defined(OS_ANDROID)
96 int64_t ClockNow(clockid_t clk_id) { 99 int64_t ClockNow(clockid_t clk_id) {
97 struct timespec ts; 100 struct timespec ts;
98 if (clock_gettime(clk_id, &ts) != 0) { 101 if (clock_gettime(clk_id, &ts) != 0) {
99 NOTREACHED() << "clock_gettime(" << clk_id << ") failed."; 102 NOTREACHED() << "clock_gettime(" << clk_id << ") failed.";
100 return 0; 103 return 0;
101 } 104 }
102 return ConvertTimespecToMicros(ts); 105 return ConvertTimespecToMicros(ts);
103 } 106 }
104 #else // _POSIX_MONOTONIC_CLOCK 107 #else // _POSIX_MONOTONIC_CLOCK
105 #error No usable tick clock function on this platform. 108 #error No usable tick clock function on this platform.
106 #endif // _POSIX_MONOTONIC_CLOCK 109 #endif // _POSIX_MONOTONIC_CLOCK
107 #endif // !defined(OS_MACOSX) 110 #endif
111
112 int64_t ComputeCurrentTicks() {
113 #if defined(OS_IOS)
114 // On iOS mach_absolute_time stops while the device is sleeping. Instead use
115 // now - KERN_BOOTTIME to get a time difference that is not impacted by clock
116 // changes. KERN_BOOTTIME will be updated by the system whenever the system
117 // clock change.
118 struct timeval boottime;
119 int mib[2] = {CTL_KERN, KERN_BOOTTIME};
120 size_t size = sizeof(boottime);
121 int kr = sysctl(mib, arraysize(mib), &boottime, &size, NULL, 0);
122 DCHECK_EQ(KERN_SUCCESS, kr);
123 base::TimeDelta time_difference = base::Time::Now() -
124 (base::Time::FromTimeT(boottime.tv_sec) +
125 base::TimeDelta::FromMicroseconds(boottime.tv_usec));
126 return time_difference.InMicroseconds();
127 #elif defined(OS_MACOSX)
128 static mach_timebase_info_data_t timebase_info;
129 if (timebase_info.denom == 0) {
130 // Zero-initialization of statics guarantees that denom will be 0 before
131 // calling mach_timebase_info. mach_timebase_info will never set denom to
132 // 0 as that would be invalid, so the zero-check can be used to determine
133 // whether mach_timebase_info has already been called. This is
134 // recommended by Apple's QA1398.
135 kern_return_t kr = mach_timebase_info(&timebase_info);
136 MACH_DCHECK(kr == KERN_SUCCESS, kr) << "mach_timebase_info";
137 }
138
139 // mach_absolute_time is it when it comes to ticks on the Mac. Other calls
140 // with less precision (such as TickCount) just call through to
141 // mach_absolute_time.
142
143 // timebase_info converts absolute time tick units into nanoseconds. Convert
144 // to microseconds up front to stave off overflows.
145 base::CheckedNumeric<uint64_t> result(
146 mach_absolute_time() / base::Time::kNanosecondsPerMicrosecond);
147 result *= timebase_info.numer;
148 result /= timebase_info.denom;
149
150 // Don't bother with the rollover handling that the Windows version does.
151 // With numer and denom = 1 (the expected case), the 64-bit absolute time
152 // reported in nanoseconds is enough to last nearly 585 years.
153 return base::checked_cast<int64_t>(result.ValueOrDie());
154 #else
155 return ClockNow(CLOCK_MONOTONIC);
156 #endif
157 }
158
159 int64_t ComputeThreadTicks() {
160 #if defined(OS_IOS)
161 NOTREACHED();
162 return 0;
163 #elif defined(OS_MACOSX)
164 base::mac::ScopedMachSendRight thread(mach_thread_self());
165 mach_msg_type_number_t thread_info_count = THREAD_BASIC_INFO_COUNT;
166 thread_basic_info_data_t thread_info_data;
167
168 if (thread.get() == MACH_PORT_NULL) {
169 DLOG(ERROR) << "Failed to get mach_thread_self()";
170 return 0;
171 }
172
173 kern_return_t kr = thread_info(
174 thread.get(),
175 THREAD_BASIC_INFO,
176 reinterpret_cast<thread_info_t>(&thread_info_data),
177 &thread_info_count);
178 MACH_DCHECK(kr == KERN_SUCCESS, kr) << "thread_info";
179
180 base::CheckedNumeric<int64_t> absolute_micros(
181 thread_info_data.user_time.seconds);
182 absolute_micros *= base::Time::kMicrosecondsPerSecond;
183 absolute_micros += thread_info_data.user_time.microseconds;
184 return absolute_micros.ValueOrDie();
185 #elif (defined(_POSIX_THREAD_CPUTIME) && (_POSIX_THREAD_CPUTIME >= 0)) || \
186 defined(OS_ANDROID)
187 return ThreadTicks(ClockNow(CLOCK_THREAD_CPUTIME_ID));
188 #else
189 NOTREACHED();
190 return 0;
191 #endif
192 }
108 193
109 } // namespace 194 } // namespace
110 195
111 namespace base { 196 namespace base {
112 197
113 struct timespec TimeDelta::ToTimeSpec() const { 198 struct timespec TimeDelta::ToTimeSpec() const {
114 int64_t microseconds = InMicroseconds(); 199 int64_t microseconds = InMicroseconds();
115 time_t seconds = 0; 200 time_t seconds = 0;
116 if (microseconds >= Time::kMicrosecondsPerSecond) { 201 if (microseconds >= Time::kMicrosecondsPerSecond) {
117 seconds = InSeconds(); 202 seconds = InSeconds();
118 microseconds -= seconds * Time::kMicrosecondsPerSecond; 203 microseconds -= seconds * Time::kMicrosecondsPerSecond;
119 } 204 }
120 struct timespec result = 205 struct timespec result =
121 {seconds, 206 {seconds,
122 static_cast<long>(microseconds * Time::kNanosecondsPerMicrosecond)}; 207 static_cast<long>(microseconds * Time::kNanosecondsPerMicrosecond)};
123 return result; 208 return result;
124 } 209 }
125 210
126 #if !defined(OS_MACOSX)
127 // The Time routines in this file use standard POSIX routines, or almost- 211 // The Time routines in this file use standard POSIX routines, or almost-
128 // standard routines in the case of timegm. We need to use a Mach-specific 212 // standard routines in the case of timegm. We need to use a Mach-specific
129 // function for TimeTicks::Now() on Mac OS X. 213 // function for TimeTicks::Now() on Mac OS X.
130 214
131 // Time ----------------------------------------------------------------------- 215 // Time -----------------------------------------------------------------------
132 216
133 // Windows uses a Gregorian epoch of 1601. We need to match this internally 217 // Windows uses a Gregorian epoch of 1601. We need to match this internally
134 // so that our time representations match across all platforms. See bug 14734. 218 // so that our time representations match across all platforms. See bug 14734.
135 // irb(main):010:0> Time.at(0).getutc() 219 // irb(main):010:0> Time.at(0).getutc()
136 // => Thu Jan 01 00:00:00 UTC 1970 220 // => Thu Jan 01 00:00:00 UTC 1970
(...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after
301 } 385 }
302 386
303 // Adjust from Unix (1970) to Windows (1601) epoch. 387 // Adjust from Unix (1970) to Windows (1601) epoch.
304 return Time((milliseconds * kMicrosecondsPerMillisecond) + 388 return Time((milliseconds * kMicrosecondsPerMillisecond) +
305 kWindowsEpochDeltaMicroseconds); 389 kWindowsEpochDeltaMicroseconds);
306 } 390 }
307 391
308 // TimeTicks ------------------------------------------------------------------ 392 // TimeTicks ------------------------------------------------------------------
309 // static 393 // static
310 TimeTicks TimeTicks::Now() { 394 TimeTicks TimeTicks::Now() {
311 return TimeTicks(ClockNow(CLOCK_MONOTONIC)); 395 return TimeTicks(ComputeCurrentTicks());
312 } 396 }
313 397
314 // static 398 // static
315 bool TimeTicks::IsHighResolution() { 399 bool TimeTicks::IsHighResolution() {
316 return true; 400 return true;
317 } 401 }
318 402
319 // static 403 // static
320 ThreadTicks ThreadTicks::Now() { 404 ThreadTicks ThreadTicks::Now() {
321 #if (defined(_POSIX_THREAD_CPUTIME) && (_POSIX_THREAD_CPUTIME >= 0)) || \ 405 return ThreadTicks(ComputeThreadTicks());
322 defined(OS_ANDROID)
323 return ThreadTicks(ClockNow(CLOCK_THREAD_CPUTIME_ID));
324 #else
325 NOTREACHED();
326 return ThreadTicks();
327 #endif
328 } 406 }
329 407
330 #endif // !OS_MACOSX
331
332 // static 408 // static
333 Time Time::FromTimeVal(struct timeval t) { 409 Time Time::FromTimeVal(struct timeval t) {
334 DCHECK_LT(t.tv_usec, static_cast<int>(Time::kMicrosecondsPerSecond)); 410 DCHECK_LT(t.tv_usec, static_cast<int>(Time::kMicrosecondsPerSecond));
335 DCHECK_GE(t.tv_usec, 0); 411 DCHECK_GE(t.tv_usec, 0);
336 if (t.tv_usec == 0 && t.tv_sec == 0) 412 if (t.tv_usec == 0 && t.tv_sec == 0)
337 return Time(); 413 return Time();
338 if (t.tv_usec == static_cast<suseconds_t>(Time::kMicrosecondsPerSecond) - 1 && 414 if (t.tv_usec == static_cast<suseconds_t>(Time::kMicrosecondsPerSecond) - 1 &&
339 t.tv_sec == std::numeric_limits<time_t>::max()) 415 t.tv_sec == std::numeric_limits<time_t>::max())
340 return Max(); 416 return Max();
341 return Time((static_cast<int64_t>(t.tv_sec) * Time::kMicrosecondsPerSecond) + 417 return Time((static_cast<int64_t>(t.tv_sec) * Time::kMicrosecondsPerSecond) +
(...skipping 11 matching lines...) Expand all
353 result.tv_sec = std::numeric_limits<time_t>::max(); 429 result.tv_sec = std::numeric_limits<time_t>::max();
354 result.tv_usec = static_cast<suseconds_t>(Time::kMicrosecondsPerSecond) - 1; 430 result.tv_usec = static_cast<suseconds_t>(Time::kMicrosecondsPerSecond) - 1;
355 return result; 431 return result;
356 } 432 }
357 int64_t us = us_ - kTimeTToMicrosecondsOffset; 433 int64_t us = us_ - kTimeTToMicrosecondsOffset;
358 result.tv_sec = us / Time::kMicrosecondsPerSecond; 434 result.tv_sec = us / Time::kMicrosecondsPerSecond;
359 result.tv_usec = us % Time::kMicrosecondsPerSecond; 435 result.tv_usec = us % Time::kMicrosecondsPerSecond;
360 return result; 436 return result;
361 } 437 }
362 438
439 #if defined(OS_MACOSX)
440 // static
441 Time Time::FromCFAbsoluteTime(CFAbsoluteTime t) {
442 static_assert(std::numeric_limits<CFAbsoluteTime>::has_infinity,
443 "CFAbsoluteTime must have an infinity value");
444 if (t == 0)
445 return Time(); // Consider 0 as a null Time.
446 if (t == std::numeric_limits<CFAbsoluteTime>::infinity())
447 return Max();
448 return Time(static_cast<int64_t>((t + kCFAbsoluteTimeIntervalSince1970) *
449 kMicrosecondsPerSecond) +
450 kWindowsEpochDeltaMicroseconds);
451 }
452
453 CFAbsoluteTime Time::ToCFAbsoluteTime() const {
454 static_assert(std::numeric_limits<CFAbsoluteTime>::has_infinity,
455 "CFAbsoluteTime must have an infinity value");
456 if (is_null())
457 return 0; // Consider 0 as a null Time.
458 if (is_max())
459 return std::numeric_limits<CFAbsoluteTime>::infinity();
460 return (static_cast<CFAbsoluteTime>(us_ - kWindowsEpochDeltaMicroseconds) /
461 kMicrosecondsPerSecond) - kCFAbsoluteTimeIntervalSince1970;
462 }
463 #endif // OS_MACOSX
464
363 } // namespace base 465 } // namespace base
OLDNEW
« no previous file with comments | « base/time/time_mac.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698