Bug 1384336 - Stop using OS-level event loop in content process (r=mstange)
authorBill McCloskey <billm@mozilla.com>
Fri, 21 Jul 2017 16:16:59 -0700
changeset 373957 01fd73e4b8b89080505bf9f004c82c3e1043f40e
parent 373956 4786ec6700d05b64bb7b2d47290e53b64a7ba2c1
child 373958 28226c771f1114d0fc219be3fa7c0e1413067e32
push id32311
push userkwierso@gmail.com
push dateFri, 11 Aug 2017 01:14:57 +0000
treeherdermozilla-central@253a8560dc34 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmstange
bugs1384336
milestone57.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 1384336 - Stop using OS-level event loop in content process (r=mstange) MozReview-Commit-ID: 1ouSlgGchWl
dom/ipc/ContentChild.cpp
dom/ipc/ContentPrefs.cpp
modules/libpref/init/all.js
toolkit/xre/nsAppRunner.cpp
toolkit/xre/nsEmbedFunctions.cpp
widget/cocoa/nsAppShell.mm
widget/nsBaseAppShell.cpp
xpcom/build/nsXULAppAPI.h
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -1447,24 +1447,38 @@ GetDirectoryPath(const char *aPath) {
   nsAutoCString directoryPath;
   if (NS_FAILED(directoryFile->GetNativePath(directoryPath))) {
     MOZ_CRASH("Failed to get path for an nsIFile");
   }
   return directoryPath;
 }
 #endif // DEBUG
 
+extern "C" {
+void CGSSetDenyWindowServerConnections(bool);
+void CGSShutdownServerConnections();
+};
+
 static bool
 StartMacOSContentSandbox()
 {
   int sandboxLevel = GetEffectiveContentSandboxLevel();
   if (sandboxLevel < 1) {
     return false;
   }
 
+  if (!XRE_UseNativeEventProcessing()) {
+    // If we've opened a connection to the window server, shut it down now. Forbid
+    // future connections as well. We do this for sandboxing, but it also ensures
+    // that the Activity Monitor will not label the content process as "Not
+    // responding" because it's not running a native event loop. See bug 1384336.
+    CGSSetDenyWindowServerConnections(true);
+    CGSShutdownServerConnections();
+  }
+
   nsAutoCString appPath, appBinaryPath, appDir;
   if (!GetAppPaths(appPath, appBinaryPath, appDir)) {
     MOZ_CRASH("Error resolving child process path");
   }
 
   // During sandboxed content process startup, before reaching
   // this point, NS_OS_TEMP_DIR is modified to refer to a sandbox-
   // writable temporary directory
--- a/dom/ipc/ContentPrefs.cpp
+++ b/dom/ipc/ContentPrefs.cpp
@@ -47,16 +47,17 @@ const char* mozilla::dom::ContentPrefs::
   "dom.enable_frame_timing",
   "dom.enable_performance",
   "dom.enable_resource_timing",
   "dom.event.handling-user-input-time-limit",
   "dom.event.touch.coalescing.enabled",
   "dom.forms.autocomplete.formautofill",
   "dom.ipc.processPriorityManager.backgroundGracePeriodMS",
   "dom.ipc.processPriorityManager.backgroundPerceivableGracePeriodMS",
+  "dom.ipc.useNativeEventProcessing.content",
   "dom.max_chrome_script_run_time",
   "dom.max_script_run_time",
   "dom.mozBrowserFramesEnabled",
   "dom.performance.enable_notify_performance_timing",
   "dom.performance.enable_user_timing_logging",
   "dom.storage.testing",
   "dom.url.encode_decode_hash",
   "dom.url.getters_decode_hash",
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -3234,16 +3234,19 @@ pref("dom.ipc.processCount", 4);
 #endif
 
 // Default to allow only one file:// URL content process.
 pref("dom.ipc.processCount.file", 1);
 
 // WebExtensions only support a single extension process.
 pref("dom.ipc.processCount.extension", 1);
 
+// Don't use a native event loop in the content process.
+pref("dom.ipc.useNativeEventProcessing.content", false);
+
 // Disable support for SVG
 pref("svg.disabled", false);
 
 // Override default dom.ipc.processCount for some remote content process types.
 pref("dom.ipc.processCount.webLargeAllocation", 10);
 
 // Enable the Large-Allocation header
 pref("dom.largeAllocationHeader.enabled", true);
--- a/toolkit/xre/nsAppRunner.cpp
+++ b/toolkit/xre/nsAppRunner.cpp
@@ -5007,16 +5007,34 @@ XRE_IsE10sParentProcess()
 }
 
 bool
 XRE_IsContentProcess()
 {
   return XRE_GetProcessType() == GeckoProcessType_Content;
 }
 
+bool
+XRE_UseNativeEventProcessing()
+{
+  if (XRE_IsContentProcess()) {
+    static bool sInited = false;
+    static bool sUseNativeEventProcessing = false;
+    if (!sInited) {
+      Preferences::AddBoolVarCache(&sUseNativeEventProcessing,
+                                   "dom.ipc.useNativeEventProcessing.content");
+      sInited = true;
+    }
+
+    return sUseNativeEventProcessing;
+  }
+
+  return true;
+}
+
 // If you add anything to this enum, please update about:support to reflect it
 enum {
   kE10sEnabledByUser = 0,
   kE10sEnabledByDefault = 1,
   kE10sDisabledByUser = 2,
   // kE10sDisabledInSafeMode = 3, was removed in bug 1172491.
   kE10sDisabledForAccessibility = 4,
   // kE10sDisabledForMacGfx = 5, was removed in bug 1068674.
--- a/toolkit/xre/nsEmbedFunctions.cpp
+++ b/toolkit/xre/nsEmbedFunctions.cpp
@@ -834,17 +834,17 @@ XRE_RunIPDLTest(int aArgc, char** aArgv)
 #endif  // ifdef MOZ_IPDL_TESTS
 
 nsresult
 XRE_RunAppShell()
 {
     nsCOMPtr<nsIAppShell> appShell(do_GetService(kAppShellCID));
     NS_ENSURE_TRUE(appShell, NS_ERROR_FAILURE);
 #if defined(XP_MACOSX)
-    {
+    if (XRE_UseNativeEventProcessing()) {
       // In content processes that want XPCOM (and hence want
       // AppShell), we usually run our hybrid event loop through
       // MessagePump::Run(), by way of nsBaseAppShell::Run().  The
       // Cocoa nsAppShell impl, however, implements its own Run()
       // that's unaware of MessagePump.  That's all rather suboptimal,
       // but oddly enough not a problem... usually.
       //
       // The problem with this setup comes during startup.
--- a/widget/cocoa/nsAppShell.mm
+++ b/widget/cocoa/nsAppShell.mm
@@ -677,23 +677,29 @@ nsAppShell::Run(void)
     return NS_OK;
 
   mStarted = true;
 
   if (XRE_IsParentProcess()) {
     AddScreenWakeLockListener();
   }
 
-  NS_OBJC_TRY_ABORT([NSApp run]);
+  // We use the native Gecko event loop in content processes.
+  nsresult rv = NS_OK;
+  if (XRE_UseNativeEventProcessing()) {
+    NS_OBJC_TRY_ABORT([NSApp run]);
+  } else {
+    rv = nsBaseAppShell::Run();
+  }
 
   if (XRE_IsParentProcess()) {
     RemoveScreenWakeLockListener();
   }
 
-  return NS_OK;
+  return rv;
 }
 
 NS_IMETHODIMP
 nsAppShell::Exit(void)
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
 
   // This method is currently called more than once -- from (according to
--- a/widget/nsBaseAppShell.cpp
+++ b/widget/nsBaseAppShell.cpp
@@ -41,21 +41,23 @@ nsBaseAppShell::~nsBaseAppShell()
 {
 }
 
 nsresult
 nsBaseAppShell::Init()
 {
   // Configure ourselves as an observer for the current thread:
 
-  nsCOMPtr<nsIThreadInternal> threadInt =
+  if (XRE_UseNativeEventProcessing()) {
+    nsCOMPtr<nsIThreadInternal> threadInt =
       do_QueryInterface(NS_GetCurrentThread());
-  NS_ENSURE_STATE(threadInt);
+    NS_ENSURE_STATE(threadInt);
 
-  threadInt->SetObserver(this);
+    threadInt->SetObserver(this);
+  }
 
   nsCOMPtr<nsIObserverService> obsSvc =
     mozilla::services::GetObserverService();
   if (obsSvc)
     obsSvc->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
   return NS_OK;
 }
 
--- a/xpcom/build/nsXULAppAPI.h
+++ b/xpcom/build/nsXULAppAPI.h
@@ -457,16 +457,23 @@ XRE_API(bool,
         XRE_IsParentProcess, ())
 
 XRE_API(bool,
         XRE_IsContentProcess, ())
 
 XRE_API(bool,
         XRE_IsGPUProcess, ())
 
+/**
+ * Returns true if the appshell should run its own native event loop. Returns
+ * false if we should rely solely on the Gecko event loop.
+ */
+XRE_API(bool,
+        XRE_UseNativeEventProcessing, ())
+
 typedef void (*MainFunction)(void* aData);
 
 XRE_API(nsresult,
         XRE_InitParentProcess, (int aArgc,
                                 char* aArgv[],
                                 MainFunction aMainFunction,
                                 void* aMainFunctionExtraData))