]> git.saurik.com Git - apple/javascriptcore.git/blobdiff - wtf/CurrentTime.cpp
JavaScriptCore-521.tar.gz
[apple/javascriptcore.git] / wtf / CurrentTime.cpp
diff --git a/wtf/CurrentTime.cpp b/wtf/CurrentTime.cpp
new file mode 100644 (file)
index 0000000..f23495f
--- /dev/null
@@ -0,0 +1,226 @@
+/*
+ * Copyright (C) 2006 Apple Computer, Inc.  All rights reserved.
+ * Copyright (C) 2008 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "CurrentTime.h"
+
+#if PLATFORM(MAC)
+#include <CoreFoundation/CFDate.h>
+#elif PLATFORM(GTK)
+#include <glib.h>
+#elif PLATFORM(WX)
+#include <wx/datetime.h>
+#elif PLATFORM(WIN_OS)
+// If defined, WIN32_LEAN_AND_MEAN disables timeBeginPeriod/timeEndPeriod.
+#undef WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <math.h>
+#include <stdint.h>
+#include <sys/timeb.h>
+#include <sys/types.h>
+#include <time.h>
+#else // Posix systems relying on the gettimeofday()
+#include <sys/time.h>
+#endif
+
+namespace WTF {
+
+const double msPerSecond = 1000.0;
+
+#if PLATFORM(MAC)
+
+double currentTime()
+{
+    return CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970;
+}
+
+#elif PLATFORM(GTK)
+
+// Note: GTK on Windows will pick up the PLATFORM(WIN) implementation above which provides
+// better accuracy compared with Windows implementation of g_get_current_time:
+// (http://www.google.com/codesearch/p?hl=en#HHnNRjks1t0/glib-2.5.2/glib/gmain.c&q=g_get_current_time).
+// Non-Windows GTK builds could use gettimeofday() directly but for the sake of consistency lets use GTK function.
+double currentTime()
+{
+    GTimeVal now;
+    g_get_current_time(&now);
+    return static_cast<double>(now.tv_sec) + static_cast<double>(now.tv_usec / 1000000.0);
+}
+
+#elif PLATFORM(WX)
+
+double currentTime()
+{
+    wxDateTime now = wxDateTime::UNow();
+    return (double)now.GetTicks() + (double)(now.GetMillisecond() / 1000.0);
+}
+
+#elif PLATFORM(WIN_OS)
+
+static LARGE_INTEGER qpcFrequency;
+static bool syncedTime;
+
+static double highResUpTime()
+{
+    // We use QPC, but only after sanity checking its result, due to bugs:
+    // http://support.microsoft.com/kb/274323
+    // http://support.microsoft.com/kb/895980
+    // 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)."
+
+    static LARGE_INTEGER qpcLast;
+    static DWORD tickCountLast;
+    static bool inited;
+
+    LARGE_INTEGER qpc;
+    QueryPerformanceCounter(&qpc);
+    DWORD tickCount = GetTickCount();
+
+    if (inited) {
+        __int64 qpcElapsed = ((qpc.QuadPart - qpcLast.QuadPart) * 1000) / qpcFrequency.QuadPart;
+        __int64 tickCountElapsed;
+        if (tickCount >= tickCountLast)
+            tickCountElapsed = (tickCount - tickCountLast);
+        else {
+#if COMPILER(MINGW)
+            __int64 tickCountLarge = tickCount + 0x100000000ULL;
+#else
+            __int64 tickCountLarge = tickCount + 0x100000000I64;
+#endif
+            tickCountElapsed = tickCountLarge - tickCountLast;
+        }
+
+        // force a re-sync if QueryPerformanceCounter differs from GetTickCount by more than 500ms.
+        // (500ms value is from http://support.microsoft.com/kb/274323)
+        __int64 diff = tickCountElapsed - qpcElapsed;
+        if (diff > 500 || diff < -500)
+            syncedTime = false;
+    } else
+        inited = true;
+
+    qpcLast = qpc;
+    tickCountLast = tickCount;
+
+    return (1000.0 * qpc.QuadPart) / static_cast<double>(qpcFrequency.QuadPart);
+}
+
+static double lowResUTCTime()
+{
+#if PLATFORM(WIN_CE)
+    SYSTEMTIME systemTime;
+    GetSystemTime(&systemTime);
+    struct tm tmtime;
+    tmtime.tm_year = systemTime.wYear - 1900;
+    tmtime.tm_mon = systemTime.wMonth - 1;
+    tmtime.tm_mday = systemTime.wDay;
+    tmtime.tm_wday = systemTime.wDayOfWeek;
+    tmtime.tm_hour = systemTime.wHour;
+    tmtime.tm_min = systemTime.wMinute;
+    tmtime.tm_sec = systemTime.wSecond;
+    time_t timet = mktime(&tmtime);
+    return timet * msPerSecond + systemTime.wMilliseconds;
+#else // PLATFORM(WIN_CE)
+    struct _timeb timebuffer;
+    _ftime(&timebuffer);
+    return timebuffer.time * msPerSecond + timebuffer.millitm;
+#endif // PLATFORM(WIN_CE)
+}
+
+static bool qpcAvailable()
+{
+    static bool available;
+    static bool checked;
+
+    if (checked)
+        return available;
+
+    available = QueryPerformanceFrequency(&qpcFrequency);
+    checked = true;
+    return available;
+}
+
+double currentTime()
+{
+    // Use a combination of ftime and QueryPerformanceCounter.
+    // ftime returns the information we want, but doesn't have sufficient resolution.
+    // QueryPerformanceCounter has high resolution, but is only usable to measure time intervals.
+    // To combine them, we call ftime and QueryPerformanceCounter initially. Later calls will use QueryPerformanceCounter
+    // by itself, adding the delta to the saved ftime.  We periodically re-sync to correct for drift.
+    static bool started;
+    static double syncLowResUTCTime;
+    static double syncHighResUpTime;
+    static double lastUTCTime;
+
+    double lowResTime = lowResUTCTime();
+
+    if (!qpcAvailable())
+        return lowResTime / 1000.0;
+
+    double highResTime = highResUpTime();
+
+    if (!syncedTime) {
+        timeBeginPeriod(1); // increase time resolution around low-res time getter
+        syncLowResUTCTime = lowResTime = lowResUTCTime();
+        timeEndPeriod(1); // restore time resolution
+        syncHighResUpTime = highResTime;
+        syncedTime = true;
+    }
+
+    double highResElapsed = highResTime - syncHighResUpTime;
+    double utc = syncLowResUTCTime + highResElapsed;
+
+    // force a clock re-sync if we've drifted
+    double lowResElapsed = lowResTime - syncLowResUTCTime;
+    const double maximumAllowedDriftMsec = 15.625 * 2.0; // 2x the typical low-res accuracy
+    if (fabs(highResElapsed - lowResElapsed) > maximumAllowedDriftMsec)
+        syncedTime = false;
+
+    // make sure time doesn't run backwards (only correct if difference is < 2 seconds, since DST or clock changes could occur)
+    const double backwardTimeLimit = 2000.0;
+    if (utc < lastUTCTime && (lastUTCTime - utc) < backwardTimeLimit)
+        return lastUTCTime / 1000.0;
+    lastUTCTime = utc;
+    return utc / 1000.0;
+}
+
+#else // Other Posix systems rely on the gettimeofday().
+
+double currentTime()
+{
+    struct timeval now;
+    struct timezone zone;
+
+    gettimeofday(&now, &zone);
+    return static_cast<double>(now.tv_sec) + (double)(now.tv_usec / 1000000.0);
+}
+
+#endif
+
+} // namespace WTF