1/* 2 * Copyright (C) 2010, 2011, 2012 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' 14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS 17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 23 * THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#import "config.h" 27#import "ProcessLauncher.h" 28 29#import "DynamicLinkerEnvironmentExtractor.h" 30#import "EnvironmentVariables.h" 31#import "WebKitSystemInterface.h" 32#import <WebCore/RunLoop.h> 33#import <crt_externs.h> 34#import <mach-o/dyld.h> 35#import <mach/machine.h> 36#import <runtime/InitializeThreading.h> 37#import <servers/bootstrap.h> 38#import <spawn.h> 39#import <sys/param.h> 40#import <sys/stat.h> 41#import <wtf/PassRefPtr.h> 42#import <wtf/RetainPtr.h> 43#import <wtf/Threading.h> 44#import <wtf/text/CString.h> 45#import <wtf/text/WTFString.h> 46 47#if HAVE(XPC) 48#import <xpc/xpc.h> 49#endif 50 51using namespace WebCore; 52 53// FIXME: We should be doing this another way. 54extern "C" kern_return_t bootstrap_register2(mach_port_t, name_t, mach_port_t, uint64_t); 55 56#if HAVE(XPC) 57extern "C" void xpc_connection_set_instance(xpc_connection_t, uuid_t); 58extern "C" void xpc_dictionary_set_mach_send(xpc_object_t, const char*, mach_port_t); 59#endif 60 61namespace WebKit { 62 63namespace { 64 65struct UUIDHolder : public RefCounted<UUIDHolder> { 66 static PassRefPtr<UUIDHolder> create() 67 { 68 return adoptRef(new UUIDHolder); 69 } 70 71 UUIDHolder() 72 { 73 uuid_generate(uuid); 74 } 75 76 uuid_t uuid; 77}; 78 79} 80 81static void setUpTerminationNotificationHandler(pid_t pid) 82{ 83#if HAVE(DISPATCH_H) 84 dispatch_source_t processDiedSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_PROC, pid, DISPATCH_PROC_EXIT, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)); 85 dispatch_source_set_event_handler(processDiedSource, ^{ 86 int status; 87 waitpid(dispatch_source_get_handle(processDiedSource), &status, 0); 88 dispatch_source_cancel(processDiedSource); 89 }); 90 dispatch_source_set_cancel_handler(processDiedSource, ^{ 91 dispatch_release(processDiedSource); 92 }); 93 dispatch_resume(processDiedSource); 94#endif 95} 96 97static void addDYLDEnvironmentAdditions(const ProcessLauncher::LaunchOptions& launchOptions, bool isWebKitDevelopmentBuild, EnvironmentVariables& environmentVariables) 98{ 99 DynamicLinkerEnvironmentExtractor environmentExtractor([[NSBundle mainBundle] executablePath], _NSGetMachExecuteHeader()->cputype); 100 environmentExtractor.getExtractedEnvironmentVariables(environmentVariables); 101 102 NSBundle *webKit2Bundle = [NSBundle bundleWithIdentifier:@"com.apple.WebKit2"]; 103 NSString *frameworksPath = [[webKit2Bundle bundlePath] stringByDeletingLastPathComponent]; 104 105 // To make engineering builds work, if the path is outside of /System set up 106 // DYLD_FRAMEWORK_PATH to pick up other frameworks, but don't do it for the 107 // production configuration because it involves extra file system access. 108 if (isWebKitDevelopmentBuild) 109 environmentVariables.appendValue("DYLD_FRAMEWORK_PATH", [frameworksPath fileSystemRepresentation], ':'); 110 111 NSString *processShimPathNSString = nil; 112#if ENABLE(PLUGIN_PROCESS) 113 if (launchOptions.processType == ProcessLauncher::PluginProcess) { 114 NSString *processPath = [webKit2Bundle pathForAuxiliaryExecutable:@"PluginProcess.app"]; 115 NSString *processAppExecutablePath = [[NSBundle bundleWithPath:processPath] executablePath]; 116 117 processShimPathNSString = [[processAppExecutablePath stringByDeletingLastPathComponent] stringByAppendingPathComponent:@"PluginProcessShim.dylib"]; 118 } else 119#endif // ENABLE(PLUGIN_PROCESS) 120 if (launchOptions.processType == ProcessLauncher::WebProcess) { 121 NSString *processPath = [webKit2Bundle pathForAuxiliaryExecutable:@"WebProcess.app"]; 122 NSString *processAppExecutablePath = [[NSBundle bundleWithPath:processPath] executablePath]; 123 124 processShimPathNSString = [[processAppExecutablePath stringByDeletingLastPathComponent] stringByAppendingPathComponent:@"WebProcessShim.dylib"]; 125 } else if (launchOptions.processType == ProcessLauncher::NetworkProcess) { 126 NSString *processPath = [webKit2Bundle pathForAuxiliaryExecutable:@"NetworkProcess.app"]; 127 NSString *processAppExecutablePath = [[NSBundle bundleWithPath:processPath] executablePath]; 128 129 processShimPathNSString = [[processAppExecutablePath stringByDeletingLastPathComponent] stringByAppendingPathComponent:@"SecItemShim.dylib"]; 130 } 131 132 // Make sure that the shim library file exists and insert it. 133 if (processShimPathNSString) { 134 const char* processShimPath = [processShimPathNSString fileSystemRepresentation]; 135 struct stat statBuf; 136 if (stat(processShimPath, &statBuf) == 0 && (statBuf.st_mode & S_IFMT) == S_IFREG) 137 environmentVariables.appendValue("DYLD_INSERT_LIBRARIES", processShimPath, ':'); 138 } 139 140} 141 142typedef void (ProcessLauncher::*DidFinishLaunchingProcessFunction)(PlatformProcessIdentifier, CoreIPC::Connection::Identifier); 143 144#if HAVE(XPC) 145 146static const char* serviceName(const ProcessLauncher::LaunchOptions& launchOptions, bool forDevelopment) 147{ 148 switch (launchOptions.processType) { 149 case ProcessLauncher::WebProcess: 150 if (forDevelopment) 151 return "com.apple.WebKit.WebContent.Development"; 152 return "com.apple.WebKit.WebContent"; 153#if ENABLE(NETWORK_PROCESS) 154 case ProcessLauncher::NetworkProcess: 155 if (forDevelopment) 156 return "com.apple.WebKit.Networking.Development"; 157 return "com.apple.WebKit.Networking"; 158#endif 159#if ENABLE(PLUGIN_PROCESS) 160 case ProcessLauncher::PluginProcess: 161 if (forDevelopment) 162 return "com.apple.WebKit.Plugin.Development"; 163 164 // FIXME: Support plugins that require an executable heap. 165 if (launchOptions.architecture == CPU_TYPE_X86) 166 return "com.apple.WebKit.Plugin.32"; 167 if (launchOptions.architecture == CPU_TYPE_X86_64) 168 return "com.apple.WebKit.Plugin.64"; 169 170 ASSERT_NOT_REACHED(); 171 return 0; 172#endif 173#if ENABLE(SHARED_WORKER_PROCESS) 174 case ProcessLauncher::SharedWorkerProcess: 175 ASSERT_NOT_REACHED(); 176 return 0; 177#endif 178 } 179} 180 181static void connectToService(const ProcessLauncher::LaunchOptions& launchOptions, bool forDevelopment, ProcessLauncher* that, DidFinishLaunchingProcessFunction didFinishLaunchingProcessFunction, UUIDHolder* instanceUUID) 182{ 183 // Create a connection to the WebKit2 XPC service. 184 xpc_connection_t connection = xpc_connection_create(serviceName(launchOptions, forDevelopment), 0); 185 xpc_connection_set_instance(connection, instanceUUID->uuid); 186 187 // XPC requires having an event handler, even if it is not used. 188 xpc_connection_set_event_handler(connection, ^(xpc_object_t event) { }); 189 xpc_connection_resume(connection); 190 191#if ENABLE(NETWORK_PROCESS) 192 if (launchOptions.processType == ProcessLauncher::NetworkProcess) { 193 xpc_object_t preBootstrapMessage = xpc_dictionary_create(0, 0, 0); 194 xpc_dictionary_set_string(preBootstrapMessage, "message-name", "pre-bootstrap"); 195 xpc_connection_send_message(connection, preBootstrapMessage); 196 xpc_release(preBootstrapMessage); 197 } 198#endif 199 200 // Create the listening port. 201 mach_port_t listeningPort; 202 mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &listeningPort); 203 204 // Insert a send right so we can send to it. 205 mach_port_insert_right(mach_task_self(), listeningPort, listeningPort, MACH_MSG_TYPE_MAKE_SEND); 206 207 NSString *bundleIdentifier = [[NSBundle mainBundle] bundleIdentifier]; 208 CString clientIdentifier = bundleIdentifier ? String([[NSBundle mainBundle] bundleIdentifier]).utf8() : *_NSGetProgname(); 209 210 xpc_object_t bootstrapMessage = xpc_dictionary_create(0, 0, 0); 211 xpc_dictionary_set_string(bootstrapMessage, "message-name", "bootstrap"); 212 xpc_dictionary_set_string(bootstrapMessage, "framework-executable-path", [[[NSBundle bundleWithIdentifier:@"com.apple.WebKit2"] executablePath] fileSystemRepresentation]); 213 xpc_dictionary_set_mach_send(bootstrapMessage, "server-port", listeningPort); 214 xpc_dictionary_set_string(bootstrapMessage, "client-identifier", clientIdentifier.data()); 215 xpc_dictionary_set_string(bootstrapMessage, "ui-process-name", [[[NSProcessInfo processInfo] processName] UTF8String]); 216 217 if (forDevelopment) { 218 xpc_dictionary_set_fd(bootstrapMessage, "stdout", STDOUT_FILENO); 219 xpc_dictionary_set_fd(bootstrapMessage, "stderr", STDERR_FILENO); 220 } 221 222 xpc_object_t extraInitializationData = xpc_dictionary_create(0, 0, 0); 223 HashMap<String, String>::const_iterator it = launchOptions.extraInitializationData.begin(); 224 HashMap<String, String>::const_iterator end = launchOptions.extraInitializationData.end(); 225 for (; it != end; ++it) 226 xpc_dictionary_set_string(extraInitializationData, it->key.utf8().data(), it->value.utf8().data()); 227 xpc_dictionary_set_value(bootstrapMessage, "extra-initialization-data", extraInitializationData); 228 xpc_release(extraInitializationData); 229 230 that->ref(); 231 232 xpc_connection_send_message_with_reply(connection, bootstrapMessage, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(xpc_object_t reply) { 233 xpc_type_t type = xpc_get_type(reply); 234 if (type == XPC_TYPE_ERROR) { 235 // We failed to launch. Release the send right. 236 mach_port_deallocate(mach_task_self(), listeningPort); 237 238 // And the receive right. 239 mach_port_mod_refs(mach_task_self(), listeningPort, MACH_PORT_RIGHT_RECEIVE, -1); 240 241 RunLoop::main()->dispatch(bind(didFinishLaunchingProcessFunction, that, 0, CoreIPC::Connection::Identifier())); 242 } else { 243 ASSERT(type == XPC_TYPE_DICTIONARY); 244 ASSERT(!strcmp(xpc_dictionary_get_string(reply, "message-name"), "process-finished-launching")); 245 246 // The process has finished launching, grab the pid from the connection. 247 pid_t processIdentifier = xpc_connection_get_pid(connection); 248 249 // We've finished launching the process, message back to the main run loop. 250 RunLoop::main()->dispatch(bind(didFinishLaunchingProcessFunction, that, processIdentifier, CoreIPC::Connection::Identifier(listeningPort, connection))); 251 } 252 253 that->deref(); 254 }); 255 xpc_release(bootstrapMessage); 256} 257 258static void connectToReExecService(const ProcessLauncher::LaunchOptions& launchOptions, ProcessLauncher* that, DidFinishLaunchingProcessFunction didFinishLaunchingProcessFunction) 259{ 260 EnvironmentVariables environmentVariables; 261 addDYLDEnvironmentAdditions(launchOptions, true, environmentVariables); 262 263 // Generate the uuid for the service instance we are about to create. 264 // FIXME: This UUID should be stored on the ChildProcessProxy. 265 RefPtr<UUIDHolder> instanceUUID = UUIDHolder::create(); 266 267 xpc_connection_t reExecConnection = xpc_connection_create(serviceName(launchOptions, true), 0); 268 xpc_connection_set_instance(reExecConnection, instanceUUID->uuid); 269 270 // Keep the ProcessLauncher alive while we do the re-execing (balanced in event handler). 271 that->ref(); 272 273 // We wait for the connection to tear itself down (indicated via an error event) 274 // to indicate that the service instance re-execed itself, and is now ready to be 275 // connected to. 276 xpc_connection_set_event_handler(reExecConnection, ^(xpc_object_t event) { 277 ASSERT(xpc_get_type(event) == XPC_TYPE_ERROR); 278 279 connectToService(launchOptions, true, that, didFinishLaunchingProcessFunction, instanceUUID.get()); 280 281 // Release the connection. 282 xpc_release(reExecConnection); 283 284 // Other end of ref called before we setup the event handler. 285 that->deref(); 286 }); 287 xpc_connection_resume(reExecConnection); 288 289 xpc_object_t reExecMessage = xpc_dictionary_create(0, 0, 0); 290 xpc_dictionary_set_string(reExecMessage, "message-name", "re-exec"); 291 292 cpu_type_t architecture = launchOptions.architecture == ProcessLauncher::LaunchOptions::MatchCurrentArchitecture ? _NSGetMachExecuteHeader()->cputype : launchOptions.architecture; 293 xpc_dictionary_set_uint64(reExecMessage, "architecture", (uint64_t)architecture); 294 295 xpc_object_t environment = xpc_array_create(0, 0); 296 char** environmentPointer = environmentVariables.environmentPointer(); 297 Vector<CString> temps; 298 for (size_t i = 0; environmentPointer[i]; ++i) { 299 CString temp(environmentPointer[i], strlen(environmentPointer[i])); 300 temps.append(temp); 301 302 xpc_array_set_string(environment, XPC_ARRAY_APPEND, temp.data()); 303 } 304 xpc_dictionary_set_value(reExecMessage, "environment", environment); 305 xpc_release(environment); 306 307 xpc_dictionary_set_bool(reExecMessage, "executable-heap", launchOptions.executableHeap); 308 309 xpc_connection_send_message(reExecConnection, reExecMessage); 310 xpc_release(reExecMessage); 311} 312 313static void createService(const ProcessLauncher::LaunchOptions& launchOptions, bool forDevelopment, ProcessLauncher* that, DidFinishLaunchingProcessFunction didFinishLaunchingProcessFunction) 314{ 315 if (forDevelopment) { 316 connectToReExecService(launchOptions, that, didFinishLaunchingProcessFunction); 317 return; 318 } 319 320 // Generate the uuid for the service instance we are about to create. 321 // FIXME: This UUID should be stored on the ChildProcessProxy. 322 RefPtr<UUIDHolder> instanceUUID = UUIDHolder::create(); 323 connectToService(launchOptions, false, that, didFinishLaunchingProcessFunction, instanceUUID.get()); 324} 325 326#endif 327 328static bool tryPreexistingProcess(const ProcessLauncher::LaunchOptions& launchOptions, ProcessLauncher* that, DidFinishLaunchingProcessFunction didFinishLaunchingProcessFunction) 329{ 330 EnvironmentVariables environmentVariables; 331 static const char* preexistingProcessServiceName = environmentVariables.get(EnvironmentVariables::preexistingProcessServiceNameKey()); 332 333 ProcessLauncher::ProcessType preexistingProcessType; 334 if (preexistingProcessServiceName) 335 ProcessLauncher::getProcessTypeFromString(environmentVariables.get(EnvironmentVariables::preexistingProcessTypeKey()), preexistingProcessType); 336 337 bool usePreexistingProcess = preexistingProcessServiceName && preexistingProcessType == launchOptions.processType; 338 if (!usePreexistingProcess) 339 return false; 340 341 // Create the listening port. 342 mach_port_t listeningPort; 343 mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &listeningPort); 344 345 // Insert a send right so we can send to it. 346 mach_port_insert_right(mach_task_self(), listeningPort, listeningPort, MACH_MSG_TYPE_MAKE_SEND); 347 348 pid_t processIdentifier = 0; 349 350 mach_port_t lookupPort; 351 bootstrap_look_up(bootstrap_port, preexistingProcessServiceName, &lookupPort); 352 353 mach_msg_header_t header; 354 header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND); 355 header.msgh_id = 0; 356 header.msgh_local_port = listeningPort; 357 header.msgh_remote_port = lookupPort; 358 header.msgh_size = sizeof(header); 359 kern_return_t kr = mach_msg(&header, MACH_SEND_MSG, sizeof(header), 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); 360 361 mach_port_deallocate(mach_task_self(), lookupPort); 362 preexistingProcessServiceName = 0; 363 364 if (kr) { 365 LOG_ERROR("Failed to pick up preexisting process at %s (%x). Launching a new process of type %s instead.", preexistingProcessServiceName, kr, ProcessLauncher::processTypeAsString(launchOptions.processType)); 366 return false; 367 } 368 369 // We've finished launching the process, message back to the main run loop. 370 RunLoop::main()->dispatch(bind(didFinishLaunchingProcessFunction, that, processIdentifier, CoreIPC::Connection::Identifier(listeningPort))); 371 return true; 372} 373 374static void createProcess(const ProcessLauncher::LaunchOptions& launchOptions, bool isWebKitDevelopmentBuild, ProcessLauncher* that, DidFinishLaunchingProcessFunction didFinishLaunchingProcessFunction) 375{ 376 EnvironmentVariables environmentVariables; 377 addDYLDEnvironmentAdditions(launchOptions, isWebKitDevelopmentBuild, environmentVariables); 378 379 // Create the listening port. 380 mach_port_t listeningPort; 381 mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &listeningPort); 382 383 // Insert a send right so we can send to it. 384 mach_port_insert_right(mach_task_self(), listeningPort, listeningPort, MACH_MSG_TYPE_MAKE_SEND); 385 386 RetainPtr<CFStringRef> cfLocalization = adoptCF(WKCopyCFLocalizationPreferredName(NULL)); 387 CString localization = String(cfLocalization.get()).utf8(); 388 389 NSBundle *webKit2Bundle = [NSBundle bundleWithIdentifier:@"com.apple.WebKit2"]; 390 391 NSString *processPath = nil; 392 switch (launchOptions.processType) { 393 case ProcessLauncher::WebProcess: 394 processPath = [webKit2Bundle pathForAuxiliaryExecutable:@"WebProcess.app"]; 395 break; 396#if ENABLE(PLUGIN_PROCESS) 397 case ProcessLauncher::PluginProcess: 398 processPath = [webKit2Bundle pathForAuxiliaryExecutable:@"PluginProcess.app"]; 399 break; 400#endif 401#if ENABLE(NETWORK_PROCESS) 402 case ProcessLauncher::NetworkProcess: 403 processPath = [webKit2Bundle pathForAuxiliaryExecutable:@"NetworkProcess.app"]; 404 break; 405#endif 406#if ENABLE(SHARED_WORKER_PROCESS) 407 case ProcessLauncher::SharedWorkerProcess: 408 processPath = [webKit2Bundle pathForAuxiliaryExecutable:@"SharedWorkerProcess.app"]; 409 break; 410#endif 411 } 412 413 NSString *frameworkExecutablePath = [webKit2Bundle executablePath]; 414 NSString *processAppExecutablePath = [[NSBundle bundleWithPath:processPath] executablePath]; 415 416 NSString *bundleIdentifier = [[NSBundle mainBundle] bundleIdentifier]; 417 CString clientIdentifier = bundleIdentifier ? String([[NSBundle mainBundle] bundleIdentifier]).utf8() : *_NSGetProgname(); 418 419 // Make a unique, per pid, per process launcher web process service name. 420 CString serviceName = String::format("com.apple.WebKit.WebProcess-%d-%p", getpid(), that).utf8(); 421 422 Vector<const char*> args; 423 args.append([processAppExecutablePath fileSystemRepresentation]); 424 args.append([frameworkExecutablePath fileSystemRepresentation]); 425 args.append("-type"); 426 args.append(ProcessLauncher::processTypeAsString(launchOptions.processType)); 427 args.append("-servicename"); 428 args.append(serviceName.data()); 429 args.append("-localization"); 430 args.append(localization.data()); 431 args.append("-client-identifier"); 432 args.append(clientIdentifier.data()); 433 args.append("-ui-process-name"); 434 args.append([[[NSProcessInfo processInfo] processName] UTF8String]); 435 436 HashMap<String, String>::const_iterator it = launchOptions.extraInitializationData.begin(); 437 HashMap<String, String>::const_iterator end = launchOptions.extraInitializationData.end(); 438 Vector<CString> temps; 439 for (; it != end; ++it) { 440 String keyPlusDash = "-" + it->key; 441 CString key(keyPlusDash.utf8().data()); 442 temps.append(key); 443 args.append(key.data()); 444 445 CString value(it->value.utf8().data()); 446 temps.append(value); 447 args.append(value.data()); 448 } 449 450 args.append(nullptr); 451 452 // Register ourselves. 453 kern_return_t kr = bootstrap_register2(bootstrap_port, const_cast<char*>(serviceName.data()), listeningPort, 0); 454 ASSERT_UNUSED(kr, kr == KERN_SUCCESS); 455 456 posix_spawnattr_t attr; 457 posix_spawnattr_init(&attr); 458 459 short flags = 0; 460 461 // We want our process to receive all signals. 462 sigset_t signalMaskSet; 463 sigemptyset(&signalMaskSet); 464 465 posix_spawnattr_setsigmask(&attr, &signalMaskSet); 466 flags |= POSIX_SPAWN_SETSIGMASK; 467 468 // Determine the architecture to use. 469 cpu_type_t architecture = launchOptions.architecture; 470 if (architecture == ProcessLauncher::LaunchOptions::MatchCurrentArchitecture) 471 architecture = _NSGetMachExecuteHeader()->cputype; 472 473 cpu_type_t cpuTypes[] = { architecture }; 474 size_t outCount = 0; 475 posix_spawnattr_setbinpref_np(&attr, 1, cpuTypes, &outCount); 476 477 // Start suspended so we can set up the termination notification handler. 478 flags |= POSIX_SPAWN_START_SUSPENDED; 479 480 static const int allowExecutableHeapFlag = 0x2000; 481 if (launchOptions.executableHeap) 482 flags |= allowExecutableHeapFlag; 483 484 posix_spawnattr_setflags(&attr, flags); 485 486 pid_t processIdentifier = 0; 487 int result = posix_spawn(&processIdentifier, args[0], 0, &attr, const_cast<char**>(args.data()), environmentVariables.environmentPointer()); 488 489 posix_spawnattr_destroy(&attr); 490 491 if (!result) { 492 // Set up the termination notification handler and then ask the child process to continue. 493 setUpTerminationNotificationHandler(processIdentifier); 494 kill(processIdentifier, SIGCONT); 495 } else { 496 // We failed to launch. Release the send right. 497 mach_port_deallocate(mach_task_self(), listeningPort); 498 499 // And the receive right. 500 mach_port_mod_refs(mach_task_self(), listeningPort, MACH_PORT_RIGHT_RECEIVE, -1); 501 502 listeningPort = MACH_PORT_NULL; 503 processIdentifier = 0; 504 } 505 506 // We've finished launching the process, message back to the main run loop. 507 RunLoop::main()->dispatch(bind(didFinishLaunchingProcessFunction, that, processIdentifier, CoreIPC::Connection::Identifier(listeningPort))); 508} 509 510void ProcessLauncher::launchProcess() 511{ 512 if (tryPreexistingProcess(m_launchOptions, this, &ProcessLauncher::didFinishLaunchingProcess)) 513 return; 514 515 bool isWebKitDevelopmentBuild = ![[[[NSBundle bundleWithIdentifier:@"com.apple.WebKit2"] bundlePath] stringByDeletingLastPathComponent] hasPrefix:@"/System/"]; 516 517#if HAVE(XPC) 518 if (m_launchOptions.useXPC) { 519 createService(m_launchOptions, isWebKitDevelopmentBuild, this, &ProcessLauncher::didFinishLaunchingProcess); 520 return; 521 } 522#endif 523 524 createProcess(m_launchOptions, isWebKitDevelopmentBuild, this, &ProcessLauncher::didFinishLaunchingProcess); 525} 526 527void ProcessLauncher::terminateProcess() 528{ 529 if (m_isLaunching) { 530 invalidate(); 531 return; 532 } 533 534 if (!m_processIdentifier) 535 return; 536 537 kill(m_processIdentifier, SIGKILL); 538 m_processIdentifier = 0; 539} 540 541void ProcessLauncher::platformInvalidate() 542{ 543} 544 545} // namespace WebKit 546