Bug 1164543 - Make plugin shutdown async in e10s (r=jimm)
authorBill McCloskey <billm@mozilla.com>
Wed, 17 Jun 2015 15:38:07 -0700
changeset 280631 7b4f3625e343a6b35ef7b27958e941cccd504345
parent 280630 a8d3d3fb49a7bdcb1afb636631d3b7a558a675a1
child 280632 f8f4a6c0654967a5514f78e47480356bd642ec8b
push id4932
push userjlund@mozilla.com
push dateMon, 10 Aug 2015 18:23:06 +0000
treeherdermozilla-beta@6dd5a4f5f745 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjimm
bugs1164543
milestone41.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1164543 - Make plugin shutdown async in e10s (r=jimm)
dom/plugins/ipc/PluginModuleChild.cpp
dom/plugins/ipc/PluginModuleChild.h
dom/plugins/ipc/PluginModuleParent.cpp
--- a/dom/plugins/ipc/PluginModuleChild.cpp
+++ b/dom/plugins/ipc/PluginModuleChild.cpp
@@ -121,16 +121,17 @@ PluginModuleChild::CreateForContentProce
     return child;
 }
 
 PluginModuleChild::PluginModuleChild(bool aIsChrome)
   : mLibrary(0)
   , mPluginFilename("")
   , mQuirks(QUIRKS_NOT_INITIALIZED)
   , mIsChrome(aIsChrome)
+  , mHasShutdown(false)
   , mTransport(nullptr)
   , mShutdownFunc(0)
   , mInitializeFunc(0)
 #if defined(OS_WIN) || defined(OS_MACOSX)
   , mGetEntryPointsFunc(0)
 #elif defined(MOZ_WIDGET_GTK)
   , mNestedLoopTimerId(0)
 #elif defined(MOZ_WIDGET_QT)
@@ -676,40 +677,53 @@ PluginModuleChild::DeinitGraphics()
 #if defined(MOZ_X11) && defined(NS_FREE_PERMANENT_DATA)
     // We free some data off of XDisplay close hooks, ensure they're
     // run.  Closing the display is pretty scary, so we only do it to
     // silence leak checkers.
     XCloseDisplay(DefaultXDisplay());
 #endif
 }
 
-bool
-PluginModuleChild::AnswerNP_Shutdown(NPError *rv)
+NPError
+PluginModuleChild::NP_Shutdown()
 {
     AssertPluginThread();
     MOZ_ASSERT(mIsChrome);
 
+    if (mHasShutdown) {
+        return NPERR_NO_ERROR;
+    }
+
 #if defined XP_WIN
     mozilla::widget::StopAudioSession();
 #endif
 
     // the PluginModuleParent shuts down this process after this interrupt
     // call pops off its stack
 
-    *rv = mShutdownFunc ? mShutdownFunc() : NPERR_NO_ERROR;
+    NPError rv = mShutdownFunc ? mShutdownFunc() : NPERR_NO_ERROR;
 
     // weakly guard against re-entry after NP_Shutdown
     memset(&mFunctions, 0, sizeof(mFunctions));
 
 #ifdef OS_WIN
     ResetEventHooks();
 #endif
 
     GetIPCChannel()->SetAbortOnError(false);
 
+    mHasShutdown = true;
+
+    return rv;
+}
+
+bool
+PluginModuleChild::AnswerNP_Shutdown(NPError *rv)
+{
+    *rv = NP_Shutdown();
     return true;
 }
 
 bool
 PluginModuleChild::AnswerOptionalFunctionsSupported(bool *aURLRedirectNotify,
                                                     bool *aClearSiteData,
                                                     bool *aGetSitesWithData)
 {
@@ -821,16 +835,21 @@ PluginModuleChild::ActorDestroy(ActorDes
         return;
     }
 
     if (AbnormalShutdown == why) {
         NS_WARNING("shutting down early because of crash!");
         QuickExit();
     }
 
+    if (!mHasShutdown) {
+        MOZ_ASSERT(gChromeInstance == this);
+        NP_Shutdown();
+    }
+
     // doesn't matter why we're being destroyed; it's up to us to
     // initiate (clean) shutdown
     XRE_ShutdownChildProcess();
 }
 
 void
 PluginModuleChild::CleanUp()
 {
--- a/dom/plugins/ipc/PluginModuleChild.h
+++ b/dom/plugins/ipc/PluginModuleChild.h
@@ -172,16 +172,18 @@ public:
                         IPC::Channel* aChannel);
 
     static PluginModuleChild*
     CreateForContentProcess(mozilla::ipc::Transport* aTransport,
                             base::ProcessId aOtherProcess);
 
     void CleanUp();
 
+    NPError NP_Shutdown();
+
     const char* GetUserAgent();
 
     static const NPNetscapeFuncs sBrowserFuncs;
 
     static PluginModuleChild* GetChrome();
 
     /**
      * The child implementation of NPN_CreateObject.
@@ -322,16 +324,17 @@ private:
 #endif
 
     PRLibrary* mLibrary;
     nsCString mPluginFilename; // UTF8
     nsCString mUserAgent;
     int mQuirks;
 
     bool mIsChrome;
+    bool mHasShutdown; // true if NP_Shutdown has run
     Transport* mTransport;
 
     // we get this from the plugin
     NP_PLUGINSHUTDOWN mShutdownFunc;
 #if defined(OS_LINUX) || defined(OS_BSD)
     NP_PLUGINUNIXINIT mInitializeFunc;
 #elif defined(OS_WIN) || defined(OS_MACOSX)
     NP_PLUGININIT mInitializeFunc;
--- a/dom/plugins/ipc/PluginModuleParent.cpp
+++ b/dom/plugins/ipc/PluginModuleParent.cpp
@@ -2381,17 +2381,22 @@ PluginModuleParent::NP_Shutdown(NPError*
 
     return NS_OK;
 }
 
 bool
 PluginModuleParent::DoShutdown(NPError* error)
 {
     bool ok = true;
-    if (IsChrome()) {
+    if (IsChrome() && mHadLocalInstance) {
+        // We synchronously call NP_Shutdown if the chrome process was using
+        // plugins itself. That way we can service any requests the plugin
+        // makes. If we're in e10s, though, the content processes will have
+        // already shut down and there's no one to talk to. So we shut down
+        // asynchronously in PluginModuleChild::ActorDestroy.
         ok = CallNP_Shutdown(error);
     }
 
     // if NP_Shutdown() is nested within another interrupt call, this will
     // break things.  but lord help us if we're doing that anyway; the
     // plugin dso will have been unloaded on the other side by the
     // CallNP_Shutdown() message
     Close();