Merge "Better solution for Docomo 1339 bug." into tizen_2.1
[framework/web/webkit-efl.git] / Source / WTF / wtf / CurrentTime.cpp
1 /*
2  * Copyright (C) 2006, 2010 Apple Inc. All rights reserved.
3  * Copyright (C) 2008 Google Inc. All rights reserved.
4  * Copyright (C) 2007-2009 Torch Mobile, Inc.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are
8  * met:
9  *
10  *     * Redistributions of source code must retain the above copyright
11  * notice, this list of conditions and the following disclaimer.
12  *     * Redistributions in binary form must reproduce the above
13  * copyright notice, this list of conditions and the following disclaimer
14  * in the documentation and/or other materials provided with the
15  * distribution.
16  *     * Neither the name of Google Inc. nor the names of its
17  * contributors may be used to endorse or promote products derived from
18  * this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32
33 #include "config.h"
34 #include "CurrentTime.h"
35
36 #if PLATFORM(MAC)
37 #include <mach/mach_time.h>
38 #include <sys/time.h>
39 #elif OS(WINDOWS)
40
41 // Windows is first since we want to use hires timers, despite USE(CF)
42 // being defined.
43 // If defined, WIN32_LEAN_AND_MEAN disables timeBeginPeriod/timeEndPeriod.
44 #undef WIN32_LEAN_AND_MEAN
45 #include <windows.h>
46 #include <math.h>
47 #include <stdint.h>
48 #include <time.h>
49
50 #elif PLATFORM(WX)
51 #include <wx/datetime.h>
52 #elif PLATFORM(EFL)
53 #include <Ecore.h>
54 #else
55 #include <sys/time.h>
56 #endif
57
58 #if PLATFORM(GTK)
59 #include <glib.h>
60 #endif
61
62 #if PLATFORM(QT)
63 #include <QElapsedTimer>
64 #endif
65
66 namespace WTF {
67
68 #if !PLATFORM(CHROMIUM)
69
70 #if OS(WINDOWS)
71
72 // Number of 100 nanosecond between January 1, 1601 and January 1, 1970.
73 static const ULONGLONG epochBias = 116444736000000000ULL;
74 static const double hundredsOfNanosecondsPerMillisecond = 10000;
75
76 static double lowResUTCTime()
77 {
78     FILETIME fileTime;
79
80 #if OS(WINCE)
81     GetCurrentFT(&fileTime);
82 #else
83     GetSystemTimeAsFileTime(&fileTime);
84 #endif
85
86     // As per Windows documentation for FILETIME, copy the resulting FILETIME structure to a
87     // ULARGE_INTEGER structure using memcpy (using memcpy instead of direct assignment can
88     // prevent alignment faults on 64-bit Windows).
89
90     ULARGE_INTEGER dateTime;
91     memcpy(&dateTime, &fileTime, sizeof(dateTime));
92
93     // Windows file times are in 100s of nanoseconds.
94     return (dateTime.QuadPart - epochBias) / hundredsOfNanosecondsPerMillisecond;
95 }
96
97 #if USE(QUERY_PERFORMANCE_COUNTER)
98
99 static LARGE_INTEGER qpcFrequency;
100 static bool syncedTime;
101
102 static double highResUpTime()
103 {
104     // We use QPC, but only after sanity checking its result, due to bugs:
105     // http://support.microsoft.com/kb/274323
106     // http://support.microsoft.com/kb/895980
107     // 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)."
108
109     static LARGE_INTEGER qpcLast;
110     static DWORD tickCountLast;
111     static bool inited;
112
113     LARGE_INTEGER qpc;
114     QueryPerformanceCounter(&qpc);
115     DWORD tickCount = GetTickCount();
116
117     if (inited) {
118         __int64 qpcElapsed = ((qpc.QuadPart - qpcLast.QuadPart) * 1000) / qpcFrequency.QuadPart;
119         __int64 tickCountElapsed;
120         if (tickCount >= tickCountLast)
121             tickCountElapsed = (tickCount - tickCountLast);
122         else {
123 #if COMPILER(MINGW)
124             __int64 tickCountLarge = tickCount + 0x100000000ULL;
125 #else
126             __int64 tickCountLarge = tickCount + 0x100000000I64;
127 #endif
128             tickCountElapsed = tickCountLarge - tickCountLast;
129         }
130
131         // force a re-sync if QueryPerformanceCounter differs from GetTickCount by more than 500ms.
132         // (500ms value is from http://support.microsoft.com/kb/274323)
133         __int64 diff = tickCountElapsed - qpcElapsed;
134         if (diff > 500 || diff < -500)
135             syncedTime = false;
136     } else
137         inited = true;
138
139     qpcLast = qpc;
140     tickCountLast = tickCount;
141
142     return (1000.0 * qpc.QuadPart) / static_cast<double>(qpcFrequency.QuadPart);
143 }
144
145 static bool qpcAvailable()
146 {
147     static bool available;
148     static bool checked;
149
150     if (checked)
151         return available;
152
153     available = QueryPerformanceFrequency(&qpcFrequency);
154     checked = true;
155     return available;
156 }
157
158 double currentTime()
159 {
160     // Use a combination of ftime and QueryPerformanceCounter.
161     // ftime returns the information we want, but doesn't have sufficient resolution.
162     // QueryPerformanceCounter has high resolution, but is only usable to measure time intervals.
163     // To combine them, we call ftime and QueryPerformanceCounter initially. Later calls will use QueryPerformanceCounter
164     // by itself, adding the delta to the saved ftime.  We periodically re-sync to correct for drift.
165     static double syncLowResUTCTime;
166     static double syncHighResUpTime;
167     static double lastUTCTime;
168
169     double lowResTime = lowResUTCTime();
170
171     if (!qpcAvailable())
172         return lowResTime / 1000.0;
173
174     double highResTime = highResUpTime();
175
176     if (!syncedTime) {
177         timeBeginPeriod(1); // increase time resolution around low-res time getter
178         syncLowResUTCTime = lowResTime = lowResUTCTime();
179         timeEndPeriod(1); // restore time resolution
180         syncHighResUpTime = highResTime;
181         syncedTime = true;
182     }
183
184     double highResElapsed = highResTime - syncHighResUpTime;
185     double utc = syncLowResUTCTime + highResElapsed;
186
187     // force a clock re-sync if we've drifted
188     double lowResElapsed = lowResTime - syncLowResUTCTime;
189     const double maximumAllowedDriftMsec = 15.625 * 2.0; // 2x the typical low-res accuracy
190     if (fabs(highResElapsed - lowResElapsed) > maximumAllowedDriftMsec)
191         syncedTime = false;
192
193     // make sure time doesn't run backwards (only correct if difference is < 2 seconds, since DST or clock changes could occur)
194     const double backwardTimeLimit = 2000.0;
195     if (utc < lastUTCTime && (lastUTCTime - utc) < backwardTimeLimit)
196         return lastUTCTime / 1000.0;
197     lastUTCTime = utc;
198     return utc / 1000.0;
199 }
200
201 #else
202
203 double currentTime()
204 {
205     static bool init = false;
206     static double lastTime;
207     static DWORD lastTickCount;
208     if (!init) {
209         lastTime = lowResUTCTime();
210         lastTickCount = GetTickCount();
211         init = true;
212         return lastTime;
213     }
214
215     DWORD tickCountNow = GetTickCount();
216     DWORD elapsed = tickCountNow - lastTickCount;
217     double timeNow = lastTime + (double)elapsed / 1000.;
218     if (elapsed >= 0x7FFFFFFF) {
219         lastTime = timeNow;
220         lastTickCount = tickCountNow;
221     }
222     return timeNow;
223 }
224
225 #endif // USE(QUERY_PERFORMANCE_COUNTER)
226
227 #elif PLATFORM(GTK)
228
229 // Note: GTK on Windows will pick up the PLATFORM(WIN) implementation above which provides
230 // better accuracy compared with Windows implementation of g_get_current_time:
231 // (http://www.google.com/codesearch/p?hl=en#HHnNRjks1t0/glib-2.5.2/glib/gmain.c&q=g_get_current_time).
232 // Non-Windows GTK builds could use gettimeofday() directly but for the sake of consistency lets use GTK function.
233 double currentTime()
234 {
235     GTimeVal now;
236     g_get_current_time(&now);
237     return static_cast<double>(now.tv_sec) + static_cast<double>(now.tv_usec / 1000000.0);
238 }
239
240 #elif PLATFORM(WX)
241
242 double currentTime()
243 {
244     wxDateTime now = wxDateTime::UNow();
245     return (double)now.GetTicks() + (double)(now.GetMillisecond() / 1000.0);
246 }
247
248 #elif PLATFORM(EFL)
249
250 double currentTime()
251 {
252     return ecore_time_unix_get();
253 }
254
255 #elif OS(QNX)
256
257 double currentTime()
258 {
259     struct timespec time;
260     if (clock_gettime(CLOCK_REALTIME, &time))
261         CRASH();
262     return time.tv_sec + time.tv_nsec / 1.0e9;
263 }
264
265 #else
266
267 double currentTime()
268 {
269     struct timeval now;
270     gettimeofday(&now, 0);
271     return now.tv_sec + now.tv_usec / 1000000.0;
272 }
273
274 #endif
275
276 #if PLATFORM(MAC)
277
278 double monotonicallyIncreasingTime()
279 {
280     // Based on listing #2 from Apple QA 1398.
281     static mach_timebase_info_data_t timebaseInfo;
282     if (!timebaseInfo.denom) {
283         kern_return_t kr = mach_timebase_info(&timebaseInfo);
284         ASSERT_UNUSED(kr, kr == KERN_SUCCESS);
285     }
286     return (mach_absolute_time() * timebaseInfo.numer) / (1.0e9 * timebaseInfo.denom);
287 }
288
289 #elif PLATFORM(EFL)
290
291 double monotonicallyIncreasingTime()
292 {
293     return ecore_time_get();
294 }
295
296 #elif PLATFORM(GTK)
297
298 double monotonicallyIncreasingTime()
299 {
300     return static_cast<double>(g_get_monotonic_time() / 1000000.0);
301 }
302
303 #elif PLATFORM(QT)
304
305 double monotonicallyIncreasingTime()
306 {
307     ASSERT(QElapsedTimer::isMonotonic());
308     static QElapsedTimer timer;
309     return timer.nsecsElapsed() / 1.0e9;
310 }
311
312 #elif OS(QNX)
313
314 double monotonicallyIncreasingTime()
315 {
316     struct timespec time;
317     if (clock_gettime(CLOCK_MONOTONIC, &time))
318         CRASH();
319     return time.tv_sec + time.tv_nsec / 1.0e9;
320 }
321
322 #else
323
324 double monotonicallyIncreasingTime()
325 {
326     static double lastTime = 0;
327     double currentTimeNow = currentTime();
328     if (currentTimeNow < lastTime)
329         return lastTime;
330     lastTime = currentTimeNow;
331     return currentTimeNow;
332 }
333
334 #endif
335
336 #endif // !PLATFORM(CHROMIUM)
337
338 void getLocalTime(const time_t* localTime, struct tm* localTM)
339 {
340 #if COMPILER(MSVC7_OR_LOWER) || COMPILER(MINGW) || OS(WINCE)
341     *localTM = *localtime(localTime);
342 #elif COMPILER(MSVC)
343     localtime_s(localTM, localTime);
344 #else
345     localtime_r(localTime, localTM);
346 #endif
347 }
348
349 void getCurrentLocalTime(struct tm* localTM)
350 {
351     time_t localTime = time(0);
352     getLocalTime(&localTime, localTM);
353 }
354
355 } // namespace WTF