Bug 1264694 - [MSE] P2. Clear mTaskQueue early when no longer required. r=jwwang, a=ritu
☠☠ backed out by 9d87d3a279a0 ☠ ☠
authorJean-Yves Avenard <jyavenard@mozilla.com>
Mon, 16 May 2016 18:30:19 +0800
changeset 333070 beddf03ae7f7dfa3a935d316a5d8d159f7b8110a
parent 333069 67974e06189741827c7c40457d43a0ad917dfff6
child 333071 72d6db53a7b3f3d6d46fba8df205692a3d0f1270
push id6048
push userkmoir@mozilla.com
push dateMon, 06 Jun 2016 19:02:08 +0000
treeherdermozilla-beta@46d72a56c57d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjwwang, ritu
bugs1264694
milestone48.0a2
Bug 1264694 - [MSE] P2. Clear mTaskQueue early when no longer required. r=jwwang, a=ritu We need to ensure that the MSE TaskQueue gets shutdown as soon as possible and not wait for the MediaSource parent to be destroyed by the cycle collector. XPCOM shutdown will deadlock if any SharedThreadPool are still in use, and it possible for the cycle collector to only occur after xpcom has shutdown. So it's important to ensure mTaskQueue is cleared when the MediaSourceDecoder has been shutdown. This is done by queueing a new DetachTask that will clear mTaskQueue when run. MozReview-Commit-ID: C3FXcRtq1wy
dom/media/mediasource/SourceBufferTask.h
dom/media/mediasource/TrackBuffersManager.cpp
dom/media/mediasource/TrackBuffersManager.h
--- a/dom/media/mediasource/SourceBufferTask.h
+++ b/dom/media/mediasource/SourceBufferTask.h
@@ -18,17 +18,18 @@ namespace mozilla {
 class SourceBufferTask {
 public:
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(SourceBufferTask);
   enum class Type  {
     AppendBuffer,
     Abort,
     Reset,
     RangeRemoval,
-    EvictData
+    EvictData,
+    Detach
   };
 
   typedef Pair<bool, SourceBufferAttributes> AppendBufferResult;
   typedef MozPromise<AppendBufferResult, nsresult, /* IsExclusive = */ true> AppendPromise;
   typedef MozPromise<bool, nsresult, /* IsExclusive = */ true> RangeRemovalPromise;
 
   virtual Type GetType() const = 0;
 
@@ -93,11 +94,17 @@ public:
 
   static const Type sType = Type::EvictData;
   Type GetType() const override { return Type::EvictData; }
 
   media::TimeUnit mPlaybackTime;
   int64_t mSizeToEvict;
 };
 
+class DetachTask : public SourceBufferTask {
+public:
+  static const Type sType = Type::Detach;
+  Type GetType() const override { return Type::Detach; }
+};
+
 } // end mozilla namespace
 
 #endif
\ No newline at end of file
--- a/dom/media/mediasource/TrackBuffersManager.cpp
+++ b/dom/media/mediasource/TrackBuffersManager.cpp
@@ -94,17 +94,16 @@ TrackBuffersManager::TrackBuffersManager
   , mNewMediaSegmentStarted(false)
   , mActiveTrack(false)
   , mType(aType)
   , mParser(ContainerParser::CreateForMIMEType(aType))
   , mProcessedInput(0)
   , mTaskQueue(aParentDecoder->GetDemuxer()->GetTaskQueue())
   , mParentDecoder(new nsMainThreadPtrHolder<MediaSourceDecoder>(aParentDecoder, false /* strict */))
   , mEnded(false)
-  , mDetached(false)
   , mVideoEvictionThreshold(Preferences::GetUint("media.mediasource.eviction_threshold.video",
                                                  100 * 1024 * 1024))
   , mAudioEvictionThreshold(Preferences::GetUint("media.mediasource.eviction_threshold.audio",
                                                  30 * 1024 * 1024))
   , mEvictionOccurred(false)
   , mMonitor("TrackBuffersManager")
 {
   MOZ_ASSERT(NS_IsMainThread(), "Must be instanciated on the main thread");
@@ -157,20 +156,16 @@ TrackBuffersManager::QueueTask(SourceBuf
 }
 
 void
 TrackBuffersManager::ProcessTasks()
 {
   MOZ_ASSERT(OnTaskQueue());
   typedef SourceBufferTask::Type Type;
 
-  if (mDetached) {
-    return;
-  }
-
   if (mCurrentTask) {
     // Already have a task pending. ProcessTask will be scheduled once the
     // current task complete.
     return;
   }
   RefPtr<SourceBufferTask> task = mQueue.Pop();
   if (!task) {
     // nothing to do.
@@ -203,16 +198,21 @@ TrackBuffersManager::ProcessTasks()
                   task->As<EvictDataTask>()->mSizeToEvict);
       break;
     case Type::Abort:
       // not handled yet, and probably never.
       break;
     case Type::Reset:
       CompleteResetParserState();
       break;
+    case Type::Detach:
+      mTaskQueue = nullptr;
+      MOZ_DIAGNOSTIC_ASSERT(mQueue.Length() == 0,
+                            "Detach task must be the last");
+      return;
     default:
       NS_WARNING("Invalid Task");
   }
   nsCOMPtr<nsIRunnable> task =
     NS_NewRunnableMethod(this, &TrackBuffersManager::ProcessTasks);
   GetTaskQueue()->Dispatch(task.forget());
 }
 
@@ -220,17 +220,16 @@ TrackBuffersManager::ProcessTasks()
 // that hasn't been completed. It is possible that a task didn't get processed
 // due to the owning SourceBuffer having shutdown.
 // We resolve/reject all pending promises and remove all pending tasks from the
 // queue.
 void
 TrackBuffersManager::CancelAllTasks()
 {
   typedef SourceBufferTask::Type Type;
-  MOZ_DIAGNOSTIC_ASSERT(mDetached);
 
   if (mCurrentTask) {
     mQueue.Push(mCurrentTask);
     mCurrentTask = nullptr;
   }
 
   RefPtr<SourceBufferTask> task;
   while ((task = mQueue.Pop())) {
@@ -385,17 +384,17 @@ TrackBuffersManager::Ended()
   mEnded = true;
 }
 
 void
 TrackBuffersManager::Detach()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MSE_DEBUG("");
-  mDetached = true;
+  QueueTask(new DetachTask());
 }
 
 void
 TrackBuffersManager::CompleteResetParserState()
 {
   MOZ_ASSERT(OnTaskQueue());
   MSE_DEBUG("");
 
@@ -754,54 +753,43 @@ TrackBuffersManager::SegmentParserLoop()
     }
   }
 }
 
 void
 TrackBuffersManager::NeedMoreData()
 {
   MSE_DEBUG("");
-  if (mDetached) {
-    // We've been detached.
-    return;
-  }
   MOZ_DIAGNOSTIC_ASSERT(mCurrentTask && mCurrentTask->GetType() == SourceBufferTask::Type::AppendBuffer);
   MOZ_DIAGNOSTIC_ASSERT(mSourceBufferAttributes);
 
   mCurrentTask->As<AppendBufferTask>()->mPromise.Resolve(
     SourceBufferTask::AppendBufferResult(mActiveTrack,
                                          *mSourceBufferAttributes),
                                          __func__);
   mSourceBufferAttributes = nullptr;
   mCurrentTask = nullptr;
   ProcessTasks();
 }
 
 void
 TrackBuffersManager::RejectAppend(nsresult aRejectValue, const char* aName)
 {
   MSE_DEBUG("rv=%d", aRejectValue);
-  if (mDetached) {
-    // We've been detached.
-    return;
-  }
   MOZ_DIAGNOSTIC_ASSERT(mCurrentTask && mCurrentTask->GetType() == SourceBufferTask::Type::AppendBuffer);
 
   mCurrentTask->As<AppendBufferTask>()->mPromise.Reject(aRejectValue, __func__);
   mSourceBufferAttributes = nullptr;
   mCurrentTask = nullptr;
   ProcessTasks();
 }
 
 void
 TrackBuffersManager::ScheduleSegmentParserLoop()
 {
-  if (mDetached) {
-    return;
-  }
   nsCOMPtr<nsIRunnable> task =
     NS_NewRunnableMethod(this, &TrackBuffersManager::SegmentParserLoop);
   GetTaskQueue()->Dispatch(task.forget());
 }
 
 void
 TrackBuffersManager::ShutdownDemuxers()
 {
--- a/dom/media/mediasource/TrackBuffersManager.h
+++ b/dom/media/mediasource/TrackBuffersManager.h
@@ -392,19 +392,16 @@ private:
   // mSourceBufferAttributes.mAppendWindowStart/End
   media::TimeInterval mAppendWindow;
 
   // Strong references to external objects.
   nsMainThreadPtrHandle<MediaSourceDecoder> mParentDecoder;
 
   // Set to true if mediasource state changed to ended.
   Atomic<bool> mEnded;
-  // Set to true if the parent SourceBuffer has shutdown.
-  // We will not reschedule or process new task once mDetached is set.
-  Atomic<bool> mDetached;
 
   // Global size of this source buffer content.
   Atomic<int64_t> mSizeSourceBuffer;
   const int64_t mVideoEvictionThreshold;
   const int64_t mAudioEvictionThreshold;
   Atomic<bool> mEvictionOccurred;
 
   // Monitor to protect following objects accessed across multipple threads.