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 457603 b044c550a87505347b4b9cd93ccfffb7fd0dc291
parent 457602 0fd1326c744bbf71cce464674593683c81d7835b
child 457604 76ac0b53d77120f59f74c8015608c7efb8f09924
push id155
push userfmarier@mozilla.com
push dateThu, 12 Apr 2018 17:56:07 +0000
reviewersmstange, froydnj
bugs1437167
milestone61.0a1
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;
       }
     }