Title: [202723] trunk/Source
Revision
202723
Author
cdu...@apple.com
Date
2016-06-30 18:29:47 -0700 (Thu, 30 Jun 2016)

Log Message

[iOS] WebContent processes do not exit promptly
https://bugs.webkit.org/show_bug.cgi?id=159301
<rdar://problem/26965488>

Reviewed by Anders Carlsson.

WebContent processes do not exit promptly, they hang around for 10 seconds
until the watchdog forcefully calls exit().

This patch addresses the issue by asking XPC to exit when clean. It also
fixes 2 XPC transactions that were leaking so that XPC can become clean.

* DatabaseProcess/EntryPoint/mac/XPCService/DatabaseServiceEntryPoint.mm:
(DatabaseServiceInitializer):
* NetworkProcess/EntryPoint/mac/XPCService/NetworkServiceEntryPoint.mm:
(NetworkServiceInitializer):
* PluginProcess/EntryPoint/mac/XPCService/PluginServiceEntryPoint.mm:
(PluginServiceInitializer):
* WebProcess/EntryPoint/mac/XPCService/WebContentServiceEntryPoint.mm:
(WebContentServiceInitializer):
Add extra priorityBoostMessage parameter which is then passed along to
ChildProcess via initialization parameters. ChildProcess is now in
charge of retaining the message for as long as it needs the priority
boost. In particular, ChildProcess now takes care of releasing the
boost message before existing to avoid leaking an XPC transaction.

* Shared/ChildProcess.cpp:
(WebKit::ChildProcess::initialize):
Retain priorityBoostMessage as a data member.

(WebKit::ChildProcess::stopRunLoop):
(WebKit::ChildProcess::platformStopRunLoop):
* Shared/ios/ChildProcessIOS.mm:
(WebKit::ChildProcess::platformStopRunLoop):
On iOS, call XPCServiceExit() to exit instead of RunLoop::main().stop()
which did not work.

* Shared/ChildProcess.h:
* Shared/EntryPointUtilities/mac/XPCService/XPCServiceEntryPoint.h:
(WebKit::XPCServiceInitializer):
Set priorityBoostMessage on ChildProcessInitializationParameters.

* Shared/EntryPointUtilities/mac/XPCService/XPCServiceEntryPoint.mm:
(WebKit::XPCServiceExit):
Add XPCServiceExit() function which destroys the priority boost
message, calls xpc_transaction_end() to balance the
xpc_transaction_begin() in XPCServiceInitializer() and then call
xpc_transaction_exit_clean() to ask XPC to exit when clean.

* Shared/EntryPointUtilities/mac/XPCService/XPCServiceMain.mm:
(WebKit::XPCServiceEventHandler):
Leaking the "pre-bootstrap" event for priority boosting would cause us to
leak an XPC transaction, which would prevent XPC from becoming clean and
exiting. Instead, we now pass it along to the initialization function.
We then pass it to ChildProcess which manages the lifetime of this message
instead of leaking it.

Modified Paths

Diff

Modified: trunk/Source/WTF/wtf/spi/darwin/XPCSPI.h (202722 => 202723)


--- trunk/Source/WTF/wtf/spi/darwin/XPCSPI.h	2016-07-01 00:13:49 UTC (rev 202722)
+++ trunk/Source/WTF/wtf/spi/darwin/XPCSPI.h	2016-07-01 01:29:47 UTC (rev 202723)
@@ -123,6 +123,8 @@
 EXTERN_C void xpc_main(xpc_connection_handler_t);
 EXTERN_C const char* xpc_string_get_string_ptr(xpc_object_t);
 EXTERN_C void xpc_transaction_begin(void);
+EXTERN_C void xpc_transaction_end(void);
+EXTERN_C void xpc_transaction_exit_clean(void);
 EXTERN_C void xpc_track_activity(void);
 
 EXTERN_C xpc_object_t xpc_connection_copy_entitlement_value(xpc_connection_t, const char* entitlement);

Modified: trunk/Source/WebKit2/ChangeLog (202722 => 202723)


--- trunk/Source/WebKit2/ChangeLog	2016-07-01 00:13:49 UTC (rev 202722)
+++ trunk/Source/WebKit2/ChangeLog	2016-07-01 01:29:47 UTC (rev 202723)
@@ -1,3 +1,62 @@
+2016-06-30  Chris Dumez  <cdu...@apple.com>
+
+        [iOS] WebContent processes do not exit promptly
+        https://bugs.webkit.org/show_bug.cgi?id=159301
+        <rdar://problem/26965488>
+
+        Reviewed by Anders Carlsson.
+
+        WebContent processes do not exit promptly, they hang around for 10 seconds
+        until the watchdog forcefully calls exit().
+
+        This patch addresses the issue by asking XPC to exit when clean. It also
+        fixes 2 XPC transactions that were leaking so that XPC can become clean.
+
+        * DatabaseProcess/EntryPoint/mac/XPCService/DatabaseServiceEntryPoint.mm:
+        (DatabaseServiceInitializer):
+        * NetworkProcess/EntryPoint/mac/XPCService/NetworkServiceEntryPoint.mm:
+        (NetworkServiceInitializer):
+        * PluginProcess/EntryPoint/mac/XPCService/PluginServiceEntryPoint.mm:
+        (PluginServiceInitializer):
+        * WebProcess/EntryPoint/mac/XPCService/WebContentServiceEntryPoint.mm:
+        (WebContentServiceInitializer):
+        Add extra priorityBoostMessage parameter which is then passed along to
+        ChildProcess via initialization parameters. ChildProcess is now in
+        charge of retaining the message for as long as it needs the priority
+        boost. In particular, ChildProcess now takes care of releasing the
+        boost message before existing to avoid leaking an XPC transaction.
+
+        * Shared/ChildProcess.cpp:
+        (WebKit::ChildProcess::initialize):
+        Retain priorityBoostMessage as a data member.
+
+        (WebKit::ChildProcess::stopRunLoop):
+        (WebKit::ChildProcess::platformStopRunLoop):
+        * Shared/ios/ChildProcessIOS.mm:
+        (WebKit::ChildProcess::platformStopRunLoop):
+        On iOS, call XPCServiceExit() to exit instead of RunLoop::main().stop()
+        which did not work.
+
+        * Shared/ChildProcess.h:
+        * Shared/EntryPointUtilities/mac/XPCService/XPCServiceEntryPoint.h:
+        (WebKit::XPCServiceInitializer):
+        Set priorityBoostMessage on ChildProcessInitializationParameters.
+
+        * Shared/EntryPointUtilities/mac/XPCService/XPCServiceEntryPoint.mm:
+        (WebKit::XPCServiceExit):
+        Add XPCServiceExit() function which destroys the priority boost
+        message, calls xpc_transaction_end() to balance the
+        xpc_transaction_begin() in XPCServiceInitializer() and then call
+        xpc_transaction_exit_clean() to ask XPC to exit when clean.
+
+        * Shared/EntryPointUtilities/mac/XPCService/XPCServiceMain.mm:
+        (WebKit::XPCServiceEventHandler):
+        Leaking the "pre-bootstrap" event for priority boosting would cause us to
+        leak an XPC transaction, which would prevent XPC from becoming clean and
+        exiting. Instead, we now pass it along to the initialization function.
+        We then pass it to ChildProcess which manages the lifetime of this message
+        instead of leaking it.
+
 2016-06-30  Brian Burg  <bb...@apple.com>
 
         REGRESSION(r202329): WebInspectorProxy's WKPagePolicyClient callbacks are not being called

Modified: trunk/Source/WebKit2/DatabaseProcess/EntryPoint/mac/XPCService/DatabaseServiceEntryPoint.mm (202722 => 202723)


--- trunk/Source/WebKit2/DatabaseProcess/EntryPoint/mac/XPCService/DatabaseServiceEntryPoint.mm	2016-07-01 00:13:49 UTC (rev 202722)
+++ trunk/Source/WebKit2/DatabaseProcess/EntryPoint/mac/XPCService/DatabaseServiceEntryPoint.mm	2016-07-01 01:29:47 UTC (rev 202723)
@@ -36,9 +36,9 @@
 
 using namespace WebKit;
 
-extern "C" WK_EXPORT void DatabaseServiceInitializer(xpc_connection_t connection, xpc_object_t initializerMessage);
+extern "C" WK_EXPORT void DatabaseServiceInitializer(xpc_connection_t connection, xpc_object_t initializerMessage, xpc_object_t priorityBoostMessage);
 
-void DatabaseServiceInitializer(xpc_connection_t connection, xpc_object_t initializerMessage)
+void DatabaseServiceInitializer(xpc_connection_t connection, xpc_object_t initializerMessage, xpc_object_t priorityBoostMessage)
 {
 #if HAVE(OS_ACTIVITY)
 #pragma clang diagnostic push
@@ -47,7 +47,7 @@
 #pragma clang diagnostic pop
 #endif
 
-    XPCServiceInitializer<DatabaseProcess, XPCServiceInitializerDelegate>(adoptOSObject(connection), initializerMessage);
+    XPCServiceInitializer<DatabaseProcess, XPCServiceInitializerDelegate>(adoptOSObject(connection), initializerMessage, priorityBoostMessage);
 
 #if HAVE(OS_ACTIVITY)
 #pragma clang diagnostic push

Modified: trunk/Source/WebKit2/NetworkProcess/EntryPoint/mac/XPCService/NetworkServiceEntryPoint.mm (202722 => 202723)


--- trunk/Source/WebKit2/NetworkProcess/EntryPoint/mac/XPCService/NetworkServiceEntryPoint.mm	2016-07-01 00:13:49 UTC (rev 202722)
+++ trunk/Source/WebKit2/NetworkProcess/EntryPoint/mac/XPCService/NetworkServiceEntryPoint.mm	2016-07-01 01:29:47 UTC (rev 202723)
@@ -48,9 +48,9 @@
 
 using namespace WebKit;
 
-extern "C" WK_EXPORT void NetworkServiceInitializer(xpc_connection_t connection, xpc_object_t initializerMessage);
+extern "C" WK_EXPORT void NetworkServiceInitializer(xpc_connection_t connection, xpc_object_t initializerMessage, xpc_object_t priorityBoostMessage);
 
-void NetworkServiceInitializer(xpc_connection_t connection, xpc_object_t initializerMessage)
+void NetworkServiceInitializer(xpc_connection_t connection, xpc_object_t initializerMessage, xpc_object_t priorityBoostMessage)
 {
     // Remove the SecItemShim from the DYLD_INSERT_LIBRARIES environment variable so any processes spawned by
     // the this process don't try to insert the shim and crash.
@@ -63,7 +63,7 @@
 #pragma clang diagnostic pop
 #endif
 
-    XPCServiceInitializer<NetworkProcess, NetworkServiceInitializerDelegate>(adoptOSObject(connection), initializerMessage);
+    XPCServiceInitializer<NetworkProcess, NetworkServiceInitializerDelegate>(adoptOSObject(connection), initializerMessage, priorityBoostMessage);
 
 #if HAVE(OS_ACTIVITY)
 #pragma clang diagnostic push

Modified: trunk/Source/WebKit2/PluginProcess/EntryPoint/mac/XPCService/PluginServiceEntryPoint.mm (202722 => 202723)


--- trunk/Source/WebKit2/PluginProcess/EntryPoint/mac/XPCService/PluginServiceEntryPoint.mm	2016-07-01 00:13:49 UTC (rev 202722)
+++ trunk/Source/WebKit2/PluginProcess/EntryPoint/mac/XPCService/PluginServiceEntryPoint.mm	2016-07-01 01:29:47 UTC (rev 202723)
@@ -69,9 +69,9 @@
 
 #endif // ENABLE(NETSCAPE_PLUGIN_API)
 
-extern "C" WK_EXPORT void PluginServiceInitializer(xpc_connection_t connection, xpc_object_t initializerMessage);
+extern "C" WK_EXPORT void PluginServiceInitializer(xpc_connection_t connection, xpc_object_t initializerMessage, xpc_object_t priorityBoostMessage);
 
-void PluginServiceInitializer(xpc_connection_t connection, xpc_object_t initializerMessage)
+void PluginServiceInitializer(xpc_connection_t connection, xpc_object_t initializerMessage, xpc_object_t priorityBoostMessage)
 {
 #if ENABLE(NETSCAPE_PLUGIN_API)
     // FIXME: Add support for teardown from PluginProcessMain.mm
@@ -87,7 +87,7 @@
 #pragma clang diagnostic pop
 #endif
 
-    XPCServiceInitializer<PluginProcess, PluginServiceInitializerDelegate>(adoptOSObject(connection), initializerMessage);
+    XPCServiceInitializer<PluginProcess, PluginServiceInitializerDelegate>(adoptOSObject(connection), initializerMessage, priorityBoostMessage);
 
 #if HAVE(OS_ACTIVITY)
 #pragma clang diagnostic push

Modified: trunk/Source/WebKit2/Shared/ChildProcess.cpp (202722 => 202723)


--- trunk/Source/WebKit2/Shared/ChildProcess.cpp	2016-07-01 00:13:49 UTC (rev 202722)
+++ trunk/Source/WebKit2/Shared/ChildProcess.cpp	2016-07-01 01:29:47 UTC (rev 202723)
@@ -64,6 +64,10 @@
 {
     platformInitialize();
 
+#if PLATFORM(COCOA)
+    m_priorityBoostMessage = parameters.priorityBoostMessage;
+#endif
+
     initializeProcess(parameters);
     initializeProcessName(parameters);
 
@@ -158,8 +162,15 @@
 
 void ChildProcess::stopRunLoop()
 {
+    platformStopRunLoop();
+}
+
+#if !PLATFORM(IOS)
+void ChildProcess::platformStopRunLoop()
+{
     RunLoop::main().stop();
 }
+#endif
 
 void ChildProcess::terminate()
 {

Modified: trunk/Source/WebKit2/Shared/ChildProcess.h (202722 => 202723)


--- trunk/Source/WebKit2/Shared/ChildProcess.h	2016-07-01 00:13:49 UTC (rev 202722)
+++ trunk/Source/WebKit2/Shared/ChildProcess.h	2016-07-01 01:29:47 UTC (rev 202723)
@@ -45,6 +45,9 @@
     String clientIdentifier;
     IPC::Connection::Identifier connectionIdentifier;
     HashMap<String, String> extraInitializationData;
+#if PLATFORM(COCOA)
+    OSObjectPtr<xpc_object_t> priorityBoostMessage;
+#endif
 };
 
 class ChildProcess : protected IPC::Connection::Client, public IPC::MessageSender {
@@ -110,6 +113,7 @@
     void terminationTimerFired();
 
     void platformInitialize();
+    void platformStopRunLoop();
 
     // The timeout, in seconds, before this process will be terminated if termination
     // has been enabled. If the timeout is 0 seconds, the process will be terminated immediately.
@@ -125,6 +129,10 @@
     IPC::MessageReceiverMap m_messageReceiverMap;
 
     UserActivity m_processSuppressionDisabled;
+
+#if PLATFORM(COCOA)
+    OSObjectPtr<xpc_object_t> m_priorityBoostMessage;
+#endif
 };
 
 } // namespace WebKit

Modified: trunk/Source/WebKit2/Shared/EntryPointUtilities/mac/XPCService/XPCServiceEntryPoint.h (202722 => 202723)


--- trunk/Source/WebKit2/Shared/EntryPointUtilities/mac/XPCService/XPCServiceEntryPoint.h	2016-07-01 00:13:49 UTC (rev 202722)
+++ trunk/Source/WebKit2/Shared/EntryPointUtilities/mac/XPCService/XPCServiceEntryPoint.h	2016-07-01 01:29:47 UTC (rev 202723)
@@ -67,7 +67,7 @@
 };
 
 template<typename XPCServiceType, typename XPCServiceInitializerDelegateType>
-void XPCServiceInitializer(OSObjectPtr<xpc_connection_t> connection, xpc_object_t initializerMessage)
+void XPCServiceInitializer(OSObjectPtr<xpc_connection_t> connection, xpc_object_t initializerMessage, xpc_object_t priorityBoostMessage)
 {
     XPCServiceInitializerDelegateType delegate(WTFMove(connection), initializerMessage);
 
@@ -81,6 +81,9 @@
         exit(EXIT_FAILURE);
 
     ChildProcessInitializationParameters parameters;
+    if (priorityBoostMessage)
+        parameters.priorityBoostMessage = adoptOSObject(xpc_retain(priorityBoostMessage));
+
     if (!delegate.getConnectionIdentifier(parameters.connectionIdentifier))
         exit(EXIT_FAILURE);
 
@@ -101,6 +104,8 @@
     XPCServiceType::singleton().initialize(parameters);
 }
 
+void XPCServiceExit(OSObjectPtr<xpc_object_t>&& priorityBoostMessage);
+
 } // namespace WebKit
 
 #endif // XPCServiceEntryPoint_h

Modified: trunk/Source/WebKit2/Shared/EntryPointUtilities/mac/XPCService/XPCServiceEntryPoint.mm (202722 => 202723)


--- trunk/Source/WebKit2/Shared/EntryPointUtilities/mac/XPCService/XPCServiceEntryPoint.mm	2016-07-01 00:13:49 UTC (rev 202722)
+++ trunk/Source/WebKit2/Shared/EntryPointUtilities/mac/XPCService/XPCServiceEntryPoint.mm	2016-07-01 01:29:47 UTC (rev 202723)
@@ -120,4 +120,13 @@
     return processIsSandboxed(xpc_connection_get_pid(m_connection.get()));
 }
 
+void XPCServiceExit(OSObjectPtr<xpc_object_t>&& priorityBoostMessage)
+{
+    // Make sure to destroy the priority boost message to avoid leaking a transaction.
+    priorityBoostMessage = nullptr;
+    // Balances the xpc_transaction_begin() in XPCServiceInitializer.
+    xpc_transaction_end();
+    xpc_transaction_exit_clean();
+}
+
 } // namespace WebKit

Modified: trunk/Source/WebKit2/Shared/EntryPointUtilities/mac/XPCService/XPCServiceMain.mm (202722 => 202723)


--- trunk/Source/WebKit2/Shared/EntryPointUtilities/mac/XPCService/XPCServiceMain.mm	2016-07-01 00:13:49 UTC (rev 202722)
+++ trunk/Source/WebKit2/Shared/EntryPointUtilities/mac/XPCService/XPCServiceMain.mm	2016-07-01 01:29:47 UTC (rev 202723)
@@ -34,6 +34,8 @@
 
 static void XPCServiceEventHandler(xpc_connection_t peer)
 {
+    static xpc_object_t priorityBoostMessage = nullptr;
+
     xpc_connection_set_target_queue(peer, dispatch_get_main_queue());
     xpc_connection_set_event_handler(peer, ^(xpc_object_t event) {
         xpc_type_t type = xpc_get_type(event);
@@ -49,7 +51,7 @@
                 CFBundleRef webKitBundle = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.WebKit"));
                 CFStringRef entryPointFunctionName = (CFStringRef)CFBundleGetValueForInfoDictionaryKey(CFBundleGetMainBundle(), CFSTR("WebKitEntryPoint"));
 
-                typedef void (*InitializerFunction)(xpc_connection_t, xpc_object_t);
+                typedef void (*InitializerFunction)(xpc_connection_t, xpc_object_t, xpc_object_t);
                 InitializerFunction initializerFunctionPtr = reinterpret_cast<InitializerFunction>(CFBundleGetFunctionPointerForName(webKitBundle, entryPointFunctionName));
                 if (!initializerFunctionPtr) {
                     NSLog(@"Unable to find entry point in WebKit.framework with name: %@", (NSString *)entryPointFunctionName);
@@ -68,12 +70,16 @@
                 if (fd != -1)
                     dup2(fd, STDERR_FILENO);
 
-                initializerFunctionPtr(peer, event);
+                initializerFunctionPtr(peer, event, priorityBoostMessage);
+                if (priorityBoostMessage)
+                    xpc_release(priorityBoostMessage);
             }
 
             // Leak a boost onto the NetworkProcess.
-            if (!strcmp(xpc_dictionary_get_string(event, "message-name"), "pre-bootstrap"))
-                xpc_retain(event);
+            if (!strcmp(xpc_dictionary_get_string(event, "message-name"), "pre-bootstrap")) {
+                assert(!priorityBoostMessage);
+                priorityBoostMessage = xpc_retain(event);
+            }
         }
     });
 

Modified: trunk/Source/WebKit2/Shared/ios/ChildProcessIOS.mm (202722 => 202723)


--- trunk/Source/WebKit2/Shared/ios/ChildProcessIOS.mm	2016-07-01 00:13:49 UTC (rev 202722)
+++ trunk/Source/WebKit2/Shared/ios/ChildProcessIOS.mm	2016-07-01 01:29:47 UTC (rev 202723)
@@ -31,6 +31,7 @@
 
 #import "SandboxInitializationParameters.h"
 #import "WebKitSystemInterface.h"
+#import "XPCServiceEntryPoint.h"
 #import <WebCore/FileSystem.h>
 #import <WebCore/FloatingPointEnvironment.h>
 #import <WebCore/SystemVersion.h>
@@ -114,6 +115,11 @@
 
 }
 
+void ChildProcess::platformStopRunLoop()
+{
+    XPCServiceExit(WTFMove(m_priorityBoostMessage));
+}
+
 } // namespace WebKit
 
 #endif

Modified: trunk/Source/WebKit2/WebProcess/EntryPoint/mac/XPCService/WebContentServiceEntryPoint.mm (202722 => 202723)


--- trunk/Source/WebKit2/WebProcess/EntryPoint/mac/XPCService/WebContentServiceEntryPoint.mm	2016-07-01 00:13:49 UTC (rev 202722)
+++ trunk/Source/WebKit2/WebProcess/EntryPoint/mac/XPCService/WebContentServiceEntryPoint.mm	2016-07-01 01:29:47 UTC (rev 202723)
@@ -43,9 +43,9 @@
 using namespace WebCore;
 using namespace WebKit;
 
-extern "C" WK_EXPORT void WebContentServiceInitializer(xpc_connection_t connection, xpc_object_t initializerMessage);
+extern "C" WK_EXPORT void WebContentServiceInitializer(xpc_connection_t connection, xpc_object_t initializerMessage, xpc_object_t priorityBoostMessage);
 
-void WebContentServiceInitializer(xpc_connection_t connection, xpc_object_t initializerMessage)
+void WebContentServiceInitializer(xpc_connection_t connection, xpc_object_t initializerMessage, xpc_object_t priorityBoostMessage)
 {
     // Remove the WebProcessShim from the DYLD_INSERT_LIBRARIES environment variable so any processes spawned by
     // the this process don't try to insert the shim and crash.
@@ -63,7 +63,7 @@
     InitWebCoreThreadSystemInterface();
 #endif // PLATFORM(IOS)
 
-    XPCServiceInitializer<WebProcess, XPCServiceInitializerDelegate>(adoptOSObject(connection), initializerMessage);
+    XPCServiceInitializer<WebProcess, XPCServiceInitializerDelegate>(adoptOSObject(connection), initializerMessage, priorityBoostMessage);
 
 #if HAVE(OS_ACTIVITY)
 #pragma clang diagnostic push
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to