| OLD | NEW |
| 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include <dirent.h> | 5 #include <dirent.h> |
| 6 #include <errno.h> | 6 #include <errno.h> |
| 7 #include <fcntl.h> | 7 #include <fcntl.h> |
| 8 #include <signal.h> | 8 #include <signal.h> |
| 9 #include <stdlib.h> | 9 #include <stdlib.h> |
| 10 #include <sys/resource.h> | 10 #include <sys/resource.h> |
| 11 #include <sys/time.h> | 11 #include <sys/time.h> |
| 12 #include <sys/types.h> | 12 #include <sys/types.h> |
| 13 #include <sys/wait.h> | 13 #include <sys/wait.h> |
| 14 #include <unistd.h> | 14 #include <unistd.h> |
| 15 | 15 |
| 16 #include <limits> | 16 #include <limits> |
| 17 #include <set> | 17 #include <set> |
| 18 | 18 |
| 19 #include "base/debug_util.h" | 19 #include "base/debug_util.h" |
| 20 #include "base/eintr_wrapper.h" | 20 #include "base/eintr_wrapper.h" |
| 21 #include "base/logging.h" | 21 #include "base/logging.h" |
| 22 #include "base/platform_thread.h" | 22 #include "base/platform_thread.h" |
| 23 #include "base/process_util.h" | 23 #include "base/process_util.h" |
| 24 #include "base/scoped_ptr.h" | 24 #include "base/scoped_ptr.h" |
| 25 #include "base/sys_info.h" | 25 #include "base/sys_info.h" |
| 26 #include "base/time.h" | 26 #include "base/time.h" |
| 27 #include "base/waitable_event.h" | 27 #include "base/waitable_event.h" |
| 28 | 28 |
| 29 #if defined(OS_MACOSX) | |
| 30 #include "base/mach_broker_mac.h" | |
| 31 | |
| 32 | |
| 33 #endif | |
| 34 | |
| 35 const int kMicrosecondsPerSecond = 1000000; | 29 const int kMicrosecondsPerSecond = 1000000; |
| 36 | 30 |
| 37 namespace base { | 31 namespace base { |
| 38 | 32 |
| 39 namespace { | 33 namespace { |
| 40 | 34 |
| 41 int WaitpidWithTimeout(ProcessHandle handle, int64 wait_milliseconds, | 35 int WaitpidWithTimeout(ProcessHandle handle, int64 wait_milliseconds, |
| 42 bool* success) { | 36 bool* success) { |
| 43 // This POSIX version of this function only guarantees that we wait no less | 37 // This POSIX version of this function only guarantees that we wait no less |
| 44 // than |wait_milliseconds| for the proces to exit. The child process may | 38 // than |wait_milliseconds| for the proces to exit. The child process may |
| (...skipping 234 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 279 if (i <= STDERR_FILENO) | 273 if (i <= STDERR_FILENO) |
| 280 continue; | 274 continue; |
| 281 | 275 |
| 282 int flags = fcntl(i, F_GETFD); | 276 int flags = fcntl(i, F_GETFD); |
| 283 if ((flags == -1) || (fcntl(i, F_SETFD, flags | FD_CLOEXEC) == -1)) { | 277 if ((flags == -1) || (fcntl(i, F_SETFD, flags | FD_CLOEXEC) == -1)) { |
| 284 DLOG(ERROR) << "fcntl failure."; | 278 DLOG(ERROR) << "fcntl failure."; |
| 285 } | 279 } |
| 286 } | 280 } |
| 287 } | 281 } |
| 288 | 282 |
| 289 #if defined(OS_MACOSX) | |
| 290 | |
| 291 #define CHECK_MACH_ERROR(err, s) \ | |
| 292 do { \ | |
| 293 if (err != KERN_SUCCESS) { \ | |
| 294 fprintf(stderr, "%s 0x%x", s, (int)err); \ | |
| 295 exit(1); \ | |
| 296 } \ | |
| 297 } while (0) | |
| 298 | |
| 299 static int | |
| 300 setup_recv_port (mach_port_t *recv_port) | |
| 301 { | |
| 302 kern_return_t err; | |
| 303 mach_port_t port = MACH_PORT_NULL; | |
| 304 err = mach_port_allocate (mach_task_self (), | |
| 305 MACH_PORT_RIGHT_RECEIVE, &port); | |
| 306 CHECK_MACH_ERROR (err, "mach_port_allocate failed:"); | |
| 307 | |
| 308 err = mach_port_insert_right (mach_task_self (), | |
| 309 port, | |
| 310 port, | |
| 311 MACH_MSG_TYPE_MAKE_SEND); | |
| 312 CHECK_MACH_ERROR (err, "mach_port_insert_right failed:"); | |
| 313 | |
| 314 *recv_port = port; | |
| 315 return 0; | |
| 316 } | |
| 317 | |
| 318 static int | |
| 319 send_port (mach_port_t remote_port, mach_port_t port) | |
| 320 { | |
| 321 kern_return_t err; | |
| 322 | |
| 323 struct { | |
| 324 mach_msg_header_t header; | |
| 325 mach_msg_body_t body; | |
| 326 mach_msg_port_descriptor_t task_port; | |
| 327 } msg; | |
| 328 | |
| 329 msg.header.msgh_remote_port = remote_port; | |
| 330 msg.header.msgh_local_port = MACH_PORT_NULL; | |
| 331 msg.header.msgh_bits = MACH_MSGH_BITS (MACH_MSG_TYPE_COPY_SEND, 0) | | |
| 332 MACH_MSGH_BITS_COMPLEX; | |
| 333 msg.header.msgh_size = sizeof msg; | |
| 334 | |
| 335 msg.body.msgh_descriptor_count = 1; | |
| 336 msg.task_port.name = port; | |
| 337 msg.task_port.disposition = MACH_MSG_TYPE_COPY_SEND; | |
| 338 msg.task_port.type = MACH_MSG_PORT_DESCRIPTOR; | |
| 339 | |
| 340 err = mach_msg_send (&msg.header); | |
| 341 CHECK_MACH_ERROR (err, "mach_msg_send failed:"); | |
| 342 | |
| 343 return 0; | |
| 344 } | |
| 345 | |
| 346 static int | |
| 347 recv_port (mach_port_t recv_port, mach_port_t *port) | |
| 348 { | |
| 349 kern_return_t err; | |
| 350 struct { | |
| 351 mach_msg_header_t header; | |
| 352 mach_msg_body_t body; | |
| 353 mach_msg_port_descriptor_t task_port; | |
| 354 mach_msg_trailer_t trailer; | |
| 355 } msg; | |
| 356 | |
| 357 err = mach_msg (&msg.header, MACH_RCV_MSG, | |
| 358 0, sizeof msg, recv_port, | |
| 359 MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); | |
| 360 CHECK_MACH_ERROR (err, "mach_msg failed:"); | |
| 361 | |
| 362 *port = msg.task_port.name; | |
| 363 return 0; | |
| 364 } | |
| 365 | |
| 366 static task_t child_task = MACH_PORT_NULL; | |
| 367 | |
| 368 pid_t | |
| 369 sampling_fork () | |
| 370 { | |
| 371 kern_return_t err; | |
| 372 mach_port_t parent_recv_port = MACH_PORT_NULL; | |
| 373 mach_port_t child_recv_port = MACH_PORT_NULL; | |
| 374 | |
| 375 if (setup_recv_port (&parent_recv_port) != 0) | |
| 376 return -1; | |
| 377 err = task_set_bootstrap_port (mach_task_self (), parent_recv_port); | |
| 378 CHECK_MACH_ERROR (err, "task_set_bootstrap_port failed:"); | |
| 379 | |
| 380 pid_t pid; | |
| 381 switch (pid = fork ()) { | |
| 382 case -1: | |
| 383 err = mach_port_deallocate (mach_task_self(), parent_recv_port); | |
| 384 CHECK_MACH_ERROR (err, "mach_port_deallocate failed:"); | |
| 385 return pid; | |
| 386 case 0: /* child */ | |
| 387 err = task_get_bootstrap_port (mach_task_self (), &parent_recv_port); | |
| 388 CHECK_MACH_ERROR (err, "task_get_bootstrap_port failed:"); | |
| 389 if (setup_recv_port (&child_recv_port) != 0) | |
| 390 return -1; | |
| 391 if (send_port (parent_recv_port, mach_task_self ()) != 0) | |
| 392 return -1; | |
| 393 if (send_port (parent_recv_port, child_recv_port) != 0) | |
| 394 return -1; | |
| 395 if (recv_port (child_recv_port, &bootstrap_port) != 0) | |
| 396 return -1; | |
| 397 err = task_set_bootstrap_port (mach_task_self (), bootstrap_port); | |
| 398 CHECK_MACH_ERROR (err, "task_set_bootstrap_port failed:"); | |
| 399 break; | |
| 400 default: /* parent */ | |
| 401 err = task_set_bootstrap_port (mach_task_self (), bootstrap_port); | |
| 402 CHECK_MACH_ERROR (err, "task_set_bootstrap_port failed:"); | |
| 403 if (recv_port (parent_recv_port, &child_task) != 0) | |
| 404 return -1; | |
| 405 if (recv_port (parent_recv_port, &child_recv_port) != 0) | |
| 406 return -1; | |
| 407 if (send_port (child_recv_port, bootstrap_port) != 0) | |
| 408 return -1; | |
| 409 err = mach_port_deallocate (mach_task_self(), parent_recv_port); | |
| 410 CHECK_MACH_ERROR (err, "mach_port_deallocate failed:"); | |
| 411 break; | |
| 412 } | |
| 413 | |
| 414 return pid; | |
| 415 } | |
| 416 #endif | |
| 417 | |
| 418 bool LaunchApp(const std::vector<std::string>& argv, | 283 bool LaunchApp(const std::vector<std::string>& argv, |
| 419 const environment_vector& environ, | 284 const environment_vector& environ, |
| 420 const file_handle_mapping_vector& fds_to_remap, | 285 const file_handle_mapping_vector& fds_to_remap, |
| 421 bool wait, ProcessHandle* process_handle) { | 286 bool wait, ProcessHandle* process_handle) { |
| 422 #if defined(OS_MACOSX) | |
| 423 // Needs to be mutexed! :-( | |
| 424 pid_t pid = sampling_fork(); | |
| 425 MachBroker::instance()->RegisterPid( | |
| 426 pid, | |
| 427 MachBroker::MachInfo().SetTask(child_task)); | |
| 428 #else | |
| 429 pid_t pid = fork(); | 287 pid_t pid = fork(); |
| 430 #endif | |
| 431 if (pid < 0) | 288 if (pid < 0) |
| 432 return false; | 289 return false; |
| 433 | 290 |
| 434 if (pid == 0) { | 291 if (pid == 0) { |
| 435 // Child process | 292 // Child process |
| 436 #if defined(OS_MACOSX) | 293 #if defined(OS_MACOSX) |
| 437 RestoreDefaultExceptionHandler(); | 294 RestoreDefaultExceptionHandler(); |
| 438 #endif | 295 #endif |
| 439 | 296 |
| 440 InjectiveMultimap fd_shuffle; | 297 InjectiveMultimap fd_shuffle; |
| (...skipping 379 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 820 const ProcessFilter* filter) { | 677 const ProcessFilter* filter) { |
| 821 bool exited_cleanly = | 678 bool exited_cleanly = |
| 822 WaitForProcessesToExit(executable_name, wait_milliseconds, | 679 WaitForProcessesToExit(executable_name, wait_milliseconds, |
| 823 filter); | 680 filter); |
| 824 if (!exited_cleanly) | 681 if (!exited_cleanly) |
| 825 KillProcesses(executable_name, exit_code, filter); | 682 KillProcesses(executable_name, exit_code, filter); |
| 826 return exited_cleanly; | 683 return exited_cleanly; |
| 827 } | 684 } |
| 828 | 685 |
| 829 } // namespace base | 686 } // namespace base |
| OLD | NEW |