1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/sandbox/chromium/base/time/time_win.cc Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,532 @@ 1.4 +// Copyright (c) 2012 The Chromium Authors. All rights reserved. 1.5 +// Use of this source code is governed by a BSD-style license that can be 1.6 +// found in the LICENSE file. 1.7 + 1.8 + 1.9 +// Windows Timer Primer 1.10 +// 1.11 +// A good article: http://www.ddj.com/windows/184416651 1.12 +// A good mozilla bug: http://bugzilla.mozilla.org/show_bug.cgi?id=363258 1.13 +// 1.14 +// The default windows timer, GetSystemTimeAsFileTime is not very precise. 1.15 +// It is only good to ~15.5ms. 1.16 +// 1.17 +// QueryPerformanceCounter is the logical choice for a high-precision timer. 1.18 +// However, it is known to be buggy on some hardware. Specifically, it can 1.19 +// sometimes "jump". On laptops, QPC can also be very expensive to call. 1.20 +// It's 3-4x slower than timeGetTime() on desktops, but can be 10x slower 1.21 +// on laptops. A unittest exists which will show the relative cost of various 1.22 +// timers on any system. 1.23 +// 1.24 +// The next logical choice is timeGetTime(). timeGetTime has a precision of 1.25 +// 1ms, but only if you call APIs (timeBeginPeriod()) which affect all other 1.26 +// applications on the system. By default, precision is only 15.5ms. 1.27 +// Unfortunately, we don't want to call timeBeginPeriod because we don't 1.28 +// want to affect other applications. Further, on mobile platforms, use of 1.29 +// faster multimedia timers can hurt battery life. See the intel 1.30 +// article about this here: 1.31 +// http://softwarecommunity.intel.com/articles/eng/1086.htm 1.32 +// 1.33 +// To work around all this, we're going to generally use timeGetTime(). We 1.34 +// will only increase the system-wide timer if we're not running on battery 1.35 +// power. Using timeBeginPeriod(1) is a requirement in order to make our 1.36 +// message loop waits have the same resolution that our time measurements 1.37 +// do. Otherwise, WaitForSingleObject(..., 1) will no less than 15ms when 1.38 +// there is nothing else to waken the Wait. 1.39 + 1.40 +#include "base/time/time.h" 1.41 + 1.42 +#pragma comment(lib, "winmm.lib") 1.43 +#include <windows.h> 1.44 +#include <mmsystem.h> 1.45 + 1.46 +#include "base/basictypes.h" 1.47 +#include "base/cpu.h" 1.48 +#include "base/logging.h" 1.49 +#include "base/memory/singleton.h" 1.50 +#include "base/synchronization/lock.h" 1.51 + 1.52 +using base::Time; 1.53 +using base::TimeDelta; 1.54 +using base::TimeTicks; 1.55 + 1.56 +namespace { 1.57 + 1.58 +// From MSDN, FILETIME "Contains a 64-bit value representing the number of 1.59 +// 100-nanosecond intervals since January 1, 1601 (UTC)." 1.60 +int64 FileTimeToMicroseconds(const FILETIME& ft) { 1.61 + // Need to bit_cast to fix alignment, then divide by 10 to convert 1.62 + // 100-nanoseconds to milliseconds. This only works on little-endian 1.63 + // machines. 1.64 + return bit_cast<int64, FILETIME>(ft) / 10; 1.65 +} 1.66 + 1.67 +void MicrosecondsToFileTime(int64 us, FILETIME* ft) { 1.68 + DCHECK_GE(us, 0LL) << "Time is less than 0, negative values are not " 1.69 + "representable in FILETIME"; 1.70 + 1.71 + // Multiply by 10 to convert milliseconds to 100-nanoseconds. Bit_cast will 1.72 + // handle alignment problems. This only works on little-endian machines. 1.73 + *ft = bit_cast<FILETIME, int64>(us * 10); 1.74 +} 1.75 + 1.76 +int64 CurrentWallclockMicroseconds() { 1.77 + FILETIME ft; 1.78 + ::GetSystemTimeAsFileTime(&ft); 1.79 + return FileTimeToMicroseconds(ft); 1.80 +} 1.81 + 1.82 +// Time between resampling the un-granular clock for this API. 60 seconds. 1.83 +const int kMaxMillisecondsToAvoidDrift = 60 * Time::kMillisecondsPerSecond; 1.84 + 1.85 +int64 initial_time = 0; 1.86 +TimeTicks initial_ticks; 1.87 + 1.88 +void InitializeClock() { 1.89 + initial_ticks = TimeTicks::Now(); 1.90 + initial_time = CurrentWallclockMicroseconds(); 1.91 +} 1.92 + 1.93 +} // namespace 1.94 + 1.95 +// Time ----------------------------------------------------------------------- 1.96 + 1.97 +// The internal representation of Time uses FILETIME, whose epoch is 1601-01-01 1.98 +// 00:00:00 UTC. ((1970-1601)*365+89)*24*60*60*1000*1000, where 89 is the 1.99 +// number of leap year days between 1601 and 1970: (1970-1601)/4 excluding 1.100 +// 1700, 1800, and 1900. 1.101 +// static 1.102 +const int64 Time::kTimeTToMicrosecondsOffset = GG_INT64_C(11644473600000000); 1.103 + 1.104 +bool Time::high_resolution_timer_enabled_ = false; 1.105 +int Time::high_resolution_timer_activated_ = 0; 1.106 + 1.107 +// static 1.108 +Time Time::Now() { 1.109 + if (initial_time == 0) 1.110 + InitializeClock(); 1.111 + 1.112 + // We implement time using the high-resolution timers so that we can get 1.113 + // timeouts which are smaller than 10-15ms. If we just used 1.114 + // CurrentWallclockMicroseconds(), we'd have the less-granular timer. 1.115 + // 1.116 + // To make this work, we initialize the clock (initial_time) and the 1.117 + // counter (initial_ctr). To compute the initial time, we can check 1.118 + // the number of ticks that have elapsed, and compute the delta. 1.119 + // 1.120 + // To avoid any drift, we periodically resync the counters to the system 1.121 + // clock. 1.122 + while (true) { 1.123 + TimeTicks ticks = TimeTicks::Now(); 1.124 + 1.125 + // Calculate the time elapsed since we started our timer 1.126 + TimeDelta elapsed = ticks - initial_ticks; 1.127 + 1.128 + // Check if enough time has elapsed that we need to resync the clock. 1.129 + if (elapsed.InMilliseconds() > kMaxMillisecondsToAvoidDrift) { 1.130 + InitializeClock(); 1.131 + continue; 1.132 + } 1.133 + 1.134 + return Time(elapsed + Time(initial_time)); 1.135 + } 1.136 +} 1.137 + 1.138 +// static 1.139 +Time Time::NowFromSystemTime() { 1.140 + // Force resync. 1.141 + InitializeClock(); 1.142 + return Time(initial_time); 1.143 +} 1.144 + 1.145 +// static 1.146 +Time Time::FromFileTime(FILETIME ft) { 1.147 + if (bit_cast<int64, FILETIME>(ft) == 0) 1.148 + return Time(); 1.149 + if (ft.dwHighDateTime == std::numeric_limits<DWORD>::max() && 1.150 + ft.dwLowDateTime == std::numeric_limits<DWORD>::max()) 1.151 + return Max(); 1.152 + return Time(FileTimeToMicroseconds(ft)); 1.153 +} 1.154 + 1.155 +FILETIME Time::ToFileTime() const { 1.156 + if (is_null()) 1.157 + return bit_cast<FILETIME, int64>(0); 1.158 + if (is_max()) { 1.159 + FILETIME result; 1.160 + result.dwHighDateTime = std::numeric_limits<DWORD>::max(); 1.161 + result.dwLowDateTime = std::numeric_limits<DWORD>::max(); 1.162 + return result; 1.163 + } 1.164 + FILETIME utc_ft; 1.165 + MicrosecondsToFileTime(us_, &utc_ft); 1.166 + return utc_ft; 1.167 +} 1.168 + 1.169 +// static 1.170 +void Time::EnableHighResolutionTimer(bool enable) { 1.171 + // Test for single-threaded access. 1.172 + static PlatformThreadId my_thread = PlatformThread::CurrentId(); 1.173 + DCHECK(PlatformThread::CurrentId() == my_thread); 1.174 + 1.175 + if (high_resolution_timer_enabled_ == enable) 1.176 + return; 1.177 + 1.178 + high_resolution_timer_enabled_ = enable; 1.179 +} 1.180 + 1.181 +// static 1.182 +bool Time::ActivateHighResolutionTimer(bool activating) { 1.183 + if (!high_resolution_timer_enabled_ && activating) 1.184 + return false; 1.185 + 1.186 + // Using anything other than 1ms makes timers granular 1.187 + // to that interval. 1.188 + const int kMinTimerIntervalMs = 1; 1.189 + MMRESULT result; 1.190 + if (activating) { 1.191 + result = timeBeginPeriod(kMinTimerIntervalMs); 1.192 + high_resolution_timer_activated_++; 1.193 + } else { 1.194 + result = timeEndPeriod(kMinTimerIntervalMs); 1.195 + high_resolution_timer_activated_--; 1.196 + } 1.197 + return result == TIMERR_NOERROR; 1.198 +} 1.199 + 1.200 +// static 1.201 +bool Time::IsHighResolutionTimerInUse() { 1.202 + // Note: we should track the high_resolution_timer_activated_ value 1.203 + // under a lock if we want it to be accurate in a system with multiple 1.204 + // message loops. We don't do that - because we don't want to take the 1.205 + // expense of a lock for this. We *only* track this value so that unit 1.206 + // tests can see if the high resolution timer is on or off. 1.207 + return high_resolution_timer_enabled_ && 1.208 + high_resolution_timer_activated_ > 0; 1.209 +} 1.210 + 1.211 +// static 1.212 +Time Time::FromExploded(bool is_local, const Exploded& exploded) { 1.213 + // Create the system struct representing our exploded time. It will either be 1.214 + // in local time or UTC. 1.215 + SYSTEMTIME st; 1.216 + st.wYear = exploded.year; 1.217 + st.wMonth = exploded.month; 1.218 + st.wDayOfWeek = exploded.day_of_week; 1.219 + st.wDay = exploded.day_of_month; 1.220 + st.wHour = exploded.hour; 1.221 + st.wMinute = exploded.minute; 1.222 + st.wSecond = exploded.second; 1.223 + st.wMilliseconds = exploded.millisecond; 1.224 + 1.225 + FILETIME ft; 1.226 + bool success = true; 1.227 + // Ensure that it's in UTC. 1.228 + if (is_local) { 1.229 + SYSTEMTIME utc_st; 1.230 + success = TzSpecificLocalTimeToSystemTime(NULL, &st, &utc_st) && 1.231 + SystemTimeToFileTime(&utc_st, &ft); 1.232 + } else { 1.233 + success = !!SystemTimeToFileTime(&st, &ft); 1.234 + } 1.235 + 1.236 + if (!success) { 1.237 + NOTREACHED() << "Unable to convert time"; 1.238 + return Time(0); 1.239 + } 1.240 + return Time(FileTimeToMicroseconds(ft)); 1.241 +} 1.242 + 1.243 +void Time::Explode(bool is_local, Exploded* exploded) const { 1.244 + if (us_ < 0LL) { 1.245 + // We are not able to convert it to FILETIME. 1.246 + ZeroMemory(exploded, sizeof(*exploded)); 1.247 + return; 1.248 + } 1.249 + 1.250 + // FILETIME in UTC. 1.251 + FILETIME utc_ft; 1.252 + MicrosecondsToFileTime(us_, &utc_ft); 1.253 + 1.254 + // FILETIME in local time if necessary. 1.255 + bool success = true; 1.256 + // FILETIME in SYSTEMTIME (exploded). 1.257 + SYSTEMTIME st; 1.258 + if (is_local) { 1.259 + SYSTEMTIME utc_st; 1.260 + // We don't use FileTimeToLocalFileTime here, since it uses the current 1.261 + // settings for the time zone and daylight saving time. Therefore, if it is 1.262 + // daylight saving time, it will take daylight saving time into account, 1.263 + // even if the time you are converting is in standard time. 1.264 + success = FileTimeToSystemTime(&utc_ft, &utc_st) && 1.265 + SystemTimeToTzSpecificLocalTime(NULL, &utc_st, &st); 1.266 + } else { 1.267 + success = !!FileTimeToSystemTime(&utc_ft, &st); 1.268 + } 1.269 + 1.270 + if (!success) { 1.271 + NOTREACHED() << "Unable to convert time, don't know why"; 1.272 + ZeroMemory(exploded, sizeof(*exploded)); 1.273 + return; 1.274 + } 1.275 + 1.276 + exploded->year = st.wYear; 1.277 + exploded->month = st.wMonth; 1.278 + exploded->day_of_week = st.wDayOfWeek; 1.279 + exploded->day_of_month = st.wDay; 1.280 + exploded->hour = st.wHour; 1.281 + exploded->minute = st.wMinute; 1.282 + exploded->second = st.wSecond; 1.283 + exploded->millisecond = st.wMilliseconds; 1.284 +} 1.285 + 1.286 +// TimeTicks ------------------------------------------------------------------ 1.287 +namespace { 1.288 + 1.289 +// We define a wrapper to adapt between the __stdcall and __cdecl call of the 1.290 +// mock function, and to avoid a static constructor. Assigning an import to a 1.291 +// function pointer directly would require setup code to fetch from the IAT. 1.292 +DWORD timeGetTimeWrapper() { 1.293 + return timeGetTime(); 1.294 +} 1.295 + 1.296 +DWORD (*tick_function)(void) = &timeGetTimeWrapper; 1.297 + 1.298 +// Accumulation of time lost due to rollover (in milliseconds). 1.299 +int64 rollover_ms = 0; 1.300 + 1.301 +// The last timeGetTime value we saw, to detect rollover. 1.302 +DWORD last_seen_now = 0; 1.303 + 1.304 +// Lock protecting rollover_ms and last_seen_now. 1.305 +// Note: this is a global object, and we usually avoid these. However, the time 1.306 +// code is low-level, and we don't want to use Singletons here (it would be too 1.307 +// easy to use a Singleton without even knowing it, and that may lead to many 1.308 +// gotchas). Its impact on startup time should be negligible due to low-level 1.309 +// nature of time code. 1.310 +base::Lock rollover_lock; 1.311 + 1.312 +// We use timeGetTime() to implement TimeTicks::Now(). This can be problematic 1.313 +// because it returns the number of milliseconds since Windows has started, 1.314 +// which will roll over the 32-bit value every ~49 days. We try to track 1.315 +// rollover ourselves, which works if TimeTicks::Now() is called at least every 1.316 +// 49 days. 1.317 +TimeDelta RolloverProtectedNow() { 1.318 + base::AutoLock locked(rollover_lock); 1.319 + // We should hold the lock while calling tick_function to make sure that 1.320 + // we keep last_seen_now stay correctly in sync. 1.321 + DWORD now = tick_function(); 1.322 + if (now < last_seen_now) 1.323 + rollover_ms += 0x100000000I64; // ~49.7 days. 1.324 + last_seen_now = now; 1.325 + return TimeDelta::FromMilliseconds(now + rollover_ms); 1.326 +} 1.327 + 1.328 +bool IsBuggyAthlon(const base::CPU& cpu) { 1.329 + // On Athlon X2 CPUs (e.g. model 15) QueryPerformanceCounter is 1.330 + // unreliable. Fallback to low-res clock. 1.331 + return cpu.vendor_name() == "AuthenticAMD" && cpu.family() == 15; 1.332 +} 1.333 + 1.334 +// Overview of time counters: 1.335 +// (1) CPU cycle counter. (Retrieved via RDTSC) 1.336 +// The CPU counter provides the highest resolution time stamp and is the least 1.337 +// expensive to retrieve. However, the CPU counter is unreliable and should not 1.338 +// be used in production. Its biggest issue is that it is per processor and it 1.339 +// is not synchronized between processors. Also, on some computers, the counters 1.340 +// will change frequency due to thermal and power changes, and stop in some 1.341 +// states. 1.342 +// 1.343 +// (2) QueryPerformanceCounter (QPC). The QPC counter provides a high- 1.344 +// resolution (100 nanoseconds) time stamp but is comparatively more expensive 1.345 +// to retrieve. What QueryPerformanceCounter actually does is up to the HAL. 1.346 +// (with some help from ACPI). 1.347 +// According to http://blogs.msdn.com/oldnewthing/archive/2005/09/02/459952.aspx 1.348 +// in the worst case, it gets the counter from the rollover interrupt on the 1.349 +// programmable interrupt timer. In best cases, the HAL may conclude that the 1.350 +// RDTSC counter runs at a constant frequency, then it uses that instead. On 1.351 +// multiprocessor machines, it will try to verify the values returned from 1.352 +// RDTSC on each processor are consistent with each other, and apply a handful 1.353 +// of workarounds for known buggy hardware. In other words, QPC is supposed to 1.354 +// give consistent result on a multiprocessor computer, but it is unreliable in 1.355 +// reality due to bugs in BIOS or HAL on some, especially old computers. 1.356 +// With recent updates on HAL and newer BIOS, QPC is getting more reliable but 1.357 +// it should be used with caution. 1.358 +// 1.359 +// (3) System time. The system time provides a low-resolution (typically 10ms 1.360 +// to 55 milliseconds) time stamp but is comparatively less expensive to 1.361 +// retrieve and more reliable. 1.362 +class HighResNowSingleton { 1.363 + public: 1.364 + static HighResNowSingleton* GetInstance() { 1.365 + return Singleton<HighResNowSingleton>::get(); 1.366 + } 1.367 + 1.368 + bool IsUsingHighResClock() { 1.369 + return ticks_per_second_ != 0.0; 1.370 + } 1.371 + 1.372 + void DisableHighResClock() { 1.373 + ticks_per_second_ = 0.0; 1.374 + } 1.375 + 1.376 + TimeDelta Now() { 1.377 + if (IsUsingHighResClock()) 1.378 + return TimeDelta::FromMicroseconds(UnreliableNow()); 1.379 + 1.380 + // Just fallback to the slower clock. 1.381 + return RolloverProtectedNow(); 1.382 + } 1.383 + 1.384 + int64 GetQPCDriftMicroseconds() { 1.385 + if (!IsUsingHighResClock()) 1.386 + return 0; 1.387 + return abs((UnreliableNow() - ReliableNow()) - skew_); 1.388 + } 1.389 + 1.390 + int64 QPCValueToMicroseconds(LONGLONG qpc_value) { 1.391 + if (!ticks_per_second_) 1.392 + return 0; 1.393 + 1.394 + // Intentionally calculate microseconds in a round about manner to avoid 1.395 + // overflow and precision issues. Think twice before simplifying! 1.396 + int64 whole_seconds = qpc_value / ticks_per_second_; 1.397 + int64 leftover_ticks = qpc_value % ticks_per_second_; 1.398 + int64 microseconds = (whole_seconds * Time::kMicrosecondsPerSecond) + 1.399 + ((leftover_ticks * Time::kMicrosecondsPerSecond) / 1.400 + ticks_per_second_); 1.401 + return microseconds; 1.402 + } 1.403 + 1.404 + private: 1.405 + HighResNowSingleton() 1.406 + : ticks_per_second_(0), 1.407 + skew_(0) { 1.408 + InitializeClock(); 1.409 + 1.410 + base::CPU cpu; 1.411 + if (IsBuggyAthlon(cpu)) 1.412 + DisableHighResClock(); 1.413 + } 1.414 + 1.415 + // Synchronize the QPC clock with GetSystemTimeAsFileTime. 1.416 + void InitializeClock() { 1.417 + LARGE_INTEGER ticks_per_sec = {0}; 1.418 + if (!QueryPerformanceFrequency(&ticks_per_sec)) 1.419 + return; // Broken, we don't guarantee this function works. 1.420 + ticks_per_second_ = ticks_per_sec.QuadPart; 1.421 + 1.422 + skew_ = UnreliableNow() - ReliableNow(); 1.423 + } 1.424 + 1.425 + // Get the number of microseconds since boot in an unreliable fashion. 1.426 + int64 UnreliableNow() { 1.427 + LARGE_INTEGER now; 1.428 + QueryPerformanceCounter(&now); 1.429 + return QPCValueToMicroseconds(now.QuadPart); 1.430 + } 1.431 + 1.432 + // Get the number of microseconds since boot in a reliable fashion. 1.433 + int64 ReliableNow() { 1.434 + return RolloverProtectedNow().InMicroseconds(); 1.435 + } 1.436 + 1.437 + int64 ticks_per_second_; // 0 indicates QPF failed and we're broken. 1.438 + int64 skew_; // Skew between lo-res and hi-res clocks (for debugging). 1.439 + 1.440 + friend struct DefaultSingletonTraits<HighResNowSingleton>; 1.441 +}; 1.442 + 1.443 +TimeDelta HighResNowWrapper() { 1.444 + return HighResNowSingleton::GetInstance()->Now(); 1.445 +} 1.446 + 1.447 +typedef TimeDelta (*NowFunction)(void); 1.448 +NowFunction now_function = RolloverProtectedNow; 1.449 + 1.450 +bool CPUReliablySupportsHighResTime() { 1.451 + base::CPU cpu; 1.452 + if (!cpu.has_non_stop_time_stamp_counter()) 1.453 + return false; 1.454 + 1.455 + if (IsBuggyAthlon(cpu)) 1.456 + return false; 1.457 + 1.458 + return true; 1.459 +} 1.460 + 1.461 +} // namespace 1.462 + 1.463 +// static 1.464 +TimeTicks::TickFunctionType TimeTicks::SetMockTickFunction( 1.465 + TickFunctionType ticker) { 1.466 + base::AutoLock locked(rollover_lock); 1.467 + TickFunctionType old = tick_function; 1.468 + tick_function = ticker; 1.469 + rollover_ms = 0; 1.470 + last_seen_now = 0; 1.471 + return old; 1.472 +} 1.473 + 1.474 +// static 1.475 +bool TimeTicks::SetNowIsHighResNowIfSupported() { 1.476 + if (!CPUReliablySupportsHighResTime()) { 1.477 + return false; 1.478 + } 1.479 + 1.480 + now_function = HighResNowWrapper; 1.481 + return true; 1.482 +} 1.483 + 1.484 +// static 1.485 +TimeTicks TimeTicks::Now() { 1.486 + return TimeTicks() + now_function(); 1.487 +} 1.488 + 1.489 +// static 1.490 +TimeTicks TimeTicks::HighResNow() { 1.491 + return TimeTicks() + HighResNowSingleton::GetInstance()->Now(); 1.492 +} 1.493 + 1.494 +// static 1.495 +TimeTicks TimeTicks::ThreadNow() { 1.496 + NOTREACHED(); 1.497 + return TimeTicks(); 1.498 +} 1.499 + 1.500 +// static 1.501 +TimeTicks TimeTicks::NowFromSystemTraceTime() { 1.502 + return HighResNow(); 1.503 +} 1.504 + 1.505 +// static 1.506 +int64 TimeTicks::GetQPCDriftMicroseconds() { 1.507 + return HighResNowSingleton::GetInstance()->GetQPCDriftMicroseconds(); 1.508 +} 1.509 + 1.510 +// static 1.511 +TimeTicks TimeTicks::FromQPCValue(LONGLONG qpc_value) { 1.512 + return TimeTicks( 1.513 + HighResNowSingleton::GetInstance()->QPCValueToMicroseconds(qpc_value)); 1.514 +} 1.515 + 1.516 +// static 1.517 +bool TimeTicks::IsHighResClockWorking() { 1.518 + return HighResNowSingleton::GetInstance()->IsUsingHighResClock(); 1.519 +} 1.520 + 1.521 +TimeTicks TimeTicks::UnprotectedNow() { 1.522 + if (now_function == HighResNowWrapper) { 1.523 + return Now(); 1.524 + } else { 1.525 + return TimeTicks() + TimeDelta::FromMilliseconds(timeGetTime()); 1.526 + } 1.527 +} 1.528 + 1.529 +// TimeDelta ------------------------------------------------------------------ 1.530 + 1.531 +// static 1.532 +TimeDelta TimeDelta::FromQPCValue(LONGLONG qpc_value) { 1.533 + return TimeDelta( 1.534 + HighResNowSingleton::GetInstance()->QPCValueToMicroseconds(qpc_value)); 1.535 +}