OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 #include "platform/globals.h" | 5 #include "platform/globals.h" |
6 #if defined(TARGET_OS_MACOS) | 6 #if defined(TARGET_OS_MACOS) |
7 | 7 |
8 #include "bin/process.h" | 8 #include "bin/process.h" |
9 | 9 |
10 #include <crt_externs.h> // NOLINT | 10 #include <crt_externs.h> // NOLINT |
(...skipping 219 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
230 | 230 |
231 | 231 |
232 class ProcessStarter { | 232 class ProcessStarter { |
233 public: | 233 public: |
234 ProcessStarter(const char* path, | 234 ProcessStarter(const char* path, |
235 char* arguments[], | 235 char* arguments[], |
236 intptr_t arguments_length, | 236 intptr_t arguments_length, |
237 const char* working_directory, | 237 const char* working_directory, |
238 char* environment[], | 238 char* environment[], |
239 intptr_t environment_length, | 239 intptr_t environment_length, |
240 bool detach, | 240 ProcessStartMode mode, |
241 intptr_t* in, | 241 intptr_t* in, |
242 intptr_t* out, | 242 intptr_t* out, |
243 intptr_t* err, | 243 intptr_t* err, |
244 intptr_t* id, | 244 intptr_t* id, |
245 intptr_t* exit_event, | 245 intptr_t* exit_event, |
246 char** os_error_message) | 246 char** os_error_message) |
247 : path_(path), | 247 : path_(path), |
248 working_directory_(working_directory), | 248 working_directory_(working_directory), |
249 detach_(detach), | 249 mode_(mode), |
250 in_(in), | 250 in_(in), |
251 out_(out), | 251 out_(out), |
252 err_(err), | 252 err_(err), |
253 id_(id), | 253 id_(id), |
254 exit_event_(exit_event), | 254 exit_event_(exit_event), |
255 os_error_message_(os_error_message) { | 255 os_error_message_(os_error_message) { |
256 read_in_[0] = -1; | 256 read_in_[0] = -1; |
257 read_in_[1] = -1; | 257 read_in_[1] = -1; |
258 read_err_[0] = -1; | 258 read_err_[0] = -1; |
259 read_err_[1] = -1; | 259 read_err_[1] = -1; |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
300 // This runs in the new process. | 300 // This runs in the new process. |
301 NewProcess(); | 301 NewProcess(); |
302 } | 302 } |
303 | 303 |
304 // This runs in the original process. | 304 // This runs in the original process. |
305 | 305 |
306 // Be sure to listen for exit-codes, now we have a child-process. | 306 // Be sure to listen for exit-codes, now we have a child-process. |
307 ExitCodeHandler::ProcessStarted(); | 307 ExitCodeHandler::ProcessStarted(); |
308 | 308 |
309 // Register the child process if not detached. | 309 // Register the child process if not detached. |
310 if (!detach_) { | 310 if (mode_ == kNormal) { |
311 err = RegisterProcess(pid); | 311 err = RegisterProcess(pid); |
312 if (err != 0) return err; | 312 if (err != 0) return err; |
313 } | 313 } |
314 | 314 |
315 // Notify child process to start. This is done to delay the call to exec | 315 // Notify child process to start. This is done to delay the call to exec |
316 // until the process is registered above, and we are ready to receive the | 316 // until the process is registered above, and we are ready to receive the |
317 // exit code. | 317 // exit code. |
318 char msg = '1'; | 318 char msg = '1'; |
319 int bytes_written = | 319 int bytes_written = |
320 FDUtils::WriteToBlocking(read_in_[1], &msg, sizeof(msg)); | 320 FDUtils::WriteToBlocking(read_in_[1], &msg, sizeof(msg)); |
321 if (bytes_written != sizeof(msg)) { | 321 if (bytes_written != sizeof(msg)) { |
322 return CleanupAndReturnError(); | 322 return CleanupAndReturnError(); |
323 } | 323 } |
324 | 324 |
325 // Read the result of executing the child process. | 325 // Read the result of executing the child process. |
326 VOID_TEMP_FAILURE_RETRY(close(exec_control_[1])); | 326 VOID_TEMP_FAILURE_RETRY(close(exec_control_[1])); |
327 exec_control_[1] = -1; | 327 exec_control_[1] = -1; |
328 if (!detach_) { | 328 if (mode_ == kNormal) { |
329 err = ReadExecResult(); | 329 err = ReadExecResult(); |
330 } else { | 330 } else { |
331 err = ReadDetachedExecResult(&pid); | 331 err = ReadDetachedExecResult(&pid); |
332 } | 332 } |
333 VOID_TEMP_FAILURE_RETRY(close(exec_control_[0])); | 333 VOID_TEMP_FAILURE_RETRY(close(exec_control_[0])); |
334 exec_control_[0] = -1; | 334 exec_control_[0] = -1; |
335 | 335 |
336 // Return error code if any failures. | 336 // Return error code if any failures. |
337 if (err != 0) { | 337 if (err != 0) { |
338 if (!detach_) { | 338 if (mode_ == kNormal) { |
339 // Since exec() failed, we're not interested in the exit code. | 339 // Since exec() failed, we're not interested in the exit code. |
340 // We close the reading side of the exit code pipe here. | 340 // We close the reading side of the exit code pipe here. |
341 // GetProcessExitCodes will get a broken pipe error when it | 341 // GetProcessExitCodes will get a broken pipe error when it |
342 // tries to write to the writing side of the pipe and it will | 342 // tries to write to the writing side of the pipe and it will |
343 // ignore the error. | 343 // ignore the error. |
344 VOID_TEMP_FAILURE_RETRY(close(*exit_event_)); | 344 VOID_TEMP_FAILURE_RETRY(close(*exit_event_)); |
345 *exit_event_ = -1; | 345 *exit_event_ = -1; |
346 } | 346 } |
347 CloseAllPipes(); | 347 CloseAllPipes(); |
348 return err; | 348 return err; |
349 } | 349 } |
350 | 350 |
351 if (!detach_) { | 351 if (mode_ != kDetached) { |
352 // Connect stdio, stdout and stderr. | 352 // Connect stdio, stdout and stderr. |
353 FDUtils::SetNonBlocking(read_in_[0]); | 353 FDUtils::SetNonBlocking(read_in_[0]); |
354 *in_ = read_in_[0]; | 354 *in_ = read_in_[0]; |
355 VOID_TEMP_FAILURE_RETRY(close(read_in_[1])); | 355 VOID_TEMP_FAILURE_RETRY(close(read_in_[1])); |
356 FDUtils::SetNonBlocking(write_out_[1]); | 356 FDUtils::SetNonBlocking(write_out_[1]); |
357 *out_ = write_out_[1]; | 357 *out_ = write_out_[1]; |
358 VOID_TEMP_FAILURE_RETRY(close(write_out_[0])); | 358 VOID_TEMP_FAILURE_RETRY(close(write_out_[0])); |
359 FDUtils::SetNonBlocking(read_err_[0]); | 359 FDUtils::SetNonBlocking(read_err_[0]); |
360 *err_ = read_err_[0]; | 360 *err_ = read_err_[0]; |
361 VOID_TEMP_FAILURE_RETRY(close(read_err_[1])); | 361 VOID_TEMP_FAILURE_RETRY(close(read_err_[1])); |
(...skipping 25 matching lines...) Expand all Loading... |
387 | 387 |
388 // For a detached process the pipe to connect stdout is still used for | 388 // For a detached process the pipe to connect stdout is still used for |
389 // signaling when to do the first fork. | 389 // signaling when to do the first fork. |
390 result = TEMP_FAILURE_RETRY(pipe(read_in_)); | 390 result = TEMP_FAILURE_RETRY(pipe(read_in_)); |
391 if (result < 0) { | 391 if (result < 0) { |
392 return CleanupAndReturnError(); | 392 return CleanupAndReturnError(); |
393 } | 393 } |
394 FDUtils::SetCloseOnExec(read_in_[0]); | 394 FDUtils::SetCloseOnExec(read_in_[0]); |
395 | 395 |
396 // For detached processes the pipe to connect stderr and stdin are not used. | 396 // For detached processes the pipe to connect stderr and stdin are not used. |
397 if (!detach_) { | 397 if (mode_ != kDetached) { |
398 result = TEMP_FAILURE_RETRY(pipe(read_err_)); | 398 result = TEMP_FAILURE_RETRY(pipe(read_err_)); |
399 if (result < 0) { | 399 if (result < 0) { |
400 return CleanupAndReturnError(); | 400 return CleanupAndReturnError(); |
401 } | 401 } |
402 FDUtils::SetCloseOnExec(read_err_[0]); | 402 FDUtils::SetCloseOnExec(read_err_[0]); |
403 | 403 |
404 result = TEMP_FAILURE_RETRY(pipe(write_out_)); | 404 result = TEMP_FAILURE_RETRY(pipe(write_out_)); |
405 if (result < 0) { | 405 if (result < 0) { |
406 return CleanupAndReturnError(); | 406 return CleanupAndReturnError(); |
407 } | 407 } |
408 FDUtils::SetCloseOnExec(write_out_[1]); | 408 FDUtils::SetCloseOnExec(write_out_[1]); |
409 } | 409 } |
410 | 410 |
411 return 0; | 411 return 0; |
412 } | 412 } |
413 | 413 |
414 | 414 |
415 void NewProcess() { | 415 void NewProcess() { |
416 // Wait for parent process before setting up the child process. | 416 // Wait for parent process before setting up the child process. |
417 char msg; | 417 char msg; |
418 int bytes_read = FDUtils::ReadFromBlocking(read_in_[0], &msg, sizeof(msg)); | 418 int bytes_read = FDUtils::ReadFromBlocking(read_in_[0], &msg, sizeof(msg)); |
419 if (bytes_read != sizeof(msg)) { | 419 if (bytes_read != sizeof(msg)) { |
420 perror("Failed receiving notification message"); | 420 perror("Failed receiving notification message"); |
421 exit(1); | 421 exit(1); |
422 } | 422 } |
423 if (detach_) { | 423 if (mode_ == kNormal) { |
| 424 ExecProcess(); |
| 425 } else { |
424 ExecDetachedProcess(); | 426 ExecDetachedProcess(); |
425 } else { | |
426 ExecProcess(); | |
427 } | 427 } |
428 } | 428 } |
429 | 429 |
430 | 430 |
431 void ExecProcess() { | 431 void ExecProcess() { |
432 VOID_TEMP_FAILURE_RETRY(close(write_out_[1])); | 432 VOID_TEMP_FAILURE_RETRY(close(write_out_[1])); |
433 VOID_TEMP_FAILURE_RETRY(close(read_in_[0])); | 433 VOID_TEMP_FAILURE_RETRY(close(read_in_[0])); |
434 VOID_TEMP_FAILURE_RETRY(close(read_err_[0])); | 434 VOID_TEMP_FAILURE_RETRY(close(read_err_[0])); |
435 VOID_TEMP_FAILURE_RETRY(close(exec_control_[0])); | 435 VOID_TEMP_FAILURE_RETRY(close(exec_control_[0])); |
436 | 436 |
(...skipping 25 matching lines...) Expand all Loading... |
462 } | 462 } |
463 | 463 |
464 VOID_TEMP_FAILURE_RETRY( | 464 VOID_TEMP_FAILURE_RETRY( |
465 execvp(path_, const_cast<char* const*>(program_arguments_))); | 465 execvp(path_, const_cast<char* const*>(program_arguments_))); |
466 | 466 |
467 ReportChildError(); | 467 ReportChildError(); |
468 } | 468 } |
469 | 469 |
470 | 470 |
471 void ExecDetachedProcess() { | 471 void ExecDetachedProcess() { |
472 ASSERT(write_out_[0] == -1); | 472 if (mode_ == kDetached) { |
473 ASSERT(write_out_[1] == -1); | 473 ASSERT(write_out_[0] == -1); |
474 ASSERT(read_err_[0] == -1); | 474 ASSERT(write_out_[1] == -1); |
475 ASSERT(read_err_[1] == -1); | 475 ASSERT(read_err_[0] == -1); |
476 // For a detached process the pipe to connect stdout is only used for | 476 ASSERT(read_err_[1] == -1); |
477 // signaling when to do the first fork. | 477 // For a detached process the pipe to connect stdout is only used for |
478 VOID_TEMP_FAILURE_RETRY(close(read_in_[0])); | 478 // signaling when to do the first fork. |
479 VOID_TEMP_FAILURE_RETRY(close(read_in_[1])); | 479 VOID_TEMP_FAILURE_RETRY(close(read_in_[0])); |
| 480 read_in_[0] = -1; |
| 481 VOID_TEMP_FAILURE_RETRY(close(read_in_[1])); |
| 482 read_in_[1] = -1; |
| 483 } else { |
| 484 // Don't close any fds if keeping stdio open to the detached process. |
| 485 ASSERT(mode_ == kDetachedWithStdio); |
| 486 } |
480 // Fork once more to start a new session. | 487 // Fork once more to start a new session. |
481 pid_t pid = TEMP_FAILURE_RETRY(fork()); | 488 pid_t pid = TEMP_FAILURE_RETRY(fork()); |
482 if (pid < 0) { | 489 if (pid < 0) { |
483 ReportChildError(); | 490 ReportChildError(); |
484 } else if (pid == 0) { | 491 } else if (pid == 0) { |
485 // Start a new session. | 492 // Start a new session. |
486 if (TEMP_FAILURE_RETRY(setsid()) == -1) { | 493 if (TEMP_FAILURE_RETRY(setsid()) == -1) { |
487 ReportChildError(); | 494 ReportChildError(); |
488 } else { | 495 } else { |
489 // Do a final fork to not be the session leader. | 496 // Do a final fork to not be the session leader. |
490 pid = TEMP_FAILURE_RETRY(fork()); | 497 pid = TEMP_FAILURE_RETRY(fork()); |
491 if (pid < 0) { | 498 if (pid < 0) { |
492 ReportChildError(); | 499 ReportChildError(); |
493 } else if (pid == 0) { | 500 } else if (pid == 0) { |
494 // Close all open file descriptors except for exec_control_[1]. | 501 if (mode_ == kDetached) { |
495 int max_fds = sysconf(_SC_OPEN_MAX); | 502 SetupDetached(); |
496 if (max_fds == -1) max_fds = _POSIX_OPEN_MAX; | 503 } else { |
497 for (int fd = 0; fd < max_fds; fd++) { | 504 SetupDetachedWithStdio(); |
498 if (fd != exec_control_[1]) { | |
499 VOID_TEMP_FAILURE_RETRY(close(fd)); | |
500 } | |
501 } | 505 } |
502 | 506 |
503 // Re-open stdin, stdout and stderr and connect them to /dev/null. | 507 if (working_directory_ != NULL && |
504 // The loop above should already have closed all of them, so | 508 TEMP_FAILURE_RETRY(chdir(working_directory_)) == -1) { |
505 // creating new file descriptors should start at STDIN_FILENO. | |
506 int fd = TEMP_FAILURE_RETRY(open("/dev/null", O_RDWR)); | |
507 if (fd != STDIN_FILENO) { | |
508 ReportChildError(); | |
509 } | |
510 if (TEMP_FAILURE_RETRY(dup2(STDIN_FILENO, STDOUT_FILENO)) != | |
511 STDOUT_FILENO) { | |
512 ReportChildError(); | |
513 } | |
514 if (TEMP_FAILURE_RETRY(dup2(STDIN_FILENO, STDERR_FILENO)) != | |
515 STDERR_FILENO) { | |
516 ReportChildError(); | 509 ReportChildError(); |
517 } | 510 } |
518 | 511 |
519 // Report the final PID and do the exec. | 512 // Report the final PID and do the exec. |
520 ReportPid(getpid()); // getpid cannot fail. | 513 ReportPid(getpid()); // getpid cannot fail. |
521 VOID_TEMP_FAILURE_RETRY( | 514 VOID_TEMP_FAILURE_RETRY( |
522 execvp(path_, const_cast<char* const*>(program_arguments_))); | 515 execvp(path_, const_cast<char* const*>(program_arguments_))); |
523 ReportChildError(); | 516 ReportChildError(); |
524 } else { | 517 } else { |
525 // Exit the intermeiate process. | 518 // Exit the intermeiate process. |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
586 child_errno = result[1]; | 579 child_errno = result[1]; |
587 ReadChildError(); | 580 ReadChildError(); |
588 return child_errno; | 581 return child_errno; |
589 } else if (bytes_read == -1) { | 582 } else if (bytes_read == -1) { |
590 return errno; | 583 return errno; |
591 } | 584 } |
592 return 0; | 585 return 0; |
593 } | 586 } |
594 | 587 |
595 | 588 |
| 589 void SetupDetached() { |
| 590 ASSERT(mode_ == kDetached); |
| 591 |
| 592 // Close all open file descriptors except for exec_control_[1]. |
| 593 int max_fds = sysconf(_SC_OPEN_MAX); |
| 594 if (max_fds == -1) max_fds = _POSIX_OPEN_MAX; |
| 595 for (int fd = 0; fd < max_fds; fd++) { |
| 596 if (fd != exec_control_[1]) { |
| 597 VOID_TEMP_FAILURE_RETRY(close(fd)); |
| 598 } |
| 599 } |
| 600 |
| 601 // Re-open stdin, stdout and stderr and connect them to /dev/null. |
| 602 // The loop above should already have closed all of them, so |
| 603 // creating new file descriptors should start at STDIN_FILENO. |
| 604 int fd = TEMP_FAILURE_RETRY(open("/dev/null", O_RDWR)); |
| 605 if (fd != STDIN_FILENO) { |
| 606 ReportChildError(); |
| 607 } |
| 608 if (TEMP_FAILURE_RETRY(dup2(STDIN_FILENO, STDOUT_FILENO)) != |
| 609 STDOUT_FILENO) { |
| 610 ReportChildError(); |
| 611 } |
| 612 if (TEMP_FAILURE_RETRY(dup2(STDIN_FILENO, STDERR_FILENO)) != |
| 613 STDERR_FILENO) { |
| 614 ReportChildError(); |
| 615 } |
| 616 } |
| 617 |
| 618 void SetupDetachedWithStdio() { |
| 619 // Close all open file descriptors except for |
| 620 // exec_control_[1], write_out_[0], read_in_[1] and |
| 621 // read_err_[1]. |
| 622 int max_fds = sysconf(_SC_OPEN_MAX); |
| 623 if (max_fds == -1) max_fds = _POSIX_OPEN_MAX; |
| 624 for (int fd = 0; fd < max_fds; fd++) { |
| 625 if (fd != exec_control_[1] && |
| 626 fd != write_out_[0] && |
| 627 fd != read_in_[1] && |
| 628 fd != read_err_[1]) { |
| 629 VOID_TEMP_FAILURE_RETRY(close(fd)); |
| 630 } |
| 631 } |
| 632 |
| 633 if (TEMP_FAILURE_RETRY(dup2(write_out_[0], STDIN_FILENO)) == -1) { |
| 634 ReportChildError(); |
| 635 } |
| 636 VOID_TEMP_FAILURE_RETRY(close(write_out_[0])); |
| 637 |
| 638 if (TEMP_FAILURE_RETRY(dup2(read_in_[1], STDOUT_FILENO)) == -1) { |
| 639 ReportChildError(); |
| 640 } |
| 641 VOID_TEMP_FAILURE_RETRY(close(read_in_[1])); |
| 642 |
| 643 if (TEMP_FAILURE_RETRY(dup2(read_err_[1], STDERR_FILENO)) == -1) { |
| 644 ReportChildError(); |
| 645 } |
| 646 VOID_TEMP_FAILURE_RETRY(close(read_err_[1])); |
| 647 } |
| 648 |
| 649 |
596 int CleanupAndReturnError() { | 650 int CleanupAndReturnError() { |
597 int actual_errno = errno; | 651 int actual_errno = errno; |
598 // If CleanupAndReturnError is called without an actual errno make | 652 // If CleanupAndReturnError is called without an actual errno make |
599 // sure to return an error anyway. | 653 // sure to return an error anyway. |
600 if (actual_errno == 0) actual_errno = EPERM; | 654 if (actual_errno == 0) actual_errno = EPERM; |
601 SetChildOsErrorMessage(); | 655 SetChildOsErrorMessage(); |
602 CloseAllPipes(); | 656 CloseAllPipes(); |
603 return actual_errno; | 657 return actual_errno; |
604 } | 658 } |
605 | 659 |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
676 int read_in_[2]; // Pipe for stdout to child process. | 730 int read_in_[2]; // Pipe for stdout to child process. |
677 int read_err_[2]; // Pipe for stderr to child process. | 731 int read_err_[2]; // Pipe for stderr to child process. |
678 int write_out_[2]; // Pipe for stdin to child process. | 732 int write_out_[2]; // Pipe for stdin to child process. |
679 int exec_control_[2]; // Pipe to get the result from exec. | 733 int exec_control_[2]; // Pipe to get the result from exec. |
680 | 734 |
681 char** program_arguments_; | 735 char** program_arguments_; |
682 char** program_environment_; | 736 char** program_environment_; |
683 | 737 |
684 const char* path_; | 738 const char* path_; |
685 const char* working_directory_; | 739 const char* working_directory_; |
686 bool detach_; | 740 ProcessStartMode mode_; |
687 intptr_t* in_; | 741 intptr_t* in_; |
688 intptr_t* out_; | 742 intptr_t* out_; |
689 intptr_t* err_; | 743 intptr_t* err_; |
690 intptr_t* id_; | 744 intptr_t* id_; |
691 intptr_t* exit_event_; | 745 intptr_t* exit_event_; |
692 char** os_error_message_; | 746 char** os_error_message_; |
693 }; | 747 }; |
694 | 748 |
695 | 749 |
696 int Process::Start(const char* path, | 750 int Process::Start(const char* path, |
697 char* arguments[], | 751 char* arguments[], |
698 intptr_t arguments_length, | 752 intptr_t arguments_length, |
699 const char* working_directory, | 753 const char* working_directory, |
700 char* environment[], | 754 char* environment[], |
701 intptr_t environment_length, | 755 intptr_t environment_length, |
702 bool detach, | 756 ProcessStartMode mode, |
703 intptr_t* in, | 757 intptr_t* in, |
704 intptr_t* out, | 758 intptr_t* out, |
705 intptr_t* err, | 759 intptr_t* err, |
706 intptr_t* id, | 760 intptr_t* id, |
707 intptr_t* exit_event, | 761 intptr_t* exit_event, |
708 char** os_error_message) { | 762 char** os_error_message) { |
709 ProcessStarter starter(path, | 763 ProcessStarter starter(path, |
710 arguments, | 764 arguments, |
711 arguments_length, | 765 arguments_length, |
712 working_directory, | 766 working_directory, |
713 environment, | 767 environment, |
714 environment_length, | 768 environment_length, |
715 detach, | 769 mode, |
716 in, | 770 in, |
717 out, | 771 out, |
718 err, | 772 err, |
719 id, | 773 id, |
720 exit_event, | 774 exit_event, |
721 os_error_message); | 775 os_error_message); |
722 return starter.Start(); | 776 return starter.Start(); |
723 } | 777 } |
724 | 778 |
725 | 779 |
(...skipping 283 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1009 bzero(&act, sizeof(act)); | 1063 bzero(&act, sizeof(act)); |
1010 act.sa_handler = SIG_DFL; | 1064 act.sa_handler = SIG_DFL; |
1011 VOID_NO_RETRY_EXPECTED(sigaction(signal, &act, NULL)); | 1065 VOID_NO_RETRY_EXPECTED(sigaction(signal, &act, NULL)); |
1012 } | 1066 } |
1013 } | 1067 } |
1014 | 1068 |
1015 } // namespace bin | 1069 } // namespace bin |
1016 } // namespace dart | 1070 } // namespace dart |
1017 | 1071 |
1018 #endif // defined(TARGET_OS_MACOS) | 1072 #endif // defined(TARGET_OS_MACOS) |
OLD | NEW |