Source/WebKit2: Allow WebProcess to launch a client process and become its first...
authormitz@apple.com <mitz@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 5 Jan 2012 04:19:28 +0000 (04:19 +0000)
committermitz@apple.com <mitz@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 5 Jan 2012 04:19:28 +0000 (04:19 +0000)
This is the WebKit2 part of fixing <http://webkit.org/b/75444> Debugging WebProcess requires running a UI process first and waiting to attach

Reviewed by Anders Carlsson.

* PluginProcess/mac/PluginProcessMainMac.mm:
(WebKit::PluginProcessMain): Added a newline to stderr output.
* UIProcess/Launcher/mac/EnvironmentVariables.cpp:
(WebKit::EnvironmentVariables::preexistingProcessServiceNameKey): Added. Returns the name
of the environment variable that optionally tells a UI processs to look for a preexisting
web process instead of launching a new one.
(WebKit::EnvironmentVariables::preexistingProcessTypeKey): Added. Returns the name of the
environment variable that tells a UI process the type of the preexisting web process
indicated by the other variable.
* UIProcess/Launcher/mac/EnvironmentVariables.h:
* UIProcess/Launcher/mac/ProcessLauncherMac.mm:
(WebKit::ProcessLauncher::launchProcess): Changed to look for a preexisting web process if
the aforementioned environment variables are set and the preexisting process has not been
used yet.
* WebProcess/mac/WebProcessMainMac.mm:
(WebKit::WebProcessMain): Changed to look for the -client-executable command-line option,
and if present, launch the specified executable, setting variables in its environment that
tell it to use this preexisting web process, then wait for it to send a send right to its
listening port.

Tools: Add a --target-web-process option to the debug-* scripts. When specified, the scripts will
start WebProcess under gdb and WebProcess will then run the client executable.

This is the Tools part of fixing <http://webkit.org/b/75444> Debugging WebProcess requires running a UI process first and waiting to attach

Reviewed by Anders Carlsson.

* Scripts/webkitdirs.pm:
(shouldTargetWebProcess): Added.
(determineShouldTargetWebProcess): Added. Checks for --target-web-process.
(execMacWebKitAppForDebugging): Changed to target gdb at WebProcess and pass the path to the
app using the -client-executable option if targeting the web process.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@104115 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebKit2/ChangeLog
Source/WebKit2/PluginProcess/mac/PluginProcessMainMac.mm
Source/WebKit2/UIProcess/Launcher/mac/EnvironmentVariables.cpp
Source/WebKit2/UIProcess/Launcher/mac/EnvironmentVariables.h
Source/WebKit2/UIProcess/Launcher/mac/ProcessLauncherMac.mm
Source/WebKit2/WebProcess/mac/WebProcessMainMac.mm
Tools/ChangeLog
Tools/Scripts/webkitdirs.pm

index 688bcc2900aeba8232810e30f3849823c4a775e1..94ca74c6d6de1a400c9142f44d7c923aa8f87cbb 100644 (file)
@@ -1,3 +1,31 @@
+2012-01-04  Dan Bernstein  <mitz@apple.com>
+
+        Allow WebProcess to launch a client process and become its first WebProcess.
+
+        This is the WebKit2 part of fixing <http://webkit.org/b/75444> Debugging WebProcess requires running a UI process first and waiting to attach
+
+        Reviewed by Anders Carlsson.
+
+        * PluginProcess/mac/PluginProcessMainMac.mm:
+        (WebKit::PluginProcessMain): Added a newline to stderr output.
+        * UIProcess/Launcher/mac/EnvironmentVariables.cpp:
+        (WebKit::EnvironmentVariables::preexistingProcessServiceNameKey): Added. Returns the name
+        of the environment variable that optionally tells a UI processs to look for a preexisting
+        web process instead of launching a new one.
+        (WebKit::EnvironmentVariables::preexistingProcessTypeKey): Added. Returns the name of the
+        environment variable that tells a UI process the type of the preexisting web process
+        indicated by the other variable.
+        * UIProcess/Launcher/mac/EnvironmentVariables.h:
+        * UIProcess/Launcher/mac/ProcessLauncherMac.mm:
+        (WebKit::ProcessLauncher::launchProcess): Changed to look for a preexisting web process if
+        the aforementioned environment variables are set and the preexisting process has not been
+        used yet.
+        * WebProcess/mac/WebProcessMainMac.mm:
+        (WebKit::WebProcessMain): Changed to look for the -client-executable command-line option,
+        and if present, launch the specified executable, setting variables in its environment that
+        tell it to use this preexisting web process, then wait for it to send a send right to its
+        listening port.
+
 2012-01-04  Alexey Proskuryakov  <ap@apple.com>
 
         First sentence is missing or clipped when printing a inline PDF
index 68160ea4b396d33d2b2eb14ae7ecc668bdab0d5e..5e93e2bdda413fb8c3d929aadae0461a3336286d 100644 (file)
@@ -76,7 +76,7 @@ int PluginProcessMain(const CommandLine& commandLine)
     mach_port_t serverPort;
     kern_return_t kr = bootstrap_look_up(bootstrap_port, serviceName.utf8().data(), &serverPort);
     if (kr) {
-        fprintf(stderr, "bootstrap_look_up result: %s (%x)", mach_error_string(kr), kr);
+        fprintf(stderr, "bootstrap_look_up result: %s (%x)\n", mach_error_string(kr), kr);
         return EXIT_FAILURE;
     }
 
index fbd232212166ed000a3798aa6c55574406d53bcc..72979f8f720df2e82eeeb0da19a36772dabfe745 100644 (file)
@@ -136,4 +136,18 @@ void EnvironmentVariables::copyEnvironmentVariables()
     m_environmentPointer = m_environmentVariables.data();
 }
 
+#if !defined(BUILDING_ON_SNOW_LEOPARD)
+
+const char* EnvironmentVariables::preexistingProcessServiceNameKey()
+{
+    return "WEBKIT_PREEXISTING_PROCESS_SERVICE_NAME";
+}
+
+const char* EnvironmentVariables::preexistingProcessTypeKey()
+{
+    return "WEBKIT_PREEXISTING_PROCESS_TYPE";
+}
+
+#endif // !defined(BUILDING_ON_SNOW_LEOPARD)
+
 } // namespace WebKit
index 0da7bf312920f0fddfd241ab0fa88e43e1bb6fa1..33829398d260f0c6ab4495825c8a908cff3cdbe5 100644 (file)
@@ -46,6 +46,11 @@ public:
 
     char** environmentPointer() const { return m_environmentPointer; }
 
+#if !defined(BUILDING_ON_SNOW_LEOPARD)
+    static const char* preexistingProcessServiceNameKey();
+    static const char* preexistingProcessTypeKey();
+#endif
+
 private:
     const char* valueIfVariableHasName(const char* environmentVariable, const char* name) const;
     const char* createStringForVariable(const char* name, const char* value);
index 1e20a8f46704fa75f396247eceb18e46f10355f1..c70f62edfbcf87c6ab28ae6bc72c4ac278d7e974 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2010, 2011, 2012 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -77,110 +77,144 @@ void ProcessLauncher::launchProcess()
     // Insert a send right so we can send to it.
     mach_port_insert_right(mach_task_self(), listeningPort, listeningPort, MACH_MSG_TYPE_MAKE_SEND);
 
-    NSBundle *webKit2Bundle = [NSBundle bundleWithIdentifier:@"com.apple.WebKit2"];
-    NSString *frameworksPath = [[webKit2Bundle bundlePath] stringByDeletingLastPathComponent];
-    const char* frameworkExecutablePath = [[webKit2Bundle executablePath] fileSystemRepresentation];
+    pid_t processIdentifier = 0;
 
-    NSString *processPath;
-    if (m_launchOptions.processType == ProcessLauncher::PluginProcess)
-        processPath = [webKit2Bundle pathForAuxiliaryExecutable:@"PluginProcess.app"];
-    else
-        processPath = [webKit2Bundle pathForAuxiliaryExecutable:@"WebProcess.app"];
-
-    NSString *processAppExecutablePath = [[NSBundle bundleWithPath:processPath] executablePath];
-
-    RetainPtr<CFStringRef> cfLocalization(AdoptCF, WKCopyCFLocalizationPreferredName(NULL));
-    CString localization = String(cfLocalization.get()).utf8();
-    
-    // Make a unique, per pid, per process launcher web process service name.
-    CString serviceName = String::format("com.apple.WebKit.WebProcess-%d-%p", getpid(), this).utf8();
+    EnvironmentVariables environmentVariables;
+#if !defined(BUILDING_ON_SNOW_LEOPARD)
+    static const char* preexistingProcessServiceName = environmentVariables.get(EnvironmentVariables::preexistingProcessServiceNameKey());
+    ProcessType preexistingProcessType;
+    if (preexistingProcessServiceName)
+        getProcessTypeFromString(environmentVariables.get(EnvironmentVariables::preexistingProcessTypeKey()), preexistingProcessType);
+
+    bool usePreexistingProcess = preexistingProcessServiceName && preexistingProcessType == m_launchOptions.processType;
+
+    if (usePreexistingProcess) {
+        mach_port_t lookupPort;
+        bootstrap_look_up(bootstrap_port, preexistingProcessServiceName, &lookupPort);
+
+        mach_msg_header_t header;
+        header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND);
+        header.msgh_id = 0;
+        header.msgh_local_port = listeningPort;
+        header.msgh_remote_port = lookupPort;
+        header.msgh_size = sizeof(header);
+        kern_return_t kr = mach_msg(&header, MACH_SEND_MSG, sizeof(header), 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
+
+        if (kr) {
+            LOG_ERROR("Failed to pick up preexisting process at %s (%x). Launching a new process of type %s instead.", preexistingProcessServiceName, kr, processTypeAsString(m_launchOptions.processType));
+            usePreexistingProcess = false;
+        }
+
+        mach_port_deallocate(mach_task_self(), lookupPort);
+
+        preexistingProcessServiceName = 0;
+    }
 
-    const char* args[] = { [processAppExecutablePath fileSystemRepresentation], frameworkExecutablePath, "-type", processTypeAsString(m_launchOptions.processType), "-servicename", serviceName.data(), "-localization", localization.data(), 0 };
+    if (!usePreexistingProcess) {
+#endif
+        NSBundle *webKit2Bundle = [NSBundle bundleWithIdentifier:@"com.apple.WebKit2"];
+        NSString *frameworksPath = [[webKit2Bundle bundlePath] stringByDeletingLastPathComponent];
+        const char* frameworkExecutablePath = [[webKit2Bundle executablePath] fileSystemRepresentation];
 
-    // Register ourselves.
-    kern_return_t kr = bootstrap_register2(bootstrap_port, const_cast<char*>(serviceName.data()), listeningPort, 0);
-    ASSERT_UNUSED(kr, kr == KERN_SUCCESS);
+        NSString *processPath;
+        if (m_launchOptions.processType == ProcessLauncher::PluginProcess)
+            processPath = [webKit2Bundle pathForAuxiliaryExecutable:@"PluginProcess.app"];
+        else
+            processPath = [webKit2Bundle pathForAuxiliaryExecutable:@"WebProcess.app"];
 
-    posix_spawnattr_t attr;
-    posix_spawnattr_init(&attr);
+        NSString *processAppExecutablePath = [[NSBundle bundleWithPath:processPath] executablePath];
 
-    short flags = 0;
+        RetainPtr<CFStringRef> cfLocalization(AdoptCF, WKCopyCFLocalizationPreferredName(NULL));
+        CString localization = String(cfLocalization.get()).utf8();
+        
+        // Make a unique, per pid, per process launcher web process service name.
+        CString serviceName = String::format("com.apple.WebKit.WebProcess-%d-%p", getpid(), this).utf8();
 
-    // We want our process to receive all signals.
-    sigset_t signalMaskSet;
-    sigemptyset(&signalMaskSet);
+        const char* args[] = { [processAppExecutablePath fileSystemRepresentation], frameworkExecutablePath, "-type", processTypeAsString(m_launchOptions.processType), "-servicename", serviceName.data(), "-localization", localization.data(), 0 };
 
-    posix_spawnattr_setsigmask(&attr, &signalMaskSet);
-    flags |= POSIX_SPAWN_SETSIGMASK;
+        // Register ourselves.
+        kern_return_t kr = bootstrap_register2(bootstrap_port, const_cast<char*>(serviceName.data()), listeningPort, 0);
+        ASSERT_UNUSED(kr, kr == KERN_SUCCESS);
 
-    // Determine the architecture to use.
-    cpu_type_t architecture = m_launchOptions.architecture;
-    if (architecture == LaunchOptions::MatchCurrentArchitecture)
-        architecture = _NSGetMachExecuteHeader()->cputype;
+        posix_spawnattr_t attr;
+        posix_spawnattr_init(&attr);
 
-    cpu_type_t cpuTypes[] = { architecture };
-    size_t outCount = 0;
-    posix_spawnattr_setbinpref_np(&attr, 1, cpuTypes, &outCount);
+        short flags = 0;
 
-    // Start suspended so we can set up the termination notification handler.
-    flags |= POSIX_SPAWN_START_SUSPENDED;
+        // We want our process to receive all signals.
+        sigset_t signalMaskSet;
+        sigemptyset(&signalMaskSet);
 
-#ifndef BUILDING_ON_SNOW_LEOPARD
-    static const int allowExecutableHeapFlag = 0x2000;
-    if (m_launchOptions.executableHeap)
-        flags |= allowExecutableHeapFlag;
-#endif
+        posix_spawnattr_setsigmask(&attr, &signalMaskSet);
+        flags |= POSIX_SPAWN_SETSIGMASK;
 
-    posix_spawnattr_setflags(&attr, flags);
+        // Determine the architecture to use.
+        cpu_type_t architecture = m_launchOptions.architecture;
+        if (architecture == LaunchOptions::MatchCurrentArchitecture)
+            architecture = _NSGetMachExecuteHeader()->cputype;
 
-    pid_t processIdentifier;
+        cpu_type_t cpuTypes[] = { architecture };
+        size_t outCount = 0;
+        posix_spawnattr_setbinpref_np(&attr, 1, cpuTypes, &outCount);
 
-    EnvironmentVariables environmentVariables;
+        // Start suspended so we can set up the termination notification handler.
+        flags |= POSIX_SPAWN_START_SUSPENDED;
 
 #ifndef BUILDING_ON_SNOW_LEOPARD
-    DynamicLinkerEnvironmentExtractor environmentExtractor([[NSBundle mainBundle] executablePath], architecture);
-    environmentExtractor.getExtractedEnvironmentVariables(environmentVariables);
+        static const int allowExecutableHeapFlag = 0x2000;
+        if (m_launchOptions.executableHeap)
+            flags |= allowExecutableHeapFlag;
 #endif
 
-    // To make engineering builds work, if the path is outside of /System set up
-    // DYLD_FRAMEWORK_PATH to pick up other frameworks, but don't do it for the
-    // production configuration because it involves extra file system access.
-    if (![frameworksPath hasPrefix:@"/System/"])
-        environmentVariables.appendValue("DYLD_FRAMEWORK_PATH", [frameworksPath fileSystemRepresentation], ':');
-
-    NSString *processShimPathNSString = nil;
-    if (m_launchOptions.processType == ProcessLauncher::PluginProcess)
-        processShimPathNSString = [[processAppExecutablePath stringByDeletingLastPathComponent] stringByAppendingPathComponent:@"PluginProcessShim.dylib"];
-    else if (m_launchOptions.processType == ProcessLauncher::WebProcess)
-        processShimPathNSString = [[processAppExecutablePath stringByDeletingLastPathComponent] stringByAppendingPathComponent:@"WebProcessShim.dylib"];
-
-    // Make sure that the shim library file exists and insert it.
-    if (processShimPathNSString) {
-        const char* processShimPath = [processShimPathNSString fileSystemRepresentation];
-        struct stat statBuf;
-        if (stat(processShimPath, &statBuf) == 0 && (statBuf.st_mode & S_IFMT) == S_IFREG)
-            environmentVariables.appendValue("DYLD_INSERT_LIBRARIES", processShimPath, ':');
-    }
-    
-    int result = posix_spawn(&processIdentifier, args[0], 0, &attr, const_cast<char**>(args), environmentVariables.environmentPointer());
+        posix_spawnattr_setflags(&attr, flags);
 
-    posix_spawnattr_destroy(&attr);
-
-    if (!result) {
-        // Set up the termination notification handler and then ask the child process to continue.
-        setUpTerminationNotificationHandler(processIdentifier);
-        kill(processIdentifier, SIGCONT);
-    } else {
-        // We failed to launch. Release the send right.
-        mach_port_deallocate(mach_task_self(), listeningPort);
+#ifndef BUILDING_ON_SNOW_LEOPARD
+        DynamicLinkerEnvironmentExtractor environmentExtractor([[NSBundle mainBundle] executablePath], architecture);
+        environmentExtractor.getExtractedEnvironmentVariables(environmentVariables);
+#endif
 
-        // And the receive right.
-        mach_port_mod_refs(mach_task_self(), listeningPort, MACH_PORT_RIGHT_RECEIVE, -1);
+        // To make engineering builds work, if the path is outside of /System set up
+        // DYLD_FRAMEWORK_PATH to pick up other frameworks, but don't do it for the
+        // production configuration because it involves extra file system access.
+        if (![frameworksPath hasPrefix:@"/System/"])
+            environmentVariables.appendValue("DYLD_FRAMEWORK_PATH", [frameworksPath fileSystemRepresentation], ':');
+
+        NSString *processShimPathNSString = nil;
+        if (m_launchOptions.processType == ProcessLauncher::PluginProcess)
+            processShimPathNSString = [[processAppExecutablePath stringByDeletingLastPathComponent] stringByAppendingPathComponent:@"PluginProcessShim.dylib"];
+        else if (m_launchOptions.processType == ProcessLauncher::WebProcess)
+            processShimPathNSString = [[processAppExecutablePath stringByDeletingLastPathComponent] stringByAppendingPathComponent:@"WebProcessShim.dylib"];
+
+        // Make sure that the shim library file exists and insert it.
+        if (processShimPathNSString) {
+            const char* processShimPath = [processShimPathNSString fileSystemRepresentation];
+            struct stat statBuf;
+            if (stat(processShimPath, &statBuf) == 0 && (statBuf.st_mode & S_IFMT) == S_IFREG)
+                environmentVariables.appendValue("DYLD_INSERT_LIBRARIES", processShimPath, ':');
+        }
         
-        listeningPort = MACH_PORT_NULL;
-        processIdentifier = 0;
+        int result = posix_spawn(&processIdentifier, args[0], 0, &attr, const_cast<char**>(args), environmentVariables.environmentPointer());
+
+        posix_spawnattr_destroy(&attr);
+
+        if (!result) {
+            // Set up the termination notification handler and then ask the child process to continue.
+            setUpTerminationNotificationHandler(processIdentifier);
+            kill(processIdentifier, SIGCONT);
+        } else {
+            // We failed to launch. Release the send right.
+            mach_port_deallocate(mach_task_self(), listeningPort);
+
+            // And the receive right.
+            mach_port_mod_refs(mach_task_self(), listeningPort, MACH_PORT_RIGHT_RECEIVE, -1);
+            
+            listeningPort = MACH_PORT_NULL;
+            processIdentifier = 0;
+        }
+#if !defined(BUILDING_ON_SNOW_LEOPARD)
     }
-    
+#endif
+
     // We've finished launching the process, message back to the main run loop.
     RunLoop::main()->dispatch(bind(&ProcessLauncher::didFinishLaunchingProcess, this, processIdentifier, listeningPort));
 }
index c6adda6bca1e7c5026efbdc772b2b230c851422f..b5a3fe07d067843be5b3c350a14a090f99c15ba0 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010, 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 2010, 2011, 2012 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -28,6 +28,7 @@
 
 #import "CommandLine.h"
 #import "EnvironmentUtilities.h"
+#import "EnvironmentVariables.h"
 #import "RunLoop.h"
 #import "WebProcess.h"
 #import "WebSystemInterface.h"
@@ -38,6 +39,7 @@
 #import <runtime/InitializeThreading.h>
 #import <servers/bootstrap.h>
 #import <signal.h>
+#import <spawn.h>
 #import <stdio.h>
 #import <sysexits.h>
 #import <unistd.h>
 #import <wtf/text/CString.h>
 #import <wtf/text/StringBuilder.h>
 
+#if !defined(BUILDING_ON_SNOW_LEOPARD)
+extern "C" kern_return_t bootstrap_register2(mach_port_t, name_t, mach_port_t, uint64_t);
+#endif
+
 @interface NSApplication (WebNSApplicationDetails)
 -(void)_installAutoreleasePoolsOnCurrentThreadIfNecessary;
 @end
@@ -58,25 +64,79 @@ namespace WebKit {
 
 int WebProcessMain(const CommandLine& commandLine)
 {
-#ifdef BUILDING_ON_SNOW_LEOPARD
     // Remove the WebProcess shim from the DYLD_INSERT_LIBRARIES environment variable so any processes spawned by
     // the WebProcess don't try to insert the shim and crash.
     EnvironmentUtilities::stripValuesEndingWithString("DYLD_INSERT_LIBRARIES", "/WebProcessShim.dylib");
-#endif
 
     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
 
     String serviceName = commandLine["servicename"];
-    if (serviceName.isEmpty())
+    String clientExecutable;
+#if !defined(BUILDING_ON_SNOW_LEOPARD)
+    clientExecutable = commandLine["client-executable"];
+#endif
+
+    if (serviceName.isEmpty() && clientExecutable.isEmpty())
         return EXIT_FAILURE;
 
     // Get the server port.
     mach_port_t serverPort;
-    kern_return_t kr = bootstrap_look_up(bootstrap_port, serviceName.utf8().data(), &serverPort);
-    if (kr) {
-        fprintf(stderr, "bootstrap_look_up result: %s (%x)", mach_error_string(kr), kr);
-        return 2;
+    if (clientExecutable.isEmpty()) {
+        kern_return_t kr = bootstrap_look_up(bootstrap_port, serviceName.utf8().data(), &serverPort);
+        if (kr) {
+            fprintf(stderr, "bootstrap_look_up result: %s (%x)\n", mach_error_string(kr), kr);
+            return 2;
+        }
+    }
+#if !defined(BUILDING_ON_SNOW_LEOPARD)
+    else {
+        mach_port_name_t publishedService;
+        mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &publishedService);
+        mach_port_insert_right(mach_task_self(), publishedService, publishedService, MACH_MSG_TYPE_MAKE_SEND);
+        // Make it possible to look up.
+        serviceName = String::format("com.apple.WebKit.WebProcess-%d", getpid());
+        if (kern_return_t kr = bootstrap_register2(bootstrap_port, const_cast<char*>(serviceName.utf8().data()), publishedService, 0)) {
+            fprintf(stderr, "Failed to register service name \"%s\". %s (%x)\n", serviceName.utf8().data(), mach_error_string(kr), kr);
+            return EXIT_FAILURE;
+        }
+
+        CString command = clientExecutable.utf8();
+        const char* args[] = { command.data(), 0 };
+
+        EnvironmentVariables environmentVariables;
+        environmentVariables.set(EnvironmentVariables::preexistingProcessServiceNameKey(), serviceName.utf8().data());
+        environmentVariables.set(EnvironmentVariables::preexistingProcessTypeKey(), commandLine["type"].utf8().data());
+
+        posix_spawn_file_actions_t fileActions;
+        posix_spawn_file_actions_init(&fileActions);
+        posix_spawn_file_actions_addinherit_np(&fileActions, STDIN_FILENO);
+        posix_spawn_file_actions_addinherit_np(&fileActions, STDOUT_FILENO);
+        posix_spawn_file_actions_addinherit_np(&fileActions, STDERR_FILENO);
+
+        posix_spawnattr_t attributes;
+        posix_spawnattr_init(&attributes);
+        posix_spawnattr_setflags(&attributes, POSIX_SPAWN_CLOEXEC_DEFAULT | POSIX_SPAWN_SETPGROUP);
+
+        int spawnResult = posix_spawn(0, command.data(), &fileActions, &attributes, const_cast<char**>(args), environmentVariables.environmentPointer());
+        if (spawnResult)
+            return 2;
+
+        mach_msg_empty_rcv_t message;
+        if (kern_return_t kr = mach_msg(&message.header, MACH_RCV_MSG, 0, sizeof(message), publishedService, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL)) {
+            fprintf(stderr, "Failed to receive port from the UI process. %s (%x)\n", mach_error_string(kr), kr);
+            return EXIT_FAILURE;
+        }
+
+        mach_port_mod_refs(mach_task_self(), publishedService, MACH_PORT_RIGHT_RECEIVE, -1);
+        serverPort = message.header.msgh_remote_port;
+        mach_port_type_t portType;
+        kern_return_t kr = mach_port_type(mach_task_self(), serverPort, &portType);
+        if (kr || !(portType & MACH_PORT_TYPE_SEND)) {
+            fprintf(stderr, "Failed to obtain send right for port received from the UI process.\n");
+            return EXIT_FAILURE;
+        }
     }
+#endif // !defined(BUILDING_ON_SNOW_LEOPARD)
 
     String localization = commandLine["localization"];
     RetainPtr<CFStringRef> cfLocalization(AdoptCF, CFStringCreateWithCharacters(0, reinterpret_cast<const UniChar*>(localization.characters()), localization.length()));
index 92c20e7276be6201e7d451ee302603cb3468b8ed..4cd626469066b636924ddae26e4f9bd6af77e4fb 100644 (file)
@@ -1,3 +1,18 @@
+2012-01-04  Dan Bernstein  <mitz@apple.com>
+
+        Add a --target-web-process option to the debug-* scripts. When specified, the scripts will
+        start WebProcess under gdb and WebProcess will then run the client executable.
+
+        This is the Tools part of fixing <http://webkit.org/b/75444> Debugging WebProcess requires running a UI process first and waiting to attach
+
+        Reviewed by Anders Carlsson.
+
+        * Scripts/webkitdirs.pm:
+        (shouldTargetWebProcess): Added.
+        (determineShouldTargetWebProcess): Added. Checks for --target-web-process.
+        (execMacWebKitAppForDebugging): Changed to target gdb at WebProcess and pass the path to the
+        app using the -client-executable option if targeting the web process.
+
 2012-01-04  Viatcheslav Ostapenko  <ostapenko.viatcheslav@nokia.com>
 
         Adding myself to committers list.
index a5666a88ba1972ea5ccb8102fa361e7b51c97f7b..7cad910161b2116c895c8b6500491b5a07dad44c 100755 (executable)
@@ -1,4 +1,4 @@
-# Copyright (C) 2005, 2006, 2007, 2010 Apple Inc. All rights reserved.
+# Copyright (C) 2005, 2006, 2007, 2010, 2012 Apple Inc. All rights reserved.
 # Copyright (C) 2009 Google Inc. All rights reserved.
 # Copyright (C) 2011 Research In Motion Limited. All rights reserved.
 #
@@ -98,6 +98,7 @@ my $isChromiumMacMake;
 my $forceChromiumUpdate;
 my $isInspectorFrontend;
 my $isWK2;
+my $shouldTargetWebProcess;
 my $xcodeVersion;
 
 # Variables for Win32 support
@@ -1306,6 +1307,18 @@ sub isWindowsNT()
     return $ENV{'OS'} eq 'Windows_NT';
 }
 
+sub shouldTargetWebProcess
+{
+    determineShouldTargetWebProcess();
+    return $shouldTargetWebProcess;
+}
+
+sub determineShouldTargetWebProcess
+{
+    return if defined($shouldTargetWebProcess);
+    $shouldTargetWebProcess = checkForArgumentAndRemoveFromARGV("--target-web-process");
+}
+
 sub relativeScriptsDir()
 {
     my $scriptDir = File::Spec->catpath("", File::Spec->abs2rel($FindBin::Bin, getcwd()), "");
@@ -2329,11 +2342,21 @@ sub execMacWebKitAppForDebugging($)
     die "Can't find gdb executable. Is gdb installed?\n" unless -x $gdbPath;
 
     my $productDir = productDir();
-    print "Starting @{[basename($appPath)]} under gdb with DYLD_FRAMEWORK_PATH set to point to built WebKit in $productDir.\n";
     $ENV{DYLD_FRAMEWORK_PATH} = $productDir;
     $ENV{WEBKIT_UNSET_DYLD_FRAMEWORK_PATH} = "YES";
     my @architectureFlags = ("-arch", architecture());
-    exec { $gdbPath } $gdbPath, @architectureFlags, "--args", $appPath, argumentsForRunAndDebugMacWebKitApp() or die;
+    if (!shouldTargetWebProcess()) {
+        print "Starting @{[basename($appPath)]} under gdb with DYLD_FRAMEWORK_PATH set to point to built WebKit in $productDir.\n";
+        exec { $gdbPath } $gdbPath, @architectureFlags, "--args", $appPath, argumentsForRunAndDebugMacWebKitApp() or die;
+    } else {
+        my $webProcessShimPath = File::Spec->catfile($productDir, "WebProcessShim.dylib");
+        my $webProcessPath = File::Spec->catdir($productDir, "WebProcess.app");
+        my $webKit2ExecutablePath = File::Spec->catfile($productDir, "WebKit2.framework", "WebKit2");
+        $ENV{DYLD_INSERT_LIBRARIES} = $webProcessShimPath;
+
+        print "Starting WebProcess under gdb with DYLD_FRAMEWORK_PATH set to point to built WebKit in $productDir.\n";
+        exec { $gdbPath } $gdbPath, @architectureFlags, "--args", $webProcessPath, $webKit2ExecutablePath, "-type", "webprocess", "-client-executable", $appPath or die;
+    }
 }
 
 sub debugSafari