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 OS(WINDOWS) 37 38// Windows is first since we want to use hires timers, despite USE(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) 49extern "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(GTK) 57#include <glib.h> 58#elif PLATFORM(WX) 59#include <wx/datetime.h> 60#elif PLATFORM(BREWMP) 61#include <AEEStdLib.h> 62#else 63#include <sys/time.h> 64#endif 65 66#if PLATFORM(CHROMIUM) 67#error Chromium uses a different timer implementation 68#endif 69 70namespace WTF { 71 72const double msPerSecond = 1000.0; 73 74#if OS(WINDOWS) 75 76#if USE(QUERY_PERFORMANCE_COUNTER) 77 78static LARGE_INTEGER qpcFrequency; 79static bool syncedTime; 80 81static 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 124static 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 146static 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 159double 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 double syncLowResUTCTime; 167 static double syncHighResUpTime; 168 static double lastUTCTime; 169 170 double lowResTime = lowResUTCTime(); 171 172 if (!qpcAvailable()) 173 return lowResTime / 1000.0; 174 175 double highResTime = highResUpTime(); 176 177 if (!syncedTime) { 178 timeBeginPeriod(1); // increase time resolution around low-res time getter 179 syncLowResUTCTime = lowResTime = lowResUTCTime(); 180 timeEndPeriod(1); // restore time resolution 181 syncHighResUpTime = highResTime; 182 syncedTime = true; 183 } 184 185 double highResElapsed = highResTime - syncHighResUpTime; 186 double utc = syncLowResUTCTime + highResElapsed; 187 188 // force a clock re-sync if we've drifted 189 double lowResElapsed = lowResTime - syncLowResUTCTime; 190 const double maximumAllowedDriftMsec = 15.625 * 2.0; // 2x the typical low-res accuracy 191 if (fabs(highResElapsed - lowResElapsed) > maximumAllowedDriftMsec) 192 syncedTime = false; 193 194 // make sure time doesn't run backwards (only correct if difference is < 2 seconds, since DST or clock changes could occur) 195 const double backwardTimeLimit = 2000.0; 196 if (utc < lastUTCTime && (lastUTCTime - utc) < backwardTimeLimit) 197 return lastUTCTime / 1000.0; 198 lastUTCTime = utc; 199 return utc / 1000.0; 200} 201 202#else 203 204static double currentSystemTime() 205{ 206 FILETIME ft; 207 GetCurrentFT(&ft); 208 209 // As per Windows documentation for FILETIME, copy the resulting FILETIME structure to a 210 // ULARGE_INTEGER structure using memcpy (using memcpy instead of direct assignment can 211 // prevent alignment faults on 64-bit Windows). 212 213 ULARGE_INTEGER t; 214 memcpy(&t, &ft, sizeof(t)); 215 216 // Windows file times are in 100s of nanoseconds. 217 // To convert to seconds, we have to divide by 10,000,000, which is more quickly 218 // done by multiplying by 0.0000001. 219 220 // Between January 1, 1601 and January 1, 1970, there were 369 complete years, 221 // of which 89 were leap years (1700, 1800, and 1900 were not leap years). 222 // That is a total of 134774 days, which is 11644473600 seconds. 223 224 return t.QuadPart * 0.0000001 - 11644473600.0; 225} 226 227double currentTime() 228{ 229 static bool init = false; 230 static double lastTime; 231 static DWORD lastTickCount; 232 if (!init) { 233 lastTime = currentSystemTime(); 234 lastTickCount = GetTickCount(); 235 init = true; 236 return lastTime; 237 } 238 239 DWORD tickCountNow = GetTickCount(); 240 DWORD elapsed = tickCountNow - lastTickCount; 241 double timeNow = lastTime + (double)elapsed / 1000.; 242 if (elapsed >= 0x7FFFFFFF) { 243 lastTime = timeNow; 244 lastTickCount = tickCountNow; 245 } 246 return timeNow; 247} 248 249#endif // USE(QUERY_PERFORMANCE_COUNTER) 250 251#elif PLATFORM(GTK) 252 253// Note: GTK on Windows will pick up the PLATFORM(WIN) implementation above which provides 254// better accuracy compared with Windows implementation of g_get_current_time: 255// (http://www.google.com/codesearch/p?hl=en#HHnNRjks1t0/glib-2.5.2/glib/gmain.c&q=g_get_current_time). 256// Non-Windows GTK builds could use gettimeofday() directly but for the sake of consistency lets use GTK function. 257double currentTime() 258{ 259 GTimeVal now; 260 g_get_current_time(&now); 261 return static_cast<double>(now.tv_sec) + static_cast<double>(now.tv_usec / 1000000.0); 262} 263 264#elif PLATFORM(WX) 265 266double currentTime() 267{ 268 wxDateTime now = wxDateTime::UNow(); 269 return (double)now.GetTicks() + (double)(now.GetMillisecond() / 1000.0); 270} 271 272#elif PLATFORM(BREWMP) 273 274// GETUTCSECONDS returns the number of seconds since 1980/01/06 00:00:00 UTC, 275// and GETTIMEMS returns the number of milliseconds that have elapsed since the last 276// occurrence of 00:00:00 local time. 277// We can combine GETUTCSECONDS and GETTIMEMS to calculate the number of milliseconds 278// since 1970/01/01 00:00:00 UTC. 279double currentTime() 280{ 281 // diffSeconds is the number of seconds from 1970/01/01 to 1980/01/06 282 const unsigned diffSeconds = 315964800; 283 return static_cast<double>(diffSeconds + GETUTCSECONDS() + ((GETTIMEMS() % 1000) / msPerSecond)); 284} 285 286#else 287 288double currentTime() 289{ 290 struct timeval now; 291 gettimeofday(&now, 0); 292 return now.tv_sec + now.tv_usec / 1000000.0; 293} 294 295#endif 296 297} // namespace WTF 298