/*
- * 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
// 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));
}
/*
- * 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
#import "CommandLine.h"
#import "EnvironmentUtilities.h"
+#import "EnvironmentVariables.h"
#import "RunLoop.h"
#import "WebProcess.h"
#import "WebSystemInterface.h"
#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
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()));
-# 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.
#
my $forceChromiumUpdate;
my $isInspectorFrontend;
my $isWK2;
+my $shouldTargetWebProcess;
my $xcodeVersion;
# Variables for Win32 support
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()), "");
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