Bug 1035653 - Proxy GMPParent creation to main thread to avoid assert in IToplevelProtocol ctor. r=jesup
☠☠ backed out by 70f3b01cb736 ☠ ☠
authorChris Pearce <cpearce@mozilla.com>
Fri, 11 Jul 2014 12:21:33 +1200
changeset 193511 412b654e5cd2ad309055f2081b62ac9679478111
parent 193510 01ba0892af2942d53a2061f4d2d778deff3e04f6
child 193512 d988238c67d80db0e1f770399523b313a0eacef9
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewersjesup
bugs1035653
milestone33.0a1
Bug 1035653 - Proxy GMPParent creation to main thread to avoid assert in IToplevelProtocol ctor. r=jesup
content/media/gmp/GMPParent.h
content/media/gmp/GMPService.cpp
--- a/content/media/gmp/GMPParent.h
+++ b/content/media/gmp/GMPParent.h
@@ -11,16 +11,17 @@
 #include "GMPVideoEncoderParent.h"
 #include "mozilla/gmp/PGMPParent.h"
 #include "nsCOMPtr.h"
 #include "nscore.h"
 #include "nsISupports.h"
 #include "nsString.h"
 #include "nsTArray.h"
 #include "nsIFile.h"
+#include "ThreadSafeRefcountingWithMainThreadDestruction.h"
 
 class nsILineInputStream;
 class nsIThread;
 
 namespace mozilla {
 namespace gmp {
 
 class GMPCapability
@@ -33,17 +34,17 @@ public:
 enum GMPState {
   GMPStateNotLoaded,
   GMPStateLoaded
 };
 
 class GMPParent MOZ_FINAL : public PGMPParent
 {
 public:
-  NS_INLINE_DECL_REFCOUNTING(GMPParent)
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_MAIN_THREAD_DESTRUCTION(GMPParent)
 
   GMPParent();
 
   nsresult Init(nsIFile* aPluginDir);
   nsresult LoadProcess();
   void MaybeUnloadProcess();
   void UnloadProcess();
   bool SupportsAPI(const nsCString& aAPI, const nsCString& aTag);
--- a/content/media/gmp/GMPService.cpp
+++ b/content/media/gmp/GMPService.cpp
@@ -359,31 +359,51 @@ GeckoMediaPluginService::SelectPluginFor
         gmp->SetOrigin(aOrigin);
       }
       return gmp;
     }
   }
   return nullptr;
 }
 
+class CreateGMPParentTask : public nsRunnable {
+public:
+  NS_IMETHOD Run() {
+    MOZ_ASSERT(NS_IsMainThread());
+    mParent = new GMPParent();
+    return NS_OK;
+  }
+  already_AddRefed<GMPParent> GetParent() {
+    return mParent.forget();
+  }
+private:
+  nsRefPtr<GMPParent> mParent;
+};
 
 void
 GeckoMediaPluginService::AddOnGMPThread(const nsAString& aDirectory)
 {
   MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
 
   nsCOMPtr<nsIFile> directory;
   nsresult rv = NS_NewLocalFile(aDirectory, false, getter_AddRefs(directory));
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return;
   }
 
-  nsRefPtr<GMPParent> gmp = new GMPParent();
+  // The GMPParent inherits from IToplevelProtocol, which must be created
+  // on the main thread to be threadsafe. See Bug 1035653.
+  nsRefPtr<CreateGMPParentTask> task(new CreateGMPParentTask());
+  nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
+  MOZ_ASSERT(mainThread);
+  mozilla::SyncRunnable::DispatchToThread(mainThread, task);
+  nsRefPtr<GMPParent> gmp = task->GetParent();
   rv = gmp->Init(directory);
   if (NS_FAILED(rv)) {
+    NS_WARNING("Can't Create GMPParent");
     return;
   }
 
   mPlugins.AppendElement(gmp);
 }
 
 void
 GeckoMediaPluginService::RemoveOnGMPThread(const nsAString& aDirectory)