| 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 |
| 11 #include <errno.h> // NOLINT | 11 #include <errno.h> // NOLINT |
| 12 #include <fcntl.h> // NOLINT | 12 #include <fcntl.h> // NOLINT |
| 13 #include <poll.h> // NOLINT | 13 #include <poll.h> // NOLINT |
| 14 #include <signal.h> // NOLINT | 14 #include <signal.h> // NOLINT |
| 15 #include <stdio.h> // NOLINT | 15 #include <stdio.h> // NOLINT |
| 16 #include <stdlib.h> // NOLINT | 16 #include <stdlib.h> // NOLINT |
| 17 #include <string.h> // NOLINT | 17 #include <string.h> // NOLINT |
| 18 #include <unistd.h> // NOLINT | 18 #include <unistd.h> // NOLINT |
| 19 | 19 |
| 20 #include "bin/fdutils.h" | 20 #include "bin/fdutils.h" |
| 21 #include "bin/lockers.h" | 21 #include "bin/lockers.h" |
| 22 #include "bin/log.h" | 22 #include "bin/log.h" |
| 23 #include "bin/thread.h" | 23 #include "bin/thread.h" |
| 24 | 24 |
| 25 #include "platform/signal_blocker.h" | 25 #include "platform/signal_blocker.h" |
| 26 | 26 |
| 27 | 27 |
| 28 | |
| 29 namespace dart { | 28 namespace dart { |
| 30 namespace bin { | 29 namespace bin { |
| 31 | 30 |
| 32 // ProcessInfo is used to map a process id to the file descriptor for | 31 // ProcessInfo is used to map a process id to the file descriptor for |
| 33 // the pipe used to communicate the exit code of the process to Dart. | 32 // the pipe used to communicate the exit code of the process to Dart. |
| 34 // ProcessInfo objects are kept in the static singly-linked | 33 // ProcessInfo objects are kept in the static singly-linked |
| 35 // ProcessInfoList. | 34 // ProcessInfoList. |
| 36 class ProcessInfo { | 35 class ProcessInfo { |
| 37 public: | 36 public: |
| 38 ProcessInfo(pid_t pid, intptr_t fd) : pid_(pid), fd_(fd) { } | 37 ProcessInfo(pid_t pid, intptr_t fd) : pid_(pid), fd_(fd) { } |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 146 if (!running_) { | 145 if (!running_) { |
| 147 return; | 146 return; |
| 148 } | 147 } |
| 149 | 148 |
| 150 // Set terminate_done_ to false, so we can use it as a guard for our | 149 // Set terminate_done_ to false, so we can use it as a guard for our |
| 151 // monitor. | 150 // monitor. |
| 152 running_ = false; | 151 running_ = false; |
| 153 | 152 |
| 154 // Fork to wake up waitpid. | 153 // Fork to wake up waitpid. |
| 155 if (TEMP_FAILURE_RETRY(fork()) == 0) { | 154 if (TEMP_FAILURE_RETRY(fork()) == 0) { |
| 156 exit(0); | 155 _exit(0); |
| 157 } | 156 } |
| 158 | 157 |
| 159 monitor_->Notify(); | 158 monitor_->Notify(); |
| 160 | 159 |
| 161 while (!terminate_done_) { | 160 while (!terminate_done_) { |
| 162 monitor_->Wait(Monitor::kNoTimeout); | 161 monitor_->Wait(Monitor::kNoTimeout); |
| 163 } | 162 } |
| 164 } | 163 } |
| 165 | 164 |
| 166 private: | 165 private: |
| (...skipping 247 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 414 return 0; | 413 return 0; |
| 415 } | 414 } |
| 416 | 415 |
| 417 | 416 |
| 418 void NewProcess() { | 417 void NewProcess() { |
| 419 // Wait for parent process before setting up the child process. | 418 // Wait for parent process before setting up the child process. |
| 420 char msg; | 419 char msg; |
| 421 int bytes_read = FDUtils::ReadFromBlocking(read_in_[0], &msg, sizeof(msg)); | 420 int bytes_read = FDUtils::ReadFromBlocking(read_in_[0], &msg, sizeof(msg)); |
| 422 if (bytes_read != sizeof(msg)) { | 421 if (bytes_read != sizeof(msg)) { |
| 423 perror("Failed receiving notification message"); | 422 perror("Failed receiving notification message"); |
| 424 exit(1); | 423 _exit(1); |
| 425 } | 424 } |
| 426 if (mode_ == kNormal) { | 425 if (mode_ == kNormal) { |
| 427 ExecProcess(); | 426 ExecProcess(); |
| 428 } else { | 427 } else { |
| 429 ExecDetachedProcess(); | 428 ExecDetachedProcess(); |
| 430 } | 429 } |
| 431 } | 430 } |
| 432 | 431 |
| 433 | 432 |
| 434 void ExecProcess() { | 433 void ExecProcess() { |
| 435 if (TEMP_FAILURE_RETRY(dup2(write_out_[0], STDIN_FILENO)) == -1) { | 434 if (TEMP_FAILURE_RETRY(dup2(write_out_[0], STDIN_FILENO)) == -1) { |
| 436 ReportChildError(); | 435 ReportChildError(); |
| 437 } | 436 } |
| 438 | 437 |
| 439 if (TEMP_FAILURE_RETRY(dup2(read_in_[1], STDOUT_FILENO)) == -1) { | 438 if (TEMP_FAILURE_RETRY(dup2(read_in_[1], STDOUT_FILENO)) == -1) { |
| 440 ReportChildError(); | 439 ReportChildError(); |
| 441 } | 440 } |
| 442 | 441 |
| 443 if (TEMP_FAILURE_RETRY(dup2(read_err_[1], STDERR_FILENO)) == -1) { | 442 if (TEMP_FAILURE_RETRY(dup2(read_err_[1], STDERR_FILENO)) == -1) { |
| 444 ReportChildError(); | 443 ReportChildError(); |
| 445 } | 444 } |
| 446 | 445 |
| 447 if (working_directory_ != NULL && | 446 if (working_directory_ != NULL && |
| 448 TEMP_FAILURE_RETRY(chdir(working_directory_)) == -1) { | 447 TEMP_FAILURE_RETRY(chdir(working_directory_)) == -1) { |
| 449 ReportChildError(); | 448 ReportChildError(); |
| 450 } | 449 } |
| 451 | 450 |
| 452 if (program_environment_ != NULL) { | 451 if (program_environment_ != NULL) { |
| 453 // On MacOS you have to do a bit of magic to get to the | 452 VOID_TEMP_FAILURE_RETRY( |
| 454 // environment strings. | 453 execvpe(path_, const_cast<char* const*>(program_arguments_), |
| 455 char*** environ = _NSGetEnviron(); | 454 program_environment_)); |
| 456 *environ = program_environment_; | 455 } else { |
| 456 VOID_TEMP_FAILURE_RETRY( |
| 457 execvp(path_, const_cast<char* const*>(program_arguments_))); |
| 457 } | 458 } |
| 458 | 459 |
| 459 VOID_TEMP_FAILURE_RETRY( | |
| 460 execvp(path_, const_cast<char* const*>(program_arguments_))); | |
| 461 | |
| 462 ReportChildError(); | 460 ReportChildError(); |
| 463 } | 461 } |
| 464 | 462 |
| 465 | 463 |
| 466 void ExecDetachedProcess() { | 464 void ExecDetachedProcess() { |
| 467 if (mode_ == kDetached) { | 465 if (mode_ == kDetached) { |
| 468 ASSERT(write_out_[0] == -1); | 466 ASSERT(write_out_[0] == -1); |
| 469 ASSERT(write_out_[1] == -1); | 467 ASSERT(write_out_[1] == -1); |
| 470 ASSERT(read_err_[0] == -1); | 468 ASSERT(read_err_[0] == -1); |
| 471 ASSERT(read_err_[1] == -1); | 469 ASSERT(read_err_[1] == -1); |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 503 TEMP_FAILURE_RETRY(chdir(working_directory_)) == -1) { | 501 TEMP_FAILURE_RETRY(chdir(working_directory_)) == -1) { |
| 504 ReportChildError(); | 502 ReportChildError(); |
| 505 } | 503 } |
| 506 | 504 |
| 507 // Report the final PID and do the exec. | 505 // Report the final PID and do the exec. |
| 508 ReportPid(getpid()); // getpid cannot fail. | 506 ReportPid(getpid()); // getpid cannot fail. |
| 509 VOID_TEMP_FAILURE_RETRY( | 507 VOID_TEMP_FAILURE_RETRY( |
| 510 execvp(path_, const_cast<char* const*>(program_arguments_))); | 508 execvp(path_, const_cast<char* const*>(program_arguments_))); |
| 511 ReportChildError(); | 509 ReportChildError(); |
| 512 } else { | 510 } else { |
| 513 // Exit the intermeiate process. | 511 // Exit the intermediate process. |
| 514 exit(0); | 512 _exit(0); |
| 515 } | 513 } |
| 516 } | 514 } |
| 517 } else { | 515 } else { |
| 518 // Exit the intermeiate process. | 516 // Exit the intermediate process. |
| 519 exit(0); | 517 _exit(0); |
| 520 } | 518 } |
| 521 } | 519 } |
| 522 | 520 |
| 523 | 521 |
| 524 int RegisterProcess(pid_t pid) { | 522 int RegisterProcess(pid_t pid) { |
| 525 int result; | 523 int result; |
| 526 int event_fds[2]; | 524 int event_fds[2]; |
| 527 result = TEMP_FAILURE_RETRY(pipe(event_fds)); | 525 result = TEMP_FAILURE_RETRY(pipe(event_fds)); |
| 528 if (result < 0) { | 526 if (result < 0) { |
| 529 return CleanupAndReturnError(); | 527 return CleanupAndReturnError(); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 541 int ReadExecResult() { | 539 int ReadExecResult() { |
| 542 int child_errno; | 540 int child_errno; |
| 543 int bytes_read = -1; | 541 int bytes_read = -1; |
| 544 // Read exec result from child. If no data is returned the exec was | 542 // Read exec result from child. If no data is returned the exec was |
| 545 // successful and the exec call closed the pipe. Otherwise the errno | 543 // successful and the exec call closed the pipe. Otherwise the errno |
| 546 // is written to the pipe. | 544 // is written to the pipe. |
| 547 bytes_read = | 545 bytes_read = |
| 548 FDUtils::ReadFromBlocking( | 546 FDUtils::ReadFromBlocking( |
| 549 exec_control_[0], &child_errno, sizeof(child_errno)); | 547 exec_control_[0], &child_errno, sizeof(child_errno)); |
| 550 if (bytes_read == sizeof(child_errno)) { | 548 if (bytes_read == sizeof(child_errno)) { |
| 551 ReadChildError(); | 549 SetOSErrorMessage(child_errno); |
| 552 return child_errno; | 550 return child_errno; |
| 553 } else if (bytes_read == -1) { | 551 } else if (bytes_read == -1) { |
| 554 return errno; | 552 return errno; |
| 555 } | 553 } |
| 556 return 0; | 554 return 0; |
| 557 } | 555 } |
| 558 | 556 |
| 559 | 557 |
| 560 int ReadDetachedExecResult(pid_t *pid) { | 558 int ReadDetachedExecResult(pid_t *pid) { |
| 561 int child_errno; | 559 int child_errno; |
| 562 int bytes_read = -1; | 560 int bytes_read = -1; |
| 563 // Read exec result from child. If only pid data is returned the exec was | 561 // Read exec result from child. If only pid data is returned the exec was |
| 564 // successful and the exec call closed the pipe. Otherwise the errno | 562 // successful and the exec call closed the pipe. Otherwise the errno |
| 565 // is written to the pipe as well. | 563 // is written to the pipe as well. |
| 566 int result[2]; | 564 int result[2]; |
| 567 bytes_read = | 565 bytes_read = |
| 568 FDUtils::ReadFromBlocking( | 566 FDUtils::ReadFromBlocking( |
| 569 exec_control_[0], result, sizeof(result)); | 567 exec_control_[0], result, sizeof(result)); |
| 570 if (bytes_read == sizeof(int)) { | 568 if (bytes_read == sizeof(int)) { |
| 571 *pid = result[0]; | 569 *pid = result[0]; |
| 572 } else if (bytes_read == 2 * sizeof(int)) { | 570 } else if (bytes_read == 2 * sizeof(int)) { |
| 573 *pid = result[0]; | 571 *pid = result[0]; |
| 574 child_errno = result[1]; | 572 child_errno = result[1]; |
| 575 ReadChildError(); | 573 SetOSErrorMessage(child_errno); |
| 576 return child_errno; | 574 return child_errno; |
| 577 } else if (bytes_read == -1) { | 575 } else if (bytes_read == -1) { |
| 578 return errno; | 576 return errno; |
| 579 } | 577 } |
| 580 return 0; | 578 return 0; |
| 581 } | 579 } |
| 582 | 580 |
| 583 | 581 |
| 584 void SetupDetached() { | 582 void SetupDetached() { |
| 585 ASSERT(mode_ == kDetached); | 583 ASSERT(mode_ == kDetached); |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 655 | 653 |
| 656 void SetChildOsErrorMessage() { | 654 void SetChildOsErrorMessage() { |
| 657 const int kBufferSize = 1024; | 655 const int kBufferSize = 1024; |
| 658 char error_message[kBufferSize]; | 656 char error_message[kBufferSize]; |
| 659 strerror_r(errno, error_message, kBufferSize); | 657 strerror_r(errno, error_message, kBufferSize); |
| 660 *os_error_message_ = strdup(error_message); | 658 *os_error_message_ = strdup(error_message); |
| 661 } | 659 } |
| 662 | 660 |
| 663 | 661 |
| 664 void ReportChildError() { | 662 void ReportChildError() { |
| 665 // In the case of failure in the child process write the errno and | 663 // In the case of failure in the child process write the errno to the exec |
| 666 // the OS error message to the exec control pipe and exit. | 664 // control pipe and exit. |
| 667 int child_errno = errno; | 665 int child_errno = errno; |
| 668 const int kBufferSize = 1024; | 666 FDUtils::WriteToBlocking( |
| 669 char os_error_message[kBufferSize]; | 667 exec_control_[1], &child_errno, sizeof(child_errno)); |
| 670 strerror_r(errno, os_error_message, kBufferSize); | 668 _exit(1); |
| 671 int bytes_written = | |
| 672 FDUtils::WriteToBlocking( | |
| 673 exec_control_[1], &child_errno, sizeof(child_errno)); | |
| 674 if (bytes_written == sizeof(child_errno)) { | |
| 675 FDUtils::WriteToBlocking( | |
| 676 exec_control_[1], os_error_message, strlen(os_error_message) + 1); | |
| 677 } | |
| 678 VOID_TEMP_FAILURE_RETRY(close(exec_control_[1])); | |
| 679 exit(1); | |
| 680 } | 669 } |
| 681 | 670 |
| 682 | 671 |
| 683 void ReportPid(int pid) { | 672 void ReportPid(int pid) { |
| 684 // In the case of starting a detached process the actual pid of that process | 673 // In the case of starting a detached process the actual pid of that process |
| 685 // is communicated using the exec control pipe. | 674 // is communicated using the exec control pipe. |
| 686 int bytes_written = | 675 int bytes_written = |
| 687 FDUtils::WriteToBlocking(exec_control_[1], &pid, sizeof(pid)); | 676 FDUtils::WriteToBlocking(exec_control_[1], &pid, sizeof(pid)); |
| 688 ASSERT(bytes_written == sizeof(int)); | 677 ASSERT(bytes_written == sizeof(int)); |
| 689 USE(bytes_written); | 678 USE(bytes_written); |
| 690 } | 679 } |
| 691 | 680 |
| 692 | 681 |
| 693 void ReadChildError() { | 682 void SetOSErrorMessage(int child_errno) { |
| 694 const int kMaxMessageSize = 256; | 683 const int kMaxMessageSize = 256; |
| 695 char* message = static_cast<char*>(malloc(kMaxMessageSize)); | 684 char* message = static_cast<char*>(calloc(kMaxMessageSize, 0)); |
| 696 if (message != NULL) { | 685 char* os_error_message = strerror_r( |
| 697 FDUtils::ReadFromBlocking(exec_control_[0], message, kMaxMessageSize); | 686 child_errno, message, kMaxMessageSize - 1); |
| 698 message[kMaxMessageSize - 1] = '\0'; | 687 if (message == os_error_message) { |
| 699 *os_error_message_ = message; | 688 *os_error_message_ = message; |
| 700 } else { | 689 } else { |
| 701 // Could not get error message. It will be NULL. | 690 free(message); |
| 702 ASSERT(*os_error_message_ == NULL); | 691 *os_error_message_ = strdup(os_error_message); |
| 703 } | 692 } |
| 704 } | 693 } |
| 705 | 694 |
| 706 | 695 |
| 707 void ClosePipe(int* fds) { | 696 void ClosePipe(int* fds) { |
| 708 for (int i = 0; i < 2; i++) { | 697 for (int i = 0; i < 2; i++) { |
| 709 if (fds[i] != -1) { | 698 if (fds[i] != -1) { |
| 710 VOID_TEMP_FAILURE_RETRY(close(fds[i])); | 699 VOID_TEMP_FAILURE_RETRY(close(fds[i])); |
| 711 fds[i] = -1; | 700 fds[i] = -1; |
| 712 } | 701 } |
| (...skipping 345 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1058 bzero(&act, sizeof(act)); | 1047 bzero(&act, sizeof(act)); |
| 1059 act.sa_handler = SIG_DFL; | 1048 act.sa_handler = SIG_DFL; |
| 1060 VOID_NO_RETRY_EXPECTED(sigaction(signal, &act, NULL)); | 1049 VOID_NO_RETRY_EXPECTED(sigaction(signal, &act, NULL)); |
| 1061 } | 1050 } |
| 1062 } | 1051 } |
| 1063 | 1052 |
| 1064 } // namespace bin | 1053 } // namespace bin |
| 1065 } // namespace dart | 1054 } // namespace dart |
| 1066 | 1055 |
| 1067 #endif // defined(TARGET_OS_MACOS) | 1056 #endif // defined(TARGET_OS_MACOS) |
| OLD | NEW |