diff --git a/xpcom/ds/TimeStamp_windows.cpp b/xpcom/ds/TimeStamp_windows.cpp index bf31a3344752..fc47a664cc6e 100644 --- a/xpcom/ds/TimeStamp_windows.cpp +++ b/xpcom/ds/TimeStamp_windows.cpp @@ -417,24 +417,22 @@ InitResolution() static ULONGLONG WINAPI GetTickCount64Fallback() { - DWORD now = GetTickCount(); - ULONGLONG lastResultHiPart = sLastGTCResult & (~0ULL << 32); - ULONGLONG result = lastResultHiPart | ULONGLONG(now); + 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 (&sLastGTCResult), + newValue, old)); - // 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. - - if (sLastGTCResult > result) { - if ((sLastGTCResult - result) > (1ULL << 31)) - result += 1ULL << 32; - else - result = sLastGTCResult; - } - - sLastGTCResult = result; - return result; + return newValue; } // Result is in [mt] @@ -569,13 +567,13 @@ CalibratedPerformanceCounter() 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;