Bug 784859 - Part 5: Change the implementation of GetTickCount64Fallback so that it never locks; r=bbondy
authorEhsan Akhgari <ehsan@mozilla.com>
Thu, 06 Sep 2012 11:01:06 -0400
changeset 104652 9544f94ccdb8
parent 104651 64ea34bc583e
child 104653 d4a8c7efef04
push id23436
push userryanvm@gmail.com
push date2012-09-09 01:10 +0000
treeherdermozilla-central@f31d1aa89848 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbbondy
bugs784859
milestone18.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 784859 - Part 5: Change the implementation of GetTickCount64Fallback so that it never locks; r=bbondy
xpcom/ds/TimeStamp_windows.cpp
--- a/xpcom/ds/TimeStamp_windows.cpp
+++ b/xpcom/ds/TimeStamp_windows.cpp
@@ -412,34 +412,32 @@ InitResolution()
 
 // Function protecting GetTickCount result from rolling over, result is in [ms]
 // @param gtc
 // Result of GetTickCount().  Passing it as an arg lets us call it out
 // of the common mutex.
 static ULONGLONG WINAPI
 GetTickCount64Fallback()
 {
-  DWORD now = GetTickCount();
-  ULONGLONG lastResultHiPart = sLastGTCResult & (~0ULL << 32);
-  ULONGLONG result = lastResultHiPart | ULONGLONG(now);
-
-  // It may happen that when accessing GTC on multiple threads the results
-  // may differ (GTC value may be lower due to running before the others
-  // right around the overflow moment).  That falsely shifts the high part.
-  // Easiest solution is to check for a significant difference.
+  ULONGLONG old, newValue;
+  do {
+    old = InterlockedRead64(&sLastGTCResult);
+    ULONGLONG oldTop = old & 0xffffffff00000000;
+    ULONG oldBottom = old & 0xffffffff;
+    ULONG newBottom = GetTickCount();
+    if (newBottom < oldBottom) {
+        // handle overflow
+        newValue = (oldTop + (1ULL<<32)) | newBottom;
+    } else {
+        newValue = oldTop | newBottom;
+    }
+  } while (old != _InterlockedCompareExchange64(reinterpret_cast<volatile __int64*> (&sLastGTCResult),
+                                                newValue, old));
 
-  if (sLastGTCResult > result) {
-    if ((sLastGTCResult - result) > (1ULL << 31))
-      result += 1ULL << 32;
-    else
-      result = sLastGTCResult;
-  }
-
-  sLastGTCResult = result;
-  return result;
+  return newValue;
 }
 
 // Result is in [mt]
 static inline ULONGLONG
 PerformanceCounter()
 {
   LARGE_INTEGER pc;
   ::QueryPerformanceCounter(&pc);
@@ -564,23 +562,23 @@ CalibratedPerformanceCounter()
   StandbyObserver::Ensure();
 
   // Don't hold the lock over call to QueryPerformanceCounter, since it is
   // the largest bottleneck, let threads read the value concurently to have
   // possibly a better performance.
 
   ULONGLONG qpc = PerformanceCounter();
 
+  // Rollover protection
+  ULONGLONG gtc = sGetTickCount64();
+
   ULONGLONG result;
   {
   AutoCriticalSection lock(&sTimeStampLock);
 
-  // Rollover protection
-  ULONGLONG gtc = sGetTickCount64();
-
   LONGLONG diff = qpc - ms2mt(gtc) - sSkew;
   LONGLONG overflow = 0;
 
   if (diff < sUnderrunThreshold) {
     overflow = sUnderrunThreshold - diff;
   }
   else if (diff > sOverrunThreshold) {
     overflow = diff - sOverrunThreshold;