Bug 1336345. Part 1 - register shutdown blocker only once when the 1st MediaDecoder is created. r=gerald
authorJW Wang <jwwang@mozilla.com>
Fri, 03 Feb 2017 15:12:22 +0800
changeset 341110 370b66055c098a255d1d6a061b357f932ed70b5f
parent 341109 2ff48b77d380c9c649d2f5f1d54b4f5c5b3340ad
child 341111 d729059d550a71caa819d9dd69470bd5cc669fed
push id86634
push usercbook@mozilla.com
push dateTue, 07 Feb 2017 13:14:58 +0000
treeherdermozilla-inbound@9dbd2d9b334e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgerald
bugs1336345
milestone54.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1336345. Part 1 - register shutdown blocker only once when the 1st MediaDecoder is created. r=gerald MozReview-Commit-ID: 80DEZEEhm9E
dom/media/MediaDecoder.cpp
dom/media/MediaShutdownManager.cpp
dom/media/MediaShutdownManager.h
--- a/dom/media/MediaDecoder.cpp
+++ b/dom/media/MediaDecoder.cpp
@@ -459,16 +459,17 @@ MediaDecoder::MediaDecoder(MediaDecoderO
   mWatchManager.Watch(mLogicallySeeking, &MediaDecoder::UpdateLogicalPosition);
 
   // mIgnoreProgressData
   mWatchManager.Watch(mLogicallySeeking, &MediaDecoder::SeekingChanged);
 
   mWatchManager.Watch(mIsAudioDataAudible,
                       &MediaDecoder::NotifyAudibleStateChanged);
 
+  MediaShutdownManager::InitStatics();
   MediaShutdownManager::Instance().Register(this);
 }
 
 #undef INIT_MIRROR
 #undef INIT_CANONICAL
 
 void
 MediaDecoder::Shutdown()
--- a/dom/media/MediaShutdownManager.cpp
+++ b/dom/media/MediaShutdownManager.cpp
@@ -33,19 +33,17 @@ MediaShutdownManager::~MediaShutdownMana
 // Note that we don't use ClearOnShutdown() on this StaticRefPtr, as that
 // may interfere with our shutdown listener.
 StaticRefPtr<MediaShutdownManager> MediaShutdownManager::sInstance;
 
 MediaShutdownManager&
 MediaShutdownManager::Instance()
 {
   MOZ_ASSERT(NS_IsMainThread());
-  if (!sInstance) {
-    sInstance = new MediaShutdownManager();
-  }
+  MOZ_DIAGNOSTIC_ASSERT(sInstance);
   return *sInstance;
 }
 
 static nsCOMPtr<nsIAsyncShutdownClient>
 GetShutdownBarrier()
 {
   nsCOMPtr<nsIAsyncShutdownService> svc = services::GetAsyncShutdown();
   MOZ_RELEASE_ASSERT(svc);
@@ -58,16 +56,43 @@ GetShutdownBarrier()
     rv = svc->GetXpcomWillShutdown(getter_AddRefs(barrier));
   }
   MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
   MOZ_RELEASE_ASSERT(barrier);
   return barrier.forget();
 }
 
 void
+MediaShutdownManager::InitStatics()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  static bool sInitDone = false;
+  if (sInitDone) {
+    return;
+  }
+
+  sInitDone = true;
+  sInstance = new MediaShutdownManager();
+
+  nsresult rv = GetShutdownBarrier()->AddBlocker(
+    sInstance, NS_LITERAL_STRING(__FILE__), __LINE__,
+    NS_LITERAL_STRING("MediaShutdownManager shutdown"));
+  if (NS_FAILED(rv)) {
+    // Leak the buffer on the heap to make sure that it lives long enough,
+    // as MOZ_CRASH_ANNOTATE expects the pointer passed to it to live to
+    // the end of the program.
+    const size_t CAPACITY = 256;
+    auto buf = new char[CAPACITY];
+    snprintf(buf, CAPACITY, "Failed to add shutdown blocker! rv=%x", uint32_t(rv));
+    MOZ_CRASH_ANNOTATE(buf);
+    MOZ_REALLY_CRASH();
+  }
+}
+
+void
 MediaShutdownManager::EnsureCorrectShutdownObserverState()
 {
   bool needShutdownObserver = mDecoders.Count() > 0;
   if (needShutdownObserver != mIsObservingShutdown) {
     mIsObservingShutdown = needShutdownObserver;
     if (mIsObservingShutdown) {
       nsresult rv = GetShutdownBarrier()->AddBlocker(
         this, NS_LITERAL_STRING(__FILE__), __LINE__,
@@ -88,36 +113,50 @@ MediaShutdownManager::EnsureCorrectShutd
       // this instance, so don't deref |this| clearing sInstance.
       sInstance = nullptr;
       DECODER_LOG(LogLevel::Debug, ("MediaShutdownManager::BlockShutdown() end."));
     }
   }
 }
 
 void
+MediaShutdownManager::RemoveBlocker()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(mIsDoingXPCOMShutDown);
+  MOZ_ASSERT(mDecoders.Count() == 0);
+  GetShutdownBarrier()->RemoveBlocker(this);
+  // Clear our singleton reference. This will probably delete
+  // this instance, so don't deref |this| clearing sInstance.
+  sInstance = nullptr;
+  DECODER_LOG(LogLevel::Debug, ("MediaShutdownManager::BlockShutdown() end."));
+}
+
+void
 MediaShutdownManager::Register(MediaDecoder* aDecoder)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_RELEASE_ASSERT(!mIsDoingXPCOMShutDown);
   // Don't call Register() after you've Unregistered() all the decoders,
   // that's not going to work.
   MOZ_ASSERT(!mDecoders.Contains(aDecoder));
   mDecoders.PutEntry(aDecoder);
   MOZ_ASSERT(mDecoders.Contains(aDecoder));
   MOZ_ASSERT(mDecoders.Count() > 0);
-  EnsureCorrectShutdownObserverState();
 }
 
 void
 MediaShutdownManager::Unregister(MediaDecoder* aDecoder)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(mDecoders.Contains(aDecoder));
   mDecoders.RemoveEntry(aDecoder);
-  EnsureCorrectShutdownObserverState();
+  if (mIsDoingXPCOMShutDown && mDecoders.Count() == 0) {
+    RemoveBlocker();
+  }
 }
 
 NS_IMETHODIMP
 MediaShutdownManager::GetName(nsAString& aName)
 {
   aName = NS_LITERAL_STRING("MediaShutdownManager: shutdown");
   return NS_OK;
 }
@@ -134,18 +173,21 @@ MediaShutdownManager::BlockShutdown(nsIA
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(sInstance);
 
   DECODER_LOG(LogLevel::Debug, ("MediaShutdownManager::BlockShutdown() start..."));
 
   // Set this flag to ensure no Register() is allowed when Shutdown() begins.
   mIsDoingXPCOMShutDown = true;
 
-  DebugOnly<uint32_t> oldCount = mDecoders.Count();
-  MOZ_ASSERT(oldCount > 0);
+  auto oldCount = mDecoders.Count();
+  if (oldCount == 0) {
+    RemoveBlocker();
+    return NS_OK;
+  }
 
   // Iterate over the decoders and shut them down.
   for (auto iter = mDecoders.Iter(); !iter.Done(); iter.Next()) {
     MediaDecoderOwner* owner = iter.Get()->GetKey()->GetOwner();
     if (owner) {
       // The owner will call MediaDecoder::Shutdown() and
       // drop its reference to the decoder.
       owner->NotifyXPCOMShutdown();
--- a/dom/media/MediaShutdownManager.h
+++ b/dom/media/MediaShutdownManager.h
@@ -49,16 +49,18 @@ class MediaDecoder;
 //  MediaShutdownManager& instance = MediaShutdownManager::Instance();
 //  instance.Unregister(someDecoder); // Warning! May delete instance!
 //  instance.Register(someOtherDecoder); // BAD! instance may be dangling!
 class MediaShutdownManager : public nsIAsyncShutdownBlocker {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIASYNCSHUTDOWNBLOCKER
 
+  static void InitStatics();
+
   // The MediaShutdownManager is a singleton, access its instance with
   // this accessor.
   static MediaShutdownManager& Instance();
 
   // Notifies the MediaShutdownManager that it needs to track the shutdown
   // of this MediaDecoder.
   void Register(MediaDecoder* aDecoder);
 
@@ -66,16 +68,17 @@ public:
   // tracking has shutdown, and it no longer needs to be shutdown in the
   // xpcom-shutdown listener.
   void Unregister(MediaDecoder* aDecoder);
 
 private:
 
   MediaShutdownManager();
   virtual ~MediaShutdownManager();
+  void RemoveBlocker();
 
   // Ensures we have a shutdown listener if we need one, and removes the
   // listener and destroys the singleton if we don't.
   void EnsureCorrectShutdownObserverState();
 
   static StaticRefPtr<MediaShutdownManager> sInstance;
 
   // References to the MediaDecoder. The decoders unregister themselves