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