Backed out changeset 439a07e5ddca (bug 1218799) for causing memory leaks
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Wed, 25 Nov 2015 16:44:49 +0100
changeset 305650 d91dbc0c93149d4145239536cb96f4b049da9c62
parent 305649 91b7f25540f09d595c5638ea0f9e60bd810cad50
child 305651 1f88b627ee6a78de1536beaab4b1a7c04a992806
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)
bugs1218799
milestone44.0a2
backs out439a07e5ddca86ec32787db32707ac28772627ea
Backed out changeset 439a07e5ddca (bug 1218799) for causing memory leaks
dom/media/MediaManager.cpp
dom/media/MediaManager.h
--- a/dom/media/MediaManager.cpp
+++ b/dom/media/MediaManager.cpp
@@ -1478,16 +1478,17 @@ 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);
@@ -2390,20 +2391,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
   }
@@ -2590,63 +2591,69 @@ 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(MediaManager* aManager,
+    ShutdownTask(already_AddRefed<MediaEngine> aBackend,
                  nsRunnable* aReply)
-      : mManager(aManager)
-      , mReply(aReply) {}
+      : mReply(aReply)
+      , mBackend(aBackend) {}
   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()
-      mManager->mBackend = nullptr; // last reference, will invoke Shutdown() again
+      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(this,
+  mMediaThread->message_loop()->PostTask(FROM_HERE, new ShutdownTask(
+      temp.forget(),
       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,17 +528,18 @@ private:
   WindowTable mActiveWindows;
   nsClassHashtable<nsStringHashKey, GetUserMediaTask> mActiveCallbacks;
   nsClassHashtable<nsUint64HashKey, nsTArray<nsString>> mCallIds;
 
   // Always exists
   nsAutoPtr<base::Thread> mMediaThread;
   nsCOMPtr<nsIAsyncShutdownBlocker> mShutdownBlocker;
 
-  // ONLY accessed from MediaManagerThread
+  Mutex mMutex;
+  // protected with mMutex:
   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)