Bug 1218799: Shutdown MediaManager engines from the MediaManager thread r=jib, a=ritu
authorRandell Jesup <rjesup@jesup.org>
Wed, 18 Nov 2015 15:03:13 -0500
changeset 305784 5d4452aacaeda4b7c0cacbc04ceb07e9f64bf2ba
parent 305783 336e17c0801d42786ec7a409afd8b07f5f8d1a5e
child 305785 edf64a97e4ea3ddf53484f1363b6a2e041cc5a48
push id1001
push userraliiev@mozilla.com
push dateMon, 18 Jan 2016 19:06:03 +0000
treeherdermozilla-release@8b89261f3ac4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjib, ritu
bugs1218799
milestone44.0a2
Bug 1218799: Shutdown MediaManager engines from the MediaManager thread r=jib, a=ritu
dom/media/MediaManager.cpp
dom/media/MediaManager.h
--- a/dom/media/MediaManager.cpp
+++ b/dom/media/MediaManager.cpp
@@ -1495,17 +1495,16 @@ MediaManager::EnumerateRawDevices(uint64
       return NS_OK;
           })));
   }));
   return p.forget();
 }
 
 MediaManager::MediaManager()
   : mMediaThread(nullptr)
-  , mMutex("mozilla::MediaManager")
   , mBackend(nullptr) {
   mPrefs.mFreq   = 1000; // 1KHz test tone
   mPrefs.mWidth  = 0; // adaptive default
   mPrefs.mHeight = 0; // adaptive default
   mPrefs.mFPS    = MediaEngine::DEFAULT_VIDEO_FPS;
   mPrefs.mMinFPS = MediaEngine::DEFAULT_VIDEO_MIN_FPS;
   nsresult rv;
   nsCOMPtr<nsIPrefService> prefs = do_GetService("@mozilla.org/preferences-service;1", &rv);
@@ -2402,20 +2401,20 @@ MediaManager::GetUserMediaDevices(nsPIDO
     }
   }
   return NS_ERROR_UNEXPECTED;
 }
 
 MediaEngine*
 MediaManager::GetBackend(uint64_t aWindowId)
 {
+  MOZ_ASSERT(MediaManager::IsInMediaThread());
   // Plugin backends as appropriate. The default engine also currently
   // includes picture support for Android.
   // This IS called off main-thread.
-  MutexAutoLock lock(mMutex);
   if (!mBackend) {
     MOZ_RELEASE_ASSERT(!sInShutdown);  // we should never create a new backend in shutdown
 #if defined(MOZ_WEBRTC)
     mBackend = new MediaEngineWebRTC(mPrefs);
 #else
     mBackend = new MediaEngineDefault();
 #endif
   }
@@ -2602,69 +2601,63 @@ MediaManager::Shutdown()
     prefs->RemoveObserver("media.navigator.video.default_minfps", this);
     prefs->RemoveObserver("media.navigator.audio.fake_frequency", this);
   }
 
   // Close off any remaining active windows.
   GetActiveWindows()->Clear();
   mActiveCallbacks.Clear();
   mCallIds.Clear();
-  {
-    MutexAutoLock lock(mMutex);
-    if (mBackend) {
-      mBackend->Shutdown(); // ok to invoke multiple times
-    }
-  }
 
   // Because mMediaThread is not an nsThread, we must dispatch to it so it can
   // clean up BackgroundChild. Continue stopping thread once this is done.
 
   class ShutdownTask : public Task
   {
   public:
-    ShutdownTask(already_AddRefed<MediaEngine> aBackend,
+    ShutdownTask(MediaManager* aManager,
                  nsRunnable* aReply)
-      : mReply(aReply)
-      , mBackend(aBackend) {}
+      : mManager(aManager)
+      , mReply(aReply) {}
   private:
     virtual void
     Run()
     {
       LOG(("MediaManager Thread Shutdown"));
       MOZ_ASSERT(MediaManager::IsInMediaThread());
+      // Must shutdown backend on MediaManager thread, since that's where we started it from!
+      {
+        if (mManager->mBackend) {
+          mManager->mBackend->Shutdown(); // ok to invoke multiple times
+        }
+      }
       mozilla::ipc::BackgroundChild::CloseForCurrentThread();
       // must explicitly do this before dispatching the reply, since the reply may kill us with Stop()
-      mBackend = nullptr; // last reference, will invoke Shutdown() again
+      mManager->mBackend = nullptr; // last reference, will invoke Shutdown() again
 
       if (NS_FAILED(NS_DispatchToMainThread(mReply.forget()))) {
         LOG(("Will leak thread: DispatchToMainthread of reply runnable failed in MediaManager shutdown"));
       }
     }
+    RefPtr<MediaManager> mManager;
     RefPtr<nsRunnable> mReply;
-    RefPtr<MediaEngine> mBackend;
   };
 
   // Post ShutdownTask to execute on mMediaThread and pass in a lambda
   // callback to be executed back on this thread once it is done.
   //
   // The lambda callback "captures" the 'this' pointer for member access.
   // This is safe since this is guaranteed to be here since sSingleton isn't
   // cleared until the lambda function clears it.
 
   // note that this == sSingleton
   RefPtr<MediaManager> that(sSingleton);
   // Release the backend (and call Shutdown()) from within the MediaManager thread
-  RefPtr<MediaEngine> temp;
-  {
-    MutexAutoLock lock(mMutex);
-    temp = mBackend.forget();
-  }
   // Don't use MediaManager::PostTask() because we're sInShutdown=true here!
-  mMediaThread->message_loop()->PostTask(FROM_HERE, new ShutdownTask(
-      temp.forget(),
+  mMediaThread->message_loop()->PostTask(FROM_HERE, new ShutdownTask(this,
       media::NewRunnableFrom([this, that]() mutable {
     LOG(("MediaManager shutdown lambda running, releasing MediaManager singleton and thread"));
     if (mMediaThread) {
       mMediaThread->Stop();
     }
 
     // Remove async shutdown blocker
 
--- a/dom/media/MediaManager.h
+++ b/dom/media/MediaManager.h
@@ -528,18 +528,17 @@ private:
   WindowTable mActiveWindows;
   nsClassHashtable<nsStringHashKey, GetUserMediaTask> mActiveCallbacks;
   nsClassHashtable<nsUint64HashKey, nsTArray<nsString>> mCallIds;
 
   // Always exists
   nsAutoPtr<base::Thread> mMediaThread;
   nsCOMPtr<nsIAsyncShutdownBlocker> mShutdownBlocker;
 
-  Mutex mMutex;
-  // protected with mMutex:
+  // ONLY accessed from MediaManagerThread
   RefPtr<MediaEngine> mBackend;
 
   static StaticRefPtr<MediaManager> sSingleton;
 
   media::CoatCheck<PledgeSourceSet> mOutstandingPledges;
   media::CoatCheck<PledgeChar> mOutstandingCharPledges;
   media::CoatCheck<GetUserMediaCallbackMediaStreamListener::PledgeVoid> mOutstandingVoidPledges;
 #if defined(MOZ_B2G_CAMERA) && defined(MOZ_WIDGET_GONK)