Bug 968016 - Ensure all threads in media SharedThreadPools are joined in MediaShutdownManager's xpcom shutdown listener. r=kinetik
authorChris Pearce <cpearce@mozilla.com>
Tue, 18 Feb 2014 11:53:53 +1300
changeset 169513 4ba0ec65173f6f34743b93b50a64a24f1fb8af13
parent 169512 2c760d0a1a3b93d2be056cf67a8390e7c57b6b70
child 169514 c1c582be4d20e51ef877d5aee83bb78d85643943
push id270
push userpvanderbeken@mozilla.com
push dateThu, 06 Mar 2014 09:24:21 +0000
reviewerskinetik
bugs968016
milestone30.0a1
Bug 968016 - Ensure all threads in media SharedThreadPools are joined in MediaShutdownManager's xpcom shutdown listener. r=kinetik
content/media/MediaShutdownManager.cpp
content/media/SharedThreadPool.cpp
content/media/SharedThreadPool.h
--- a/content/media/MediaShutdownManager.cpp
+++ b/content/media/MediaShutdownManager.cpp
@@ -2,21 +2,29 @@
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "MediaShutdownManager.h"
 #include "nsContentUtils.h"
 #include "mozilla/StaticPtr.h"
-#include "mozilla/ClearOnShutdown.h"
 #include "MediaDecoder.h"
+#include "SharedThreadPool.h"
+#include "prlog.h"
 
 namespace mozilla {
 
+#ifdef PR_LOGGING
+extern PRLogModuleInfo* gMediaDecoderLog;
+#define DECODER_LOG(type, msg) PR_LOG(gMediaDecoderLog, type, msg)
+#else
+#define DECODER_LOG(type, msg)
+#endif
+
 NS_IMPL_ISUPPORTS1(MediaShutdownManager, nsIObserver)
 
 MediaShutdownManager::MediaShutdownManager()
   : mIsObservingShutdown(false),
     mIsDoingXPCOMShutDown(false)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_COUNT_CTOR(MediaShutdownManager);
@@ -104,29 +112,38 @@ ShutdownMediaDecoder(nsRefPtrHashKey<Med
 }
 
 void
 MediaShutdownManager::Shutdown()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(sInstance);
 
+  DECODER_LOG(PR_LOG_DEBUG, ("MediaShutdownManager::Shutdown() start..."));
+
   // Mark that we're shutting down, so that Unregister(*) calls don't remove
   // hashtable entries. If Unregsiter(*) was to remove from the hash table,
   // the iterations over the hashtables below would be disrupted.
   mIsDoingXPCOMShutDown = true;
 
   // Iterate over the decoders and shut them down, and remove them from the
   // hashtable.
   mDecoders.EnumerateEntries(ShutdownMediaDecoder, nullptr);
- 
+
+  // Ensure all media shared thread pools are shutdown. This joins with all
+  // threads in the state machine thread pool, the decoder thread pool, and
+  // any others.
+  SharedThreadPool::SpinUntilShutdown();
+
   // Remove the MediaShutdownManager instance from the shutdown observer
   // list.
   nsContentUtils::UnregisterShutdownObserver(this);
 
   // Clear the singleton instance. The only remaining reference should be the
   // reference that the observer service used to call us with. The
   // MediaShutdownManager will be deleted once the observer service cleans
   // up after it finishes its notifications.
   sInstance = nullptr;
+
+  DECODER_LOG(PR_LOG_DEBUG, ("MediaShutdownManager::Shutdown() end."));
 }
 
 } // namespace mozilla
--- a/content/media/SharedThreadPool.cpp
+++ b/content/media/SharedThreadPool.cpp
@@ -63,16 +63,31 @@ DestroySharedThreadPoolHashTable()
     // Note we don't need to lock sMonitor, since we only modify the
     // hash table on the main thread, and if the hash table is empty
     // there are no external references into its contents.
     sPools = nullptr;
     sMonitor = nullptr;
   }
 }
 
+/* static */
+void
+SharedThreadPool::SpinUntilShutdown()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  // Wait until the ShutdownPoolsEvent has been run and shutdown the pool.
+  while (sPools) {
+    if (!NS_ProcessNextEvent(NS_GetCurrentThread(), true)) {
+      break;
+    }
+  }
+  MOZ_ASSERT(!sPools);
+  MOZ_ASSERT(!sMonitor);
+}
+
 TemporaryRef<SharedThreadPool>
 SharedThreadPool::Get(const nsCString& aName, uint32_t aThreadLimit)
 {
   MOZ_ASSERT(NS_IsMainThread());
   EnsureInitialized();
   MOZ_ASSERT(sMonitor);
   ReentrantMonitorAutoEnter mon(*sMonitor);
   SharedThreadPool* pool = nullptr;
@@ -158,21 +173,23 @@ NS_IMETHODIMP_(nsrefcnt) SharedThreadPoo
 NS_IMPL_QUERY_INTERFACE2(SharedThreadPool, nsIThreadPool, nsIEventTarget)
 
 SharedThreadPool::SharedThreadPool(const nsCString& aName,
                                    nsIThreadPool* aPool)
   : mName(aName)
   , mPool(aPool)
   , mRefCnt(0)
 {
+  MOZ_COUNT_CTOR(SharedThreadPool);
   mEventTarget = do_QueryInterface(aPool);
 }
 
 SharedThreadPool::~SharedThreadPool()
 {
+  MOZ_COUNT_DTOR(SharedThreadPool);
 }
 
 #ifdef XP_WIN
 
 // Thread pool listener which ensures that MSCOM is initialized and
 // deinitialized on the thread pool thread. We may call into WMF or
 // DirectShow on this thread, so we need MSCOM working.
 class MSCOMInitThreadPoolListener MOZ_FINAL : public nsIThreadPoolListener {
--- a/content/media/SharedThreadPool.h
+++ b/content/media/SharedThreadPool.h
@@ -30,16 +30,20 @@ class SharedThreadPool : public nsIThrea
 public:
 
   // Gets (possibly creating) the shared thread pool singleton instance with
   // thread pool named aName.
   // *Must* be called on the main thread.
   static TemporaryRef<SharedThreadPool> Get(const nsCString& aName,
                                             uint32_t aThreadLimit = 4);
 
+  // Spins the event loop until all thread pools are shutdown.
+  // *Must* be called on the main thread.
+  static void SpinUntilShutdown();
+
   // We implement custom threadsafe AddRef/Release pair, that destroys the
   // the shared pool singleton when the refcount drops to 0. The addref/release
   // are implemented using locking, so it's not recommended that you use them
   // in a tight loop.
   NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr);
   NS_IMETHOD_(nsrefcnt) AddRef(void);
   NS_IMETHOD_(nsrefcnt) Release(void);