1 | /*
|
---|
2 | * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
|
---|
3 | * Copyright (C) 2008 Google Inc. All rights reserved.
|
---|
4 | *
|
---|
5 | * Redistribution and use in source and binary forms, with or without
|
---|
6 | * modification, are permitted provided that the following conditions are
|
---|
7 | * met:
|
---|
8 | *
|
---|
9 | * * Redistributions of source code must retain the above copyright
|
---|
10 | * notice, this list of conditions and the following disclaimer.
|
---|
11 | * * Redistributions in binary form must reproduce the above
|
---|
12 | * copyright notice, this list of conditions and the following disclaimer
|
---|
13 | * in the documentation and/or other materials provided with the
|
---|
14 | * distribution.
|
---|
15 | * * Neither the name of Google Inc. nor the names of its
|
---|
16 | * contributors may be used to endorse or promote products derived from
|
---|
17 | * this software without specific prior written permission.
|
---|
18 | *
|
---|
19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
---|
20 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
---|
21 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
---|
22 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
---|
23 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
---|
24 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
---|
25 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
---|
26 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
---|
27 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
---|
28 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
---|
29 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
---|
30 | */
|
---|
31 |
|
---|
32 | #include "config.h"
|
---|
33 | #include "CurrentTime.h"
|
---|
34 |
|
---|
35 | #if PLATFORM(MAC)
|
---|
36 | #include <CoreFoundation/CFDate.h>
|
---|
37 | #elif PLATFORM(GTK)
|
---|
38 | #include <glib.h>
|
---|
39 | #elif PLATFORM(WX)
|
---|
40 | #include <wx/datetime.h>
|
---|
41 | #elif PLATFORM(WIN_OS)
|
---|
42 | // If defined, WIN32_LEAN_AND_MEAN disables timeBeginPeriod/timeEndPeriod.
|
---|
43 | #undef WIN32_LEAN_AND_MEAN
|
---|
44 | #include <windows.h>
|
---|
45 | #include <math.h>
|
---|
46 | #include <stdint.h>
|
---|
47 | #include <sys/timeb.h>
|
---|
48 | #include <sys/types.h>
|
---|
49 | #include <time.h>
|
---|
50 | #else // Posix systems relying on the gettimeofday()
|
---|
51 | #include <sys/time.h>
|
---|
52 | #endif
|
---|
53 |
|
---|
54 | namespace WTF {
|
---|
55 |
|
---|
56 | const double msPerSecond = 1000.0;
|
---|
57 |
|
---|
58 | #if PLATFORM(MAC)
|
---|
59 |
|
---|
60 | double currentTime()
|
---|
61 | {
|
---|
62 | return CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970;
|
---|
63 | }
|
---|
64 |
|
---|
65 | #elif PLATFORM(GTK)
|
---|
66 |
|
---|
67 | // Note: GTK on Windows will pick up the PLATFORM(WIN) implementation above which provides
|
---|
68 | // better accuracy compared with Windows implementation of g_get_current_time:
|
---|
69 | // (http://www.google.com/codesearch/p?hl=en#HHnNRjks1t0/glib-2.5.2/glib/gmain.c&q=g_get_current_time).
|
---|
70 | // Non-Windows GTK builds could use gettimeofday() directly but for the sake of consistency lets use GTK function.
|
---|
71 | double currentTime()
|
---|
72 | {
|
---|
73 | GTimeVal now;
|
---|
74 | g_get_current_time(&now);
|
---|
75 | return static_cast<double>(now.tv_sec) + static_cast<double>(now.tv_usec / 1000000.0);
|
---|
76 | }
|
---|
77 |
|
---|
78 | #elif PLATFORM(WX)
|
---|
79 |
|
---|
80 | double currentTime()
|
---|
81 | {
|
---|
82 | wxDateTime now = wxDateTime::UNow();
|
---|
83 | return (double)now.GetTicks() + (double)(now.GetMillisecond() / 1000.0);
|
---|
84 | }
|
---|
85 |
|
---|
86 | #elif PLATFORM(WIN_OS)
|
---|
87 |
|
---|
88 | static LARGE_INTEGER qpcFrequency;
|
---|
89 | static bool syncedTime;
|
---|
90 |
|
---|
91 | static double highResUpTime()
|
---|
92 | {
|
---|
93 | // We use QPC, but only after sanity checking its result, due to bugs:
|
---|
94 | // http://support.microsoft.com/kb/274323
|
---|
95 | // http://support.microsoft.com/kb/895980
|
---|
96 | // http://msdn.microsoft.com/en-us/library/ms644904.aspx ("...you can get different results on different processors due to bugs in the basic input/output system (BIOS) or the hardware abstraction layer (HAL)."
|
---|
97 |
|
---|
98 | static LARGE_INTEGER qpcLast;
|
---|
99 | static DWORD tickCountLast;
|
---|
100 | static bool inited;
|
---|
101 |
|
---|
102 | LARGE_INTEGER qpc;
|
---|
103 | QueryPerformanceCounter(&qpc);
|
---|
104 | DWORD tickCount = GetTickCount();
|
---|
105 |
|
---|
106 | if (inited) {
|
---|
107 | __int64 qpcElapsed = ((qpc.QuadPart - qpcLast.QuadPart) * 1000) / qpcFrequency.QuadPart;
|
---|
108 | __int64 tickCountElapsed;
|
---|
109 | if (tickCount >= tickCountLast)
|
---|
110 | tickCountElapsed = (tickCount - tickCountLast);
|
---|
111 | else {
|
---|
112 | #if COMPILER(MINGW)
|
---|
113 | __int64 tickCountLarge = tickCount + 0x100000000ULL;
|
---|
114 | #else
|
---|
115 | __int64 tickCountLarge = tickCount + 0x100000000I64;
|
---|
116 | #endif
|
---|
117 | tickCountElapsed = tickCountLarge - tickCountLast;
|
---|
118 | }
|
---|
119 |
|
---|
120 | // force a re-sync if QueryPerformanceCounter differs from GetTickCount by more than 500ms.
|
---|
121 | // (500ms value is from http://support.microsoft.com/kb/274323)
|
---|
122 | __int64 diff = tickCountElapsed - qpcElapsed;
|
---|
123 | if (diff > 500 || diff < -500)
|
---|
124 | syncedTime = false;
|
---|
125 | } else
|
---|
126 | inited = true;
|
---|
127 |
|
---|
128 | qpcLast = qpc;
|
---|
129 | tickCountLast = tickCount;
|
---|
130 |
|
---|
131 | return (1000.0 * qpc.QuadPart) / static_cast<double>(qpcFrequency.QuadPart);
|
---|
132 | }
|
---|
133 |
|
---|
134 | static double lowResUTCTime()
|
---|
135 | {
|
---|
136 | #if PLATFORM(WIN_CE)
|
---|
137 | SYSTEMTIME systemTime;
|
---|
138 | GetSystemTime(&systemTime);
|
---|
139 | struct tm tmtime;
|
---|
140 | tmtime.tm_year = systemTime.wYear - 1900;
|
---|
141 | tmtime.tm_mon = systemTime.wMonth - 1;
|
---|
142 | tmtime.tm_mday = systemTime.wDay;
|
---|
143 | tmtime.tm_wday = systemTime.wDayOfWeek;
|
---|
144 | tmtime.tm_hour = systemTime.wHour;
|
---|
145 | tmtime.tm_min = systemTime.wMinute;
|
---|
146 | tmtime.tm_sec = systemTime.wSecond;
|
---|
147 | time_t timet = mktime(&tmtime);
|
---|
148 | return timet * msPerSecond + systemTime.wMilliseconds;
|
---|
149 | #else // PLATFORM(WIN_CE)
|
---|
150 | struct _timeb timebuffer;
|
---|
151 | _ftime(&timebuffer);
|
---|
152 | return timebuffer.time * msPerSecond + timebuffer.millitm;
|
---|
153 | #endif // PLATFORM(WIN_CE)
|
---|
154 | }
|
---|
155 |
|
---|
156 | static bool qpcAvailable()
|
---|
157 | {
|
---|
158 | static bool available;
|
---|
159 | static bool checked;
|
---|
160 |
|
---|
161 | if (checked)
|
---|
162 | return available;
|
---|
163 |
|
---|
164 | available = QueryPerformanceFrequency(&qpcFrequency);
|
---|
165 | checked = true;
|
---|
166 | return available;
|
---|
167 | }
|
---|
168 |
|
---|
169 | double currentTime()
|
---|
170 | {
|
---|
171 | // Use a combination of ftime and QueryPerformanceCounter.
|
---|
172 | // ftime returns the information we want, but doesn't have sufficient resolution.
|
---|
173 | // QueryPerformanceCounter has high resolution, but is only usable to measure time intervals.
|
---|
174 | // To combine them, we call ftime and QueryPerformanceCounter initially. Later calls will use QueryPerformanceCounter
|
---|
175 | // by itself, adding the delta to the saved ftime. We periodically re-sync to correct for drift.
|
---|
176 | static bool started;
|
---|
177 | static double syncLowResUTCTime;
|
---|
178 | static double syncHighResUpTime;
|
---|
179 | static double lastUTCTime;
|
---|
180 |
|
---|
181 | double lowResTime = lowResUTCTime();
|
---|
182 |
|
---|
183 | if (!qpcAvailable())
|
---|
184 | return lowResTime / 1000.0;
|
---|
185 |
|
---|
186 | double highResTime = highResUpTime();
|
---|
187 |
|
---|
188 | if (!syncedTime) {
|
---|
189 | timeBeginPeriod(1); // increase time resolution around low-res time getter
|
---|
190 | syncLowResUTCTime = lowResTime = lowResUTCTime();
|
---|
191 | timeEndPeriod(1); // restore time resolution
|
---|
192 | syncHighResUpTime = highResTime;
|
---|
193 | syncedTime = true;
|
---|
194 | }
|
---|
195 |
|
---|
196 | double highResElapsed = highResTime - syncHighResUpTime;
|
---|
197 | double utc = syncLowResUTCTime + highResElapsed;
|
---|
198 |
|
---|
199 | // force a clock re-sync if we've drifted
|
---|
200 | double lowResElapsed = lowResTime - syncLowResUTCTime;
|
---|
201 | const double maximumAllowedDriftMsec = 15.625 * 2.0; // 2x the typical low-res accuracy
|
---|
202 | if (fabs(highResElapsed - lowResElapsed) > maximumAllowedDriftMsec)
|
---|
203 | syncedTime = false;
|
---|
204 |
|
---|
205 | // make sure time doesn't run backwards (only correct if difference is < 2 seconds, since DST or clock changes could occur)
|
---|
206 | const double backwardTimeLimit = 2000.0;
|
---|
207 | if (utc < lastUTCTime && (lastUTCTime - utc) < backwardTimeLimit)
|
---|
208 | return lastUTCTime / 1000.0;
|
---|
209 | lastUTCTime = utc;
|
---|
210 | return utc / 1000.0;
|
---|
211 | }
|
---|
212 |
|
---|
213 | #else // Other Posix systems rely on the gettimeofday().
|
---|
214 |
|
---|
215 | double currentTime()
|
---|
216 | {
|
---|
217 | struct timeval now;
|
---|
218 | struct timezone zone;
|
---|
219 |
|
---|
220 | gettimeofday(&now, &zone);
|
---|
221 | return static_cast<double>(now.tv_sec) + (double)(now.tv_usec / 1000000.0);
|
---|
222 | }
|
---|
223 |
|
---|
224 | #endif
|
---|
225 |
|
---|
226 | } // namespace WTF
|
---|