Bug 1104964 - Split shutdown initiatation and queue-drain-waiting into separate pieces. r=cpearce, a=sledru
authorBobby Holley <bobbyholley@gmail.com>
Mon, 01 Dec 2014 21:51:02 -0800
changeset 242433 a52f49bac58b7d3056611c2995fb2339a0742a53
parent 242432 78b691bfdee36ed06fb3717e176ea8f0f1c30fac
child 242434 0f823d3509129763762b1f51491ea07a56727e6c
push id4311
push userraliiev@mozilla.com
push dateMon, 12 Jan 2015 19:37:41 +0000
treeherdermozilla-beta@150c9fed433b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscpearce, sledru
bugs1104964
milestone36.0a2
Bug 1104964 - Split shutdown initiatation and queue-drain-waiting into separate pieces. r=cpearce, a=sledru This patch shouldn't change any behavior. The upcoming patch takes advantage of these separate pieces.
dom/media/MediaDecoderStateMachine.cpp
dom/media/MediaTaskQueue.cpp
dom/media/MediaTaskQueue.h
dom/media/fmp4/MP4Reader.cpp
dom/media/fmp4/eme/EMEDecoderModule.cpp
dom/media/gtest/TestMP4Reader.cpp
dom/media/mediasource/TrackBuffer.cpp
dom/media/omx/MediaCodecReader.cpp
dom/media/webm/WebMReader.cpp
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -2484,17 +2484,18 @@ nsresult MediaDecoderStateMachine::RunSt
       // Put a task in the decode queue to shutdown the reader.
       RefPtr<nsIRunnable> task;
       task = NS_NewRunnableMethod(mReader, &MediaDecoderReader::Shutdown);
       mDecodeTaskQueue->Dispatch(task);
 
       {
         // Wait for the thread decoding to exit.
         ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor());
-        mDecodeTaskQueue->Shutdown();
+        mDecodeTaskQueue->BeginShutdown();
+        mDecodeTaskQueue->AwaitShutdownAndIdle();
         mDecodeTaskQueue = nullptr;
       }
 
       // The reader's listeners hold references to the state machine,
       // creating a cycle which keeps the state machine and its shared
       // thread pools alive. So break it here.
       AudioQueue().ClearListeners();
       VideoQueue().ClearListeners();
--- a/dom/media/MediaTaskQueue.cpp
+++ b/dom/media/MediaTaskQueue.cpp
@@ -113,21 +113,31 @@ MediaTaskQueue::AwaitIdleLocked()
   mQueueMonitor.AssertCurrentThreadOwns();
   MOZ_ASSERT(mIsRunning || mTasks.empty());
   while (mIsRunning) {
     mQueueMonitor.Wait();
   }
 }
 
 void
-MediaTaskQueue::Shutdown()
+MediaTaskQueue::AwaitShutdownAndIdle()
+{
+  MonitorAutoLock mon(mQueueMonitor);
+  while (!mIsShutdown) {
+    mQueueMonitor.Wait();
+  }
+  AwaitIdleLocked();
+}
+
+void
+MediaTaskQueue::BeginShutdown()
 {
   MonitorAutoLock mon(mQueueMonitor);
   mIsShutdown = true;
-  AwaitIdleLocked();
+  mon.NotifyAll();
 }
 
 nsresult
 MediaTaskQueue::FlushAndDispatch(TemporaryRef<nsIRunnable> aRunnable)
 {
   MonitorAutoLock mon(mQueueMonitor);
   AutoSetFlushing autoFlush(this);
   while (!mTasks.empty()) {
--- a/dom/media/MediaTaskQueue.h
+++ b/dom/media/MediaTaskQueue.h
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef MediaTaskQueue_h_
 #define MediaTaskQueue_h_
 
 #include <queue>
 #include "mozilla/RefPtr.h"
 #include "mozilla/Monitor.h"
+#include "SharedThreadPool.h"
 #include "nsThreadUtils.h"
 
 class nsIRunnable;
 
 namespace mozilla {
 
 class SharedThreadPool;
 
@@ -36,23 +37,29 @@ public:
   nsresult SyncDispatch(TemporaryRef<nsIRunnable> aRunnable);
 
   nsresult FlushAndDispatch(TemporaryRef<nsIRunnable> aRunnable);
 
   // Removes all pending tasks from the task queue, and blocks until
   // the currently running task (if any) finishes.
   void Flush();
 
-  // Blocks until all tasks finish executing, then shuts down the task queue
-  // and exits.
-  void Shutdown();
+  // Puts the queue in a shutdown state and returns immediately. The queue will
+  // remain alive at least until all the events are drained, because the Runners
+  // hold a strong reference to the task queue, and one of them is always held
+  // by the threadpool event queue when the task queue is non-empty.
+  void BeginShutdown();
 
   // Blocks until all task finish executing.
   void AwaitIdle();
 
+  // Blocks until the queue is flagged for shutdown and all tasks have finished
+  // executing.
+  void AwaitShutdownAndIdle();
+
   bool IsEmpty();
 
   // Returns true if the current thread is currently running a Runnable in
   // the task queue. This is for debugging/validation purposes only.
   bool IsCurrentThreadIn();
 
 private:
 
--- a/dom/media/fmp4/MP4Reader.cpp
+++ b/dom/media/fmp4/MP4Reader.cpp
@@ -145,26 +145,28 @@ MP4Reader::Shutdown()
   MOZ_ASSERT(GetTaskQueue()->IsCurrentThreadIn());
 
   if (mAudio.mDecoder) {
     Flush(kAudio);
     mAudio.mDecoder->Shutdown();
     mAudio.mDecoder = nullptr;
   }
   if (mAudio.mTaskQueue) {
-    mAudio.mTaskQueue->Shutdown();
+    mAudio.mTaskQueue->BeginShutdown();
+    mAudio.mTaskQueue->AwaitShutdownAndIdle();
     mAudio.mTaskQueue = nullptr;
   }
   if (mVideo.mDecoder) {
     Flush(kVideo);
     mVideo.mDecoder->Shutdown();
     mVideo.mDecoder = nullptr;
   }
   if (mVideo.mTaskQueue) {
-    mVideo.mTaskQueue->Shutdown();
+    mVideo.mTaskQueue->BeginShutdown();
+    mVideo.mTaskQueue->AwaitShutdownAndIdle();
     mVideo.mTaskQueue = nullptr;
   }
   // Dispose of the queued sample before shutting down the demuxer
   mQueuedVideoSample = nullptr;
 
   if (mPlatform) {
     mPlatform->Shutdown();
     mPlatform = nullptr;
--- a/dom/media/fmp4/eme/EMEDecoderModule.cpp
+++ b/dom/media/fmp4/eme/EMEDecoderModule.cpp
@@ -147,17 +147,18 @@ public:
   }
 
   virtual nsresult Shutdown() MOZ_OVERRIDE {
     mTaskQueue->SyncDispatch(
       NS_NewRunnableMethod(
         mDecoder,
         &MediaDataDecoder::Shutdown));
     mDecoder = nullptr;
-    mTaskQueue->Shutdown();
+    mTaskQueue->BeginShutdown();
+    mTaskQueue->AwaitShutdownAndIdle();
     mTaskQueue = nullptr;
     mProxy = nullptr;
     return NS_OK;
   }
 
 private:
 
   nsRefPtr<MediaDataDecoder> mDecoder;
@@ -184,17 +185,18 @@ EMEDecoderModule::~EMEDecoderModule()
 }
 
 nsresult
 EMEDecoderModule::Shutdown()
 {
   if (mPDM) {
     return mPDM->Shutdown();
   }
-  mTaskQueue->Shutdown();
+  mTaskQueue->BeginShutdown();
+  mTaskQueue->AwaitShutdownAndIdle();
   return NS_OK;
 }
 
 already_AddRefed<MediaDataDecoder>
 EMEDecoderModule::CreateVideoDecoder(const VideoDecoderConfig& aConfig,
                                      layers::LayersBackend aLayersBackend,
                                      layers::ImageContainer* aImageContainer,
                                      MediaTaskQueue* aVideoTaskQueue,
--- a/dom/media/gtest/TestMP4Reader.cpp
+++ b/dom/media/gtest/TestMP4Reader.cpp
@@ -54,17 +54,18 @@ public:
     thread->Shutdown();
   }
 
 private:
   virtual ~TestBinding()
   {
     reader->GetTaskQueue()->Dispatch(NS_NewRunnableMethod(reader,
                                                           &MP4Reader::Shutdown));
-    reader->GetTaskQueue()->Shutdown();
+    reader->GetTaskQueue()->BeginShutdown();
+    reader->GetTaskQueue()->AwaitShutdownAndIdle();
 
     decoder = nullptr;
     resource = nullptr;
     reader = nullptr;
     SharedThreadPool::SpinUntilShutdown();
   }
 
   void ReadMetadata()
--- a/dom/media/mediasource/TrackBuffer.cpp
+++ b/dom/media/mediasource/TrackBuffer.cpp
@@ -98,17 +98,18 @@ private:
 
 void
 TrackBuffer::Shutdown()
 {
   // Finish any decoder initialization, which may add to mInitializedDecoders.
   // Shutdown waits for any pending events, which may require the monitor,
   // so we must not hold the monitor during this call.
   mParentDecoder->GetReentrantMonitor().AssertNotCurrentThreadIn();
-  mTaskQueue->Shutdown();
+  mTaskQueue->BeginShutdown();
+  mTaskQueue->AwaitShutdownAndIdle();
   mTaskQueue = nullptr;
 
   ReentrantMonitorAutoEnter mon(mParentDecoder->GetReentrantMonitor());
   for (uint32_t i = 0; i < mDecoders.Length(); ++i) {
     mDecoders[i]->GetReader()->Shutdown();
   }
   mInitializedDecoders.Clear();
   mParentDecoder = nullptr;
--- a/dom/media/omx/MediaCodecReader.cpp
+++ b/dom/media/omx/MediaCodecReader.cpp
@@ -1244,21 +1244,23 @@ MediaCodecReader::DestroyMediaSources()
   mVideoTrack.mSource = nullptr;
   mAudioOffloadTrack.mSource = nullptr;
 }
 
 void
 MediaCodecReader::ShutdownTaskQueues()
 {
   if(mAudioTrack.mTaskQueue) {
-    mAudioTrack.mTaskQueue->Shutdown();
+    mAudioTrack.mTaskQueue->BeginShutdown();
+    mAudioTrack.mTaskQueue->AwaitShutdownAndIdle();
     mAudioTrack.mTaskQueue = nullptr;
   }
   if(mVideoTrack.mTaskQueue) {
-    mVideoTrack.mTaskQueue->Shutdown();
+    mVideoTrack.mTaskQueue->BeginShutdown();
+    mVideoTrack.mTaskQueue->AwaitShutdownAndIdle();
     mVideoTrack.mTaskQueue = nullptr;
   }
 }
 
 bool
 MediaCodecReader::CreateTaskQueues()
 {
   if (mAudioTrack.mSource != nullptr && mAudioTrack.mCodec != nullptr &&
--- a/dom/media/webm/WebMReader.cpp
+++ b/dom/media/webm/WebMReader.cpp
@@ -222,17 +222,18 @@ WebMReader::~WebMReader()
   MOZ_ASSERT(!mVideoDecoder);
   MOZ_COUNT_DTOR(WebMReader);
 }
 
 void WebMReader::Shutdown()
 {
 #if defined(MOZ_PDM_VPX)
   if (mTaskQueue) {
-    mTaskQueue->Shutdown();
+    mTaskQueue->BeginShutdown();
+    mTaskQueue->AwaitShutdownAndIdle();
   }
 #endif
 
   if (mVideoDecoder) {
     mVideoDecoder->Shutdown();
     mVideoDecoder = nullptr;
   }