Chromium Code Reviews| 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_LINUX) | 6 #if defined(TARGET_OS_LINUX) |
| 7 | 7 |
| 8 #include "bin/process.h" | 8 #include "bin/process.h" |
| 9 | 9 |
| 10 #include <errno.h> // NOLINT | 10 #include <errno.h> // NOLINT |
| 11 #include <fcntl.h> // NOLINT | 11 #include <fcntl.h> // NOLINT |
| 12 #include <poll.h> // NOLINT | 12 #include <poll.h> // NOLINT |
| 13 #include <stdio.h> // NOLINT | 13 #include <stdio.h> // NOLINT |
| 14 #include <stdlib.h> // NOLINT | 14 #include <stdlib.h> // NOLINT |
| 15 #include <string.h> // NOLINT | 15 #include <string.h> // NOLINT |
| 16 #include <sys/wait.h> // NOLINT | 16 #include <sys/wait.h> // NOLINT |
| 17 #include <unistd.h> // NOLINT | 17 #include <unistd.h> // NOLINT |
| 18 | 18 |
| 19 #include "platform/signal_blocker.h" | 19 #include "platform/signal_blocker.h" |
| 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 | 25 |
| 26 extern char **environ; | |
| 27 | |
| 28 | |
| 29 namespace dart { | 26 namespace dart { |
| 30 namespace bin { | 27 namespace bin { |
| 31 | 28 |
| 32 // ProcessInfo is used to map a process id to the file descriptor for | 29 // 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. | 30 // the pipe used to communicate the exit code of the process to Dart. |
| 34 // ProcessInfo objects are kept in the static singly-linked | 31 // ProcessInfo objects are kept in the static singly-linked |
| 35 // ProcessInfoList. | 32 // ProcessInfoList. |
| 36 class ProcessInfo { | 33 class ProcessInfo { |
| 37 public: | 34 public: |
| 38 ProcessInfo(pid_t pid, intptr_t fd) : pid_(pid), fd_(fd) { } | 35 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_) { | 143 if (!running_) { |
| 147 return; | 144 return; |
| 148 } | 145 } |
| 149 | 146 |
| 150 // Set terminate_done_ to false, so we can use it as a guard for our | 147 // Set terminate_done_ to false, so we can use it as a guard for our |
| 151 // monitor. | 148 // monitor. |
| 152 running_ = false; | 149 running_ = false; |
| 153 | 150 |
| 154 // Fork to wake up waitpid. | 151 // Fork to wake up waitpid. |
| 155 if (TEMP_FAILURE_RETRY(fork()) == 0) { | 152 if (TEMP_FAILURE_RETRY(fork()) == 0) { |
| 156 exit(0); | 153 _exit(0); |
| 157 } | 154 } |
| 158 | 155 |
| 159 monitor_->Notify(); | 156 monitor_->Notify(); |
| 160 | 157 |
| 161 while (!terminate_done_) { | 158 while (!terminate_done_) { |
| 162 monitor_->Wait(Monitor::kNoTimeout); | 159 monitor_->Wait(Monitor::kNoTimeout); |
| 163 } | 160 } |
| 164 } | 161 } |
| 165 | 162 |
| 166 private: | 163 private: |
| (...skipping 239 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 406 return 0; | 403 return 0; |
| 407 } | 404 } |
| 408 | 405 |
| 409 | 406 |
| 410 void NewProcess() { | 407 void NewProcess() { |
| 411 // Wait for parent process before setting up the child process. | 408 // Wait for parent process before setting up the child process. |
| 412 char msg; | 409 char msg; |
| 413 int bytes_read = FDUtils::ReadFromBlocking(read_in_[0], &msg, sizeof(msg)); | 410 int bytes_read = FDUtils::ReadFromBlocking(read_in_[0], &msg, sizeof(msg)); |
| 414 if (bytes_read != sizeof(msg)) { | 411 if (bytes_read != sizeof(msg)) { |
| 415 perror("Failed receiving notification message"); | 412 perror("Failed receiving notification message"); |
| 416 exit(1); | 413 _exit(1); |
|
Søren Gjesse
2015/06/10 07:20:25
Good catch!
| |
| 417 } | 414 } |
| 418 if (mode_ == kNormal) { | 415 if (mode_ == kNormal) { |
| 419 ExecProcess(); | 416 ExecProcess(); |
| 420 } else { | 417 } else { |
| 421 ExecDetachedProcess(); | 418 ExecDetachedProcess(); |
| 422 } | 419 } |
| 423 } | 420 } |
| 424 | 421 |
| 425 | 422 |
| 426 void ExecProcess() { | 423 void ExecProcess() { |
| 427 if (TEMP_FAILURE_RETRY(dup2(write_out_[0], STDIN_FILENO)) == -1) { | 424 if (TEMP_FAILURE_RETRY(dup2(write_out_[0], STDIN_FILENO)) == -1) { |
| 428 ReportChildError(); | 425 ReportChildError(); |
| 429 } | 426 } |
| 430 | 427 |
| 431 if (TEMP_FAILURE_RETRY(dup2(read_in_[1], STDOUT_FILENO)) == -1) { | 428 if (TEMP_FAILURE_RETRY(dup2(read_in_[1], STDOUT_FILENO)) == -1) { |
| 432 ReportChildError(); | 429 ReportChildError(); |
| 433 } | 430 } |
| 434 | 431 |
| 435 if (TEMP_FAILURE_RETRY(dup2(read_err_[1], STDERR_FILENO)) == -1) { | 432 if (TEMP_FAILURE_RETRY(dup2(read_err_[1], STDERR_FILENO)) == -1) { |
| 436 ReportChildError(); | 433 ReportChildError(); |
| 437 } | 434 } |
| 438 | 435 |
| 439 if (working_directory_ != NULL && | 436 if (working_directory_ != NULL && |
| 440 TEMP_FAILURE_RETRY(chdir(working_directory_)) == -1) { | 437 TEMP_FAILURE_RETRY(chdir(working_directory_)) == -1) { |
| 441 ReportChildError(); | 438 ReportChildError(); |
| 442 } | 439 } |
| 443 | 440 |
| 444 if (program_environment_ != NULL) { | 441 if (program_environment_ != NULL) { |
| 445 environ = program_environment_; | 442 VOID_TEMP_FAILURE_RETRY( |
| 443 execvpe(path_, const_cast<char* const*>(program_arguments_), | |
| 444 program_environment_)); | |
| 445 } else { | |
| 446 VOID_TEMP_FAILURE_RETRY( | |
| 447 execvp(path_, const_cast<char* const*>(program_arguments_))); | |
| 446 } | 448 } |
| 447 | 449 |
| 448 VOID_TEMP_FAILURE_RETRY( | |
| 449 execvp(path_, const_cast<char* const*>(program_arguments_))); | |
| 450 | 450 |
| 451 ReportChildError(); | 451 ReportChildError(); |
| 452 } | 452 } |
| 453 | 453 |
| 454 | 454 |
| 455 void ExecDetachedProcess() { | 455 void ExecDetachedProcess() { |
| 456 if (mode_ == kDetached) { | 456 if (mode_ == kDetached) { |
| 457 ASSERT(write_out_[0] == -1); | 457 ASSERT(write_out_[0] == -1); |
| 458 ASSERT(write_out_[1] == -1); | 458 ASSERT(write_out_[1] == -1); |
| 459 ASSERT(read_err_[0] == -1); | 459 ASSERT(read_err_[0] == -1); |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 492 TEMP_FAILURE_RETRY(chdir(working_directory_)) == -1) { | 492 TEMP_FAILURE_RETRY(chdir(working_directory_)) == -1) { |
| 493 ReportChildError(); | 493 ReportChildError(); |
| 494 } | 494 } |
| 495 | 495 |
| 496 // Report the final PID and do the exec. | 496 // Report the final PID and do the exec. |
| 497 ReportPid(getpid()); // getpid cannot fail. | 497 ReportPid(getpid()); // getpid cannot fail. |
| 498 VOID_TEMP_FAILURE_RETRY( | 498 VOID_TEMP_FAILURE_RETRY( |
| 499 execvp(path_, const_cast<char* const*>(program_arguments_))); | 499 execvp(path_, const_cast<char* const*>(program_arguments_))); |
| 500 ReportChildError(); | 500 ReportChildError(); |
| 501 } else { | 501 } else { |
| 502 // Exit the intermeiate process. | 502 // Exit the intermeiate process. |
|
Søren Gjesse
2015/06/10 07:20:25
Not you fault, but please change
intermeiate -> i
Anders Johnsen
2015/06/10 08:00:45
Done.
| |
| 503 exit(0); | 503 _exit(0); |
| 504 } | 504 } |
| 505 } | 505 } |
| 506 } else { | 506 } else { |
| 507 // Exit the intermeiate process. | 507 // Exit the intermeiate process. |
|
Søren Gjesse
2015/06/10 07:20:25
ditto.
Anders Johnsen
2015/06/10 08:00:45
Done.
| |
| 508 exit(0); | 508 _exit(0); |
| 509 } | 509 } |
| 510 } | 510 } |
| 511 | 511 |
| 512 | 512 |
| 513 int RegisterProcess(pid_t pid) { | 513 int RegisterProcess(pid_t pid) { |
| 514 int result; | 514 int result; |
| 515 int event_fds[2]; | 515 int event_fds[2]; |
| 516 result = TEMP_FAILURE_RETRY(pipe2(event_fds, O_CLOEXEC)); | 516 result = TEMP_FAILURE_RETRY(pipe2(event_fds, O_CLOEXEC)); |
| 517 if (result < 0) { | 517 if (result < 0) { |
| 518 return CleanupAndReturnError(); | 518 return CleanupAndReturnError(); |
| 519 } | 519 } |
| 520 | 520 |
| 521 ProcessInfoList::AddProcess(pid, event_fds[1]); | 521 ProcessInfoList::AddProcess(pid, event_fds[1]); |
| 522 *exit_event_ = event_fds[0]; | 522 *exit_event_ = event_fds[0]; |
| 523 FDUtils::SetNonBlocking(event_fds[0]); | 523 FDUtils::SetNonBlocking(event_fds[0]); |
| 524 return 0; | 524 return 0; |
| 525 } | 525 } |
| 526 | 526 |
| 527 | 527 |
| 528 int ReadExecResult() { | 528 int ReadExecResult() { |
| 529 int child_errno; | 529 int child_errno; |
| 530 int bytes_read = -1; | 530 int bytes_read = -1; |
| 531 // Read exec result from child. If no data is returned the exec was | 531 // Read exec result from child. If no data is returned the exec was |
| 532 // successful and the exec call closed the pipe. Otherwise the errno | 532 // successful and the exec call closed the pipe. Otherwise the errno |
| 533 // is written to the pipe. | 533 // is written to the pipe. |
| 534 bytes_read = | 534 bytes_read = |
| 535 FDUtils::ReadFromBlocking( | 535 FDUtils::ReadFromBlocking( |
| 536 exec_control_[0], &child_errno, sizeof(child_errno)); | 536 exec_control_[0], &child_errno, sizeof(child_errno)); |
| 537 if (bytes_read == sizeof(child_errno)) { | 537 if (bytes_read == sizeof(child_errno)) { |
| 538 ReadChildError(); | 538 ReadChildError(child_errno); |
| 539 return child_errno; | 539 return child_errno; |
| 540 } else if (bytes_read == -1) { | 540 } else if (bytes_read == -1) { |
| 541 return errno; | 541 return errno; |
| 542 } | 542 } |
| 543 return 0; | 543 return 0; |
| 544 } | 544 } |
| 545 | 545 |
| 546 | 546 |
| 547 int ReadDetachedExecResult(pid_t *pid) { | 547 int ReadDetachedExecResult(pid_t *pid) { |
| 548 int child_errno; | 548 int child_errno; |
| 549 int bytes_read = -1; | 549 int bytes_read = -1; |
| 550 // Read exec result from child. If only pid data is returned the exec was | 550 // Read exec result from child. If only pid data is returned the exec was |
| 551 // successful and the exec call closed the pipe. Otherwise the errno | 551 // successful and the exec call closed the pipe. Otherwise the errno |
| 552 // is written to the pipe as well. | 552 // is written to the pipe as well. |
| 553 int result[2]; | 553 int result[2]; |
| 554 bytes_read = | 554 bytes_read = |
| 555 FDUtils::ReadFromBlocking( | 555 FDUtils::ReadFromBlocking( |
| 556 exec_control_[0], result, sizeof(result)); | 556 exec_control_[0], result, sizeof(result)); |
| 557 if (bytes_read == sizeof(int)) { | 557 if (bytes_read == sizeof(int)) { |
| 558 *pid = result[0]; | 558 *pid = result[0]; |
| 559 } else if (bytes_read == 2 * sizeof(int)) { | 559 } else if (bytes_read == 2 * sizeof(int)) { |
| 560 *pid = result[0]; | 560 *pid = result[0]; |
| 561 child_errno = result[1]; | 561 child_errno = result[1]; |
| 562 ReadChildError(); | 562 ReadChildError(child_errno); |
| 563 return child_errno; | 563 return child_errno; |
| 564 } else if (bytes_read == -1) { | 564 } else if (bytes_read == -1) { |
| 565 return errno; | 565 return errno; |
| 566 } | 566 } |
| 567 return 0; | 567 return 0; |
| 568 } | 568 } |
| 569 | 569 |
| 570 | 570 |
| 571 void SetupDetached() { | 571 void SetupDetached() { |
| 572 ASSERT(mode_ == kDetached); | 572 ASSERT(mode_ == kDetached); |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 641 | 641 |
| 642 | 642 |
| 643 void SetChildOsErrorMessage() { | 643 void SetChildOsErrorMessage() { |
| 644 const int kBufferSize = 1024; | 644 const int kBufferSize = 1024; |
| 645 char error_buf[kBufferSize]; | 645 char error_buf[kBufferSize]; |
| 646 *os_error_message_ = strdup(strerror_r(errno, error_buf, kBufferSize)); | 646 *os_error_message_ = strdup(strerror_r(errno, error_buf, kBufferSize)); |
| 647 } | 647 } |
| 648 | 648 |
| 649 | 649 |
| 650 void ReportChildError() { | 650 void ReportChildError() { |
| 651 // In the case of failure in the child process write the errno and | 651 // In the case of failure in the child process write the errno to the exec |
| 652 // the OS error message to the exec control pipe and exit. | 652 // control pipe and exit. |
| 653 int child_errno = errno; | 653 int child_errno = errno; |
| 654 const int kBufferSize = 1024; | 654 FDUtils::WriteToBlocking( |
| 655 char error_buf[kBufferSize]; | 655 exec_control_[1], &child_errno, sizeof(child_errno)); |
| 656 char* os_error_message = strerror_r(errno, error_buf, kBufferSize); | 656 _exit(1); |
| 657 int bytes_written = | |
| 658 FDUtils::WriteToBlocking( | |
| 659 exec_control_[1], &child_errno, sizeof(child_errno)); | |
| 660 if (bytes_written == sizeof(child_errno)) { | |
| 661 FDUtils::WriteToBlocking( | |
| 662 exec_control_[1], os_error_message, strlen(os_error_message) + 1); | |
| 663 } | |
| 664 VOID_TEMP_FAILURE_RETRY(close(exec_control_[1])); | |
| 665 exit(1); | |
| 666 } | 657 } |
| 667 | 658 |
| 668 | 659 |
| 669 void ReportPid(int pid) { | 660 void ReportPid(int pid) { |
| 670 // In the case of starting a detached process the actual pid of that process | 661 // In the case of starting a detached process the actual pid of that process |
| 671 // is communicated using the exec control pipe. | 662 // is communicated using the exec control pipe. |
| 672 int bytes_written = | 663 int bytes_written = |
| 673 FDUtils::WriteToBlocking(exec_control_[1], &pid, sizeof(pid)); | 664 FDUtils::WriteToBlocking(exec_control_[1], &pid, sizeof(pid)); |
| 674 ASSERT(bytes_written == sizeof(int)); | 665 ASSERT(bytes_written == sizeof(int)); |
| 675 USE(bytes_written); | 666 USE(bytes_written); |
| 676 } | 667 } |
| 677 | 668 |
| 678 | 669 |
| 679 void ReadChildError() { | 670 void ReadChildError(int child_errno) { |
|
Søren Gjesse
2015/06/10 07:20:25
Please rename this to e.g. SetOSErrorMessage.
Anders Johnsen
2015/06/10 08:00:45
Done.
| |
| 680 const int kMaxMessageSize = 256; | 671 const int kMaxMessageSize = 256; |
| 681 char* message = static_cast<char*>(malloc(kMaxMessageSize)); | 672 char* message = static_cast<char*>(calloc(kMaxMessageSize, 0)); |
| 682 if (message != NULL) { | 673 char* os_error_message = strerror_r( |
| 683 FDUtils::ReadFromBlocking(exec_control_[0], message, kMaxMessageSize); | 674 child_errno, message, kMaxMessageSize - 1); |
| 684 message[kMaxMessageSize - 1] = '\0'; | 675 if (message == os_error_message) { |
| 685 *os_error_message_ = message; | 676 *os_error_message_ = message; |
| 686 } else { | 677 } else { |
| 687 // Could not get error message. It will be NULL. | 678 free(message); |
| 688 ASSERT(*os_error_message_ == NULL); | 679 *os_error_message_ = strdup(os_error_message); |
| 689 } | 680 } |
| 690 } | 681 } |
| 691 | 682 |
| 692 | 683 |
| 693 void ClosePipe(int* fds) { | 684 void ClosePipe(int* fds) { |
| 694 for (int i = 0; i < 2; i++) { | 685 for (int i = 0; i < 2; i++) { |
| 695 if (fds[i] != -1) { | 686 if (fds[i] != -1) { |
| 696 VOID_TEMP_FAILURE_RETRY(close(fds[i])); | 687 VOID_TEMP_FAILURE_RETRY(close(fds[i])); |
| 697 fds[i] = -1; | 688 fds[i] = -1; |
| 698 } | 689 } |
| (...skipping 294 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 993 bzero(&act, sizeof(act)); | 984 bzero(&act, sizeof(act)); |
| 994 act.sa_handler = SIG_DFL; | 985 act.sa_handler = SIG_DFL; |
| 995 sigaction(signal, &act, NULL); | 986 sigaction(signal, &act, NULL); |
| 996 } | 987 } |
| 997 } | 988 } |
| 998 | 989 |
| 999 } // namespace bin | 990 } // namespace bin |
| 1000 } // namespace dart | 991 } // namespace dart |
| 1001 | 992 |
| 1002 #endif // defined(TARGET_OS_LINUX) | 993 #endif // defined(TARGET_OS_LINUX) |
| OLD | NEW |