Bug 1336345 - Register shutdown blocker only once when the 1st MediaDecoder is created. r=gerald, a=lizzard
authorJW Wang <jwwang@mozilla.com>
Mon, 06 Mar 2017 10:32:11 +0800
changeset 378961 f56896f4d1a5c68bb140bf7a2c6d92997edd626a
parent 378960 dcf431ccb619707fd8b34603427723d78b7f8011
child 378962 ecc496aa06dc32e8407193c5a6dfef660d6295c7
push id1419
push userjlund@mozilla.com
push dateMon, 10 Apr 2017 20:44:07 +0000
treeherdermozilla-release@5e6801b73ef6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgerald, lizzard
bugs1336345
milestone53.0
Bug 1336345 - Register shutdown blocker only once when the 1st MediaDecoder is created. r=gerald, a=lizzard
dom/media/MediaDecoder.cpp
dom/media/MediaShutdownManager.cpp
dom/media/MediaShutdownManager.h
--- a/dom/media/MediaDecoder.cpp
+++ b/dom/media/MediaDecoder.cpp
@@ -455,16 +455,17 @@ MediaDecoder::MediaDecoder(MediaDecoderO
   mWatchManager.Watch(mPlayState, &MediaDecoder::UpdateLogicalPosition);
   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
@@ -14,18 +14,16 @@
 namespace mozilla {
 
 extern LazyLogModule gMediaDecoderLog;
 #define DECODER_LOG(type, msg) MOZ_LOG(gMediaDecoderLog, type, msg)
 
 NS_IMPL_ISUPPORTS(MediaShutdownManager, nsIAsyncShutdownBlocker)
 
 MediaShutdownManager::MediaShutdownManager()
-  : mIsObservingShutdown(false)
-  , mIsDoingXPCOMShutDown(false)
 {
   MOZ_ASSERT(NS_IsMainThread());
 }
 
 MediaShutdownManager::~MediaShutdownManager()
 {
   MOZ_ASSERT(NS_IsMainThread());
 }
@@ -33,19 +31,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,66 +54,77 @@ GetShutdownBarrier()
     rv = svc->GetXpcomWillShutdown(getter_AddRefs(barrier));
   }
   MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
   MOZ_RELEASE_ASSERT(barrier);
   return barrier.forget();
 }
 
 void
-MediaShutdownManager::EnsureCorrectShutdownObserverState()
+MediaShutdownManager::InitStatics()
 {
-  bool needShutdownObserver = mDecoders.Count() > 0;
-  if (needShutdownObserver != mIsObservingShutdown) {
-    mIsObservingShutdown = needShutdownObserver;
-    if (mIsObservingShutdown) {
-      nsresult rv = GetShutdownBarrier()->AddBlocker(
-        this, 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();
-      }
-    } else {
-      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."));
-    }
+  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::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 +141,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,29 +68,23 @@ 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();
-
-  // Ensures we have a shutdown listener if we need one, and removes the
-  // listener and destroys the singleton if we don't.
-  void EnsureCorrectShutdownObserverState();
+  void RemoveBlocker();
 
   static StaticRefPtr<MediaShutdownManager> sInstance;
 
   // References to the MediaDecoder. The decoders unregister themselves
   // in their Shutdown() method, so we'll drop the reference naturally when
   // we're shutting down (in the non xpcom-shutdown case).
   nsTHashtable<nsRefPtrHashKey<MediaDecoder>> mDecoders;
 
-  // True if we have an XPCOM shutdown observer.
-  bool mIsObservingShutdown;
-
-  bool mIsDoingXPCOMShutDown;
+  bool mIsDoingXPCOMShutDown = false;
 };
 
 } // namespace mozilla
 
 #endif