| 1 | /* | 
| 2 |  * Copyright (C) 2006 Apple Computer, 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 OS(WINDOWS) | 
| 37 |  | 
| 38 | // Windows is first since we want to use hires timers, despite PLATFORM(CF) | 
| 39 | // being defined. | 
| 40 | // If defined, WIN32_LEAN_AND_MEAN disables timeBeginPeriod/timeEndPeriod. | 
| 41 | #undef WIN32_LEAN_AND_MEAN | 
| 42 | #include <windows.h> | 
| 43 | #include <math.h> | 
| 44 | #include <stdint.h> | 
| 45 | #include <time.h> | 
| 46 |  | 
| 47 | #if USE(QUERY_PERFORMANCE_COUNTER) | 
| 48 | #if OS(WINCE) | 
| 49 | extern "C"  time_t mktime(struct tm *t); | 
| 50 | #else | 
| 51 | #include <sys/timeb.h> | 
| 52 | #include <sys/types.h> | 
| 53 | #endif | 
| 54 | #endif | 
| 55 |  | 
| 56 | #elif PLATFORM(CF) | 
| 57 | #include <CoreFoundation/CFDate.h> | 
| 58 | #elif PLATFORM(GTK) | 
| 59 | #include <glib.h> | 
| 60 | #elif PLATFORM(WX) | 
| 61 | #include <wx/datetime.h> | 
| 62 | #else // Posix systems relying on the gettimeofday() | 
| 63 | #include <sys/time.h> | 
| 64 | #endif | 
| 65 |  | 
| 66 | #if PLATFORM(CHROMIUM) | 
| 67 | #error Chromium uses a different timer implementation | 
| 68 | #endif | 
| 69 |  | 
| 70 | namespace WTF { | 
| 71 |  | 
| 72 | const double msPerSecond = 1000.0; | 
| 73 |  | 
| 74 | #if OS(WINDOWS) | 
| 75 |  | 
| 76 | #if USE(QUERY_PERFORMANCE_COUNTER) | 
| 77 |  | 
| 78 | static LARGE_INTEGER qpcFrequency; | 
| 79 | static bool syncedTime; | 
| 80 |  | 
| 81 | static double highResUpTime() | 
| 82 | { | 
| 83 |     // We use QPC, but only after sanity checking its result, due to bugs: | 
| 84 |     // http://support.microsoft.com/kb/274323 | 
| 85 |     // http://support.microsoft.com/kb/895980 | 
| 86 |     // 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)." | 
| 87 |  | 
| 88 |     static LARGE_INTEGER qpcLast; | 
| 89 |     static DWORD tickCountLast; | 
| 90 |     static bool inited; | 
| 91 |  | 
| 92 |     LARGE_INTEGER qpc; | 
| 93 |     QueryPerformanceCounter(&qpc); | 
| 94 |     DWORD tickCount = GetTickCount(); | 
| 95 |  | 
| 96 |     if (inited) { | 
| 97 |         __int64 qpcElapsed = ((qpc.QuadPart - qpcLast.QuadPart) * 1000) / qpcFrequency.QuadPart; | 
| 98 |         __int64 tickCountElapsed; | 
| 99 |         if (tickCount >= tickCountLast) | 
| 100 |             tickCountElapsed = (tickCount - tickCountLast); | 
| 101 |         else { | 
| 102 | #if COMPILER(MINGW) | 
| 103 |             __int64 tickCountLarge = tickCount + 0x100000000ULL; | 
| 104 | #else | 
| 105 |             __int64 tickCountLarge = tickCount + 0x100000000I64; | 
| 106 | #endif | 
| 107 |             tickCountElapsed = tickCountLarge - tickCountLast; | 
| 108 |         } | 
| 109 |  | 
| 110 |         // force a re-sync if QueryPerformanceCounter differs from GetTickCount by more than 500ms. | 
| 111 |         // (500ms value is from http://support.microsoft.com/kb/274323) | 
| 112 |         __int64 diff = tickCountElapsed - qpcElapsed; | 
| 113 |         if (diff > 500 || diff < -500) | 
| 114 |             syncedTime = false; | 
| 115 |     } else | 
| 116 |         inited = true; | 
| 117 |  | 
| 118 |     qpcLast = qpc; | 
| 119 |     tickCountLast = tickCount; | 
| 120 |  | 
| 121 |     return (1000.0 * qpc.QuadPart) / static_cast<double>(qpcFrequency.QuadPart); | 
| 122 | } | 
| 123 |  | 
| 124 | static double lowResUTCTime() | 
| 125 | { | 
| 126 | #if OS(WINCE) | 
| 127 |     SYSTEMTIME systemTime; | 
| 128 |     GetSystemTime(&systemTime); | 
| 129 |     struct tm tmtime; | 
| 130 |     tmtime.tm_year = systemTime.wYear - 1900; | 
| 131 |     tmtime.tm_mon = systemTime.wMonth - 1; | 
| 132 |     tmtime.tm_mday = systemTime.wDay; | 
| 133 |     tmtime.tm_wday = systemTime.wDayOfWeek; | 
| 134 |     tmtime.tm_hour = systemTime.wHour; | 
| 135 |     tmtime.tm_min = systemTime.wMinute; | 
| 136 |     tmtime.tm_sec = systemTime.wSecond; | 
| 137 |     time_t timet = mktime(&tmtime); | 
| 138 |     return timet * msPerSecond + systemTime.wMilliseconds; | 
| 139 | #else | 
| 140 |     struct _timeb timebuffer; | 
| 141 |     _ftime(&timebuffer); | 
| 142 |     return timebuffer.time * msPerSecond + timebuffer.millitm; | 
| 143 | #endif | 
| 144 | } | 
| 145 |  | 
| 146 | static bool qpcAvailable() | 
| 147 | { | 
| 148 |     static bool available; | 
| 149 |     static bool checked; | 
| 150 |  | 
| 151 |     if (checked) | 
| 152 |         return available; | 
| 153 |  | 
| 154 |     available = QueryPerformanceFrequency(&qpcFrequency); | 
| 155 |     checked = true; | 
| 156 |     return available; | 
| 157 | } | 
| 158 |  | 
| 159 | double currentTime() | 
| 160 | { | 
| 161 |     // Use a combination of ftime and QueryPerformanceCounter. | 
| 162 |     // ftime returns the information we want, but doesn't have sufficient resolution. | 
| 163 |     // QueryPerformanceCounter has high resolution, but is only usable to measure time intervals. | 
| 164 |     // To combine them, we call ftime and QueryPerformanceCounter initially. Later calls will use QueryPerformanceCounter | 
| 165 |     // by itself, adding the delta to the saved ftime.  We periodically re-sync to correct for drift. | 
| 166 |     static bool started; | 
| 167 |     static double syncLowResUTCTime; | 
| 168 |     static double syncHighResUpTime; | 
| 169 |     static double lastUTCTime; | 
| 170 |  | 
| 171 |     double lowResTime = lowResUTCTime(); | 
| 172 |  | 
| 173 |     if (!qpcAvailable()) | 
| 174 |         return lowResTime / 1000.0; | 
| 175 |  | 
| 176 |     double highResTime = highResUpTime(); | 
| 177 |  | 
| 178 |     if (!syncedTime) { | 
| 179 |         timeBeginPeriod(1); // increase time resolution around low-res time getter | 
| 180 |         syncLowResUTCTime = lowResTime = lowResUTCTime(); | 
| 181 |         timeEndPeriod(1); // restore time resolution | 
| 182 |         syncHighResUpTime = highResTime; | 
| 183 |         syncedTime = true; | 
| 184 |     } | 
| 185 |  | 
| 186 |     double highResElapsed = highResTime - syncHighResUpTime; | 
| 187 |     double utc = syncLowResUTCTime + highResElapsed; | 
| 188 |  | 
| 189 |     // force a clock re-sync if we've drifted | 
| 190 |     double lowResElapsed = lowResTime - syncLowResUTCTime; | 
| 191 |     const double maximumAllowedDriftMsec = 15.625 * 2.0; // 2x the typical low-res accuracy | 
| 192 |     if (fabs(highResElapsed - lowResElapsed) > maximumAllowedDriftMsec) | 
| 193 |         syncedTime = false; | 
| 194 |  | 
| 195 |     // make sure time doesn't run backwards (only correct if difference is < 2 seconds, since DST or clock changes could occur) | 
| 196 |     const double backwardTimeLimit = 2000.0; | 
| 197 |     if (utc < lastUTCTime && (lastUTCTime - utc) < backwardTimeLimit) | 
| 198 |         return lastUTCTime / 1000.0; | 
| 199 |     lastUTCTime = utc; | 
| 200 |     return utc / 1000.0; | 
| 201 | } | 
| 202 |  | 
| 203 | #else | 
| 204 |  | 
| 205 | static double currentSystemTime() | 
| 206 | { | 
| 207 |     FILETIME ft; | 
| 208 |     GetCurrentFT(&ft); | 
| 209 |  | 
| 210 |     // As per Windows documentation for FILETIME, copy the resulting FILETIME structure to a | 
| 211 |     // ULARGE_INTEGER structure using memcpy (using memcpy instead of direct assignment can | 
| 212 |     // prevent alignment faults on 64-bit Windows). | 
| 213 |  | 
| 214 |     ULARGE_INTEGER t; | 
| 215 |     memcpy(&t, &ft, sizeof(t)); | 
| 216 |  | 
| 217 |     // Windows file times are in 100s of nanoseconds. | 
| 218 |     // To convert to seconds, we have to divide by 10,000,000, which is more quickly | 
| 219 |     // done by multiplying by 0.0000001. | 
| 220 |  | 
| 221 |     // Between January 1, 1601 and January 1, 1970, there were 369 complete years, | 
| 222 |     // of which 89 were leap years (1700, 1800, and 1900 were not leap years). | 
| 223 |     // That is a total of 134774 days, which is 11644473600 seconds. | 
| 224 |  | 
| 225 |     return t.QuadPart * 0.0000001 - 11644473600.0; | 
| 226 | } | 
| 227 |  | 
| 228 | double currentTime() | 
| 229 | { | 
| 230 |     static bool init = false; | 
| 231 |     static double lastTime; | 
| 232 |     static DWORD lastTickCount; | 
| 233 |     if (!init) { | 
| 234 |         lastTime = currentSystemTime(); | 
| 235 |         lastTickCount = GetTickCount(); | 
| 236 |         init = true; | 
| 237 |         return lastTime; | 
| 238 |     } | 
| 239 |  | 
| 240 |     DWORD tickCountNow = GetTickCount(); | 
| 241 |     DWORD elapsed = tickCountNow - lastTickCount; | 
| 242 |     double timeNow = lastTime + (double)elapsed / 1000.; | 
| 243 |     if (elapsed >= 0x7FFFFFFF) { | 
| 244 |         lastTime = timeNow; | 
| 245 |         lastTickCount = tickCountNow; | 
| 246 |     } | 
| 247 |     return timeNow; | 
| 248 | } | 
| 249 |  | 
| 250 | #endif // USE(QUERY_PERFORMANCE_COUNTER) | 
| 251 |  | 
| 252 | #elif PLATFORM(CF) | 
| 253 |  | 
| 254 | double currentTime() | 
| 255 | { | 
| 256 |     return CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970; | 
| 257 | } | 
| 258 |  | 
| 259 | #elif PLATFORM(GTK) | 
| 260 |  | 
| 261 | // Note: GTK on Windows will pick up the PLATFORM(WIN) implementation above which provides | 
| 262 | // better accuracy compared with Windows implementation of g_get_current_time: | 
| 263 | // (http://www.google.com/codesearch/p?hl=en#HHnNRjks1t0/glib-2.5.2/glib/gmain.c&q=g_get_current_time). | 
| 264 | // Non-Windows GTK builds could use gettimeofday() directly but for the sake of consistency lets use GTK function. | 
| 265 | double currentTime() | 
| 266 | { | 
| 267 |     GTimeVal now; | 
| 268 |     g_get_current_time(&now); | 
| 269 |     return static_cast<double>(now.tv_sec) + static_cast<double>(now.tv_usec / 1000000.0); | 
| 270 | } | 
| 271 |  | 
| 272 | #elif PLATFORM(WX) | 
| 273 |  | 
| 274 | double currentTime() | 
| 275 | { | 
| 276 |     wxDateTime now = wxDateTime::UNow(); | 
| 277 |     return (double)now.GetTicks() + (double)(now.GetMillisecond() / 1000.0); | 
| 278 | } | 
| 279 |  | 
| 280 | #else // Other Posix systems rely on the gettimeofday(). | 
| 281 |  | 
| 282 | double currentTime() | 
| 283 | { | 
| 284 |     struct timeval now; | 
| 285 |     struct timezone zone; | 
| 286 |  | 
| 287 |     gettimeofday(tv: &now, tz: &zone); | 
| 288 |     return static_cast<double>(now.tv_sec) + (double)(now.tv_usec / 1000000.0); | 
| 289 | } | 
| 290 |  | 
| 291 | #endif | 
| 292 |  | 
| 293 | } // namespace WTF | 
| 294 |  |