Back out bug 1072780 & bug 1072775 (by reverting to cset before them, d71444b75291) for pthread assertion failures
authorDaniel Holbert <dholbert@cs.stanford.edu>
Sun, 28 Sep 2014 09:56:40 -0700
changeset 223038 0c8faa128dffdc052c7bd286a5a0659849eb50c8
parent 223037 f2138c7f8569c8302d8651d37be17a6cdd8fcd76
child 223039 7a4c925ca8d736b89b68b29de5422d3bd94fc222
push id7107
push userraliiev@mozilla.com
push dateMon, 13 Oct 2014 17:43:31 +0000
treeherdermozilla-aurora@b4b34e0acc75 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1072780, 1072775
milestone35.0a1
Back out bug 1072780 & bug 1072775 (by reverting to cset before them, d71444b75291) for pthread assertion failures
content/media/GraphDriver.cpp
content/media/GraphDriver.h
content/media/MediaStreamGraph.cpp
content/media/MediaStreamGraphImpl.h
--- a/content/media/GraphDriver.cpp
+++ b/content/media/GraphDriver.cpp
@@ -48,16 +48,17 @@ struct AutoProfilerUnregisterThread
 
 GraphDriver::GraphDriver(MediaStreamGraphImpl* aGraphImpl)
   : mIterationStart(0),
     mIterationEnd(0),
     mStateComputedTime(0),
     mNextStateComputedTime(0),
     mGraphImpl(aGraphImpl),
     mWaitState(WAITSTATE_RUNNING),
+    mNeedAnotherIteration(false),
     mCurrentTimeStamp(TimeStamp::Now()),
     mPreviousDriver(nullptr),
     mNextDriver(nullptr)
 { }
 
 void GraphDriver::SetGraphTime(GraphDriver* aPreviousDriver,
                                GraphTime aLastSwitchNextIterationStart,
                                GraphTime aLastSwitchNextIterationEnd,
@@ -89,17 +90,16 @@ void GraphDriver::SwitchAtNextIteration(
   MOZ_ASSERT(!mNextDriver || mNextDriver->AsAudioCallbackDriver());
   mNextDriver = aNextDriver;
 }
 
 void GraphDriver::EnsureImmediateWakeUpLocked()
 {
   mGraphImpl->GetMonitor().AssertCurrentThreadOwns();
   mWaitState = WAITSTATE_WAKING_UP;
-  mGraphImpl->mGraphDriverAsleep = false; // atomic
   mGraphImpl->GetMonitor().Notify();
 }
 
 void GraphDriver::UpdateStateComputedTime(GraphTime aStateComputedTime)
 {
   MOZ_ASSERT(aStateComputedTime > mIterationEnd);
   // The next state computed time can be the same as the previous, here: it
   // means the driver would be have been blocking indefinitly, but the graph has
@@ -108,17 +108,32 @@ void GraphDriver::UpdateStateComputedTim
     printf("State time can't go backward %ld < %ld.\n", static_cast<long>(aStateComputedTime), static_cast<long>(mStateComputedTime));
   }
 
   mStateComputedTime = aStateComputedTime;
 }
 
 void GraphDriver::EnsureNextIteration()
 {
-  mGraphImpl->EnsureNextIteration();
+  MonitorAutoLock lock(mGraphImpl->GetMonitor());
+  EnsureNextIterationLocked();
+}
+
+void GraphDriver::EnsureNextIterationLocked()
+{
+  mGraphImpl->GetMonitor().AssertCurrentThreadOwns();
+
+  if (IsWaitingIndefinitly()) {
+    WakeUp();
+  }
+
+  if (mNeedAnotherIteration) {
+    return;
+  }
+  mNeedAnotherIteration = true;
 }
 
 class MediaStreamGraphShutdownThreadRunnable : public nsRunnable {
 public:
   explicit MediaStreamGraphShutdownThreadRunnable(GraphDriver* aDriver)
     : mDriver(aDriver)
   {
   }
@@ -205,38 +220,31 @@ private:
   ThreadedDriver* mDriver;
 };
 
 void
 ThreadedDriver::Start()
 {
   LIFECYCLE_LOG("Starting thread for a SystemClockDriver  %p\n", mGraphImpl);
   nsCOMPtr<nsIRunnable> event = new MediaStreamGraphInitThreadRunnable(this);
-  // Note: mThread may be null during event->Run() if we pass to NewNamedThread!  See AudioInitTask
-  nsresult rv = NS_NewNamedThread("MediaStreamGrph", getter_AddRefs(mThread));
-  if (NS_SUCCEEDED(rv)) {
-    mThread->Dispatch(event, NS_DISPATCH_NORMAL);
-  }
+  NS_NewNamedThread("MediaStreamGrph", getter_AddRefs(mThread), event);
 }
 
 void
 ThreadedDriver::Resume()
 {
   Start();
 }
 
 void
 ThreadedDriver::Revive()
 {
-  // Note: only called on MainThread, without monitor
-  // We know were weren't in a running state
   STREAM_LOG(PR_LOG_DEBUG, ("AudioCallbackDriver reviving."));
   // If we were switching, switch now. Otherwise, tell thread to run the main
   // loop again.
-  MonitorAutoLock mon(mGraphImpl->GetMonitor());
   if (mNextDriver) {
     mNextDriver->SetGraphTime(this, mIterationStart, mIterationEnd,
                                mStateComputedTime, mNextStateComputedTime);
     mGraphImpl->SetCurrentDriver(mNextDriver);
     mNextDriver->Start();
   } else {
     nsCOMPtr<nsIRunnable> event = new MediaStreamGraphInitThreadRunnable(this);
     mThread->Dispatch(event, NS_DISPATCH_NORMAL);
@@ -247,17 +255,16 @@ void
 ThreadedDriver::Stop()
 {
   NS_ASSERTION(NS_IsMainThread(), "Must be called on main thread");
   // mGraph's thread is not running so it's OK to do whatever here
   STREAM_LOG(PR_LOG_DEBUG, ("Stopping threads for MediaStreamGraph %p", this));
 
   if (mThread) {
     mThread->Shutdown();
-    mThread = nullptr;
   }
 }
 
 SystemClockDriver::SystemClockDriver(MediaStreamGraphImpl* aGraphImpl)
   : ThreadedDriver(aGraphImpl),
     mInitialTimeStamp(TimeStamp::Now()),
     mLastTimeStamp(TimeStamp::Now())
 {}
@@ -341,52 +348,44 @@ OfflineClockDriver::GetCurrentTimeStamp(
 
 void
 SystemClockDriver::WaitForNextIteration()
 {
   mGraphImpl->GetMonitor().AssertCurrentThreadOwns();
 
   PRIntervalTime timeout = PR_INTERVAL_NO_TIMEOUT;
   TimeStamp now = TimeStamp::Now();
-  if (mGraphImpl->mNeedAnotherIteration) {
+  if (mNeedAnotherIteration) {
     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));
     STREAM_LOG(PR_LOG_DEBUG+1, ("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;
   } else {
-    mGraphImpl->mGraphDriverAsleep = true; // atomic
     mWaitState = WAITSTATE_WAITING_INDEFINITELY;
   }
   if (timeout > 0) {
     mGraphImpl->GetMonitor().Wait(timeout);
     STREAM_LOG(PR_LOG_DEBUG+1, ("Resuming after timeout; at %f, elapsed=%f",
           (TimeStamp::Now() - mInitialTimeStamp).ToSeconds(),
           (TimeStamp::Now() - now).ToSeconds()));
   }
 
-  if (mWaitState == WAITSTATE_WAITING_INDEFINITELY) {
-    mGraphImpl->mGraphDriverAsleep = false; // atomic
-  }
   mWaitState = WAITSTATE_RUNNING;
-  mGraphImpl->mNeedAnotherIteration = false;
+  mNeedAnotherIteration = false;
 }
 
 void
 SystemClockDriver::WakeUp()
 {
   mGraphImpl->GetMonitor().AssertCurrentThreadOwns();
   mWaitState = WAITSTATE_WAKING_UP;
-  mGraphImpl->mGraphDriverAsleep = false; // atomic
   mGraphImpl->GetMonitor().Notify();
 }
 
 OfflineClockDriver::OfflineClockDriver(MediaStreamGraphImpl* aGraphImpl, GraphTime aSlice)
   : ThreadedDriver(aGraphImpl),
     mSlice(aSlice)
 {
 
@@ -396,35 +395,29 @@ class MediaStreamGraphShutdownThreadRunn
 public:
   explicit MediaStreamGraphShutdownThreadRunnable2(nsIThread* aThread)
     : mThread(aThread)
   {
   }
   NS_IMETHOD Run()
   {
     MOZ_ASSERT(NS_IsMainThread());
-    MOZ_ASSERT(mThread);
-
     mThread->Shutdown();
-    mThread = nullptr;
     return NS_OK;
   }
 private:
-  nsCOMPtr<nsIThread> mThread;
+  nsRefPtr<nsIThread> mThread;
 };
 
 OfflineClockDriver::~OfflineClockDriver()
 {
   // transfer the ownership of mThread to the event
-  // XXX should use .forget()/etc
-  if (mThread) {
-    nsCOMPtr<nsIRunnable> event = new MediaStreamGraphShutdownThreadRunnable2(mThread);
-    mThread = nullptr;
-    NS_DispatchToMainThread(event);
-  }
+  nsCOMPtr<nsIRunnable> event = new MediaStreamGraphShutdownThreadRunnable2(mThread);
+  mThread = nullptr;
+  NS_DispatchToMainThread(event);
 }
 
 void
 OfflineClockDriver::GetIntervalForIteration(GraphTime& aFrom, GraphTime& aTo)
 {
   aFrom = mIterationStart = IterationEnd();
   aTo = mIterationEnd = IterationEnd() + mGraphImpl->MillisecondsToMediaTime(mSlice);
 
@@ -498,24 +491,22 @@ AsyncCubebTask::Run()
       mDriver = nullptr;
       mShutdownGrip = nullptr;
       break;
     case AsyncCubebOperation::SLEEP: {
       {
         LIFECYCLE_LOG("AsyncCubebOperation::SLEEP\n");
         MonitorAutoLock mon(mDriver->mGraphImpl->GetMonitor());
         // We might just have been awoken
-        if (mDriver->mGraphImpl->mNeedAnotherIteration) {
+        if (mDriver->mNeedAnotherIteration) {
           mDriver->mPauseRequested = false;
           mDriver->mWaitState = AudioCallbackDriver::WAITSTATE_RUNNING;
-          mDriver->mGraphImpl->mGraphDriverAsleep = false	; // atomic
           break;
         }
         mDriver->Stop();
-        mDriver->mGraphImpl->mGraphDriverAsleep = true; // atomic
         mDriver->mWaitState = AudioCallbackDriver::WAITSTATE_WAITING_INDEFINITELY;
         mDriver->mPauseRequested = false;
         mDriver->mGraphImpl->GetMonitor().Wait(PR_INTERVAL_NO_TIMEOUT);
       }
       STREAM_LOG(PR_LOG_DEBUG, ("Restarting audio stream from sleep."));
       mDriver->StartStream();
       break;
     }
@@ -664,31 +655,26 @@ AudioCallbackDriver::Stop()
   if (cubeb_stream_stop(mAudioStream) != CUBEB_OK) {
     NS_WARNING("Could not stop cubeb stream for MSG.");
   }
 }
 
 void
 AudioCallbackDriver::Revive()
 {
-  // Note: only called on MainThread, without monitor
-  // We know were weren't in a running state
   STREAM_LOG(PR_LOG_DEBUG, ("AudioCallbackDriver reviving."));
   // If we were switching, switch now. Otherwise, start the audio thread again.
-  MonitorAutoLock mon(mGraphImpl->GetMonitor());
   if (mNextDriver) {
     mNextDriver->SetGraphTime(this, mIterationStart, mIterationEnd,
-                              mStateComputedTime, mNextStateComputedTime);
+                               mStateComputedTime, mNextStateComputedTime);
     mGraphImpl->SetCurrentDriver(mNextDriver);
     mNextDriver->Start();
   } else {
-    STREAM_LOG(PR_LOG_DEBUG, ("Starting audio threads for MediaStreamGraph %p from a new thread.", mGraphImpl));
-    nsRefPtr<AsyncCubebTask> initEvent =
-      new AsyncCubebTask(this, AsyncCubebTask::INIT);
-    initEvent->Dispatch();
+    Init();
+    Start();
   }
 }
 
 void
 AudioCallbackDriver::GetIntervalForIteration(GraphTime& aFrom,
                                              GraphTime& aTo)
 {
 }
@@ -708,17 +694,17 @@ AudioCallbackDriver::GetCurrentTime()
 void AudioCallbackDriver::WaitForNextIteration()
 {
 #if 0
   mGraphImpl->GetMonitor().AssertCurrentThreadOwns();
 
   // We can't block on the monitor in the audio callback, so we kick off a new
   // thread that will pause the audio stream, and restart it when unblocked.
   // We don't want to sleep when we haven't started the driver yet.
-  if (!mGraphImpl->mNeedAnotherIteration && mAudioStream && mGraphImpl->Running()) {
+  if (!mNeedAnotherIteration && mAudioStream && mGraphImpl->Running()) {
     STREAM_LOG(PR_LOG_DEBUG+1, ("AudioCallbackDriver going to sleep"));
     mPauseRequested = true;
     nsRefPtr<AsyncCubebTask> sleepEvent =
       new AsyncCubebTask(this, AsyncCubebTask::SLEEP);
     sleepEvent->Dispatch();
   }
 #endif
 }
@@ -750,45 +736,43 @@ AudioCallbackDriver::StateCallback_s(cub
 /* static */ void
 AudioCallbackDriver::DeviceChangedCallback_s(void* aUser)
 {
   AudioCallbackDriver* driver = reinterpret_cast<AudioCallbackDriver*>(aUser);
   driver->DeviceChangedCallback();
 }
 
 bool AudioCallbackDriver::InCallback() {
+  MonitorAutoLock mon(mGraphImpl->GetMonitor());
   return mInCallback;
 }
 
 AudioCallbackDriver::AutoInCallback::AutoInCallback(AudioCallbackDriver* aDriver)
   : mDriver(aDriver)
 {
+  MonitorAutoLock mon(mDriver->mGraphImpl->GetMonitor());
   mDriver->mInCallback = true;
 }
 
 AudioCallbackDriver::AutoInCallback::~AutoInCallback() {
+  MonitorAutoLock mon(mDriver->mGraphImpl->GetMonitor());
   mDriver->mInCallback = false;
 }
 
 long
 AudioCallbackDriver::DataCallback(AudioDataValue* aBuffer, long aFrames)
 {
   bool stillProcessing;
 
   if (mPauseRequested) {
     PodZero(aBuffer, aFrames * mGraphImpl->AudioChannelCount());
     return aFrames;
   }
 
-#ifdef DEBUG
-  // DebugOnly<> doesn't work here... it forces an initialization that will cause
-  // mInCallback to be set back to false before we exit the statement.  Do it by
-  // hand instead.
-  AutoInCallback aic(this);
-#endif
+  DebugOnly<AutoInCallback> aic(AutoInCallback(this));
 
   if (mStateComputedTime == 0) {
     MonitorAutoLock mon(mGraphImpl->GetMonitor());
     // Because this function is called during cubeb_stream_init (to prefill the
     // audio buffers), it can be that we don't have a message here (because this
     // driver is the first one for this graph), and the graph would exit. Simply
     // return here until we have messages.
     if (!mGraphImpl->MessagesQueued()) {
--- a/content/media/GraphDriver.h
+++ b/content/media/GraphDriver.h
@@ -6,17 +6,16 @@
 #ifndef GRAPHDRIVER_H_
 #define GRAPHDRIVER_H_
 
 #include "nsAutoPtr.h"
 #include "nsAutoRef.h"
 #include "AudioBufferUtils.h"
 #include "AudioMixer.h"
 #include "AudioSegment.h"
-#include "mozilla/Atomics.h"
 
 struct cubeb_stream;
 
 template <>
 class nsAutoRefTraits<cubeb_stream> : public nsPointerRefTraits<cubeb_stream>
 {
 public:
   static void Release(cubeb_stream* aStream) { cubeb_stream_destroy(aStream); }
@@ -194,18 +193,16 @@ public:
    * Same thing, but not locked.
    */
   void EnsureNextIterationLocked();
 
   MediaStreamGraphImpl* GraphImpl() {
     return mGraphImpl;
   }
 
-  virtual bool OnThread() = 0;
-
 protected:
   // Time of the start of this graph iteration.
   GraphTime mIterationStart;
   // Time of the end of this graph iteration.
   GraphTime mIterationEnd;
   // Time, in the future, for which blocking has been computed.
   GraphTime mStateComputedTime;
   GraphTime mNextStateComputedTime;
@@ -223,16 +220,18 @@ protected:
     // RunThread() is paused indefinitely waiting for something to change
     WAITSTATE_WAITING_INDEFINITELY,
     // Something has signaled RunThread() to wake up immediately,
     // but it hasn't done so yet
     WAITSTATE_WAKING_UP
   };
   WaitState mWaitState;
 
+  // True if the graph needs another iteration after the current iteration.
+  bool mNeedAnotherIteration;
   TimeStamp mCurrentTimeStamp;
   // This is non-null only when this driver has recently switched from an other
   // driver, and has not cleaned it up yet (for example because the audio stream
   // is currently calling the callback during initialization).
   nsRefPtr<GraphDriver> mPreviousDriver;
   // This is non-null only when this driver is going to switch to an other
   // driver at the end of this iteration.
   nsRefPtr<GraphDriver> mNextDriver;
@@ -258,19 +257,16 @@ public:
    * Runs main control loop on the graph thread. Normally a single invocation
    * of this runs for the entire lifetime of the graph thread.
    */
   void RunThread();
   friend class MediaStreamGraphInitThreadRunnable;
   uint32_t IterationDuration() {
     return MEDIA_GRAPH_TARGET_PERIOD_MS;
   }
-
-  virtual bool OnThread() MOZ_OVERRIDE { return !mThread || NS_GetCurrentThread() == mThread; }
-
 protected:
   nsCOMPtr<nsIThread> mThread;
 };
 
 /**
  * A SystemClockDriver drives a MediaStreamGraph using a system clock, and waits
  * using a monitor, between each iteration.
  */
@@ -383,18 +379,16 @@ public:
     return this;
   }
 
   /**
    * Whether the audio callback is processing. This is for asserting only.
    */
   bool InCallback();
 
-  virtual bool OnThread() MOZ_OVERRIDE { return !mStarted || InCallback(); }
-
   /* Whether the underlying cubeb stream has been started. See comment for
    * mStarted for details. */
   bool IsStarted();
 
   /* Tell the driver whether this process is using a microphone or not. This is
    * thread safe. */
   void SetMicrophoneActive(bool aActive);
 private:
@@ -450,17 +444,18 @@ private:
     ~AutoInCallback();
     AudioCallbackDriver* mDriver;
   };
 
   /* Thread for off-main-thread initialization and
    * shutdown of the audio stream. */
   nsCOMPtr<nsIThread> mInitShutdownThread;
   dom::AudioChannel mAudioChannel;
-  Atomic<bool> mInCallback;
+  /* This can only be accessed with the graph's monitor held. */
+  bool mInCallback;
   /* A thread has been created to be able to pause and restart the audio thread,
    * but has not done so yet. This indicates that the callback should return
    * early */
   bool mPauseRequested;
   /**
    * True if microphone is being used by this process. This is synchronized by
    * the graph's monitor. */
   bool mMicrophoneActive;
--- a/content/media/MediaStreamGraph.cpp
+++ b/content/media/MediaStreamGraph.cpp
@@ -90,17 +90,17 @@ MediaStreamGraphImpl::FinishStream(Media
   if (aStream->mFinished)
     return;
   STREAM_LOG(PR_LOG_DEBUG, ("MediaStream %p will finish", aStream));
   aStream->mFinished = true;
   aStream->mBuffer.AdvanceKnownTracksTime(STREAM_TIME_MAX);
   // Force at least one more iteration of the control loop, since we rely
   // on UpdateCurrentTimeForStreams to notify our listeners once the stream end
   // has been reached.
-  EnsureNextIteration();
+  CurrentDriver()->EnsureNextIteration();
 
   SetStreamOrderDirty();
 }
 
 void
 MediaStreamGraphImpl::AddStream(MediaStream* aStream)
 {
   aStream->mBufferStartTime = IterationEnd();
@@ -773,17 +773,17 @@ MediaStreamGraphImpl::RecomputeBlocking(
   STREAM_LOG(PR_LOG_DEBUG+1, ("Media graph %p computed blocking for interval %f to %f",
                               this, MediaTimeToSeconds(CurrentDriver()->StateComputedTime()),
                               MediaTimeToSeconds(aEndBlockingDecisions)));
 
   CurrentDriver()->UpdateStateComputedTime(aEndBlockingDecisions);
 
   if (blockingDecisionsWillChange) {
     // Make sure we wake up to notify listeners about these changes.
-    EnsureNextIteration();
+    CurrentDriver()->EnsureNextIteration();
   }
 }
 
 void
 MediaStreamGraphImpl::AddBlockingRelatedStreamsToSet(nsTArray<MediaStream*>* aStreams,
                                                      MediaStream* aStream)
 {
   if (aStream->mInBlockingSet)
@@ -1283,17 +1283,17 @@ MediaStreamGraphImpl::UpdateGraph(GraphT
   // The loop is woken up so soon that IterationEnd() barely advances and we
   // end up having aEndBlockingDecision == CurrentDriver()->StateComputedTime().
   // Since stream blocking is computed in the interval of
   // [CurrentDriver()->StateComputedTime(), aEndBlockingDecision), it won't be computed at all.
   // We should ensure next iteration so that pending blocking changes will be
   // computed in next loop.
   if (ensureNextIteration ||
       aEndBlockingDecision == CurrentDriver()->StateComputedTime()) {
-    EnsureNextIteration();
+    CurrentDriver()->EnsureNextIteration();
   }
 
   // Figure out which streams are blocked and when.
   RecomputeBlocking(aEndBlockingDecision);
 }
 
 void
 MediaStreamGraphImpl::Process(GraphTime aFrom, GraphTime aTo)
@@ -1377,17 +1377,17 @@ MediaStreamGraphImpl::Process(GraphTime 
       isStarted = CurrentDriver()->AsAudioCallbackDriver()->IsStarted();
     }
     if (isStarted) {
       mMixer.RemoveCallback(CurrentDriver()->AsAudioCallbackDriver());
     }
   }
 
   if (!allBlockedForever) {
-    EnsureNextIteration();
+    CurrentDriver()->EnsureNextIteration();
   }
 }
 
 bool
 MediaStreamGraphImpl::OneIteration(GraphTime aFrom, GraphTime aTo,
                                    GraphTime aStateFrom, GraphTime aStateEnd)
 {
   {
@@ -1463,17 +1463,17 @@ MediaStreamGraphImpl::ApplyStreamUpdate(
 void
 MediaStreamGraphImpl::ForceShutDown()
 {
   NS_ASSERTION(NS_IsMainThread(), "Must be called on main thread");
   STREAM_LOG(PR_LOG_DEBUG, ("MediaStreamGraph %p ForceShutdown", this));
   {
     MonitorAutoLock lock(mMonitor);
     mForceShutDown = true;
-    EnsureNextIterationLocked();
+    CurrentDriver()->EnsureNextIterationLocked();
   }
 }
 
 namespace {
 
 class MediaStreamGraphShutDownRunnable : public nsRunnable {
 public:
   explicit MediaStreamGraphShutDownRunnable(MediaStreamGraphImpl* aGraph)
@@ -1481,28 +1481,21 @@ public:
   {}
   NS_IMETHOD Run()
   {
     NS_ASSERTION(mGraph->mDetectedNotRunning,
                  "We should know the graph thread control loop isn't running!");
 
     LIFECYCLE_LOG("Shutting down graph %p", mGraph.get());
 
-    // We've asserted the graph isn't running.  Use mDriver instead of CurrentDriver
-    // to avoid thread-safety checks
-#if 0 // AudioCallbackDrivers are released asynchronously anyways
-    // XXX a better test would be have setting mDetectedNotRunning make sure
-    // any current callback has finished and block future ones -- or just
-    // handle it all in Shutdown()!
-    if (mGraph->mDriver->AsAudioCallbackDriver()) {
-      MOZ_ASSERT(!mGraph->mDriver->AsAudioCallbackDriver()->InCallback());
+    if (mGraph->CurrentDriver()->AsAudioCallbackDriver()) {
+      MOZ_ASSERT(!mGraph->CurrentDriver()->AsAudioCallbackDriver()->InCallback());
     }
-#endif
 
-    mGraph->mDriver->Shutdown();
+    mGraph->CurrentDriver()->Shutdown();
 
     // mGraph's thread is not running so it's OK to do whatever here
     if (mGraph->IsEmpty()) {
       // mGraph is no longer needed, so delete it.
       mGraph->Destroy();
     } else {
       // The graph is not empty.  We must be in a forced shutdown, or a
       // non-realtime graph that has finished processing.  Some later
@@ -1639,58 +1632,56 @@ MediaStreamGraphImpl::RunInStableState(b
         }
       }
     } else {
       if (mLifecycleState <= LIFECYCLE_WAITING_FOR_MAIN_THREAD_CLEANUP) {
         MessageBlock* block = mBackMessageQueue.AppendElement();
         block->mMessages.SwapElements(mCurrentTaskMessageQueue);
         block->mGraphUpdateIndex = mNextGraphUpdateIndex;
         ++mNextGraphUpdateIndex;
-        EnsureNextIterationLocked();
+        CurrentDriver()->EnsureNextIterationLocked();
       }
 
       // If the MediaStreamGraph has more messages going to it, try to revive
       // it to process those messages. Don't do this if we're in a forced
       // shutdown or it's a non-realtime graph that has already terminated
       // processing.
       if (mLifecycleState == LIFECYCLE_WAITING_FOR_MAIN_THREAD_CLEANUP &&
           mRealtime && !mForceShutDown) {
         mLifecycleState = LIFECYCLE_RUNNING;
         // Revive the MediaStreamGraph since we have more messages going to it.
         // Note that we need to put messages into its queue before reviving it,
         // or it might exit immediately.
         {
+          MonitorAutoUnlock unlock(mMonitor);
           LIFECYCLE_LOG("Reviving a graph (%p) ! %s\n",
               this, CurrentDriver()->AsAudioCallbackDriver() ? "AudioDriver" :
                                                                "SystemDriver");
-          nsRefPtr<GraphDriver> driver = CurrentDriver();
-          MonitorAutoUnlock unlock(mMonitor);
-          driver->Revive();
+          CurrentDriver()->Revive();
         }
       }
     }
 
     // Don't start the thread for a non-realtime graph until it has been
     // explicitly started by StartNonRealtimeProcessing.
     if (mLifecycleState == LIFECYCLE_THREAD_NOT_STARTED &&
         (mRealtime || mNonRealtimeProcessing)) {
       mLifecycleState = LIFECYCLE_RUNNING;
       // Start the thread now. We couldn't start it earlier because
       // the graph might exit immediately on finding it has no streams. The
       // first message for a new graph must create a stream.
       {
         // We should exit the monitor for now, because starting a stream might
         // take locks, and we don't want to deadlock.
+        MonitorAutoUnlock unlock(mMonitor);
         LIFECYCLE_LOG("Starting a graph (%p) ! %s\n",
                       this,
                       CurrentDriver()->AsAudioCallbackDriver() ? "AudioDriver" :
                                                                  "SystemDriver");
-        nsRefPtr<GraphDriver> driver = CurrentDriver();
-        MonitorAutoUnlock unlock(mMonitor);
-        driver->Start();
+        CurrentDriver()->Start();
       }
     }
 
     if ((mForceShutDown || !mRealtime) &&
         mLifecycleState == LIFECYCLE_WAITING_FOR_MAIN_THREAD_CLEANUP) {
       // Defer calls to RunDuringShutdown() to happen while mMonitor is not held.
       for (uint32_t i = 0; i < mBackMessageQueue.Length(); ++i) {
         MessageBlock& mb = mBackMessageQueue[i];
@@ -1722,17 +1713,16 @@ MediaStreamGraphImpl::RunInStableState(b
   }
 
 #ifdef DEBUG
   mCanRunMessagesSynchronously = mDetectedNotRunning &&
     mLifecycleState >= LIFECYCLE_WAITING_FOR_THREAD_SHUTDOWN;
 #endif
 }
 
-
 static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
 
 void
 MediaStreamGraphImpl::EnsureRunInStableState()
 {
   NS_ASSERTION(NS_IsMainThread(), "main thread only");
 
   if (mPostedRunInStableState)
@@ -2263,17 +2253,17 @@ SourceMediaStream::DestroyImpl()
 }
 
 void
 SourceMediaStream::SetPullEnabled(bool aEnabled)
 {
   MutexAutoLock lock(mMutex);
   mPullEnabled = aEnabled;
   if (mPullEnabled && GraphImpl()) {
-    GraphImpl()->EnsureNextIteration();
+    GraphImpl()->CurrentDriver()->EnsureNextIteration();
   }
 }
 
 void
 SourceMediaStream::AddTrack(TrackID aID, TrackRate aRate, TrackTicks aStart,
                             MediaSegment* aSegment)
 {
   MutexAutoLock lock(mMutex);
@@ -2283,17 +2273,17 @@ SourceMediaStream::AddTrack(TrackID aID,
   // We resample all audio input tracks to the sample rate of the audio mixer.
   data->mOutputRate = aSegment->GetType() == MediaSegment::AUDIO ?
                       GraphImpl()->AudioSampleRate() : aRate;
   data->mStart = aStart;
   data->mCommands = TRACK_CREATE;
   data->mData = aSegment;
   data->mHaveEnough = false;
   if (auto graph = GraphImpl()) {
-    graph->EnsureNextIteration();
+    graph->CurrentDriver()->EnsureNextIteration();
   }
 }
 
 void
 SourceMediaStream::ResampleAudioToGraphSampleRate(TrackData* aTrackData, MediaSegment* aSegment)
 {
   if (aSegment->GetType() != MediaSegment::AUDIO ||
       aTrackData->mInputRate == GraphImpl()->AudioSampleRate()) {
@@ -2345,17 +2335,17 @@ SourceMediaStream::AppendToTrack(TrackID
       ApplyTrackDisabling(aID, aSegment, aRawSegment);
 
       ResampleAudioToGraphSampleRate(track, aSegment);
 
       // Must notify first, since AppendFrom() will empty out aSegment
       NotifyDirectConsumers(track, aRawSegment ? aRawSegment : aSegment);
       track->mData->AppendFrom(aSegment); // note: aSegment is now dead
       appended = true;
-      GraphImpl()->EnsureNextIteration();
+      GraphImpl()->CurrentDriver()->EnsureNextIteration();
     } else {
       aSegment->Clear();
     }
   }
   return appended;
 }
 
 void
@@ -2469,38 +2459,38 @@ SourceMediaStream::EndTrack(TrackID aID)
   // ::EndAllTrackAndFinished() can end these before the sources call this
   if (!mFinished) {
     TrackData *track = FindDataForTrack(aID);
     if (track) {
       track->mCommands |= TRACK_END;
     }
   }
   if (auto graph = GraphImpl()) {
-    graph->EnsureNextIteration();
+    graph->CurrentDriver()->EnsureNextIteration();
   }
 }
 
 void
 SourceMediaStream::AdvanceKnownTracksTime(StreamTime aKnownTime)
 {
   MutexAutoLock lock(mMutex);
   MOZ_ASSERT(aKnownTime >= mUpdateKnownTracksTime);
   mUpdateKnownTracksTime = aKnownTime;
   if (auto graph = GraphImpl()) {
-    graph->EnsureNextIteration();
+    graph->CurrentDriver()->EnsureNextIteration();
   }
 }
 
 void
 SourceMediaStream::FinishWithLockHeld()
 {
   mMutex.AssertCurrentThreadOwns();
   mUpdateFinished = true;
   if (auto graph = GraphImpl()) {
-    graph->EnsureNextIteration();
+    graph->CurrentDriver()->EnsureNextIteration();
   }
 }
 
 void
 SourceMediaStream::EndAllTrackAndFinish()
 {
   MutexAutoLock lock(mMutex);
   for (uint32_t i = 0; i < mUpdateTracks.Length(); ++i) {
@@ -2707,18 +2697,16 @@ ProcessedMediaStream::DestroyImpl()
 }
 
 MediaStreamGraphImpl::MediaStreamGraphImpl(bool aRealtime,
                                            TrackRate aSampleRate,
                                            DOMMediaStream::TrackTypeHints aHint= DOMMediaStream::HINT_CONTENTS_UNKNOWN,
                                            dom::AudioChannel aChannel)
   : mProcessingGraphUpdateIndex(0)
   , mPortCount(0)
-  , mNeedAnotherIteration(false)
-  , mGraphDriverAsleep(false)
   , mMonitor("MediaStreamGraphImpl")
   , mLifecycleState(LIFECYCLE_THREAD_NOT_STARTED)
   , mEndTime(GRAPH_TIME_MAX)
   , mSampleRate(aSampleRate)
   , mForceShutDown(false)
   , mPostedRunInStableStateEvent(false)
   , mDetectedNotRunning(false)
   , mPostedRunInStableState(false)
--- a/content/media/MediaStreamGraphImpl.h
+++ b/content/media/MediaStreamGraphImpl.h
@@ -145,22 +145,16 @@ public:
   void ShutdownThreads();
 
   /**
    * Called before the thread runs.
    */
   void Init();
   // The following methods run on the graph thread (or possibly the main thread if
   // mLifecycleState > LIFECYCLE_RUNNING)
-  void AssertOnGraphThreadOrNotRunning() {
-    // either we're on the right thread (and calling CurrentDriver() is safe),
-    // or we're going to assert anyways, so don't cross-check CurrentDriver
-    MOZ_ASSERT(mDriver->OnThread() ||
-               (mLifecycleState > LIFECYCLE_RUNNING && NS_IsMainThread()));
-  }
   /*
    * This does the actual iteration: Message processing, MediaStream ordering,
    * blocking computation and processing.
    */
   void DoIteration();
 
   bool OneIteration(GraphTime aFrom, GraphTime aTo,
                     GraphTime aStateFrom, GraphTime aStateEnd);
@@ -415,66 +409,34 @@ public:
 
   /**
    * Signal to the graph that the thread has paused indefinitly,
    * or resumed.
    */
   void PausedIndefinitly();
   void ResumedFromPaused();
 
-  /**
-   * Not safe to call off the MediaStreamGraph thread unless monitor is held!
-   */
   GraphDriver* CurrentDriver() {
-#ifdef DEBUG
-    // #ifdef since we're not wrapping it all in MOZ_ASSERT()
-    if (mDriver->OnThread()) {
-      mMonitor.AssertCurrentThreadOwns();
-    }
-#endif
     return mDriver;
   }
 
   /**
    * Effectively set the new driver, while we are switching.
    * It is only safe to call this at the very end of an iteration, when there
    * has been a SwitchAtNextIteration call during the iteration. The driver
    * should return and pass the control to the new driver shortly after.
-   * We can also switch from Revive() (on MainThread), in which case the
-   * monitor is held
    */
   void SetCurrentDriver(GraphDriver* aDriver) {
-#ifdef DEBUG
-    // #ifdef since we're not wrapping it all in MOZ_ASSERT()
-    if (mDriver->OnThread()) {
-      mMonitor.AssertCurrentThreadOwns();
-    }
-#endif
     mDriver = aDriver;
   }
 
   Monitor& GetMonitor() {
     return mMonitor;
   }
 
-  void EnsureNextIteration() {
-    mNeedAnotherIteration = true; // atomic
-    if (mGraphDriverAsleep) { // atomic
-      MonitorAutoLock mon(mMonitor);
-      CurrentDriver()->WakeUp(); // Might not be the same driver; might have woken already
-    }
-  }
-
-  void EnsureNextIterationLocked() {
-    mNeedAnotherIteration = true; // atomic
-    if (mGraphDriverAsleep) { // atomic
-      CurrentDriver()->WakeUp(); // Might not be the same driver; might have woken already
-    }
-  }
-
   // Data members
   //
   /**
    * Graphs own owning references to their driver, until shutdown. When a driver
    * switch occur, previous driver is either deleted, or it's ownership is
    * passed to a event that will take care of the asynchronous cleanup, as
    * audio stream can take some time to shut down.
    */
@@ -504,30 +466,25 @@ public:
    * Which update batch we are currently processing.
    */
   int64_t mProcessingGraphUpdateIndex;
   /**
    * Number of active MediaInputPorts
    */
   int32_t mPortCount;
 
-  // True if the graph needs another iteration after the current iteration.
-  Atomic<bool> mNeedAnotherIteration;
-  // GraphDriver may need a WakeUp() if something changes
-  Atomic<bool> mGraphDriverAsleep;
-
   // mMonitor guards the data below.
   // MediaStreamGraph normally does its work without holding mMonitor, so it is
   // not safe to just grab mMonitor from some thread and start monkeying with
   // the graph. Instead, communicate with the graph thread using provided
   // mechanisms such as the ControlMessage queue.
   Monitor mMonitor;
 
   // Data guarded by mMonitor (must always be accessed with mMonitor held,
-  // regardless of the value of mLifecycleState).
+  // regardless of the value of mLifecycleState.
 
   /**
    * State to copy to main thread
    */
   nsTArray<StreamUpdate> mStreamUpdates;
   /**
    * Runnables to run after the next update to main thread state.
    */
@@ -598,16 +555,20 @@ public:
 
   /**
    * Sample rate at which this graph runs. For real time graphs, this is
    * the rate of the audio mixer. For offline graphs, this is the rate specified
    * at construction.
    */
   TrackRate mSampleRate;
   /**
+   * True when another iteration of the control loop is required.
+   */
+  bool mNeedAnotherIteration;
+  /**
    * True when we need to do a forced shutdown during application shutdown.
    */
   bool mForceShutDown;
   /**
    * True when we have posted an event to the main thread to run
    * RunInStableState() and the event hasn't run yet.
    */
   bool mPostedRunInStableStateEvent;