Bug 1437167 - Part 1: Stop using PRIntervalTime as the argument to CondVar::Wait and Monitor::Wait, r=mstange, r=froydnj
authorNika Layzell <nika@thelayzells.com>
Fri, 09 Feb 2018 15:17:26 -0500
changeset 412759 b044c550a87505347b4b9cd93ccfffb7fd0dc291
parent 412758 0fd1326c744bbf71cce464674593683c81d7835b
child 412760 76ac0b53d77120f59f74c8015608c7efb8f09924
push id33818
push userapavel@mozilla.com
push dateWed, 11 Apr 2018 14:36:40 +0000
treeherdermozilla-central@cfe6399e142c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmstange, froydnj
bugs1437167
milestone61.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 1437167 - Part 1: Stop using PRIntervalTime as the argument to CondVar::Wait and Monitor::Wait, r=mstange, r=froydnj
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();
 
-  PRIntervalTime timeout = PR_INTERVAL_NO_TIMEOUT;
+  TimeDuration timeout = TimeDuration::Forever();
   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 = PR_MillisecondsToInterval(uint32_t(timeoutMS));
+    timeout = TimeDuration::FromMilliseconds(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 > 0) {
+  if (!timeout.IsZero()) {
     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,17 +176,16 @@ 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()
@@ -526,17 +525,18 @@ StorageDBThread::ThreadFunc()
       mThreadObserver->ClearPendingEvents();
       MonitorAutoUnlock unlock(mThreadObserver->GetMonitor());
       bool processedEvent;
       do {
         rv = thread->ProcessNextEvent(false, &processedEvent);
       } while (NS_SUCCEEDED(rv) && processedEvent);
     }
 
-    if (MOZ_UNLIKELY(TimeUntilFlush() == 0)) {
+    TimeDuration timeUntilFlush = TimeUntilFlush();
+    if (MOZ_UNLIKELY(timeUntilFlush.IsZero())) {
       // 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,53 +820,49 @@ StorageDBThread::ShutdownDatabase()
 void
 StorageDBThread::ScheduleFlush()
 {
   if (mDirtyEpoch) {
     return; // Already scheduled
   }
 
   // Must be non-zero to indicate we are scheduled
-  mDirtyEpoch = PR_IntervalNow() | 1;
+  mDirtyEpoch = TimeStamp::Now();
 
   // 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 = 0;
+  mDirtyEpoch = TimeStamp();
 }
 
-PRIntervalTime
+TimeDuration
 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 PR_INTERVAL_NO_TIMEOUT; // No pending task...
+    return TimeDuration::Forever(); // No pending task...
   }
 
-  static const PRIntervalTime kMaxAge = PR_MillisecondsToInterval(FLUSHING_INTERVAL_MS);
-
-  PRIntervalTime now = PR_IntervalNow() | 1;
-  PRIntervalTime age = now - mDirtyEpoch;
+  TimeStamp now = TimeStamp::Now();
+  TimeDuration age = now - mDirtyEpoch;
+  static const TimeDuration kMaxAge = TimeDuration::FromMilliseconds(FLUSHING_INTERVAL_MS);
   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,16 +9,17 @@
 
 #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;
@@ -435,17 +436,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
-  PRIntervalTime mDirtyEpoch;
+  TimeStamp 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;
 
@@ -481,22 +482,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:
-  // - 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();
+  // - 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();
 
   // 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
@@ -3587,17 +3587,17 @@ WorkerPrivate::InterruptCallback(JSConte
     }
 
     while ((mayContinue = MayContinueRunning())) {
       MutexAutoLock lock(mMutex);
       if (!mControlQueue.IsEmpty()) {
         break;
       }
 
-      WaitForWorkerEvents(PR_MillisecondsToInterval(UINT32_MAX));
+      WaitForWorkerEvents();
     }
   }
 
   if (!mayContinue) {
     // We want only uncatchable exceptions here.
     NS_ASSERTION(!JS_IsExceptionPending(aCx),
                  "Should not have an exception set here!");
     return false;
@@ -3708,23 +3708,23 @@ WorkerPrivate::DisableMemoryReporter()
 
   // Finally unregister the memory reporter.
   if (NS_FAILED(UnregisterWeakMemoryReporter(memoryReporter))) {
     NS_WARNING("Failed to unregister memory reporter!");
   }
 }
 
 void
-WorkerPrivate::WaitForWorkerEvents(PRIntervalTime aInterval)
+WorkerPrivate::WaitForWorkerEvents()
 {
   AssertIsOnWorkerThread();
   mMutex.AssertCurrentThreadOwns();
 
   // Wait for a worker event.
-  mCondVar.Wait(aInterval);
+  mCondVar.Wait();
 }
 
 WorkerPrivate::ProcessAllControlRunnablesResult
 WorkerPrivate::ProcessAllControlRunnablesLocked()
 {
   AssertIsOnWorkerThread();
   mMutex.AssertCurrentThreadOwns();
 
--- a/dom/workers/WorkerPrivate.h
+++ b/dom/workers/WorkerPrivate.h
@@ -1279,17 +1279,17 @@ private:
 
   void
   EnableMemoryReporter();
 
   void
   DisableMemoryReporter();
 
   void
-  WaitForWorkerEvents(PRIntervalTime interval = PR_INTERVAL_NO_TIMEOUT);
+  WaitForWorkerEvents();
 
   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,18 +44,17 @@ public:
   {
     MOZ_ASSERT(NS_IsMainThread());
     if (DidGetVsyncNotification()) {
       return;
     }
 
     { // scope lock
       MonitorAutoLock lock(mVsyncMonitor);
-      PRIntervalTime timeout = PR_MillisecondsToInterval(kVsyncTimeoutMS);
-      lock.Wait(timeout);
+      lock.Wait(TimeDuration::FromMilliseconds(kVsyncTimeoutMS));
     }
   }
 
   bool DidGetVsyncNotification()
   {
     MonitorAutoLock lock(mVsyncMonitor);
     return mDidGetVsyncNotification;
   }
--- a/image/DecodePool.cpp
+++ b/image/DecodePool.cpp
@@ -5,16 +5,17 @@
 
 #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"
@@ -53,17 +54,17 @@ struct Work
 class DecodePoolImpl
 {
 public:
   MOZ_DECLARE_REFCOUNTED_TYPENAME(DecodePoolImpl)
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DecodePoolImpl)
 
   DecodePoolImpl(uint8_t aMaxThreads,
                  uint8_t aMaxIdleThreads,
-                 PRIntervalTime aIdleTimeout)
+                 TimeDuration aIdleTimeout)
     : mMonitor("DecodePoolImpl")
     , mThreads(aMaxThreads)
     , mIdleTimeout(aIdleTimeout)
     , mMaxIdleThreads(aMaxIdleThreads)
     , mAvailableThreads(aMaxThreads)
     , mIdleThreads(0)
     , mShuttingDown(false)
   {
@@ -173,17 +174,17 @@ public:
   }
 
 private:
   /// Pops a new work item, blocking if necessary.
   Work PopWorkLocked(bool aShutdownIdle)
   {
     mMonitor.AssertCurrentThreadOwns();
 
-    PRIntervalTime timeout = mIdleTimeout;
+    TimeDuration timeout = mIdleTimeout;
     do {
       if (!mHighPriorityQueue.IsEmpty()) {
         return PopWorkFromQueue(mHighPriorityQueue);
       }
 
       if (!mLowPriorityQueue.IsEmpty()) {
         return PopWorkFromQueue(mLowPriorityQueue);
       }
@@ -198,29 +199,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 == 0) {
+        if (timeout.IsZero()) {
           return CreateShutdownWork();
         }
 
         ++mIdleThreads;
         MOZ_ASSERT(mIdleThreads <= mThreads.Capacity());
 
-        PRIntervalTime now = PR_IntervalNow();
+        TimeStamp now = TimeStamp::Now();
         mMonitor.Wait(timeout);
-        PRIntervalTime delta = PR_IntervalNow() - now;
+        TimeDuration delta = TimeStamp::Now() - now;
         if (delta > timeout) {
           timeout = 0;
-        } else {
+        } else if (timeout != TimeDuration::Forever()) {
           timeout -= delta;
         }
       }
 
       MOZ_ASSERT(mIdleThreads > 0);
       --mIdleThreads;
     } while (true);
   }
@@ -247,17 +248,17 @@ private:
 
   nsThreadPoolNaming mThreadNaming;
 
   // mMonitor guards everything below.
   mutable Monitor mMonitor;
   nsTArray<RefPtr<IDecodingTask>> mHighPriorityQueue;
   nsTArray<RefPtr<IDecodingTask>> mLowPriorityQueue;
   nsTArray<nsCOMPtr<nsIThread>> mThreads;
-  PRIntervalTime mIdleTimeout;
+  TimeDuration 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
 {
@@ -384,22 +385,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();
-  PRIntervalTime idleTimeout;
+  TimeDuration idleTimeout;
   if (prefIdleTimeout <= 0) {
-    idleTimeout = PR_INTERVAL_NO_TIMEOUT;
+    idleTimeout = TimeDuration::Forever();
     idleLimit = limit;
   } else {
-    idleTimeout = PR_MillisecondsToInterval(static_cast<uint32_t>(prefIdleTimeout));
+    idleTimeout = TimeDuration::FromMilliseconds(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
@@ -369,40 +369,39 @@ 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.
-  PRIntervalTime timeoutTicks = (aTimeoutMs > 0) ?
-    PR_MillisecondsToInterval(aTimeoutMs) : PR_INTERVAL_NO_TIMEOUT;
+  TimeDuration timeout = (aTimeoutMs > 0) ?
+    TimeDuration::FromMilliseconds(aTimeoutMs) : TimeDuration::Forever();
 
   MonitorAutoLock lock(mMonitor);
-  PRIntervalTime waitStart = PR_IntervalNow();
-  PRIntervalTime current;
+  TimeStamp waitStart = TimeStamp::Now();
+  TimeStamp 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;
     }
 
-    lock.Wait(timeoutTicks);
+    CVStatus status = lock.Wait(timeout);
+    if (status == CVStatus::Timeout) {
+      break;
+    }
 
-    if (timeoutTicks != PR_INTERVAL_NO_TIMEOUT) {
-      current = PR_IntervalNow();
-      PRIntervalTime elapsed = current - waitStart;
-      if (elapsed > timeoutTicks) {
-        break;
-      }
-      timeoutTicks = timeoutTicks - elapsed;
+    if (timeout != TimeDuration::Forever()) {
+      current = TimeStamp::Now();
+      timeout -= current - waitStart;
       waitStart = current;
     }
   }
 
   return mProcessState == PROCESS_CONNECTED;
 }
 
 bool
--- a/ipc/glue/MessageChannel.cpp
+++ b/ipc/glue/MessageChannel.cpp
@@ -2313,23 +2313,16 @@ 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;
         }
@@ -2349,27 +2342,24 @@ 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
 
-    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);
+    TimeDuration timeout = (kNoTimeout == mTimeoutMs) ?
+                           TimeDuration::Forever() :
+                           TimeDuration::FromMilliseconds(mTimeoutMs);
+    CVStatus status = mMonitor->Wait(timeout);
 
     // If the timeout didn't expire, we know we received an event. The
     // converse is not true.
-    return WaitResponse(IsTimeoutExpired(waitStart, timeout));
+    return WaitResponse(status == CVStatus::Timeout);
 }
 
 bool
 MessageChannel::WaitForInterruptNotify()
 {
     return WaitForSyncNotify(true);
 }
 
--- a/ipc/glue/WindowsMessageLoop.cpp
+++ b/ipc/glue/WindowsMessageLoop.cpp
@@ -852,23 +852,16 @@ 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(),
@@ -1036,37 +1029,31 @@ 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) {
-    PRIntervalTime timeout = (kNoTimeout == mTimeoutMs) ?
-                             PR_INTERVAL_NO_TIMEOUT :
-                             PR_MillisecondsToInterval(mTimeoutMs);
-    PRIntervalTime waitStart = 0;
-
-    if (timeout != PR_INTERVAL_NO_TIMEOUT) {
-      waitStart = PR_IntervalNow();
-    }
+    TimeDuration timeout = (kNoTimeout == mTimeoutMs) ?
+                           TimeDuration::Forever() :
+                           TimeDuration::FromMilliseconds(mTimeoutMs);
 
     MOZ_ASSERT(!mIsSyncWaitingOnNonMainThread);
     mIsSyncWaitingOnNonMainThread = true;
 
-    mMonitor->Wait(timeout);
+    CVStatus status = 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(timeout == PR_INTERVAL_NO_TIMEOUT ?
-                        false : IsTimeoutExpired(waitStart, timeout));
+    return WaitResponse(status == CVStatus::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::detail::CVStatus::Timeout
+    return impl_.wait_for(lock.lock, rel_time) == mozilla::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
@@ -719,17 +719,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(10000);
+        mal.Wait(TimeDuration::FromSeconds(10));
     }
 
     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::detail::CVStatus
+mozilla::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,17 +54,17 @@ 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::detail::CVStatus
+mozilla::CVStatus
 mozilla::detail::ConditionVariableImpl::wait_for(MutexImpl& lock,
                                                  const mozilla::TimeDuration& rel_time)
 {
   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.
--- 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
@@ -72,16 +72,18 @@
 #include "mozilla/net/HttpBaseChannel.h"
 #include "nsIScriptError.h"
 #include "nsISiteSecurityService.h"
 #include "nsHttpHandler.h"
 #include "nsNSSComponent.h"
 #include "nsIRedirectHistoryEntry.h"
 #include "nsICertBlocklist.h"
 #include "nsICertOverrideService.h"
+#include "nsQueryObject.h"
+#include "mozIThirdPartyUtil.h"
 
 #include <limits>
 
 using namespace mozilla;
 using namespace mozilla::net;
 using mozilla::dom::ClientInfo;
 using mozilla::dom::PerformanceStorage;
 using mozilla::dom::ServiceWorkerDescriptor;
@@ -1654,18 +1656,17 @@ private:
         mTaskQueue = new TaskQueue(target.forget());
 
         MonitorAutoLock lock(mMonitor);
 
         nsCOMPtr<nsIRunnable> runnable = this;
         nsresult rv = mTaskQueue->Dispatch(runnable.forget());
         NS_ENSURE_SUCCESS(rv, rv);
 
-        rv = lock.Wait();
-        NS_ENSURE_SUCCESS(rv, rv);
+        lock.Wait();
 
         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
@@ -1607,17 +1607,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(PR_SecondsToInterval(3)); }
+    void Wait()   { mCondVar.Wait(TimeDuration::FromSeconds(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));
 
-    PRIntervalTime const waitTime = PR_MillisecondsToInterval(1000);
+    TimeDuration waitTime = TimeDuration::FromSeconds(1);
     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(PR_INTERVAL_NO_TIMEOUT);
+      lock.Wait();
 
     } 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
@@ -525,18 +525,18 @@ nsHostResolver::nsHostResolver(uint32_t 
     , mShutdown(true)
     , mNumIdleThreads(0)
     , mThreadCount(0)
     , mActiveAnyThreadCount(0)
     , mPendingCount(0)
 {
     mCreationTime = PR_Now();
 
-    mLongIdleTimeout  = PR_SecondsToInterval(LongIdleTimeoutSeconds);
-    mShortIdleTimeout = PR_SecondsToInterval(ShortIdleTimeoutSeconds);
+    mLongIdleTimeout  = TimeDuration::FromSeconds(LongIdleTimeoutSeconds);
+    mShortIdleTimeout = TimeDuration::FromSeconds(ShortIdleTimeoutSeconds);
 }
 
 nsHostResolver::~nsHostResolver() = default;
 
 nsresult
 nsHostResolver::Init()
 {
     MOZ_ASSERT(NS_IsMainThread());
@@ -1308,22 +1308,23 @@ nsHostResolver::DeQueue(LinkedList<RefPt
     rec.forget(aResult);
     (*aResult)->onQueue = false;
 }
 
 bool
 nsHostResolver::GetHostToLookup(nsHostRecord **result)
 {
     bool timedOut = false;
-    PRIntervalTime epoch, now, timeout;
+    TimeDuration timeout;
+    TimeStamp epoch, now;
 
     MutexAutoLock lock(mLock);
 
     timeout = (mNumIdleThreads >= HighThreadThreshold) ? mShortIdleTimeout : mLongIdleTimeout;
-    epoch = PR_IntervalNow();
+    epoch = TimeStamp::Now();
 
     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);
@@ -1358,25 +1359,26 @@ 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 = PR_IntervalNow();
+        now = TimeStamp::Now();
 
-        if ((PRIntervalTime)(now - epoch) >= timeout)
+        if (now - epoch >= timeout) {
             timedOut = true;
-        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);
+        } 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;
             epoch = now;
         }
     }
 
     // tell thread to exit...
     return false;
 }
 
--- a/netwerk/dns/nsHostResolver.h
+++ b/netwerk/dns/nsHostResolver.h
@@ -450,18 +450,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;
-    PRIntervalTime mLongIdleTimeout;
-    PRIntervalTime mShortIdleTimeout;
+    mozilla::TimeDuration mLongIdleTimeout;
+    mozilla::TimeDuration 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,20 +586,17 @@ DataStorage::AsyncReadData(bool& aHavePr
 
 void
 DataStorage::WaitForReady()
 {
   MOZ_DIAGNOSTIC_ASSERT(mInitCalled, "Waiting before Init() has been called?");
 
   MonitorAutoLock readyLock(mReadyMonitor);
   while (!mReady) {
-    nsresult rv = readyLock.Wait();
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      break;
-    }
+    readyLock.Wait();
   }
   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();
-    PRIntervalTime wait_interval;
+    TimeDuration 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 = PR_MicrosecondsToInterval(50);
+      wait_interval = TimeDuration::FromMicroseconds(50);
     }
     else
     {
       // On a secondary thread, it's fine to wait some more for
       // for the condition variable.
-      wait_interval = PR_MillisecondsToInterval(250);
+      wait_interval = TimeDuration::FromMilliseconds(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
@@ -1103,20 +1103,17 @@ nsNSSComponent::HasUserCertsInstalled(bo
   return NS_OK;
 }
 
 nsresult
 nsNSSComponent::BlockUntilLoadableRootsLoaded()
 {
   MonitorAutoLock rootsLoadedLock(mLoadableRootsLoadedMonitor);
   while (!mLoadableRootsLoaded) {
-    nsresult rv = rootsLoadedLock.Wait();
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return rv;
-    }
+    rootsLoadedLock.Wait();
   }
   MOZ_ASSERT(mLoadableRootsLoaded);
 
   return mLoadableRootsLoadedResult;
 }
 
 nsresult
 nsNSSComponent::CheckForSmartCardChanges()
--- a/toolkit/components/backgroundhangmonitor/BackgroundHangMonitor.cpp
+++ b/toolkit/components/backgroundhangmonitor/BackgroundHangMonitor.cpp
@@ -92,17 +92,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
-  PRIntervalTime mIntervalNow;
+  TimeStamp mNow;
   // List of BackgroundHangThread instances associated with each thread
   LinkedList<BackgroundHangThread> mHangThreads;
 
   // Unwinding and reporting of hangs is despatched to this thread.
   nsCOMPtr<nsIThread> mHangProcessingThread;
 
   // Allows us to watch CPU usage and annotate hangs when the system is
   // under high external load.
@@ -176,24 +176,24 @@ public:
   static BackgroundHangThread* FindThread();
 
   static void Startup()
   {
     /* We can tolerate init() failing. */
     sTlsKeyInitialized = sTlsKey.init();
   }
 
-  // Hang timeout in ticks
-  const PRIntervalTime mTimeout;
-  // PermaHang timeout in ticks
-  const PRIntervalTime mMaxTimeout;
+  // Hang timeout
+  const TimeDuration mTimeout;
+  // PermaHang timeout
+  const TimeDuration mMaxTimeout;
   // Time at last activity
-  PRIntervalTime mInterval;
+  TimeStamp mLastActivity;
   // Time when a hang started
-  PRIntervalTime mHangStart;
+  TimeStamp 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
@@ -212,17 +212,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(PRIntervalTime aHangTime);
+  void ReportHang(TimeDuration aHangTime);
   // Report a permanent hang; aManager->mLock IS locked
   void ReportPermaHang();
   // Called by BackgroundHangMonitor::NotifyActivity
   void NotifyActivity()
   {
     MonitorAutoLock autoLock(mManager->mLock);
     Update();
   }
@@ -235,17 +235,17 @@ public:
       return;
     }
 
     Update();
     if (mHanging) {
       // We were hanging! We're done with that now, so let's report it.
       // ReportHang() doesn't do much work on the current thread, and is
       // safe to call from any thread as long as we're holding the lock.
-      ReportHang(mInterval - mHangStart);
+      ReportHang(mLastActivity - mHangStart);
       mHanging = false;
     }
     mWaiting = true;
   }
 
   // Returns true if this thread is (or might be) shared between other
   // BackgroundHangMonitors for the monitored thread.
   bool IsShared() {
@@ -257,17 +257,16 @@ StaticRefPtr<BackgroundHangManager> Back
 bool BackgroundHangManager::sDisabled = false;
 
 MOZ_THREAD_LOCAL(BackgroundHangThread*) BackgroundHangThread::sTlsKey;
 bool BackgroundHangThread::sTlsKeyInitialized;
 
 BackgroundHangManager::BackgroundHangManager()
   : mShutdown(false)
   , mLock("BackgroundHangManager")
-  , mIntervalNow(0)
 {
   // 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);
 
@@ -300,82 +299,81 @@ BackgroundHangManager::~BackgroundHangMa
 }
 
 void
 BackgroundHangManager::RunMonitorThread()
 {
   // Keep us locked except when waiting
   MonitorAutoLock autoLock(mLock);
 
-  /* mIntervalNow is updated at various intervals determined by waitTime.
+  /* mNow 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 mIntervalNow at all. This is done so that
+     sleep, etc.), we don't update mNow at all. This is done so that
      long latencies in our timing are not detected as hangs. systemTime is
-     used to track PR_IntervalNow() and determine our latency. */
+     used to track TimeStamp::Now() and determine our latency. */
 
-  PRIntervalTime systemTime = PR_IntervalNow();
+  TimeStamp systemTime = TimeStamp::Now();
   // Default values for the first iteration of thread loop
-  PRIntervalTime waitTime = PR_INTERVAL_NO_WAIT;
-  PRIntervalTime recheckTimeout = PR_INTERVAL_NO_WAIT;
-  PRIntervalTime lastCheckedCPUUsage = systemTime;
-  PRIntervalTime checkCPUUsageInterval =
-    PR_MillisecondsToInterval(kCheckCPUIntervalMilliseconds);
+  TimeDuration waitTime;
+  TimeDuration recheckTimeout;
+  TimeStamp lastCheckedCPUUsage = systemTime;
+  TimeDuration checkCPUUsageInterval =
+    TimeDuration::FromMilliseconds(kCheckCPUIntervalMilliseconds);
 
   while (!mShutdown) {
-    nsresult rv = autoLock.Wait(waitTime);
+    autoLock.Wait(waitTime);
 
-    PRIntervalTime newTime = PR_IntervalNow();
-    PRIntervalTime systemInterval = newTime - systemTime;
+    TimeStamp newTime = TimeStamp::Now();
+    TimeDuration 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 mIntervalNow. */
-    if (MOZ_LIKELY(waitTime != PR_INTERVAL_NO_TIMEOUT &&
-                   systemInterval < 2 * waitTime)) {
-      mIntervalNow += systemInterval;
+       we can update mNow. */
+    if (MOZ_LIKELY(waitTime != TimeDuration::Forever() &&
+                   systemInterval < waitTime * 2)) {
+      mNow += 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 &&
-                   rv == NS_OK)) {
+                   systemInterval >= waitTime)) {
       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 = PR_INTERVAL_NO_TIMEOUT;
-    recheckTimeout = PR_INTERVAL_NO_TIMEOUT;
+    waitTime = TimeDuration::Forever();
+    recheckTimeout = TimeDuration::Forever();
 
-    // Locally hold mIntervalNow
-    PRIntervalTime intervalNow = mIntervalNow;
+    // Locally hold mNow
+    TimeStamp now = mNow;
 
     // iterate through hang monitors
     for (BackgroundHangThread* currentThread = mHangThreads.getFirst();
          currentThread; currentThread = currentThread->getNext()) {
 
       if (currentThread->mWaiting) {
         // Thread is waiting, not hanging
         continue;
       }
-      PRIntervalTime interval = currentThread->mInterval;
-      PRIntervalTime hangTime = intervalNow - interval;
+      TimeStamp lastActivity = currentThread->mLastActivity;
+      TimeDuration hangTime = now - lastActivity;
       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;
       }
@@ -394,70 +392,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 = interval;
+          currentThread->mHangStart = lastActivity;
           currentThread->mHanging = true;
           currentThread->mAnnotations =
             currentThread->mAnnotators.GatherAnnotations();
         }
       } else {
-        if (MOZ_LIKELY(interval != currentThread->mHangStart)) {
+        if (MOZ_LIKELY(lastActivity != currentThread->mHangStart)) {
           // A hang ended
-          currentThread->ReportHang(intervalNow - currentThread->mHangStart);
+          currentThread->ReportHang(now - 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. */
-      PRIntervalTime nextRecheck;
+      TimeDuration nextRecheck;
       if (currentThread->mHanging) {
         nextRecheck = currentThread->mMaxTimeout;
       } else {
         nextRecheck = currentThread->mTimeout;
       }
-      recheckTimeout = std::min(recheckTimeout, nextRecheck - hangTime);
+      recheckTimeout = TimeDuration::Min(recheckTimeout, nextRecheck - hangTime);
 
-      if (currentThread->mTimeout != PR_INTERVAL_NO_TIMEOUT) {
+      if (currentThread->mTimeout != TimeDuration::Forever()) {
         /* We wait for a quarter of the shortest timeout
-           value to give mIntervalNow enough granularity. */
-        waitTime = std::min(waitTime, currentThread->mTimeout / 4);
+           value to give mNow enough granularity. */
+        waitTime = TimeDuration::Min(waitTime, currentThread->mTimeout / (int64_t) 4);
       }
     }
   }
 
   /* We are shutting down now.
      Wait for all outstanding monitors to unregister. */
   while (!mHangThreads.isEmpty()) {
-    autoLock.Wait(PR_INTERVAL_NO_TIMEOUT);
+    autoLock.Wait();
   }
 }
 
 
 BackgroundHangThread::BackgroundHangThread(const char* aName,
                                            uint32_t aTimeoutMs,
                                            uint32_t aMaxTimeoutMs,
                                            BackgroundHangMonitor::ThreadType aThreadType)
   : mManager(BackgroundHangManager::sInstance)
   , mThreadID(PR_GetCurrentThread())
   , mTimeout(aTimeoutMs == BackgroundHangMonitor::kNoTimeout
-             ? PR_INTERVAL_NO_TIMEOUT
-             : PR_MillisecondsToInterval(aTimeoutMs))
+             ? TimeDuration::Forever()
+             : TimeDuration::FromMilliseconds(aTimeoutMs))
   , mMaxTimeout(aMaxTimeoutMs == BackgroundHangMonitor::kNoTimeout
-                ? PR_INTERVAL_NO_TIMEOUT
-                : PR_MillisecondsToInterval(aMaxTimeoutMs))
-  , mInterval(mManager->mIntervalNow)
-  , mHangStart(mInterval)
+                ? TimeDuration::Forever()
+                : TimeDuration::FromMilliseconds(aMaxTimeoutMs))
+  , mLastActivity(mManager->mNow)
+  , mHangStart(mLastActivity)
   , mHanging(false)
   , mWaiting(true)
   , mThreadType(aThreadType)
   , mThreadName(aName)
 {
   if (sTlsKeyInitialized && IsShared()) {
     sTlsKey.set(this);
   }
@@ -480,17 +478,17 @@ BackgroundHangThread::~BackgroundHangThr
 
   // We no longer have a thread
   if (sTlsKeyInitialized && IsShared()) {
     sTlsKey.set(nullptr);
   }
 }
 
 void
-BackgroundHangThread::ReportHang(PRIntervalTime aHangTime)
+BackgroundHangThread::ReportHang(TimeDuration 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));
@@ -519,17 +517,17 @@ BackgroundHangThread::ReportHang(PRInter
     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 - TimeDuration::FromMilliseconds(aHangTime);
+    TimeStamp startTime = endTime - aHangTime;
     profiler_add_marker_for_thread(
       mStackHelper.GetThreadId(),
       "BHR-detected hang",
       MakeUnique<HangMarkerPayload>(startTime, endTime));
   }
 #endif
 }
 
@@ -546,30 +544,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()
 {
-  PRIntervalTime intervalNow = mManager->mIntervalNow;
+  TimeStamp now = mManager->mNow;
   if (mWaiting) {
-    mInterval = intervalNow;
+    mLastActivity = now;
     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 {
-    PRIntervalTime duration = intervalNow - mInterval;
+    TimeDuration duration = now - mLastActivity;
     if (MOZ_UNLIKELY(duration >= mTimeout)) {
       /* Wake up the manager thread to tell it that a hang ended */
       mManager->Wakeup();
     }
-    mInterval = intervalNow;
+    mLastActivity = now;
   }
 }
 
 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(uint32_t* aDuration)
+nsHangDetails::GetDuration(double* aDuration)
 {
-  *aDuration = mDetails.duration();
+  *aDuration = mDetails.duration().ToMilliseconds();
   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,28 +64,9 @@ 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,14 +1,16 @@
 /* -*- 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
@@ -76,17 +78,17 @@ struct HangAnnotation
 {
     nsString name;
     nsString value;
 };
 
 // The information about an individual hang which is sent over IPC.
 struct HangDetails
 {
-    uint32_t duration;
+    TimeDuration 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.
+   * The detected duration of the hang in milliseconds.
    */
-  readonly attribute uint32_t duration;
+  readonly attribute double 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,19 +92,19 @@ 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(PR_SecondsToInterval(60));
-  if (NS_FAILED(rv)) {
-    LOG(("Update driver timed out waiting for SetupMacCommandLine: %d\n", rv));
+  CVStatus status = MonitorAutoLock(monitor).Wait(TimeDuration::FromSeconds(60));
+  if (status == CVStatus::Timeout) {
+    LOG(("Update driver timed out waiting for SetupMacCommandLine\n"));
   }
 }
 #endif
 
 static nsresult
 GetCurrentWorkingDir(char *buf, size_t size)
 {
   // Cannot use NS_GetSpecialDirectory because XPCOM is not yet initialized.
--- 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(PR_SecondsToInterval(300));
+        mon.Wait(TimeDuration::FromSeconds(300));
       }
       EXPECT_TRUE(mDone);
       return NS_OK;
     }
   private:
     Monitor& mMonitor;
     bool& mDone;
   };
--- a/xpcom/threads/BlockingResourceBase.cpp
+++ b/xpcom/threads/BlockingResourceBase.cpp
@@ -581,40 +581,44 @@ RecursiveMutex::Unlock()
 void
 RecursiveMutex::AssertCurrentThreadIn()
 {
   MOZ_ASSERT(IsAcquired() && mOwningThread == PR_GetCurrentThread());
 }
 
 //
 // Debug implementation of CondVar
-nsresult
-CondVar::Wait(PRIntervalTime aInterval)
+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)
 {
   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()
-  if (aInterval == PR_INTERVAL_NO_TIMEOUT) {
-    mImpl.wait(*mLock);
-  } else {
-    mImpl.wait_for(*mLock, TimeDuration::FromMilliseconds(double(aInterval)));
-  }
+  CVStatus status = mImpl.wait_for(*mLock, aDuration);
 
   // restore saved state
   mLock->SetAcquisitionState(savedAcquisitionState);
   mLock->mChainPrev = savedChainPrev;
   mLock->mOwningThread = savedOwningThread;
 
-  return NS_OK;
+  return status;
 }
 
 #endif // ifdef DEBUG
 
 
 } // namespace mozilla
--- a/xpcom/threads/CondVar.h
+++ b/xpcom/threads/CondVar.h
@@ -48,37 +48,41 @@ public:
    * ~CondVar
    * Clean up after this CondVar, but NOT its associated Mutex.
    **/
   ~CondVar()
   {
     MOZ_COUNT_DTOR(CondVar);
   }
 
-#ifndef DEBUG
   /**
    * Wait
    * @see prcvar.h
    **/
-  nsresult Wait(PRIntervalTime aInterval = PR_INTERVAL_NO_TIMEOUT)
+#ifndef DEBUG
+  void Wait()
   {
-
 #ifdef MOZILLA_INTERNAL_API
     AUTO_PROFILER_THREAD_SLEEP;
 #endif //MOZILLA_INTERNAL_API
-    if (aInterval == PR_INTERVAL_NO_TIMEOUT) {
-      mImpl.wait(*mLock);
-    } else {
-      mImpl.wait_for(*mLock, TimeDuration::FromMilliseconds(double(aInterval)));
-    }
-    return NS_OK;
+    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);
   }
 #else
-  nsresult Wait(PRIntervalTime aInterval = PR_INTERVAL_NO_TIMEOUT);
-#endif // ifndef DEBUG
+  // NOTE: debug impl is in BlockingResourceBase.cpp
+  void Wait();
+  CVStatus Wait(TimeDuration aDuration);
+#endif
 
   /**
    * Notify
    * @see prcvar.h
    **/
   nsresult Notify()
   {
     mImpl.notify_one();
@@ -124,13 +128,12 @@ 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;
     }
 
-    PRIntervalTime timeout;
+    TimeDuration timeout;
     if (gTimeout <= 0) {
-      timeout = PR_INTERVAL_NO_TIMEOUT;
+      timeout = TimeDuration::Forever();
     } else {
-      timeout = PR_MillisecondsToInterval(gTimeout * 500);
+      timeout = TimeDuration::FromMilliseconds(gTimeout * 500);
     }
     lock.Wait(timeout);
   }
 }
 
 void
 Startup()
 {
--- a/xpcom/threads/Monitor.h
+++ b/xpcom/threads/Monitor.h
@@ -30,20 +30,18 @@ public:
   {
   }
 
   ~Monitor() {}
 
   void Lock() { mMutex.Lock(); }
   void Unlock() { mMutex.Unlock(); }
 
-  nsresult Wait(PRIntervalTime aInterval = PR_INTERVAL_NO_TIMEOUT)
-  {
-    return mCondVar.Wait(aInterval);
-  }
+  void Wait() { mCondVar.Wait(); }
+  CVStatus Wait(TimeDuration aDuration) { return mCondVar.Wait(aDuration); }
 
   nsresult Notify() { return mCondVar.Notify(); }
   nsresult NotifyAll() { return mCondVar.NotifyAll(); }
 
   void AssertCurrentThreadOwns() const
   {
     mMutex.AssertCurrentThreadOwns();
   }
@@ -78,20 +76,18 @@ public:
     mMonitor->Lock();
   }
 
   ~MonitorAutoLock()
   {
     mMonitor->Unlock();
   }
 
-  nsresult Wait(PRIntervalTime aInterval = PR_INTERVAL_NO_TIMEOUT)
-  {
-    return mMonitor->Wait(aInterval);
-  }
+  void Wait() { mMonitor->Wait(); }
+  CVStatus Wait(TimeDuration aDuration) { return mMonitor->Wait(aDuration); }
 
   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(PR_MicrosecondsToInterval(50));
+    mShutdownCondVar.Wait(TimeDuration::FromMicroseconds(50));
   }
 }
 
 /* static */ void
 SchedulerImpl::SwitcherThread(void* aData)
 {
   static_cast<SchedulerImpl*>(aData)->Switcher();
 }
--- a/xpcom/threads/TimerThread.cpp
+++ b/xpcom/threads/TimerThread.cpp
@@ -416,29 +416,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
-    PRIntervalTime waitFor;
+    TimeDuration 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 = PR_MillisecondsToInterval(milliseconds);
+      waitFor = TimeDuration::FromMilliseconds(milliseconds);
     } else {
-      waitFor = PR_INTERVAL_NO_TIMEOUT;
+      waitFor = TimeDuration::Forever();
       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
@@ -515,30 +515,30 @@ TimerThread::Run()
             sFractions[ChaosMode::randomUint32LessThan(ArrayLength(sFractions))];
           forceRunNextTimer = true;
         }
 
         if (microseconds < mAllowedEarlyFiringMicroseconds) {
           forceRunNextTimer = false;
           goto next; // round down; execute event now
         }
-        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
+        waitFor = TimeDuration::FromMicroseconds(microseconds);
+        if (waitFor.IsZero()) {
+          // round up, wait the minimum time we can wait
+          waitFor = TimeDuration::FromMicroseconds(1);
         }
       }
 
       if (MOZ_LOG_TEST(GetTimerLog(), LogLevel::Debug)) {
-        if (waitFor == PR_INTERVAL_NO_TIMEOUT)
+        if (waitFor == TimeDuration::Forever())
           MOZ_LOG(GetTimerLog(), LogLevel::Debug,
-                 ("waiting for PR_INTERVAL_NO_TIMEOUT\n"));
+                 ("waiting forever\n"));
         else
           MOZ_LOG(GetTimerLog(), LogLevel::Debug,
-                 ("waiting for %u\n", PR_IntervalToMilliseconds(waitFor)));
+                 ("waiting for %f\n", waitFor.ToMilliseconds()));
       }
     }
 
     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;
-  PRIntervalTime idleSince;
+  TimeStamp 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) {
-        PRIntervalTime now     = PR_IntervalNow();
-        PRIntervalTime timeout = PR_MillisecondsToInterval(mIdleThreadTimeout);
+        TimeStamp now = TimeStamp::Now();
+        TimeDuration timeout = TimeDuration::FromMilliseconds(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,18 +208,19 @@ nsThreadPool::Run()
         }
 
         if (exitThread) {
           if (wasIdle) {
             --mIdleCount;
           }
           shutdownThreadOnExit = mThreads.RemoveObject(current);
         } else {
-          PRIntervalTime delta = timeout - (now - idleSince);
-          LOG(("THRD-P(%p) %s waiting [%d]\n", this, mName.BeginReading(), delta));
+          TimeDuration delta = timeout - (now - idleSince);
+          LOG(("THRD-P(%p) %s waiting [%f]\n", this, mName.BeginReading(),
+               delta.ToMilliseconds()));
           mEventsAvailable.Wait(delta);
           LOG(("THRD-P(%p) done waiting\n", this));
         }
       } else if (wasIdle) {
         wasIdle = false;
         --mIdleCount;
       }
     }