1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
4 // Use of this source code is governed by a BSD-style license that can be
5 // found in the LICENSE file.
6 
7 // Windows Timer Primer
8 //
9 // A good article:  http://www.ddj.com/windows/184416651
10 // A good mozilla bug:  http://bugzilla.mozilla.org/show_bug.cgi?id=363258
11 //
12 // The default windows timer, GetSystemTimeAsFileTime is not very precise.
13 // It is only good to ~15.5ms.
14 //
15 // QueryPerformanceCounter is the logical choice for a high-precision timer.
16 // However, it is known to be buggy on some hardware.  Specifically, it can
17 // sometimes "jump".  On laptops, QPC can also be very expensive to call.
18 // It's 3-4x slower than timeGetTime() on desktops, but can be 10x slower
19 // on laptops.  A unittest exists which will show the relative cost of various
20 // timers on any system.
21 //
22 // The next logical choice is timeGetTime().  timeGetTime has a precision of
23 // 1ms, but only if you call APIs (timeBeginPeriod()) which affect all other
24 // applications on the system.  By default, precision is only 15.5ms.
25 // Unfortunately, we don't want to call timeBeginPeriod because we don't
26 // want to affect other applications.  Further, on mobile platforms, use of
27 // faster multimedia timers can hurt battery life.  See the intel
28 // article about this here:
29 // http://softwarecommunity.intel.com/articles/eng/1086.htm
30 //
31 // To work around all this, we're going to generally use timeGetTime().  We
32 // will only increase the system-wide timer if we're not running on battery
33 // power.  Using timeBeginPeriod(1) is a requirement in order to make our
34 // message loop waits have the same resolution that our time measurements
35 // do.  Otherwise, WaitForSingleObject(..., 1) will no less than 15ms when
36 // there is nothing else to waken the Wait.
37 
38 #include "base/time.h"
39 
40 #ifndef __MINGW32__
41 #  pragma comment(lib, "winmm.lib")
42 #endif
43 #include <windows.h>
44 #include <mmsystem.h>
45 
46 #include "base/basictypes.h"
47 #include "base/logging.h"
48 #include "mozilla/Casting.h"
49 #include "mozilla/StaticMutex.h"
50 
51 using base::Time;
52 using base::TimeDelta;
53 using base::TimeTicks;
54 using mozilla::BitwiseCast;
55 
56 namespace {
57 
58 // From MSDN, FILETIME "Contains a 64-bit value representing the number of
59 // 100-nanosecond intervals since January 1, 1601 (UTC)."
FileTimeToMicroseconds(const FILETIME & ft)60 int64_t FileTimeToMicroseconds(const FILETIME& ft) {
61   // Need to BitwiseCast to fix alignment, then divide by 10 to convert
62   // 100-nanoseconds to milliseconds. This only works on little-endian
63   // machines.
64   return BitwiseCast<int64_t>(ft) / 10;
65 }
66 
MicrosecondsToFileTime(int64_t us,FILETIME * ft)67 void MicrosecondsToFileTime(int64_t us, FILETIME* ft) {
68   DCHECK(us >= 0) << "Time is less than 0, negative values are not "
69                      "representable in FILETIME";
70 
71   // Multiply by 10 to convert milliseconds to 100-nanoseconds. BitwiseCast will
72   // handle alignment problems. This only works on little-endian machines.
73   *ft = BitwiseCast<FILETIME>(us * 10);
74 }
75 
CurrentWallclockMicroseconds()76 int64_t CurrentWallclockMicroseconds() {
77   FILETIME ft;
78   ::GetSystemTimeAsFileTime(&ft);
79   return FileTimeToMicroseconds(ft);
80 }
81 
82 // Time between resampling the un-granular clock for this API.  60 seconds.
83 const int kMaxMillisecondsToAvoidDrift = 60 * Time::kMillisecondsPerSecond;
84 
85 int64_t initial_time = 0;
86 TimeTicks initial_ticks;
87 
InitializeClock()88 void InitializeClock() {
89   initial_ticks = TimeTicks::Now();
90   initial_time = CurrentWallclockMicroseconds();
91 }
92 
93 }  // namespace
94 
95 // Time -----------------------------------------------------------------------
96 
97 // The internal representation of Time uses FILETIME, whose epoch is 1601-01-01
98 // 00:00:00 UTC.  ((1970-1601)*365+89)*24*60*60*1000*1000, where 89 is the
99 // number of leap year days between 1601 and 1970: (1970-1601)/4 excluding
100 // 1700, 1800, and 1900.
101 // static
102 const int64_t Time::kTimeTToMicrosecondsOffset = GG_INT64_C(11644473600000000);
103 
104 // static
Now()105 Time Time::Now() {
106   if (initial_time == 0) InitializeClock();
107 
108   // We implement time using the high-resolution timers so that we can get
109   // timeouts which are smaller than 10-15ms.  If we just used
110   // CurrentWallclockMicroseconds(), we'd have the less-granular timer.
111   //
112   // To make this work, we initialize the clock (initial_time) and the
113   // counter (initial_ctr).  To compute the initial time, we can check
114   // the number of ticks that have elapsed, and compute the delta.
115   //
116   // To avoid any drift, we periodically resync the counters to the system
117   // clock.
118   while (true) {
119     TimeTicks ticks = TimeTicks::Now();
120 
121     // Calculate the time elapsed since we started our timer
122     TimeDelta elapsed = ticks - initial_ticks;
123 
124     // Check if enough time has elapsed that we need to resync the clock.
125     if (elapsed.InMilliseconds() > kMaxMillisecondsToAvoidDrift) {
126       InitializeClock();
127       continue;
128     }
129 
130     return Time(elapsed + Time(initial_time));
131   }
132 }
133 
134 // static
NowFromSystemTime()135 Time Time::NowFromSystemTime() {
136   // Force resync.
137   InitializeClock();
138   return Time(initial_time);
139 }
140 
141 // static
FromExploded(bool is_local,const Exploded & exploded)142 Time Time::FromExploded(bool is_local, const Exploded& exploded) {
143   // Create the system struct representing our exploded time. It will either be
144   // in local time or UTC.
145   SYSTEMTIME st;
146   st.wYear = exploded.year;
147   st.wMonth = exploded.month;
148   st.wDayOfWeek = exploded.day_of_week;
149   st.wDay = exploded.day_of_month;
150   st.wHour = exploded.hour;
151   st.wMinute = exploded.minute;
152   st.wSecond = exploded.second;
153   st.wMilliseconds = exploded.millisecond;
154 
155   // Convert to FILETIME.
156   FILETIME ft;
157   if (!SystemTimeToFileTime(&st, &ft)) {
158     NOTREACHED() << "Unable to convert time";
159     return Time(0);
160   }
161 
162   // Ensure that it's in UTC.
163   if (is_local) {
164     FILETIME utc_ft;
165     LocalFileTimeToFileTime(&ft, &utc_ft);
166     return Time(FileTimeToMicroseconds(utc_ft));
167   }
168   return Time(FileTimeToMicroseconds(ft));
169 }
170 
Explode(bool is_local,Exploded * exploded) const171 void Time::Explode(bool is_local, Exploded* exploded) const {
172   // FILETIME in UTC.
173   FILETIME utc_ft;
174   MicrosecondsToFileTime(us_, &utc_ft);
175 
176   // FILETIME in local time if necessary.
177   BOOL success = TRUE;
178   FILETIME ft;
179   if (is_local)
180     success = FileTimeToLocalFileTime(&utc_ft, &ft);
181   else
182     ft = utc_ft;
183 
184   // FILETIME in SYSTEMTIME (exploded).
185   SYSTEMTIME st;
186   if (!success || !FileTimeToSystemTime(&ft, &st)) {
187     NOTREACHED() << "Unable to convert time, don't know why";
188     ZeroMemory(exploded, sizeof(*exploded));
189     return;
190   }
191 
192   exploded->year = st.wYear;
193   exploded->month = st.wMonth;
194   exploded->day_of_week = st.wDayOfWeek;
195   exploded->day_of_month = st.wDay;
196   exploded->hour = st.wHour;
197   exploded->minute = st.wMinute;
198   exploded->second = st.wSecond;
199   exploded->millisecond = st.wMilliseconds;
200 }
201 
202 // TimeTicks ------------------------------------------------------------------
203 namespace {
204 
205 // We define a wrapper to adapt between the __stdcall and __cdecl call of the
206 // mock function, and to avoid a static constructor.  Assigning an import to a
207 // function pointer directly would require setup code to fetch from the IAT.
timeGetTimeWrapper()208 DWORD timeGetTimeWrapper() { return timeGetTime(); }
209 
210 DWORD (*tick_function)(void) = &timeGetTimeWrapper;
211 
212 // We use timeGetTime() to implement TimeTicks::Now().  This can be problematic
213 // because it returns the number of milliseconds since Windows has started,
214 // which will roll over the 32-bit value every ~49 days.  We try to track
215 // rollover ourselves, which works if TimeTicks::Now() is called at least every
216 // 49 days.
217 class NowSingleton {
218  public:
Now()219   TimeDelta Now() {
220     mozilla::StaticMutexAutoLock locked(lock_);
221     // We should hold the lock while calling tick_function to make sure that
222     // we keep our last_seen_ stay correctly in sync.
223     DWORD now = tick_function();
224     if (now < last_seen_)
225       rollover_ +=
226           TimeDelta::FromMilliseconds(GG_LONGLONG(0x100000000));  // ~49.7 days.
227     last_seen_ = now;
228     return TimeDelta::FromMilliseconds(now) + rollover_;
229   }
230 
instance()231   static NowSingleton& instance() {
232     // This setup is a little gross: the `now` instance lives until libxul is
233     // unloaded, but leak checking runs prior to that, and would see a Mutex
234     // instance contained in NowSingleton as still live.  Said instance would
235     // be reported as a leak...but it's not, really.  To avoid that, we need
236     // to use StaticMutex (which is not leak-checked), but StaticMutex can't
237     // be a member variable.  So we have to have this separate variable and
238     // pass it into the NowSingleton constructor.
239     static mozilla::StaticMutex mutex;
240     static NowSingleton now(mutex);
241     return now;
242   }
243 
244  private:
NowSingleton(mozilla::StaticMutex & aMutex)245   explicit NowSingleton(mozilla::StaticMutex& aMutex)
246       : lock_(aMutex),
247         rollover_(TimeDelta::FromMilliseconds(0)),
248         last_seen_(0) {}
249   ~NowSingleton() = default;
250 
251   mozilla::StaticMutex& lock_;  // To protected last_seen_ and rollover_.
252   TimeDelta rollover_;          // Accumulation of time lost due to rollover.
253   DWORD last_seen_;  // The last timeGetTime value we saw, to detect rollover.
254 
255   DISALLOW_COPY_AND_ASSIGN(NowSingleton);
256 };
257 
258 }  // namespace
259 
260 // static
Now()261 TimeTicks TimeTicks::Now() {
262   return TimeTicks() + NowSingleton::instance().Now();
263 }
264