summaryrefslogtreecommitdiffstats
path: root/base/time_win.cc
diff options
context:
space:
mode:
authordeanm@google.com <deanm@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2008-09-02 08:28:37 +0000
committerdeanm@google.com <deanm@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2008-09-02 08:28:37 +0000
commit5f6eee53a4ba6995b68a8ec6f22d3281529060c8 (patch)
tree1464c7ca7fdaaa3b7f387da90db9667988c1f25d /base/time_win.cc
parent38f70a3e2ade7049c09831ed8f5b8ea90d9e68d6 (diff)
downloadchromium_src-5f6eee53a4ba6995b68a8ec6f22d3281529060c8.zip
chromium_src-5f6eee53a4ba6995b68a8ec6f22d3281529060c8.tar.gz
chromium_src-5f6eee53a4ba6995b68a8ec6f22d3281529060c8.tar.bz2
Cleanup some Windows TimeTicks functions. Move TickTicks::Now and TicksTicks::UnreliableHighResNow to Singletons, which cleans up the code and removes some possible unsafe cross-thread access.
Move the Windows-specific rollover tests to time_unittests_win. git-svn-id: svn://svn.chromium.org/chrome/trunk/src@1633 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base/time_win.cc')
-rw-r--r--base/time_win.cc125
1 files changed, 70 insertions, 55 deletions
diff --git a/base/time_win.cc b/base/time_win.cc
index 9d38993..a919395 100644
--- a/base/time_win.cc
+++ b/base/time_win.cc
@@ -7,9 +7,11 @@
#pragma comment(lib, "winmm.lib")
#include <windows.h>
#include <mmsystem.h>
+
#include "base/basictypes.h"
#include "base/lock.h"
#include "base/logging.h"
+#include "base/singleton.h"
namespace {
@@ -122,53 +124,39 @@ void Time::Explode(bool is_local, Exploded* exploded) const {
}
// TimeTicks ------------------------------------------------------------------
-
-TimeTicks::TickFunction TimeTicks::tick_function_=
+TimeTicks::TickFunction TimeTicks::tick_function_ =
reinterpret_cast<TickFunction>(&timeGetTime);
-// static
-TimeTicks TimeTicks::Now() {
- // Uses the multimedia timers on Windows to get a higher resolution clock.
- // timeGetTime() provides a resolution which is variable depending on
- // hardware and system configuration. It can also be changed by other
- // apps. This class does not attempt to change the resolution of the
- // timer, because we don't want to affect other applications.
-
- // timeGetTime() should at least be accurate to ~5ms on all systems.
- // timeGetTime() returns a 32-bit millisecond counter which has rollovers
- // every ~49 days.
- static DWORD last_tick_count = 0;
- static int64 tick_rollover_accum = 0;
- static Lock* tick_lock = NULL; // To protect during rollover periods.
-
- // Lazily create the lock we use.
- if (!tick_lock) {
- Lock* new_lock = new Lock;
- if (InterlockedCompareExchangePointer(
- reinterpret_cast<PVOID*>(&tick_lock), new_lock, NULL)) {
- delete new_lock;
- }
- }
+namespace {
- // Atomically protect the low and high 32bit values for time.
- // In the future we may be able to optimize with
- // InterlockedCompareExchange64, but that doesn't work on XP.
- DWORD tick_count;
- int64 rollover_count;
- {
- AutoLock lock(*tick_lock);
- tick_count = tick_function_();
- if (tick_count < last_tick_count)
- tick_rollover_accum += GG_INT64_C(0x100000000);
-
- last_tick_count = tick_count;
- rollover_count = tick_rollover_accum;
+// We use timeGetTime() to implement TimeTicks::Now(). This can be problematic
+// because it returns the number of millisecond since Windows has started, which
+// will roll over the 32-bit value every ~49 days. We try to track rollover
+// ourselves, which works if TimeTicks::Now() is called at least every 49 days.
+class NowSingleton {
+ public:
+ NowSingleton()
+ : rollover_(TimeDelta::FromMilliseconds(0)),
+ last_seen_(TimeTicks::tick_function_()) { }
+
+ TimeDelta Now() {
+ AutoLock locked(lock_);
+ // We should hold the lock while calling tick_function_ to make sure that
+ // we keep our last_seen_ stay correctly in sync.
+ DWORD now = TimeTicks::tick_function_();
+ if (now < last_seen_)
+ rollover_ += TimeDelta::FromMilliseconds(0x100000000I64); // ~49.7 days.
+ last_seen_ = now;
+ return TimeDelta::FromMilliseconds(now) + rollover_;
}
- // GetTickCount returns milliseconds, we want microseconds.
- return TimeTicks((tick_count + rollover_count) *
- Time::kMicrosecondsPerMillisecond);
-}
+ private:
+ Lock lock_; // To protected last_seen_ and rollover_.
+ TimeDelta rollover_; // Accumulation of time lost do to rollover.
+ DWORD last_seen_; // The last timeGetTime value we saw, to detect rollover.
+
+ DISALLOW_COPY_AND_ASSIGN(NowSingleton);
+};
// Overview of time counters:
// (1) CPU cycle counter. (Retrieved via RDTSC)
@@ -198,23 +186,50 @@ TimeTicks TimeTicks::Now() {
// (3) System time. The system time provides a low-resolution (typically 10ms
// to 55 milliseconds) time stamp but is comparatively less expensive to
// retrieve and more reliable.
+class UnreliableHighResNowSingleton {
+ public:
+ UnreliableHighResNowSingleton() : ticks_per_microsecond_(0) {
+ LARGE_INTEGER ticks_per_sec = {0};
+ if (!QueryPerformanceFrequency(&ticks_per_sec))
+ return; // Broken, we don't guarantee this function works.
+ ticks_per_microsecond_ =
+ ticks_per_sec.QuadPart / Time::kMicrosecondsPerSecond;
+ }
-// static
-TimeTicks TimeTicks::UnreliableHighResNow() {
+ bool IsBroken() {
+ return ticks_per_microsecond_ == 0;
+ }
+
+ TimeDelta Now() {
+ LARGE_INTEGER now;
+ QueryPerformanceCounter(&now);
+ return TimeDelta::FromMicroseconds(now.QuadPart / ticks_per_microsecond_);
+ }
+
+ private:
// Cached clock frequency -> microseconds. This assumes that the clock
// frequency is faster than one microsecond (which is 1MHz, should be OK).
- static int64 ticks_per_microsecond = 0;
+ int64 ticks_per_microsecond_; // 0 indicates QPF failed and we're broken.
- if (ticks_per_microsecond == 0) {
- LARGE_INTEGER ticks_per_sec = { 0, 0 };
- if (!QueryPerformanceFrequency(&ticks_per_sec))
- return TimeTicks(0); // Broken, we don't guarantee this function works.
- ticks_per_microsecond =
- ticks_per_sec.QuadPart / Time::kMicrosecondsPerSecond;
- }
+ DISALLOW_COPY_AND_ASSIGN(UnreliableHighResNowSingleton);
+};
+
+} // namespace
- LARGE_INTEGER now;
- QueryPerformanceCounter(&now);
- return TimeTicks(now.QuadPart / ticks_per_microsecond);
+// static
+TimeTicks TimeTicks::Now() {
+ return TimeTicks() + Singleton<NowSingleton>::get()->Now();
}
+// static
+TimeTicks TimeTicks::UnreliableHighResNow() {
+ UnreliableHighResNowSingleton* now =
+ Singleton<UnreliableHighResNowSingleton>::get();
+
+ if (now->IsBroken()) {
+ NOTREACHED() << "QueryPerformanceCounter is broken.";
+ return TimeTicks(0);
+ }
+
+ return TimeTicks() + now->Now();
+}