Backed out 4 changesets (bug 1437167) for build bustages on nsUpdateDriver.cpp and WindowsMessageLoop.cpp on a CLOSED TREE.
authorCosmin Sabou <csabou@mozilla.com>
Tue, 06 Mar 2018 00:09:46 +0200
changeset 461696 f082f787a988d88f2fd14962f7af37671c539a7f
parent 461695 e372427420a80b8953cd16a55ee41e4250fdc697
child 461697 fd038d63f99f3b9bc855e8aab4eb0a0c60353149
push id1683
push usersfraser@mozilla.com
push dateThu, 26 Apr 2018 16:43:40 +0000
treeherdermozilla-release@5af6cb21869d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1437167
milestone60.0a1
backs outb98740e7c6391c14300fbea43e65fcd7ed04286f
4476e8f51fa6fb2151ce5997c3516980c22ca0e1
c79dc40faa417607f4c06c80fe555088b6982908
b608d2dcbb86f0e53644ef5b6881b349b3472725
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
Backed out 4 changesets (bug 1437167) for build bustages on nsUpdateDriver.cpp and WindowsMessageLoop.cpp on a CLOSED TREE. Backed out changeset b98740e7c639 (bug 1437167) Backed out changeset 4476e8f51fa6 (bug 1437167) Backed out changeset c79dc40faa41 (bug 1437167) Backed out changeset b608d2dcbb86 (bug 1437167)
dom/media/GraphDriver.cpp
dom/storage/StorageDBThread.cpp
dom/storage/StorageDBThread.h
dom/workers/WorkerPrivate.cpp
dom/workers/WorkerPrivate.h
gfx/tests/gtest/TestVsync.cpp
image/DecodePool.cpp
ipc/glue/GeckoChildProcessHost.cpp
ipc/glue/MessageChannel.cpp
ipc/glue/WindowsMessageLoop.cpp
js/src/threading/ConditionVariable.h
js/xpconnect/loader/ScriptPreloader.cpp
mozglue/misc/ConditionVariable_posix.cpp
mozglue/misc/ConditionVariable_windows.cpp
mozglue/misc/PlatformConditionVariable.h
netwerk/base/nsNetUtil.cpp
netwerk/base/nsProtocolProxyService.cpp
netwerk/cache2/CacheFileIOManager.cpp
netwerk/cache2/CacheIOThread.cpp
netwerk/dns/nsHostResolver.cpp
netwerk/dns/nsHostResolver.h
security/manager/ssl/DataStorage.cpp
security/manager/ssl/nsNSSCallbacks.cpp
security/manager/ssl/nsNSSComponent.cpp
toolkit/components/backgroundhangmonitor/BackgroundHangMonitor.cpp
toolkit/components/backgroundhangmonitor/HangDetails.cpp
toolkit/components/backgroundhangmonitor/HangDetails.h
toolkit/components/backgroundhangmonitor/HangTypes.ipdlh
toolkit/components/backgroundhangmonitor/nsIHangDetails.idl
toolkit/xre/nsUpdateDriver.cpp
xpcom/tests/gtest/TestThreadPool.cpp
xpcom/threads/BlockingResourceBase.cpp
xpcom/threads/CondVar.h
xpcom/threads/HangMonitor.cpp
xpcom/threads/Monitor.h
xpcom/threads/Scheduler.cpp
xpcom/threads/TimerThread.cpp
xpcom/threads/nsThreadPool.cpp
--- a/dom/media/GraphDriver.cpp
+++ b/dom/media/GraphDriver.cpp
@@ -360,17 +360,17 @@ OfflineClockDriver::GetCurrentTimeStamp(
   return TimeStamp();
 }
 
 void
 SystemClockDriver::WaitForNextIteration()
 {
   mGraphImpl->GetMonitor().AssertCurrentThreadOwns();
 
-  TimeDuration timeout = TimeDuration::Forever();
+  PRIntervalTime timeout = PR_INTERVAL_NO_TIMEOUT;
   TimeStamp now = TimeStamp::Now();
 
   // This lets us avoid hitting the Atomic twice when we know we won't sleep
   bool another = mGraphImpl->mNeedAnotherIteration; // atomic
   if (!another) {
     mGraphImpl->mGraphDriverAsleep = true; // atomic
     mWaitState = WAITSTATE_WAITING_INDEFINITELY;
   }
@@ -379,27 +379,27 @@ SystemClockDriver::WaitForNextIteration(
   // (EnsureNextIteration sets mNeedAnotherIteration, then tests
   // mGraphDriverAsleep
   if (another || mGraphImpl->mNeedAnotherIteration) { // atomic
     int64_t timeoutMS = MEDIA_GRAPH_TARGET_PERIOD_MS -
       int64_t((now - mCurrentTimeStamp).ToMilliseconds());
     // Make sure timeoutMS doesn't overflow 32 bits by waking up at
     // least once a minute, if we need to wake up at all
     timeoutMS = std::max<int64_t>(0, std::min<int64_t>(timeoutMS, 60*1000));
-    timeout = TimeDuration::FromMilliseconds(timeoutMS);
+    timeout = PR_MillisecondsToInterval(uint32_t(timeoutMS));
     LOG(LogLevel::Verbose,
         ("Waiting for next iteration; at %f, timeout=%f",
          (now - mInitialTimeStamp).ToSeconds(),
          timeoutMS / 1000.0));
     if (mWaitState == WAITSTATE_WAITING_INDEFINITELY) {
       mGraphImpl->mGraphDriverAsleep = false; // atomic
     }
     mWaitState = WAITSTATE_WAITING_FOR_NEXT_ITERATION;
   }
-  if (!timeout.IsZero()) {
+  if (timeout > 0) {
     mGraphImpl->GetMonitor().Wait(timeout);
     LOG(LogLevel::Verbose,
         ("Resuming after timeout; at %f, elapsed=%f",
          (TimeStamp::Now() - mInitialTimeStamp).ToSeconds(),
          (TimeStamp::Now() - now).ToSeconds()));
   }
 
   if (mWaitState == WAITSTATE_WAITING_INDEFINITELY) {
--- a/dom/storage/StorageDBThread.cpp
+++ b/dom/storage/StorageDBThread.cpp
@@ -176,16 +176,17 @@ StorageDBThread::StorageDBThread()
   : mThread(nullptr)
   , mThreadObserver(new ThreadObserver())
   , mStopIOThread(false)
   , mWALModeEnabled(false)
   , mDBReady(false)
   , mStatus(NS_OK)
   , mWorkerStatements(mWorkerConnection)
   , mReaderStatements(mReaderConnection)
+  , mDirtyEpoch(0)
   , mFlushImmediately(false)
   , mPriorityCounter(0)
 {
 }
 
 // static
 StorageDBThread*
 StorageDBThread::Get()
@@ -525,18 +526,17 @@ StorageDBThread::ThreadFunc()
       mThreadObserver->ClearPendingEvents();
       MonitorAutoUnlock unlock(mThreadObserver->GetMonitor());
       bool processedEvent;
       do {
         rv = thread->ProcessNextEvent(false, &processedEvent);
       } while (NS_SUCCEEDED(rv) && processedEvent);
     }
 
-    TimeDuration timeUntilFlush = TimeUntilFlush();
-    if (MOZ_UNLIKELY(timeUntilFlush.IsZero())) {
+    if (MOZ_UNLIKELY(TimeUntilFlush() == 0)) {
       // Flush time is up or flush has been forced, do it now.
       UnscheduleFlush();
       if (mPendingTasks.Prepare()) {
         {
           MonitorAutoUnlock unlockMonitor(mThreadObserver->GetMonitor());
           rv = mPendingTasks.Execute(this);
         }
 
@@ -553,17 +553,17 @@ StorageDBThread::ThreadFunc()
         MonitorAutoUnlock unlockMonitor(mThreadObserver->GetMonitor());
         op->PerformAndFinalize(this);
       }
 
       if (op->Type() == DBOperation::opPreloadUrgent) {
         SetDefaultPriority(); // urgent preload unscheduled
       }
     } else if (MOZ_UNLIKELY(!mStopIOThread)) {
-      lockMonitor.Wait(timeUntilFlush);
+      lockMonitor.Wait(TimeUntilFlush());
     }
   } // thread loop
 
   mStatus = ShutdownDatabase();
 
   if (threadInternal) {
     threadInternal->SetObserver(nullptr);
   }
@@ -820,49 +820,53 @@ StorageDBThread::ShutdownDatabase()
 void
 StorageDBThread::ScheduleFlush()
 {
   if (mDirtyEpoch) {
     return; // Already scheduled
   }
 
   // Must be non-zero to indicate we are scheduled
-  mDirtyEpoch = TimeStamp::Now();
+  mDirtyEpoch = PR_IntervalNow() | 1;
 
   // Wake the monitor from indefinite sleep...
   (mThreadObserver->GetMonitor()).Notify();
 }
 
 void
 StorageDBThread::UnscheduleFlush()
 {
   // We are just about to do the flush, drop flags
   mFlushImmediately = false;
-  mDirtyEpoch = TimeStamp();
+  mDirtyEpoch = 0;
 }
 
-TimeDuration
+PRIntervalTime
 StorageDBThread::TimeUntilFlush()
 {
   if (mFlushImmediately) {
     return 0; // Do it now regardless the timeout.
   }
 
+  static_assert(PR_INTERVAL_NO_TIMEOUT != 0,
+      "PR_INTERVAL_NO_TIMEOUT must be non-zero");
+
   if (!mDirtyEpoch) {
-    return TimeDuration::Forever(); // No pending task...
+    return PR_INTERVAL_NO_TIMEOUT; // No pending task...
   }
 
-  TimeStamp now = TimeStamp::Now();
-  TimeDuration age = now - mDirtyEpoch;
-  static const TimeDuration kMaxAge = TimeDuration::FromMilliseconds(FLUSHING_INTERVAL_MS);
+  static const PRIntervalTime kMaxAge = PR_MillisecondsToInterval(FLUSHING_INTERVAL_MS);
+
+  PRIntervalTime now = PR_IntervalNow() | 1;
+  PRIntervalTime age = now - mDirtyEpoch;
   if (age > kMaxAge) {
     return 0; // It is time.
   }
 
-  return kMaxAge - age; // Time left. This is used to sleep the monitor.
+  return kMaxAge - age; // Time left, this is used to sleep the monitor
 }
 
 void
 StorageDBThread::NotifyFlushCompletion()
 {
 #ifdef DOM_STORAGE_TESTS
   if (!NS_IsMainThread()) {
     RefPtr<nsRunnableMethod<StorageDBThread, void, false>> event =
--- a/dom/storage/StorageDBThread.h
+++ b/dom/storage/StorageDBThread.h
@@ -9,17 +9,16 @@
 
 #include "prthread.h"
 #include "prinrval.h"
 #include "nsTArray.h"
 #include "mozilla/Atomics.h"
 #include "mozilla/Monitor.h"
 #include "mozilla/BasePrincipal.h"
 #include "mozilla/storage/StatementCache.h"
-#include "mozilla/TimeStamp.h"
 #include "nsAutoPtr.h"
 #include "nsString.h"
 #include "nsCOMPtr.h"
 #include "nsClassHashtable.h"
 #include "nsIFile.h"
 #include "nsIThreadInternal.h"
 
 class mozIStorageConnection;
@@ -436,17 +435,17 @@ private:
   // Connection used only on the main thread for sync read operations
   nsCOMPtr<mozIStorageConnection> mReaderConnection;
 
   StatementCache mWorkerStatements;
   StatementCache mReaderStatements;
 
   // Time the first pending operation has been added to the pending operations
   // list
-  TimeStamp mDirtyEpoch;
+  PRIntervalTime mDirtyEpoch;
 
   // Flag to force immediate flush of all pending operations
   bool mFlushImmediately;
 
   // List of preloading operations, in chronological or priority order.
   // Executed prioritly over pending update operations.
   nsTArray<DBOperation*> mPreloads;
 
@@ -482,22 +481,22 @@ private:
   // Called when flush of pending tasks is being executed
   void UnscheduleFlush();
 
   // This method is used for two purposes:
   // 1. as a value passed to monitor.Wait() method
   // 2. as in indicator that flush has to be performed
   //
   // Return:
-  // - TimeDuration::Forever() when no pending tasks are scheduled
-  // - Non-zero TimeDuration when tasks have been scheduled, but it
-  //   is still not time to perform the flush ; it is actual time to
-  //   wait until the flush has to happen.
-  // - 0 TimeDuration when it is time to do the flush
-  TimeDuration TimeUntilFlush();
+  // - PR_INTERVAL_NO_TIMEOUT when no pending tasks are scheduled
+  // - larger then zero when tasks have been scheduled, but it is
+  //   still not time to perform the flush ; it is actual interval
+  //   time to wait until the flush has to happen
+  // - 0 when it is time to do the flush
+  PRIntervalTime TimeUntilFlush();
 
   // Notifies to the main thread that flush has completed
   void NotifyFlushCompletion();
 
   // Thread loop
   static void ThreadFunc(void* aArg);
   void ThreadFunc();
 };
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -3609,17 +3609,17 @@ WorkerPrivate::InterruptCallback(JSConte
     }
 
     while ((mayContinue = MayContinueRunning())) {
       MutexAutoLock lock(mMutex);
       if (!mControlQueue.IsEmpty()) {
         break;
       }
 
-      WaitForWorkerEvents();
+      WaitForWorkerEvents(PR_MillisecondsToInterval(UINT32_MAX));
     }
   }
 
   if (!mayContinue) {
     // We want only uncatchable exceptions here.
     NS_ASSERTION(!JS_IsExceptionPending(aCx),
                  "Should not have an exception set here!");
     return false;
@@ -3730,23 +3730,23 @@ WorkerPrivate::DisableMemoryReporter()
 
   // Finally unregister the memory reporter.
   if (NS_FAILED(UnregisterWeakMemoryReporter(memoryReporter))) {
     NS_WARNING("Failed to unregister memory reporter!");
   }
 }
 
 void
-WorkerPrivate::WaitForWorkerEvents()
+WorkerPrivate::WaitForWorkerEvents(PRIntervalTime aInterval)
 {
   AssertIsOnWorkerThread();
   mMutex.AssertCurrentThreadOwns();
 
   // Wait for a worker event.
-  mCondVar.Wait();
+  mCondVar.Wait(aInterval);
 }
 
 WorkerPrivate::ProcessAllControlRunnablesResult
 WorkerPrivate::ProcessAllControlRunnablesLocked()
 {
   AssertIsOnWorkerThread();
   mMutex.AssertCurrentThreadOwns();
 
--- a/dom/workers/WorkerPrivate.h
+++ b/dom/workers/WorkerPrivate.h
@@ -1269,17 +1269,17 @@ private:
 
   void
   EnableMemoryReporter();
 
   void
   DisableMemoryReporter();
 
   void
-  WaitForWorkerEvents();
+  WaitForWorkerEvents(PRIntervalTime interval = PR_INTERVAL_NO_TIMEOUT);
 
   void
   PostMessageToParentInternal(JSContext* aCx,
                               JS::Handle<JS::Value> aMessage,
                               const Sequence<JSObject*>& aTransferable,
                               ErrorResult& aRv);
 
   // If the worker shutdown status is equal or greater then aFailStatus, this
--- a/gfx/tests/gtest/TestVsync.cpp
+++ b/gfx/tests/gtest/TestVsync.cpp
@@ -44,17 +44,18 @@ public:
   {
     MOZ_ASSERT(NS_IsMainThread());
     if (DidGetVsyncNotification()) {
       return;
     }
 
     { // scope lock
       MonitorAutoLock lock(mVsyncMonitor);
-      lock.Wait(TimeDuration::FromMilliseconds(kVsyncTimeoutMS));
+      PRIntervalTime timeout = PR_MillisecondsToInterval(kVsyncTimeoutMS);
+      lock.Wait(timeout);
     }
   }
 
   bool DidGetVsyncNotification()
   {
     MonitorAutoLock lock(mVsyncMonitor);
     return mDidGetVsyncNotification;
   }
--- a/image/DecodePool.cpp
+++ b/image/DecodePool.cpp
@@ -5,17 +5,16 @@
 
 #include "DecodePool.h"
 
 #include <algorithm>
 
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/Monitor.h"
-#include "mozilla/TimeStamp.h"
 #include "nsCOMPtr.h"
 #include "nsIObserverService.h"
 #include "nsIThreadPool.h"
 #include "nsThreadManager.h"
 #include "nsThreadUtils.h"
 #include "nsXPCOMCIDInternal.h"
 #include "prsystem.h"
 #include "nsIXULRuntime.h"
@@ -54,17 +53,17 @@ struct Work
 class DecodePoolImpl
 {
 public:
   MOZ_DECLARE_REFCOUNTED_TYPENAME(DecodePoolImpl)
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DecodePoolImpl)
 
   DecodePoolImpl(uint8_t aMaxThreads,
                  uint8_t aMaxIdleThreads,
-                 TimeDuration aIdleTimeout)
+                 PRIntervalTime aIdleTimeout)
     : mMonitor("DecodePoolImpl")
     , mThreads(aMaxThreads)
     , mIdleTimeout(aIdleTimeout)
     , mMaxIdleThreads(aMaxIdleThreads)
     , mAvailableThreads(aMaxThreads)
     , mIdleThreads(0)
     , mShuttingDown(false)
   {
@@ -168,17 +167,17 @@ public:
   }
 
 private:
   /// Pops a new work item, blocking if necessary.
   Work PopWorkLocked(bool aShutdownIdle)
   {
     mMonitor.AssertCurrentThreadOwns();
 
-    TimeDuration timeout = mIdleTimeout;
+    PRIntervalTime timeout = mIdleTimeout;
     do {
       if (!mHighPriorityQueue.IsEmpty()) {
         return PopWorkFromQueue(mHighPriorityQueue);
       }
 
       if (!mLowPriorityQueue.IsEmpty()) {
         return PopWorkFromQueue(mLowPriorityQueue);
       }
@@ -193,29 +192,29 @@ private:
         // will never shutdown until the process itself is torn down.
         ++mIdleThreads;
         MOZ_ASSERT(mIdleThreads <= mThreads.Capacity());
         mMonitor.Wait();
       } else {
         // This thread should shutdown if it is idle. If we have waited longer
         // than the timeout period without having done any work, then we should
         // shutdown the thread.
-        if (timeout.IsZero()) {
+        if (timeout == 0) {
           return CreateShutdownWork();
         }
 
         ++mIdleThreads;
         MOZ_ASSERT(mIdleThreads <= mThreads.Capacity());
 
-        TimeStamp now = TimeStamp::Now();
+        PRIntervalTime now = PR_IntervalNow();
         mMonitor.Wait(timeout);
-        TimeDuration delta = TimeStamp::Now() - now;
+        PRIntervalTime delta = PR_IntervalNow() - now;
         if (delta > timeout) {
           timeout = 0;
-        } else if (timeout != TimeDuration::Forever()) {
+        } else {
           timeout -= delta;
         }
       }
 
       MOZ_ASSERT(mIdleThreads > 0);
       --mIdleThreads;
     } while (true);
   }
@@ -243,17 +242,17 @@ private:
 
   nsThreadPoolNaming mThreadNaming;
 
   // mMonitor guards everything below.
   Monitor mMonitor;
   nsTArray<RefPtr<IDecodingTask>> mHighPriorityQueue;
   nsTArray<RefPtr<IDecodingTask>> mLowPriorityQueue;
   nsTArray<nsCOMPtr<nsIThread>> mThreads;
-  TimeDuration mIdleTimeout;
+  PRIntervalTime mIdleTimeout;
   uint8_t mMaxIdleThreads;   // Maximum number of workers when idle.
   uint8_t mAvailableThreads; // How many new threads can be created.
   uint8_t mIdleThreads; // How many created threads are waiting.
   bool mShuttingDown;
 };
 
 class DecodePoolWorker final : public Runnable
 {
@@ -379,22 +378,22 @@ DecodePool::DecodePool()
     limit = 4;
   }
 
   // The maximum number of idle threads allowed.
   uint32_t idleLimit;
 
   // The timeout period before shutting down idle threads.
   int32_t prefIdleTimeout = gfxPrefs::ImageMTDecodingIdleTimeout();
-  TimeDuration idleTimeout;
+  PRIntervalTime idleTimeout;
   if (prefIdleTimeout <= 0) {
-    idleTimeout = TimeDuration::Forever();
+    idleTimeout = PR_INTERVAL_NO_TIMEOUT;
     idleLimit = limit;
   } else {
-    idleTimeout = TimeDuration::FromMilliseconds(prefIdleTimeout);
+    idleTimeout = PR_MillisecondsToInterval(static_cast<uint32_t>(prefIdleTimeout));
     idleLimit = (limit + 1) / 2;
   }
 
   // Initialize the thread pool.
   mImpl = new DecodePoolImpl(limit, idleLimit, idleTimeout);
 
   // Initialize the I/O thread.
   nsresult rv = NS_NewNamedThread("ImageIO", getter_AddRefs(mIOThread));
--- a/ipc/glue/GeckoChildProcessHost.cpp
+++ b/ipc/glue/GeckoChildProcessHost.cpp
@@ -367,39 +367,40 @@ GeckoChildProcessHost::AsyncLaunch(std::
 
 bool
 GeckoChildProcessHost::WaitUntilConnected(int32_t aTimeoutMs)
 {
   AUTO_PROFILER_LABEL("GeckoChildProcessHost::WaitUntilConnected", OTHER);
 
   // NB: this uses a different mechanism than the chromium parent
   // class.
-  TimeDuration timeout = (aTimeoutMs > 0) ?
-    TimeDuration::FromMilliseconds(aTimeoutMs) : TimeDuration::Forever();
+  PRIntervalTime timeoutTicks = (aTimeoutMs > 0) ?
+    PR_MillisecondsToInterval(aTimeoutMs) : PR_INTERVAL_NO_TIMEOUT;
 
   MonitorAutoLock lock(mMonitor);
-  TimeStamp waitStart = TimeStamp::Now();
-  TimeStamp current;
+  PRIntervalTime waitStart = PR_IntervalNow();
+  PRIntervalTime current;
 
   // We'll receive several notifications, we need to exit when we
   // have either successfully launched or have timed out.
   while (mProcessState != PROCESS_CONNECTED) {
     // If there was an error then return it, don't wait out the timeout.
     if (mProcessState == PROCESS_ERROR) {
       break;
     }
 
-    CVStatus status = lock.Wait(timeout);
-    if (status == CVStatus::Timeout) {
-      break;
-    }
+    lock.Wait(timeoutTicks);
 
-    if (timeout != TimeDuration::Forever()) {
-      current = TimeStamp::Now();
-      timeout -= current - waitStart;
+    if (timeoutTicks != PR_INTERVAL_NO_TIMEOUT) {
+      current = PR_IntervalNow();
+      PRIntervalTime elapsed = current - waitStart;
+      if (elapsed > timeoutTicks) {
+        break;
+      }
+      timeoutTicks = timeoutTicks - elapsed;
       waitStart = current;
     }
   }
 
   return mProcessState == PROCESS_CONNECTED;
 }
 
 bool
--- a/ipc/glue/MessageChannel.cpp
+++ b/ipc/glue/MessageChannel.cpp
@@ -2311,16 +2311,23 @@ MessageChannel::EnqueuePendingMessages()
     MaybeUndeferIncall();
 
     // XXX performance tuning knob: could process all or k pending
     // messages here, rather than enqueuing for later processing
 
     RepostAllMessages();
 }
 
+static inline bool
+IsTimeoutExpired(PRIntervalTime aStart, PRIntervalTime aTimeout)
+{
+    return (aTimeout != PR_INTERVAL_NO_TIMEOUT) &&
+           (aTimeout <= (PR_IntervalNow() - aStart));
+}
+
 bool
 MessageChannel::WaitResponse(bool aWaitTimedOut)
 {
     if (aWaitTimedOut) {
         if (mInTimeoutSecondHalf) {
             // We've really timed out this time.
             return false;
         }
@@ -2340,24 +2347,27 @@ MessageChannel::WaitForSyncNotify(bool /
     // WARNING: We don't release the lock here. We can't because the link thread
     // could signal at this time and we would miss it. Instead we require
     // ArtificialTimeout() to be extremely simple.
     if (mListener->ArtificialTimeout()) {
         return false;
     }
 #endif
 
-    TimeDuration timeout = (kNoTimeout == mTimeoutMs) ?
-                           TimeDuration::Forever() :
-                           TimeDuration::FromMilliseconds(mTimeoutMs);
-    CVStatus status = mMonitor->Wait(timeout);
+    PRIntervalTime timeout = (kNoTimeout == mTimeoutMs) ?
+                             PR_INTERVAL_NO_TIMEOUT :
+                             PR_MillisecondsToInterval(mTimeoutMs);
+    // XXX could optimize away this syscall for "no timeout" case if desired
+    PRIntervalTime waitStart = PR_IntervalNow();
+
+    mMonitor->Wait(timeout);
 
     // If the timeout didn't expire, we know we received an event. The
     // converse is not true.
-    return WaitResponse(status == CVStatus::Timeout);
+    return WaitResponse(IsTimeoutExpired(waitStart, timeout));
 }
 
 bool
 MessageChannel::WaitForInterruptNotify()
 {
     return WaitForSyncNotify(true);
 }
 
--- a/ipc/glue/WindowsMessageLoop.cpp
+++ b/ipc/glue/WindowsMessageLoop.cpp
@@ -841,16 +841,23 @@ MessageChannel::SpinInternalEventLoop()
                                              QS_ALLINPUT);
     if (result == WAIT_OBJECT_0) {
       // Our NotifyWorkerThread event was signaled
       return;
     }
   } while (true);
 }
 
+static inline bool
+IsTimeoutExpired(PRIntervalTime aStart, PRIntervalTime aTimeout)
+{
+  return (aTimeout != PR_INTERVAL_NO_TIMEOUT) &&
+    (aTimeout <= (PR_IntervalNow() - aStart));
+}
+
 static HHOOK gWindowHook;
 
 static inline void
 StartNeutering()
 {
   MOZ_ASSERT(gUIThreadId);
   MOZ_ASSERT(!gWindowHook);
   NS_ASSERTION(!MessageChannel::IsPumpingMessages(),
@@ -1018,31 +1025,37 @@ MessageChannel::WaitForSyncNotify(bool a
     MOZ_ASSERT(!(mFlags & REQUIRE_DEFERRED_MESSAGE_PROTECTION));
     return WaitForSyncNotifyWithA11yReentry();
   }
 #endif
 
   // Use a blocking wait if this channel does not require
   // Windows message deferral behavior.
   if (!(mFlags & REQUIRE_DEFERRED_MESSAGE_PROTECTION) || !aHandleWindowsMessages) {
-    TimeDuration timeout = (kNoTimeout == mTimeoutMs) ?
-                           TimeDuration::Forever() :
-                           TimeDuration::FromMilliseconds(mTimeoutMs);
+    PRIntervalTime timeout = (kNoTimeout == mTimeoutMs) ?
+                             PR_INTERVAL_NO_TIMEOUT :
+                             PR_MillisecondsToInterval(mTimeoutMs);
+    PRIntervalTime waitStart = 0;
+
+    if (timeout != PR_INTERVAL_NO_TIMEOUT) {
+      waitStart = PR_IntervalNow();
+    }
 
     MOZ_ASSERT(!mIsSyncWaitingOnNonMainThread);
     mIsSyncWaitingOnNonMainThread = true;
 
-    CVStatus status = mMonitor->Wait(timeout);
+    mMonitor->Wait(timeout);
 
     MOZ_ASSERT(mIsSyncWaitingOnNonMainThread);
     mIsSyncWaitingOnNonMainThread = false;
 
     // If the timeout didn't expire, we know we received an event. The
     // converse is not true.
-    return WaitResponse(status == CVStatus::Timeout);
+    return WaitResponse(timeout == PR_INTERVAL_NO_TIMEOUT ?
+                        false : IsTimeoutExpired(waitStart, timeout));
   }
 
   NS_ASSERTION(mFlags & REQUIRE_DEFERRED_MESSAGE_PROTECTION,
                "Shouldn't be here for channels that don't use message deferral!");
   NS_ASSERTION(mTopFrame && !mTopFrame->mInterrupt,
                "Top frame is not a sync frame!");
 
   MonitorAutoUnlock unlock(*mMonitor);
--- a/js/src/threading/ConditionVariable.h
+++ b/js/src/threading/ConditionVariable.h
@@ -93,17 +93,17 @@ public:
 
   // Block the current thread of execution until woken from another thread, or
   // the given time duration has elapsed. Given that the system may be
   // interrupted between the callee and the actual wait beginning, this call
   // has a minimum granularity of the system's scheduling interval, and may
   // encounter substantially longer delays, depending on system load.
   CVStatus wait_for(UniqueLock<Mutex>& lock,
                     const mozilla::TimeDuration& rel_time) {
-    return impl_.wait_for(lock.lock, rel_time) == mozilla::CVStatus::Timeout
+    return impl_.wait_for(lock.lock, rel_time) == mozilla::detail::CVStatus::Timeout
       ? CVStatus::Timeout : CVStatus::NoTimeout;
   }
 
   // As with |wait_for|, block the current thread of execution until woken from
   // another thread or the given time duration has elapsed. This method will
   // resume waiting once woken until the given Predicate |pred| evaluates to
   // true.
   template <typename Predicate>
--- a/js/xpconnect/loader/ScriptPreloader.cpp
+++ b/js/xpconnect/loader/ScriptPreloader.cpp
@@ -690,17 +690,17 @@ ScriptPreloader::Run()
 {
     MonitorAutoLock mal(mSaveMonitor);
 
     // Ideally wait about 10 seconds before saving, to avoid unnecessary IO
     // during early startup. But only if the cache hasn't been invalidated,
     // since that can trigger a new write during shutdown, and we don't want to
     // cause shutdown hangs.
     if (!mCacheInvalidated) {
-        mal.Wait(TimeDuration::FromSeconds(10));
+        mal.Wait(10000);
     }
 
     auto result = URLPreloader::GetSingleton().WriteCache();
     Unused << NS_WARN_IF(result.isErr());
 
     result = WriteCache();
     Unused << NS_WARN_IF(result.isErr());
 
--- a/mozglue/misc/ConditionVariable_posix.cpp
+++ b/mozglue/misc/ConditionVariable_posix.cpp
@@ -114,17 +114,17 @@ mozilla::detail::ConditionVariableImpl::
 {
   pthread_cond_t* ptCond = &platformData()->ptCond;
   pthread_mutex_t* ptMutex = &lock.platformData()->ptMutex;
 
   int r = pthread_cond_wait(ptCond, ptMutex);
   MOZ_RELEASE_ASSERT(r == 0);
 }
 
-mozilla::CVStatus
+mozilla::detail::CVStatus
 mozilla::detail::ConditionVariableImpl::wait_for(MutexImpl& lock,
 						 const TimeDuration& a_rel_time)
 {
   if (a_rel_time == TimeDuration::Forever()) {
     wait(lock);
     return CVStatus::NoTimeout;
   }
 
--- a/mozglue/misc/ConditionVariable_windows.cpp
+++ b/mozglue/misc/ConditionVariable_windows.cpp
@@ -54,45 +54,31 @@ mozilla::detail::ConditionVariableImpl::
 void
 mozilla::detail::ConditionVariableImpl::wait(MutexImpl& lock)
 {
   CRITICAL_SECTION* cs = &lock.platformData()->criticalSection;
   bool r = SleepConditionVariableCS(&platformData()->cv_, cs, INFINITE);
   MOZ_RELEASE_ASSERT(r);
 }
 
-mozilla::CVStatus
+mozilla::detail::CVStatus
 mozilla::detail::ConditionVariableImpl::wait_for(MutexImpl& lock,
                                                  const mozilla::TimeDuration& rel_time)
 {
-  if (rel_time == mozilla::TimeDuration::Forever()) {
-    wait(lock);
-    return CVStatus::NoTimeout;
-  }
-
   CRITICAL_SECTION* cs = &lock.platformData()->criticalSection;
 
-  // Note that DWORD is unsigned, so we have to be careful to clamp at 0. If
-  // rel_time is Forever, then ToMilliseconds is +inf, which evaluates as
-  // greater than UINT32_MAX, resulting in the correct INFINITE wait. We also
-  // don't want to round sub-millisecond waits to 0, as that wastes energy (see
-  // bug 1437167 comment 6), so we instead round submillisecond waits to 1ms.
+  // Note that DWORD is unsigned, so we have to be careful to clamp at 0.
+  // If rel_time is Forever, then ToMilliseconds is +inf, which evaluates as
+  // greater than UINT32_MAX, resulting in the correct INFINITE wait.
   double msecd = rel_time.ToMilliseconds();
-  DWORD msec;
-  if (msecd < 0.0) {
-    msec = 0;
-  } else if (msecd > UINT32_MAX) {
-    msec = INFINITE;
-  } else {
-    msec = static_cast<DWORD>(msecd);
-    // Round submillisecond waits to 1ms.
-    if (msec == 0 && !rel_time.IsZero()) {
-      msec = 1;
-    }
-  }
+  DWORD msec = msecd < 0.0
+               ? 0
+               : msecd > UINT32_MAX
+                 ? INFINITE
+                 : static_cast<DWORD>(msecd);
 
   BOOL r = SleepConditionVariableCS(&platformData()->cv_, cs, msec);
   if (r)
     return CVStatus::NoTimeout;
   MOZ_RELEASE_ASSERT(GetLastError() == ERROR_TIMEOUT);
   return CVStatus::Timeout;
 }
 
--- a/mozglue/misc/PlatformConditionVariable.h
+++ b/mozglue/misc/PlatformConditionVariable.h
@@ -14,23 +14,23 @@
 
 #include <stdint.h>
 #ifndef XP_WIN
 # include <pthread.h>
 #endif
 
 namespace mozilla {
 
+namespace detail {
+
 enum class CVStatus {
   NoTimeout,
   Timeout
 };
 
-namespace detail {
-
 class ConditionVariableImpl {
 public:
   struct PlatformData;
 
   MFBT_API ConditionVariableImpl();
   MFBT_API ~ConditionVariableImpl();
 
   // Wake one thread that is waiting on this condition.
--- a/netwerk/base/nsNetUtil.cpp
+++ b/netwerk/base/nsNetUtil.cpp
@@ -1672,17 +1672,18 @@ private:
         mTaskQueue = new TaskQueue(target.forget());
 
         MonitorAutoLock lock(mMonitor);
 
         nsCOMPtr<nsIRunnable> runnable = this;
         nsresult rv = mTaskQueue->Dispatch(runnable.forget());
         NS_ENSURE_SUCCESS(rv, rv);
 
-        lock.Wait();
+        rv = lock.Wait();
+        NS_ENSURE_SUCCESS(rv, rv);
 
         mCompleted = true;
         return mAsyncResult;
     }
 
     // This method runs on the I/O Thread when the owning thread is blocked by
     // the mMonitor. It is called multiple times until mCount is greater than 0
     // or until there is something to read in the stream.
--- a/netwerk/base/nsProtocolProxyService.cpp
+++ b/netwerk/base/nsProtocolProxyService.cpp
@@ -1609,17 +1609,17 @@ class nsAsyncBridgeRequest final  : publ
         mStatus = status;
         mPACString = pacString;
         mPACURL = newPACURL;
         mCondVar.Notify();
     }
 
     void Lock()   { mMutex.Lock(); }
     void Unlock() { mMutex.Unlock(); }
-    void Wait()   { mCondVar.Wait(TimeDuration::FromSeconds(3)); }
+    void Wait()   { mCondVar.Wait(PR_SecondsToInterval(3)); }
 
 private:
     ~nsAsyncBridgeRequest()
     {
     }
 
     friend class nsProtocolProxyService;
 
--- a/netwerk/cache2/CacheFileIOManager.cpp
+++ b/netwerk/cache2/CacheFileIOManager.cpp
@@ -573,17 +573,17 @@ public:
   {
     MonitorAutoLock mon(mMonitor);
 
     DebugOnly<nsresult> rv;
     rv = CacheFileIOManager::gInstance->mIOThread->Dispatch(
       this, CacheIOThread::WRITE); // When writes and closing of handles is done
     MOZ_ASSERT(NS_SUCCEEDED(rv));
 
-    TimeDuration waitTime = TimeDuration::FromSeconds(1);
+    PRIntervalTime const waitTime = PR_MillisecondsToInterval(1000);
     while (!mNotified) {
       mon.Wait(waitTime);
       if (!mNotified) {
         // If there is any IO blocking on the IO thread, this will
         // try to cancel it.  Returns no later than after two seconds.
         MonitorAutoUnlock unmon(mMonitor); // Prevent delays
         CacheFileIOManager::gInstance->mIOThread->CancelBlockingIO();
       }
--- a/netwerk/cache2/CacheIOThread.cpp
+++ b/netwerk/cache2/CacheIOThread.cpp
@@ -514,17 +514,17 @@ loopStart:
       if (EventsPending()) {
         continue;
       }
 
       if (mShutdown) {
         break;
       }
 
-      lock.Wait();
+      lock.Wait(PR_INTERVAL_NO_TIMEOUT);
 
     } while (true);
 
     MOZ_ASSERT(!EventsPending());
 
 #ifdef DEBUG
     // This is for correct assertion on XPCOM events dispatch.
     mInsideLoop = false;
--- a/netwerk/dns/nsHostResolver.cpp
+++ b/netwerk/dns/nsHostResolver.cpp
@@ -519,18 +519,18 @@ nsHostResolver::nsHostResolver(uint32_t 
     , mShutdown(true)
     , mNumIdleThreads(0)
     , mThreadCount(0)
     , mActiveAnyThreadCount(0)
     , mPendingCount(0)
 {
     mCreationTime = PR_Now();
 
-    mLongIdleTimeout  = TimeDuration::FromSeconds(LongIdleTimeoutSeconds);
-    mShortIdleTimeout = TimeDuration::FromSeconds(ShortIdleTimeoutSeconds);
+    mLongIdleTimeout  = PR_SecondsToInterval(LongIdleTimeoutSeconds);
+    mShortIdleTimeout = PR_SecondsToInterval(ShortIdleTimeoutSeconds);
 }
 
 nsHostResolver::~nsHostResolver() = default;
 
 nsresult
 nsHostResolver::Init()
 {
     MOZ_ASSERT(NS_IsMainThread());
@@ -1292,23 +1292,22 @@ nsHostResolver::DeQueue(LinkedList<RefPt
     rec.forget(aResult);
     (*aResult)->onQueue = false;
 }
 
 bool
 nsHostResolver::GetHostToLookup(nsHostRecord **result)
 {
     bool timedOut = false;
-    TimeDuration timeout;
-    TimeStamp epoch, now;
+    PRIntervalTime epoch, now, timeout;
 
     MutexAutoLock lock(mLock);
 
     timeout = (mNumIdleThreads >= HighThreadThreshold) ? mShortIdleTimeout : mLongIdleTimeout;
-    epoch = TimeStamp::Now();
+    epoch = PR_IntervalNow();
 
     while (!mShutdown) {
         // remove next record from Q; hand over owning reference. Check high, then med, then low
 
 #define SET_GET_TTL(var, val) (var)->mGetTtl = sGetTtlEnabled && (val)
 
         if (!mHighQ.isEmpty()) {
             DeQueue (mHighQ, result);
@@ -1343,26 +1342,25 @@ nsHostResolver::GetHostToLookup(nsHostRe
         //  (1) the pending queue has a host record to process
         //  (2) the shutdown flag has been set
         //  (3) the thread has been idle for too long
 
         mNumIdleThreads++;
         mIdleThreadCV.Wait(timeout);
         mNumIdleThreads--;
 
-        now = TimeStamp::Now();
+        now = PR_IntervalNow();
 
-        if (now - epoch >= timeout) {
+        if ((PRIntervalTime)(now - epoch) >= timeout)
             timedOut = true;
-        } else {
-            // It is possible that CondVar::Wait() was interrupted and returned
-            // early, in which case we will loop back and re-enter it. In that
-            // case we want to do so with the new timeout reduced to reflect
-            // time already spent waiting.
-            timeout -= now - epoch;
+        else {
+            // It is possible that PR_WaitCondVar() was interrupted and returned early,
+            // in which case we will loop back and re-enter it. In that case we want to
+            // do so with the new timeout reduced to reflect time already spent waiting.
+            timeout -= (PRIntervalTime)(now - epoch);
             epoch = now;
         }
     }
 
     // tell thread to exit...
     return false;
 }
 
--- a/netwerk/dns/nsHostResolver.h
+++ b/netwerk/dns/nsHostResolver.h
@@ -439,18 +439,18 @@ private:
     CondVar       mIdleThreadCV;
     nsRefPtrHashtable<nsGenericHashKey<nsHostKey>, nsHostRecord> mRecordDB;
     mozilla::LinkedList<RefPtr<nsHostRecord>> mHighQ;
     mozilla::LinkedList<RefPtr<nsHostRecord>> mMediumQ;
     mozilla::LinkedList<RefPtr<nsHostRecord>> mLowQ;
     mozilla::LinkedList<RefPtr<nsHostRecord>> mEvictionQ;
     uint32_t      mEvictionQSize;
     PRTime        mCreationTime;
-    mozilla::TimeDuration mLongIdleTimeout;
-    mozilla::TimeDuration mShortIdleTimeout;
+    PRIntervalTime mLongIdleTimeout;
+    PRIntervalTime mShortIdleTimeout;
 
     mozilla::Atomic<bool>     mShutdown;
     mozilla::Atomic<uint32_t> mNumIdleThreads;
     mozilla::Atomic<uint32_t> mThreadCount;
     mozilla::Atomic<uint32_t> mActiveAnyThreadCount;
     mozilla::Atomic<uint32_t> mPendingCount;
 
     // Set the expiration time stamps appropriately.
--- a/security/manager/ssl/DataStorage.cpp
+++ b/security/manager/ssl/DataStorage.cpp
@@ -586,17 +586,20 @@ DataStorage::AsyncReadData(bool& aHavePr
 
 void
 DataStorage::WaitForReady()
 {
   MOZ_DIAGNOSTIC_ASSERT(mInitCalled, "Waiting before Init() has been called?");
 
   MonitorAutoLock readyLock(mReadyMonitor);
   while (!mReady) {
-    readyLock.Wait();
+    nsresult rv = readyLock.Wait();
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      break;
+    }
   }
   MOZ_ASSERT(mReady);
 }
 
 nsCString
 DataStorage::Get(const nsCString& aKey, DataStorageType aType)
 {
   WaitForReady();
--- a/security/manager/ssl/nsNSSCallbacks.cpp
+++ b/security/manager/ssl/nsNSSCallbacks.cpp
@@ -422,36 +422,36 @@ nsNSSHttpRequestSession::internal_send_r
   }
 
   bool request_canceled = false;
 
   {
     MutexAutoLock locker(waitLock);
 
     const TimeStamp startTime = TimeStamp::NowLoRes();
-    TimeDuration wait_interval;
+    PRIntervalTime wait_interval;
 
     bool running_on_main_thread = NS_IsMainThread();
     if (running_on_main_thread)
     {
       // The result of running this on the main thread
       // is a series of small timeouts mixed with spinning the
       // event loop - this is always dangerous as there is so much main
       // thread code that does not expect to be called re-entrantly. Your
       // app really shouldn't do that.
       NS_WARNING("Security network blocking I/O on Main Thread");
 
       // let's process events quickly
-      wait_interval = TimeDuration::FromMicroseconds(50);
+      wait_interval = PR_MicrosecondsToInterval(50);
     }
     else
     {
       // On a secondary thread, it's fine to wait some more for
       // for the condition variable.
-      wait_interval = TimeDuration::FromMilliseconds(250);
+      wait_interval = PR_MillisecondsToInterval(250);
     }
 
     while (waitFlag)
     {
       if (running_on_main_thread)
       {
         // Networking runs on the main thread, which we happen to block here.
         // Processing events will allow the OCSP networking to run while we
--- a/security/manager/ssl/nsNSSComponent.cpp
+++ b/security/manager/ssl/nsNSSComponent.cpp
@@ -1097,17 +1097,20 @@ nsNSSComponent::HasUserCertsInstalled(bo
   return NS_OK;
 }
 
 nsresult
 nsNSSComponent::BlockUntilLoadableRootsLoaded()
 {
   MonitorAutoLock rootsLoadedLock(mLoadableRootsLoadedMonitor);
   while (!mLoadableRootsLoaded) {
-    rootsLoadedLock.Wait();
+    nsresult rv = rootsLoadedLock.Wait();
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
   }
   MOZ_ASSERT(mLoadableRootsLoaded);
 
   return mLoadableRootsLoadedResult;
 }
 
 nsresult
 nsNSSComponent::CheckForSmartCardChanges()
--- a/toolkit/components/backgroundhangmonitor/BackgroundHangMonitor.cpp
+++ b/toolkit/components/backgroundhangmonitor/BackgroundHangMonitor.cpp
@@ -93,17 +93,17 @@ public:
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_NSIOBSERVER
   static StaticRefPtr<BackgroundHangManager> sInstance;
   static bool sDisabled;
 
   // Lock for access to members of this class
   Monitor mLock;
   // Current time as seen by hang monitors
-  TimeStamp mNow;
+  PRIntervalTime mIntervalNow;
   // List of BackgroundHangThread instances associated with each thread
   LinkedList<BackgroundHangThread> mHangThreads;
   // A reference to the StreamTransportService. This is gotten on the main
   // thread, and carried around, as nsStreamTransportService::Init is
   // non-threadsafe.
   nsCOMPtr<nsIEventTarget> mSTS;
   // Allows us to watch CPU usage and annotate hangs when the system is
   // under high external load.
@@ -177,24 +177,24 @@ public:
   static BackgroundHangThread* FindThread();
 
   static void Startup()
   {
     /* We can tolerate init() failing. */
     sTlsKeyInitialized = sTlsKey.init();
   }
 
-  // Hang timeout
-  const TimeDuration mTimeout;
-  // PermaHang timeout
-  const TimeDuration mMaxTimeout;
+  // Hang timeout in ticks
+  const PRIntervalTime mTimeout;
+  // PermaHang timeout in ticks
+  const PRIntervalTime mMaxTimeout;
   // Time at last activity
-  TimeStamp mLastActivity;
+  PRIntervalTime mInterval;
   // Time when a hang started
-  TimeStamp mHangStart;
+  PRIntervalTime mHangStart;
   // Is the thread in a hang
   bool mHanging;
   // Is the thread in a waiting state
   bool mWaiting;
   // Is the thread dedicated to a single BackgroundHangMonitor
   BackgroundHangMonitor::ThreadType mThreadType;
 #ifdef MOZ_GECKO_PROFILER
   // Platform-specific helper to get hang stacks
@@ -213,17 +213,17 @@ public:
 
   BackgroundHangThread(const char* aName,
                        uint32_t aTimeoutMs,
                        uint32_t aMaxTimeoutMs,
                        BackgroundHangMonitor::ThreadType aThreadType = BackgroundHangMonitor::THREAD_SHARED);
 
   // Report a hang; aManager->mLock IS locked. The hang will be processed
   // off-main-thread, and will then be submitted back.
-  void ReportHang(TimeDuration aHangTime);
+  void ReportHang(PRIntervalTime aHangTime);
   // Report a permanent hang; aManager->mLock IS locked
   void ReportPermaHang();
   // Called by BackgroundHangMonitor::NotifyActivity
   void NotifyActivity()
   {
     MonitorAutoLock autoLock(mManager->mLock);
     Update();
   }
@@ -251,16 +251,17 @@ StaticRefPtr<BackgroundHangManager> Back
 bool BackgroundHangManager::sDisabled = false;
 
 MOZ_THREAD_LOCAL(BackgroundHangThread*) BackgroundHangThread::sTlsKey;
 bool BackgroundHangThread::sTlsKeyInitialized;
 
 BackgroundHangManager::BackgroundHangManager()
   : mShutdown(false)
   , mLock("BackgroundHangManager")
+  , mIntervalNow(0)
   , mSTS(do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID))
 {
   // Lock so we don't race against the new monitor thread
   MonitorAutoLock autoLock(mLock);
 
   mHangMonitorThread = PR_CreateThread(
     PR_USER_THREAD, MonitorThread, this,
     PR_PRIORITY_LOW, PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0);
@@ -282,81 +283,82 @@ BackgroundHangManager::~BackgroundHangMa
 }
 
 void
 BackgroundHangManager::RunMonitorThread()
 {
   // Keep us locked except when waiting
   MonitorAutoLock autoLock(mLock);
 
-  /* mNow is updated at various intervals determined by waitTime.
+  /* mIntervalNow is updated at various intervals determined by waitTime.
      However, if an update latency is too long (due to CPU scheduling, system
-     sleep, etc.), we don't update mNow at all. This is done so that
+     sleep, etc.), we don't update mIntervalNow at all. This is done so that
      long latencies in our timing are not detected as hangs. systemTime is
-     used to track TimeStamp::Now() and determine our latency. */
+     used to track PR_IntervalNow() and determine our latency. */
 
-  TimeStamp systemTime = TimeStamp::Now();
+  PRIntervalTime systemTime = PR_IntervalNow();
   // Default values for the first iteration of thread loop
-  TimeDuration waitTime;
-  TimeDuration recheckTimeout;
-  TimeStamp lastCheckedCPUUsage = systemTime;
-  TimeDuration checkCPUUsageInterval =
-    TimeDuration::FromMilliseconds(kCheckCPUIntervalMilliseconds);
+  PRIntervalTime waitTime = PR_INTERVAL_NO_WAIT;
+  PRIntervalTime recheckTimeout = PR_INTERVAL_NO_WAIT;
+  PRIntervalTime lastCheckedCPUUsage = systemTime;
+  PRIntervalTime checkCPUUsageInterval =
+    PR_MillisecondsToInterval(kCheckCPUIntervalMilliseconds);
 
   while (!mShutdown) {
-    autoLock.Wait(waitTime);
+    nsresult rv = autoLock.Wait(waitTime);
 
-    TimeStamp newTime = TimeStamp::Now();
-    TimeDuration systemInterval = newTime - systemTime;
+    PRIntervalTime newTime = PR_IntervalNow();
+    PRIntervalTime systemInterval = newTime - systemTime;
     systemTime = newTime;
 
     if (systemTime - lastCheckedCPUUsage > checkCPUUsageInterval) {
       Unused << NS_WARN_IF(mCPUUsageWatcher.CollectCPUUsage().isErr());
       lastCheckedCPUUsage = systemTime;
     }
 
     /* waitTime is a quarter of the shortest timeout value; If our timing
        latency is low enough (less than half the shortest timeout value),
-       we can update mNow. */
-    if (MOZ_LIKELY(waitTime != TimeDuration::Forever() &&
-                   systemInterval < waitTime * 2)) {
-      mNow += systemInterval;
+       we can update mIntervalNow. */
+    if (MOZ_LIKELY(waitTime != PR_INTERVAL_NO_TIMEOUT &&
+                   systemInterval < 2 * waitTime)) {
+      mIntervalNow += systemInterval;
     }
 
     /* If it's before the next recheck timeout, and our wait did not get
        interrupted, we can keep the current waitTime and skip iterating
        through hang monitors. */
     if (MOZ_LIKELY(systemInterval < recheckTimeout &&
-                   systemInterval >= waitTime)) {
+                   systemInterval >= waitTime &&
+                   rv == NS_OK)) {
       recheckTimeout -= systemInterval;
       continue;
     }
 
     /* We are in one of the following scenarios,
      - Hang or permahang recheck timeout
      - Thread added/removed
      - Thread wait or hang ended
        In all cases, we want to go through our list of hang
        monitors and update waitTime and recheckTimeout. */
-    waitTime = TimeDuration::Forever();
-    recheckTimeout = TimeDuration::Forever();
+    waitTime = PR_INTERVAL_NO_TIMEOUT;
+    recheckTimeout = PR_INTERVAL_NO_TIMEOUT;
 
-    // Locally hold mNow
-    TimeStamp now = mNow;
+    // Locally hold mIntervalNow
+    PRIntervalTime intervalNow = mIntervalNow;
 
     // iterate through hang monitors
     for (BackgroundHangThread* currentThread = mHangThreads.getFirst();
          currentThread; currentThread = currentThread->getNext()) {
 
       if (currentThread->mWaiting) {
         // Thread is waiting, not hanging
         continue;
       }
-      TimeStamp lastActivity = currentThread->mLastActivity;
-      TimeDuration hangTime = now - lastActivity;
+      PRIntervalTime interval = currentThread->mInterval;
+      PRIntervalTime hangTime = intervalNow - interval;
       if (MOZ_UNLIKELY(hangTime >= currentThread->mMaxTimeout)) {
         // A permahang started
         // Skip subsequent iterations and tolerate a race on mWaiting here
         currentThread->mWaiting = true;
         currentThread->mHanging = false;
         currentThread->ReportPermaHang();
         continue;
       }
@@ -375,70 +377,70 @@ BackgroundHangManager::RunMonitorThread(
           // CPU usage is going to be an average across the whole time we were
           // sleeping. Accordingly, we want to make sure that when we hang, we
           // collect a fresh value.
           if (systemTime != lastCheckedCPUUsage) {
             Unused << NS_WARN_IF(mCPUUsageWatcher.CollectCPUUsage().isErr());
             lastCheckedCPUUsage = systemTime;
           }
 
-          currentThread->mHangStart = lastActivity;
+          currentThread->mHangStart = interval;
           currentThread->mHanging = true;
           currentThread->mAnnotations =
             currentThread->mAnnotators.GatherAnnotations();
         }
       } else {
-        if (MOZ_LIKELY(lastActivity != currentThread->mHangStart)) {
+        if (MOZ_LIKELY(interval != currentThread->mHangStart)) {
           // A hang ended
-          currentThread->ReportHang(now - currentThread->mHangStart);
+          currentThread->ReportHang(intervalNow - currentThread->mHangStart);
           currentThread->mHanging = false;
         }
       }
 
       /* If we are hanging, the next time we check for hang status is when
          the hang turns into a permahang. If we're not hanging, the next
          recheck timeout is when we may be entering a hang. */
-      TimeDuration nextRecheck;
+      PRIntervalTime nextRecheck;
       if (currentThread->mHanging) {
         nextRecheck = currentThread->mMaxTimeout;
       } else {
         nextRecheck = currentThread->mTimeout;
       }
-      recheckTimeout = TimeDuration::Min(recheckTimeout, nextRecheck - hangTime);
+      recheckTimeout = std::min(recheckTimeout, nextRecheck - hangTime);
 
-      if (currentThread->mTimeout != TimeDuration::Forever()) {
+      if (currentThread->mTimeout != PR_INTERVAL_NO_TIMEOUT) {
         /* We wait for a quarter of the shortest timeout
-           value to give mNow enough granularity. */
-        waitTime = TimeDuration::Min(waitTime, currentThread->mTimeout / (int64_t) 4);
+           value to give mIntervalNow enough granularity. */
+        waitTime = std::min(waitTime, currentThread->mTimeout / 4);
       }
     }
   }
 
   /* We are shutting down now.
      Wait for all outstanding monitors to unregister. */
   while (!mHangThreads.isEmpty()) {
-    autoLock.Wait();
+    autoLock.Wait(PR_INTERVAL_NO_TIMEOUT);
   }
 }
 
 
 BackgroundHangThread::BackgroundHangThread(const char* aName,
                                            uint32_t aTimeoutMs,
                                            uint32_t aMaxTimeoutMs,
                                            BackgroundHangMonitor::ThreadType aThreadType)
   : mManager(BackgroundHangManager::sInstance)
   , mThreadID(PR_GetCurrentThread())
   , mTimeout(aTimeoutMs == BackgroundHangMonitor::kNoTimeout
-             ? TimeDuration::Forever()
-             : TimeDuration::FromMilliseconds(aTimeoutMs))
+             ? PR_INTERVAL_NO_TIMEOUT
+             : PR_MillisecondsToInterval(aTimeoutMs))
   , mMaxTimeout(aMaxTimeoutMs == BackgroundHangMonitor::kNoTimeout
-                ? TimeDuration::Forever()
-                : TimeDuration::FromMilliseconds(aMaxTimeoutMs))
-  , mLastActivity(mManager->mNow)
-  , mHangStart(mLastActivity)
+                ? PR_INTERVAL_NO_TIMEOUT
+                : PR_MillisecondsToInterval(aMaxTimeoutMs))
+  , mInterval(mManager->mIntervalNow)
+  , mHangStart(mInterval)
   , mHanging(false)
   , mWaiting(true)
   , mThreadType(aThreadType)
   , mThreadName(aName)
 {
   if (sTlsKeyInitialized && IsShared()) {
     sTlsKey.set(this);
   }
@@ -461,17 +463,17 @@ BackgroundHangThread::~BackgroundHangThr
 
   // We no longer have a thread
   if (sTlsKeyInitialized && IsShared()) {
     sTlsKey.set(nullptr);
   }
 }
 
 void
-BackgroundHangThread::ReportHang(TimeDuration aHangTime)
+BackgroundHangThread::ReportHang(PRIntervalTime aHangTime)
 {
   // Recovered from a hang; called on the monitor thread
   // mManager->mLock IS locked
 
   nsTArray<HangAnnotation> annotations;
   for (auto& annotation : mAnnotations) {
     HangAnnotation annot(annotation.mName, annotation.mValue);
     annotations.AppendElement(mozilla::Move(annot));
@@ -499,17 +501,17 @@ BackgroundHangThread::ReportHang(TimeDur
     RefPtr<nsHangDetails> hd = new nsHangDetails(Move(hangDetails));
     hd->Submit();
   }
 
   // If the profiler is enabled, add a marker.
 #ifdef MOZ_GECKO_PROFILER
   if (profiler_is_active()) {
     TimeStamp endTime = TimeStamp::Now();
-    TimeStamp startTime = endTime - aHangTime;
+    TimeStamp startTime = endTime - TimeDuration::FromMilliseconds(aHangTime);
     profiler_add_marker_for_thread(
       mStackHelper.GetThreadId(),
       "BHR-detected hang",
       MakeUnique<HangMarkerPayload>(startTime, endTime));
   }
 #endif
 }
 
@@ -526,30 +528,30 @@ BackgroundHangThread::ReportPermaHang()
   // We currently don't look at hang reports outside of nightly, and already
   // collect native stacks eagerly on nightly, so this should be OK.
   ReportHang(mMaxTimeout);
 }
 
 MOZ_ALWAYS_INLINE void
 BackgroundHangThread::Update()
 {
-  TimeStamp now = mManager->mNow;
+  PRIntervalTime intervalNow = mManager->mIntervalNow;
   if (mWaiting) {
-    mLastActivity = now;
+    mInterval = intervalNow;
     mWaiting = false;
     /* We have to wake up the manager thread because when all threads
        are waiting, the manager thread waits indefinitely as well. */
     mManager->Wakeup();
   } else {
-    TimeDuration duration = now - mLastActivity;
+    PRIntervalTime duration = intervalNow - mInterval;
     if (MOZ_UNLIKELY(duration >= mTimeout)) {
       /* Wake up the manager thread to tell it that a hang ended */
       mManager->Wakeup();
     }
-    mLastActivity = now;
+    mInterval = intervalNow;
   }
 }
 
 BackgroundHangThread*
 BackgroundHangThread::FindThread()
 {
 #ifdef MOZ_ENABLE_BACKGROUND_HANG_MONITOR
   if (BackgroundHangManager::sInstance == nullptr) {
--- a/toolkit/components/backgroundhangmonitor/HangDetails.cpp
+++ b/toolkit/components/backgroundhangmonitor/HangDetails.cpp
@@ -8,19 +8,19 @@
 
 #ifdef MOZ_GECKO_PROFILER
 #include "shared-libraries.h"
 #endif
 
 namespace mozilla {
 
 NS_IMETHODIMP
-nsHangDetails::GetDuration(double* aDuration)
+nsHangDetails::GetDuration(uint32_t* aDuration)
 {
-  *aDuration = mDetails.duration().ToMilliseconds();
+  *aDuration = mDetails.duration();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsHangDetails::GetThread(nsACString& aName)
 {
   aName.Assign(mDetails.threadName());
   return NS_OK;
--- a/toolkit/components/backgroundhangmonitor/HangDetails.h
+++ b/toolkit/components/backgroundhangmonitor/HangDetails.h
@@ -64,9 +64,28 @@ public:
   NS_IMETHOD Run() override;
 
 private:
   HangDetails mHangDetails;
 };
 
 } // namespace mozilla
 
+// We implement the ability to send the HangDetails object over IPC. We need to
+// do this rather than rely on StructuredClone of the objects created by the
+// XPCOM getters on nsHangDetails because we want to run BHR in the GPU process
+// which doesn't run any JS.
+namespace IPC {
+
+template<>
+class ParamTraits<mozilla::HangDetails>
+{
+public:
+  typedef mozilla::HangDetails paramType;
+  static void Write(Message* aMsg, const paramType& aParam);
+  static bool Read(const Message* aMsg,
+                   PickleIterator* aIter,
+                   paramType* aResult);
+};
+
+} // namespace IPC
+
 #endif // mozilla_HangDetails_h
--- a/toolkit/components/backgroundhangmonitor/HangTypes.ipdlh
+++ b/toolkit/components/backgroundhangmonitor/HangTypes.ipdlh
@@ -1,16 +1,14 @@
 /* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */
 /* vim: set sw=4 ts=8 et tw=80 ft=cpp : */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-using class mozilla::TimeDuration from "mozilla/TimeStamp.h";
-
 namespace mozilla {
 
 // The different kinds of hang entries which we're going to need to handle in
 // our HangStacks.
 
 struct HangEntryBufOffset
 {
     // NOTE: Don't trust this index without checking it is a valid index into
@@ -78,17 +76,17 @@ struct HangAnnotation
 {
     nsString name;
     nsString value;
 };
 
 // The information about an individual hang which is sent over IPC.
 struct HangDetails
 {
-    TimeDuration duration;
+    uint32_t duration;
     nsCString process;
     nsString remoteType;
     nsCString threadName;
     nsCString runnableName;
     HangStack stack;
     HangAnnotation[] annotations;
 };
 
--- a/toolkit/components/backgroundhangmonitor/nsIHangDetails.idl
+++ b/toolkit/components/backgroundhangmonitor/nsIHangDetails.idl
@@ -16,19 +16,19 @@ class HangDetails;
 /**
  * A scriptable interface for getting information about a BHR detected hang.
  * This is the type of the subject of the "bhr-thread-hang" observer topic.
  */
 [scriptable, uuid(23d63fff-38d6-4003-9c57-2c90aca1180a)]
 interface nsIHangDetails : nsISupports
 {
   /**
-   * The detected duration of the hang in milliseconds.
+   * The detected duration of the hang.
    */
-  readonly attribute double duration;
+  readonly attribute uint32_t duration;
 
   /**
    * The name of the thread which hung.
    */
   readonly attribute ACString thread;
 
   /**
    * The name of the runnable which hung if it hung on the main thread.
--- a/toolkit/xre/nsUpdateDriver.cpp
+++ b/toolkit/xre/nsUpdateDriver.cpp
@@ -92,17 +92,17 @@ UpdateDriverSetupMacCommandLine(int& arg
 
   if (NS_FAILED(rv)) {
     LOG(("Update driver error dispatching SetupMacCommandLine to main thread: %d\n", rv));
     return;
   }
 
   // The length of this wait is arbitrary, but should be long enough that having
   // it expire means something is seriously wrong.
-  rv = MonitorAutoLock(monitor).Wait(TimeDuration::FromSeconds(60));
+  rv = MonitorAutoLock(monitor).Wait(PR_SecondsToInterval(60));
   if (NS_FAILED(rv)) {
     LOG(("Update driver timed out waiting for SetupMacCommandLine: %d\n", rv));
   }
 }
 #endif
 
 static nsresult
 GetCurrentWorkingDir(char *buf, size_t size)
--- a/xpcom/tests/gtest/TestThreadPool.cpp
+++ b/xpcom/tests/gtest/TestThreadPool.cpp
@@ -82,17 +82,17 @@ TEST(ThreadPool, Parallelism)
     {
     }
 
     NS_IMETHOD Run() override {
       MonitorAutoLock mon(mMonitor);
       if (!mDone) {
         // Wait for a reasonable timeout since we don't want to block gtests
         // forever should any regression happen.
-        mon.Wait(TimeDuration::FromSeconds(300));
+        mon.Wait(PR_SecondsToInterval(300));
       }
       EXPECT_TRUE(mDone);
       return NS_OK;
     }
   private:
     Monitor& mMonitor;
     bool& mDone;
   };
--- a/xpcom/threads/BlockingResourceBase.cpp
+++ b/xpcom/threads/BlockingResourceBase.cpp
@@ -581,44 +581,40 @@ RecursiveMutex::Unlock()
 void
 RecursiveMutex::AssertCurrentThreadIn()
 {
   MOZ_ASSERT(IsAcquired() && mOwningThread == PR_GetCurrentThread());
 }
 
 //
 // Debug implementation of CondVar
-void
-CondVar::Wait()
-{
-  // Forward to the timed version of CondVar::Wait to avoid code duplication.
-  CVStatus status = Wait(TimeDuration::Forever());
-  MOZ_ASSERT(status == CVStatus::NoTimeout);
-}
-
-CVStatus
-CondVar::Wait(TimeDuration aDuration)
+nsresult
+CondVar::Wait(PRIntervalTime aInterval)
 {
   AssertCurrentThreadOwnsMutex();
 
   // save mutex state and reset to empty
   AcquisitionState savedAcquisitionState = mLock->GetAcquisitionState();
   BlockingResourceBase* savedChainPrev = mLock->mChainPrev;
   PRThread* savedOwningThread = mLock->mOwningThread;
   mLock->ClearAcquisitionState();
   mLock->mChainPrev = 0;
   mLock->mOwningThread = nullptr;
 
   // give up mutex until we're back from Wait()
-  CVStatus status = mImpl.wait_for(*mLock, aDuration);
+  if (aInterval == PR_INTERVAL_NO_TIMEOUT) {
+    mImpl.wait(*mLock);
+  } else {
+    mImpl.wait_for(*mLock, TimeDuration::FromMilliseconds(double(aInterval)));
+  }
 
   // restore saved state
   mLock->SetAcquisitionState(savedAcquisitionState);
   mLock->mChainPrev = savedChainPrev;
   mLock->mOwningThread = savedOwningThread;
 
-  return status;
+  return NS_OK;
 }
 
 #endif // ifdef DEBUG
 
 
 } // namespace mozilla
--- a/xpcom/threads/CondVar.h
+++ b/xpcom/threads/CondVar.h
@@ -48,41 +48,37 @@ public:
    * ~CondVar
    * Clean up after this CondVar, but NOT its associated Mutex.
    **/
   ~CondVar()
   {
     MOZ_COUNT_DTOR(CondVar);
   }
 
+#ifndef DEBUG
   /**
    * Wait
    * @see prcvar.h
    **/
-#ifndef DEBUG
-  void Wait()
+  nsresult Wait(PRIntervalTime aInterval = PR_INTERVAL_NO_TIMEOUT)
   {
+
 #ifdef MOZILLA_INTERNAL_API
     AUTO_PROFILER_THREAD_SLEEP;
 #endif //MOZILLA_INTERNAL_API
-    mImpl.wait(*mLock);
-  }
-
-  CVStatus Wait(TimeDuration aDuration)
-  {
-#ifdef MOZILLA_INTERNAL_API
-    AUTO_PROFILER_THREAD_SLEEP;
-#endif //MOZILLA_INTERNAL_API
-    return mImpl.wait_for(*mLock, aDuration);
+    if (aInterval == PR_INTERVAL_NO_TIMEOUT) {
+      mImpl.wait(*mLock);
+    } else {
+      mImpl.wait_for(*mLock, TimeDuration::FromMilliseconds(double(aInterval)));
+    }
+    return NS_OK;
   }
 #else
-  // NOTE: debug impl is in BlockingResourceBase.cpp
-  void Wait();
-  CVStatus Wait(TimeDuration aDuration);
-#endif
+  nsresult Wait(PRIntervalTime aInterval = PR_INTERVAL_NO_TIMEOUT);
+#endif // ifndef DEBUG
 
   /**
    * Notify
    * @see prcvar.h
    **/
   nsresult Notify()
   {
     mImpl.notify_one();
@@ -128,12 +124,13 @@ private:
   CondVar();
   CondVar(const CondVar&) = delete;
   CondVar& operator=(const CondVar&) = delete;
 
   Mutex* mLock;
   detail::ConditionVariableImpl mImpl;
 };
 
+
 } // namespace mozilla
 
 
 #endif  // ifndef mozilla_CondVar_h
--- a/xpcom/threads/HangMonitor.cpp
+++ b/xpcom/threads/HangMonitor.cpp
@@ -257,21 +257,21 @@ ThreadMain(void*)
                                     firefoxUptime, Move(annotations));
         stack.Clear();
       }
 #endif
       lastTimestamp = timestamp;
       waitCount = 0;
     }
 
-    TimeDuration timeout;
+    PRIntervalTime timeout;
     if (gTimeout <= 0) {
-      timeout = TimeDuration::Forever();
+      timeout = PR_INTERVAL_NO_TIMEOUT;
     } else {
-      timeout = TimeDuration::FromMilliseconds(gTimeout * 500);
+      timeout = PR_MillisecondsToInterval(gTimeout * 500);
     }
     lock.Wait(timeout);
   }
 }
 
 void
 Startup()
 {
--- a/xpcom/threads/Monitor.h
+++ b/xpcom/threads/Monitor.h
@@ -30,18 +30,20 @@ public:
   {
   }
 
   ~Monitor() {}
 
   void Lock() { mMutex.Lock(); }
   void Unlock() { mMutex.Unlock(); }
 
-  void Wait() { mCondVar.Wait(); }
-  CVStatus Wait(TimeDuration aDuration) { return mCondVar.Wait(aDuration); }
+  nsresult Wait(PRIntervalTime aInterval = PR_INTERVAL_NO_TIMEOUT)
+  {
+    return mCondVar.Wait(aInterval);
+  }
 
   nsresult Notify() { return mCondVar.Notify(); }
   nsresult NotifyAll() { return mCondVar.NotifyAll(); }
 
   void AssertCurrentThreadOwns() const
   {
     mMutex.AssertCurrentThreadOwns();
   }
@@ -76,18 +78,20 @@ public:
     mMonitor->Lock();
   }
 
   ~MonitorAutoLock()
   {
     mMonitor->Unlock();
   }
 
-  void Wait() { mMonitor->Wait(); }
-  CVStatus Wait(TimeDuration aDuration) { return mMonitor->Wait(aDuration); }
+  nsresult Wait(PRIntervalTime aInterval = PR_INTERVAL_NO_TIMEOUT)
+  {
+    return mMonitor->Wait(aInterval);
+  }
 
   nsresult Notify() { return mMonitor->Notify(); }
   nsresult NotifyAll() { return mMonitor->NotifyAll(); }
 
 private:
   MonitorAutoLock();
   MonitorAutoLock(const MonitorAutoLock&);
   MonitorAutoLock& operator=(const MonitorAutoLock&);
--- a/xpcom/threads/Scheduler.cpp
+++ b/xpcom/threads/Scheduler.cpp
@@ -438,17 +438,17 @@ SchedulerImpl::Switcher()
     CooperativeThreadPool::SelectedThread threadIndex = mThreadPool->CurrentThreadIndex(lock);
     if (threadIndex.is<size_t>()) {
       JSContext* cx = mContexts[threadIndex.as<size_t>()];
       if (cx) {
         JS_RequestInterruptCallbackCanWait(cx);
       }
     }
 
-    mShutdownCondVar.Wait(TimeDuration::FromMicroseconds(50));
+    mShutdownCondVar.Wait(PR_MicrosecondsToInterval(50));
   }
 }
 
 /* static */ void
 SchedulerImpl::SwitcherThread(void* aData)
 {
   static_cast<SchedulerImpl*>(aData)->Switcher();
 }
--- a/xpcom/threads/TimerThread.cpp
+++ b/xpcom/threads/TimerThread.cpp
@@ -412,29 +412,29 @@ TimerThread::Run()
 
   // Half of the amount of microseconds needed to get positive PRIntervalTime.
   // We use this to decide how to round our wait times later
   mAllowedEarlyFiringMicroseconds = usIntervalResolution / 2;
   bool forceRunNextTimer = false;
 
   while (!mShutdown) {
     // Have to use PRIntervalTime here, since PR_WaitCondVar takes it
-    TimeDuration waitFor;
+    PRIntervalTime waitFor;
     bool forceRunThisTimer = forceRunNextTimer;
     forceRunNextTimer = false;
 
     if (mSleeping) {
       // Sleep for 0.1 seconds while not firing timers.
       uint32_t milliseconds = 100;
       if (ChaosMode::isActive(ChaosFeature::TimerScheduling)) {
         milliseconds = ChaosMode::randomUint32LessThan(200);
       }
-      waitFor = TimeDuration::FromMilliseconds(milliseconds);
+      waitFor = PR_MillisecondsToInterval(milliseconds);
     } else {
-      waitFor = TimeDuration::Forever();
+      waitFor = PR_INTERVAL_NO_TIMEOUT;
       TimeStamp now = TimeStamp::Now();
 
       RemoveLeadingCanceledTimersInternal();
 
       if (!mTimers.IsEmpty()) {
         if (now >= mTimers[0]->Value()->mTimeout || forceRunThisTimer) {
     next:
           // NB: AddRef before the Release under RemoveTimerInternal to avoid
@@ -511,30 +511,30 @@ TimerThread::Run()
             sFractions[ChaosMode::randomUint32LessThan(ArrayLength(sFractions))];
           forceRunNextTimer = true;
         }
 
         if (microseconds < mAllowedEarlyFiringMicroseconds) {
           forceRunNextTimer = false;
           goto next; // round down; execute event now
         }
-        waitFor = TimeDuration::FromMicroseconds(microseconds);
-        if (waitFor.IsZero()) {
-          // round up, wait the minimum time we can wait
-          waitFor = TimeDuration::FromMicroseconds(1);
+        waitFor = PR_MicrosecondsToInterval(
+          static_cast<uint32_t>(microseconds)); // Floor is accurate enough.
+        if (waitFor == 0) {
+          waitFor = 1;  // round up, wait the minimum time we can wait
         }
       }
 
       if (MOZ_LOG_TEST(GetTimerLog(), LogLevel::Debug)) {
-        if (waitFor == TimeDuration::Forever())
+        if (waitFor == PR_INTERVAL_NO_TIMEOUT)
           MOZ_LOG(GetTimerLog(), LogLevel::Debug,
-                 ("waiting forever\n"));
+                 ("waiting for PR_INTERVAL_NO_TIMEOUT\n"));
         else
           MOZ_LOG(GetTimerLog(), LogLevel::Debug,
-                 ("waiting for %f\n", waitFor.ToMilliseconds()));
+                 ("waiting for %u\n", PR_IntervalToMilliseconds(waitFor)));
       }
     }
 
     mWaiting = true;
     mNotified = false;
     mMonitor.Wait(waitFor);
     if (mNotified) {
       forceRunNextTimer = false;
--- a/xpcom/threads/nsThreadPool.cpp
+++ b/xpcom/threads/nsThreadPool.cpp
@@ -158,17 +158,17 @@ nsThreadPool::Run()
   LOG(("THRD-P(%p) enter %s\n", this, mName.BeginReading()));
 
   nsCOMPtr<nsIThread> current;
   nsThreadManager::get().GetCurrentThread(getter_AddRefs(current));
 
   bool shutdownThreadOnExit = false;
   bool exitThread = false;
   bool wasIdle = false;
-  TimeStamp idleSince;
+  PRIntervalTime idleSince;
 
   nsCOMPtr<nsIThreadPoolListener> listener;
   {
     MutexAutoLock lock(mMutex);
     listener = mListener;
   }
 
   if (listener) {
@@ -177,18 +177,18 @@ nsThreadPool::Run()
 
   do {
     nsCOMPtr<nsIRunnable> event;
     {
       MutexAutoLock lock(mMutex);
 
       event = mEvents.GetEvent(nullptr, lock);
       if (!event) {
-        TimeStamp now = TimeStamp::Now();
-        TimeDuration timeout = TimeDuration::FromMilliseconds(mIdleThreadTimeout);
+        PRIntervalTime now     = PR_IntervalNow();
+        PRIntervalTime timeout = PR_MillisecondsToInterval(mIdleThreadTimeout);
 
         // If we are shutting down, then don't keep any idle threads
         if (mShutdown) {
           exitThread = true;
         } else {
           if (wasIdle) {
             // if too many idle threads or idle for too long, then bail.
             if (mIdleCount > mIdleThreadLimit ||
@@ -208,19 +208,18 @@ nsThreadPool::Run()
         }
 
         if (exitThread) {
           if (wasIdle) {
             --mIdleCount;
           }
           shutdownThreadOnExit = mThreads.RemoveObject(current);
         } else {
-          TimeDuration delta = timeout - (now - idleSince);
-          LOG(("THRD-P(%p) %s waiting [%f]\n", this, mName.BeginReading(),
-               delta.ToMilliseconds()));
+          PRIntervalTime delta = timeout - (now - idleSince);
+          LOG(("THRD-P(%p) %s waiting [%d]\n", this, mName.BeginReading(), delta));
           mEventsAvailable.Wait(delta);
           LOG(("THRD-P(%p) done waiting\n", this));
         }
       } else if (wasIdle) {
         wasIdle = false;
         --mIdleCount;
       }
     }