| 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 #if !defined(DART_IO_DISABLED) | 5 #if !defined(DART_IO_DISABLED) |
| 6 | 6 |
| 7 #include "platform/globals.h" | 7 #include "platform/globals.h" |
| 8 #if defined(TARGET_OS_LINUX) | 8 #if defined(TARGET_OS_LINUX) |
| 9 | 9 |
| 10 #include "bin/process.h" | 10 #include "bin/process.h" |
| 11 | 11 |
| 12 #include <errno.h> // NOLINT | 12 #include <errno.h> // NOLINT |
| 13 #include <fcntl.h> // NOLINT | 13 #include <fcntl.h> // NOLINT |
| 14 #include <poll.h> // NOLINT | 14 #include <poll.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 <sys/wait.h> // NOLINT | 18 #include <sys/wait.h> // NOLINT |
| 19 #include <unistd.h> // NOLINT | 19 #include <unistd.h> // NOLINT |
| 20 | 20 |
| 21 #include "bin/dartutils.h" | 21 #include "bin/dartutils.h" |
| 22 #include "bin/fdutils.h" | 22 #include "bin/fdutils.h" |
| 23 #include "bin/lockers.h" | 23 #include "bin/lockers.h" |
| 24 #include "bin/log.h" | 24 #include "bin/log.h" |
| 25 #include "bin/thread.h" | 25 #include "bin/thread.h" |
| 26 | 26 |
| 27 #include "platform/signal_blocker.h" | 27 #include "platform/signal_blocker.h" |
| 28 #include "platform/utils.h" | 28 #include "platform/utils.h" |
| 29 | 29 |
| 30 extern char **environ; | 30 extern char** environ; |
| 31 | 31 |
| 32 namespace dart { | 32 namespace dart { |
| 33 namespace bin { | 33 namespace bin { |
| 34 | 34 |
| 35 int Process::global_exit_code_ = 0; | 35 int Process::global_exit_code_ = 0; |
| 36 Mutex* Process::global_exit_code_mutex_ = new Mutex(); | 36 Mutex* Process::global_exit_code_mutex_ = new Mutex(); |
| 37 Process::ExitHook Process::exit_hook_ = NULL; | 37 Process::ExitHook Process::exit_hook_ = NULL; |
| 38 | 38 |
| 39 // ProcessInfo is used to map a process id to the file descriptor for | 39 // ProcessInfo is used to map a process id to the file descriptor for |
| 40 // the pipe used to communicate the exit code of the process to Dart. | 40 // the pipe used to communicate the exit code of the process to Dart. |
| 41 // ProcessInfo objects are kept in the static singly-linked | 41 // ProcessInfo objects are kept in the static singly-linked |
| 42 // ProcessInfoList. | 42 // ProcessInfoList. |
| 43 class ProcessInfo { | 43 class ProcessInfo { |
| 44 public: | 44 public: |
| 45 ProcessInfo(pid_t pid, intptr_t fd) : pid_(pid), fd_(fd) { } | 45 ProcessInfo(pid_t pid, intptr_t fd) : pid_(pid), fd_(fd) {} |
| 46 ~ProcessInfo() { | 46 ~ProcessInfo() { |
| 47 int closed = TEMP_FAILURE_RETRY(close(fd_)); | 47 int closed = TEMP_FAILURE_RETRY(close(fd_)); |
| 48 if (closed != 0) { | 48 if (closed != 0) { |
| 49 FATAL("Failed to close process exit code pipe"); | 49 FATAL("Failed to close process exit code pipe"); |
| 50 } | 50 } |
| 51 } | 51 } |
| 52 pid_t pid() { return pid_; } | 52 pid_t pid() { return pid_; } |
| 53 intptr_t fd() { return fd_; } | 53 intptr_t fd() { return fd_; } |
| 54 ProcessInfo* next() { return next_; } | 54 ProcessInfo* next() { return next_; } |
| 55 void set_next(ProcessInfo* info) { next_ = info; } | 55 void set_next(ProcessInfo* info) { next_ = info; } |
| (...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 199 int negative = 0; | 199 int negative = 0; |
| 200 if (WIFEXITED(status)) { | 200 if (WIFEXITED(status)) { |
| 201 exit_code = WEXITSTATUS(status); | 201 exit_code = WEXITSTATUS(status); |
| 202 } | 202 } |
| 203 if (WIFSIGNALED(status)) { | 203 if (WIFSIGNALED(status)) { |
| 204 exit_code = WTERMSIG(status); | 204 exit_code = WTERMSIG(status); |
| 205 negative = 1; | 205 negative = 1; |
| 206 } | 206 } |
| 207 intptr_t exit_code_fd = ProcessInfoList::LookupProcessExitFd(pid); | 207 intptr_t exit_code_fd = ProcessInfoList::LookupProcessExitFd(pid); |
| 208 if (exit_code_fd != 0) { | 208 if (exit_code_fd != 0) { |
| 209 int message[2] = { exit_code, negative }; | 209 int message[2] = {exit_code, negative}; |
| 210 ssize_t result = | 210 ssize_t result = |
| 211 FDUtils::WriteToBlocking(exit_code_fd, &message, sizeof(message)); | 211 FDUtils::WriteToBlocking(exit_code_fd, &message, sizeof(message)); |
| 212 // If the process has been closed, the read end of the exit | 212 // If the process has been closed, the read end of the exit |
| 213 // pipe has been closed. It is therefore not a problem that | 213 // pipe has been closed. It is therefore not a problem that |
| 214 // write fails with a broken pipe error. Other errors should | 214 // write fails with a broken pipe error. Other errors should |
| 215 // not happen. | 215 // not happen. |
| 216 if ((result != -1) && (result != sizeof(message))) { | 216 if ((result != -1) && (result != sizeof(message))) { |
| 217 FATAL("Failed to write entire process exit message"); | 217 FATAL("Failed to write entire process exit message"); |
| 218 } else if ((result == -1) && (errno != EPIPE)) { | 218 } else if ((result == -1) && (errno != EPIPE)) { |
| 219 FATAL1("Failed to write exit code: %d", errno); | 219 FATAL1("Failed to write exit code: %d", errno); |
| (...skipping 319 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 539 return 0; | 539 return 0; |
| 540 } | 540 } |
| 541 | 541 |
| 542 | 542 |
| 543 int ReadExecResult() { | 543 int ReadExecResult() { |
| 544 int child_errno; | 544 int child_errno; |
| 545 int bytes_read = -1; | 545 int bytes_read = -1; |
| 546 // Read exec result from child. If no data is returned the exec was | 546 // Read exec result from child. If no data is returned the exec was |
| 547 // successful and the exec call closed the pipe. Otherwise the errno | 547 // successful and the exec call closed the pipe. Otherwise the errno |
| 548 // is written to the pipe. | 548 // is written to the pipe. |
| 549 bytes_read = FDUtils::ReadFromBlocking( | 549 bytes_read = FDUtils::ReadFromBlocking(exec_control_[0], &child_errno, |
| 550 exec_control_[0], &child_errno, sizeof(child_errno)); | 550 sizeof(child_errno)); |
| 551 if (bytes_read == sizeof(child_errno)) { | 551 if (bytes_read == sizeof(child_errno)) { |
| 552 ReadChildError(); | 552 ReadChildError(); |
| 553 return child_errno; | 553 return child_errno; |
| 554 } else if (bytes_read == -1) { | 554 } else if (bytes_read == -1) { |
| 555 return errno; | 555 return errno; |
| 556 } | 556 } |
| 557 return 0; | 557 return 0; |
| 558 } | 558 } |
| 559 | 559 |
| 560 | 560 |
| 561 int ReadDetachedExecResult(pid_t *pid) { | 561 int ReadDetachedExecResult(pid_t* pid) { |
| 562 int child_errno; | 562 int child_errno; |
| 563 int bytes_read = -1; | 563 int bytes_read = -1; |
| 564 // Read exec result from child. If only pid data is returned the exec was | 564 // Read exec result from child. If only pid data is returned the exec was |
| 565 // successful and the exec call closed the pipe. Otherwise the errno | 565 // successful and the exec call closed the pipe. Otherwise the errno |
| 566 // is written to the pipe as well. | 566 // is written to the pipe as well. |
| 567 int result[2]; | 567 int result[2]; |
| 568 bytes_read = | 568 bytes_read = |
| 569 FDUtils::ReadFromBlocking(exec_control_[0], result, sizeof(result)); | 569 FDUtils::ReadFromBlocking(exec_control_[0], result, sizeof(result)); |
| 570 if (bytes_read == sizeof(int)) { | 570 if (bytes_read == sizeof(int)) { |
| 571 *pid = result[0]; | 571 *pid = result[0]; |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 614 | 614 |
| 615 void SetupDetachedWithStdio() { | 615 void SetupDetachedWithStdio() { |
| 616 // Close all open file descriptors except for | 616 // Close all open file descriptors except for |
| 617 // exec_control_[1], write_out_[0], read_in_[1] and | 617 // exec_control_[1], write_out_[0], read_in_[1] and |
| 618 // read_err_[1]. | 618 // read_err_[1]. |
| 619 int max_fds = sysconf(_SC_OPEN_MAX); | 619 int max_fds = sysconf(_SC_OPEN_MAX); |
| 620 if (max_fds == -1) { | 620 if (max_fds == -1) { |
| 621 max_fds = _POSIX_OPEN_MAX; | 621 max_fds = _POSIX_OPEN_MAX; |
| 622 } | 622 } |
| 623 for (int fd = 0; fd < max_fds; fd++) { | 623 for (int fd = 0; fd < max_fds; fd++) { |
| 624 if ((fd != exec_control_[1]) && | 624 if ((fd != exec_control_[1]) && (fd != write_out_[0]) && |
| 625 (fd != write_out_[0]) && | 625 (fd != read_in_[1]) && (fd != read_err_[1])) { |
| 626 (fd != read_in_[1]) && | |
| 627 (fd != read_err_[1])) { | |
| 628 VOID_TEMP_FAILURE_RETRY(close(fd)); | 626 VOID_TEMP_FAILURE_RETRY(close(fd)); |
| 629 } | 627 } |
| 630 } | 628 } |
| 631 | 629 |
| 632 if (TEMP_FAILURE_RETRY(dup2(write_out_[0], STDIN_FILENO)) == -1) { | 630 if (TEMP_FAILURE_RETRY(dup2(write_out_[0], STDIN_FILENO)) == -1) { |
| 633 ReportChildError(); | 631 ReportChildError(); |
| 634 } | 632 } |
| 635 VOID_TEMP_FAILURE_RETRY(close(write_out_[0])); | 633 VOID_TEMP_FAILURE_RETRY(close(write_out_[0])); |
| 636 | 634 |
| 637 if (TEMP_FAILURE_RETRY(dup2(read_in_[1], STDOUT_FILENO)) == -1) { | 635 if (TEMP_FAILURE_RETRY(dup2(read_in_[1], STDOUT_FILENO)) == -1) { |
| (...skipping 29 matching lines...) Expand all Loading... |
| 667 } | 665 } |
| 668 | 666 |
| 669 | 667 |
| 670 void ReportChildError() { | 668 void ReportChildError() { |
| 671 // In the case of failure in the child process write the errno and | 669 // In the case of failure in the child process write the errno and |
| 672 // the OS error message to the exec control pipe and exit. | 670 // the OS error message to the exec control pipe and exit. |
| 673 int child_errno = errno; | 671 int child_errno = errno; |
| 674 const int kBufferSize = 1024; | 672 const int kBufferSize = 1024; |
| 675 char error_buf[kBufferSize]; | 673 char error_buf[kBufferSize]; |
| 676 char* os_error_message = Utils::StrError(errno, error_buf, kBufferSize); | 674 char* os_error_message = Utils::StrError(errno, error_buf, kBufferSize); |
| 677 int bytes_written = FDUtils::WriteToBlocking( | 675 int bytes_written = FDUtils::WriteToBlocking(exec_control_[1], &child_errno, |
| 678 exec_control_[1], &child_errno, sizeof(child_errno)); | 676 sizeof(child_errno)); |
| 679 if (bytes_written == sizeof(child_errno)) { | 677 if (bytes_written == sizeof(child_errno)) { |
| 680 FDUtils::WriteToBlocking( | 678 FDUtils::WriteToBlocking(exec_control_[1], os_error_message, |
| 681 exec_control_[1], os_error_message, strlen(os_error_message) + 1); | 679 strlen(os_error_message) + 1); |
| 682 } | 680 } |
| 683 VOID_TEMP_FAILURE_RETRY(close(exec_control_[1])); | 681 VOID_TEMP_FAILURE_RETRY(close(exec_control_[1])); |
| 684 exit(1); | 682 exit(1); |
| 685 } | 683 } |
| 686 | 684 |
| 687 | 685 |
| 688 void ReportPid(int pid) { | 686 void ReportPid(int pid) { |
| 689 // In the case of starting a detached process the actual pid of that process | 687 // In the case of starting a detached process the actual pid of that process |
| 690 // is communicated using the exec control pipe. | 688 // is communicated using the exec control pipe. |
| 691 int bytes_written = | 689 int bytes_written = |
| (...skipping 28 matching lines...) Expand all Loading... |
| 720 | 718 |
| 721 | 719 |
| 722 void CloseAllPipes() { | 720 void CloseAllPipes() { |
| 723 ClosePipe(exec_control_); | 721 ClosePipe(exec_control_); |
| 724 ClosePipe(read_in_); | 722 ClosePipe(read_in_); |
| 725 ClosePipe(read_err_); | 723 ClosePipe(read_err_); |
| 726 ClosePipe(write_out_); | 724 ClosePipe(write_out_); |
| 727 } | 725 } |
| 728 | 726 |
| 729 | 727 |
| 730 int read_in_[2]; // Pipe for stdout to child process. | 728 int read_in_[2]; // Pipe for stdout to child process. |
| 731 int read_err_[2]; // Pipe for stderr to child process. | 729 int read_err_[2]; // Pipe for stderr to child process. |
| 732 int write_out_[2]; // Pipe for stdin to child process. | 730 int write_out_[2]; // Pipe for stdin to child process. |
| 733 int exec_control_[2]; // Pipe to get the result from exec. | 731 int exec_control_[2]; // Pipe to get the result from exec. |
| 734 | 732 |
| 735 char** program_arguments_; | 733 char** program_arguments_; |
| 736 char** program_environment_; | 734 char** program_environment_; |
| 737 | 735 |
| 738 const char* path_; | 736 const char* path_; |
| 739 const char* working_directory_; | 737 const char* working_directory_; |
| 740 ProcessStartMode mode_; | 738 ProcessStartMode mode_; |
| 741 intptr_t* in_; | 739 intptr_t* in_; |
| 742 intptr_t* out_; | 740 intptr_t* out_; |
| (...skipping 13 matching lines...) Expand all Loading... |
| 756 const char* working_directory, | 754 const char* working_directory, |
| 757 char* environment[], | 755 char* environment[], |
| 758 intptr_t environment_length, | 756 intptr_t environment_length, |
| 759 ProcessStartMode mode, | 757 ProcessStartMode mode, |
| 760 intptr_t* in, | 758 intptr_t* in, |
| 761 intptr_t* out, | 759 intptr_t* out, |
| 762 intptr_t* err, | 760 intptr_t* err, |
| 763 intptr_t* id, | 761 intptr_t* id, |
| 764 intptr_t* exit_event, | 762 intptr_t* exit_event, |
| 765 char** os_error_message) { | 763 char** os_error_message) { |
| 766 ProcessStarter starter(path, | 764 ProcessStarter starter(path, arguments, arguments_length, working_directory, |
| 767 arguments, | 765 environment, environment_length, mode, in, out, err, |
| 768 arguments_length, | 766 id, exit_event, os_error_message); |
| 769 working_directory, | |
| 770 environment, | |
| 771 environment_length, | |
| 772 mode, | |
| 773 in, | |
| 774 out, | |
| 775 err, | |
| 776 id, | |
| 777 exit_event, | |
| 778 os_error_message); | |
| 779 return starter.Start(); | 767 return starter.Start(); |
| 780 } | 768 } |
| 781 | 769 |
| 782 | 770 |
| 783 class BufferList: public BufferListBase { | 771 class BufferList : public BufferListBase { |
| 784 public: | 772 public: |
| 785 BufferList() {} | 773 BufferList() {} |
| 786 | 774 |
| 787 bool Read(int fd, intptr_t available) { | 775 bool Read(int fd, intptr_t available) { |
| 788 // Read all available bytes. | 776 // Read all available bytes. |
| 789 while (available > 0) { | 777 while (available > 0) { |
| 790 if (free_size_ == 0) { | 778 if (free_size_ == 0) { |
| 791 Allocate(); | 779 Allocate(); |
| 792 } | 780 } |
| 793 ASSERT(free_size_ > 0); | 781 ASSERT(free_size_ > 0); |
| 794 ASSERT(free_size_ <= kBufferSize); | 782 ASSERT(free_size_ <= kBufferSize); |
| 795 intptr_t block_size = dart::Utils::Minimum(free_size_, available); | 783 intptr_t block_size = dart::Utils::Minimum(free_size_, available); |
| 796 intptr_t bytes = TEMP_FAILURE_RETRY(read( | 784 intptr_t bytes = TEMP_FAILURE_RETRY( |
| 797 fd, | 785 read(fd, reinterpret_cast<void*>(FreeSpaceAddress()), block_size)); |
| 798 reinterpret_cast<void*>(FreeSpaceAddress()), | |
| 799 block_size)); | |
| 800 if (bytes < 0) { | 786 if (bytes < 0) { |
| 801 return false; | 787 return false; |
| 802 } | 788 } |
| 803 data_size_ += bytes; | 789 data_size_ += bytes; |
| 804 free_size_ -= bytes; | 790 free_size_ -= bytes; |
| 805 available -= bytes; | 791 available -= bytes; |
| 806 } | 792 } |
| 807 return true; | 793 return true; |
| 808 } | 794 } |
| 809 | 795 |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 865 if (fds[i].fd == out) { | 851 if (fds[i].fd == out) { |
| 866 if (!out_data.Read(out, avail)) { | 852 if (!out_data.Read(out, avail)) { |
| 867 return CloseProcessBuffers(fds); | 853 return CloseProcessBuffers(fds); |
| 868 } | 854 } |
| 869 } else if (fds[i].fd == err) { | 855 } else if (fds[i].fd == err) { |
| 870 if (!err_data.Read(err, avail)) { | 856 if (!err_data.Read(err, avail)) { |
| 871 return CloseProcessBuffers(fds); | 857 return CloseProcessBuffers(fds); |
| 872 } | 858 } |
| 873 } else if (fds[i].fd == exit_event) { | 859 } else if (fds[i].fd == exit_event) { |
| 874 if (avail == 8) { | 860 if (avail == 8) { |
| 875 intptr_t b = TEMP_FAILURE_RETRY(read(exit_event, | 861 intptr_t b = |
| 876 exit_code_data.bytes, 8)); | 862 TEMP_FAILURE_RETRY(read(exit_event, exit_code_data.bytes, 8)); |
| 877 if (b != 8) { | 863 if (b != 8) { |
| 878 return CloseProcessBuffers(fds); | 864 return CloseProcessBuffers(fds); |
| 879 } | 865 } |
| 880 } | 866 } |
| 881 } else { | 867 } else { |
| 882 UNREACHABLE(); | 868 UNREACHABLE(); |
| 883 } | 869 } |
| 884 } | 870 } |
| 885 if ((fds[i].revents & POLLHUP) != 0) { | 871 if ((fds[i].revents & POLLHUP) != 0) { |
| 886 VOID_TEMP_FAILURE_RETRY(close(fds[i].fd)); | 872 VOID_TEMP_FAILURE_RETRY(close(fds[i].fd)); |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 920 | 906 |
| 921 intptr_t Process::CurrentProcessId() { | 907 intptr_t Process::CurrentProcessId() { |
| 922 return static_cast<intptr_t>(getpid()); | 908 return static_cast<intptr_t>(getpid()); |
| 923 } | 909 } |
| 924 | 910 |
| 925 | 911 |
| 926 static Mutex* signal_mutex = new Mutex(); | 912 static Mutex* signal_mutex = new Mutex(); |
| 927 static SignalInfo* signal_handlers = NULL; | 913 static SignalInfo* signal_handlers = NULL; |
| 928 static const int kSignalsCount = 7; | 914 static const int kSignalsCount = 7; |
| 929 static const int kSignals[kSignalsCount] = { | 915 static const int kSignals[kSignalsCount] = { |
| 930 SIGHUP, | 916 SIGHUP, SIGINT, SIGTERM, SIGUSR1, SIGUSR2, SIGWINCH, |
| 931 SIGINT, | 917 SIGQUIT // Allow VMService to listen on SIGQUIT. |
| 932 SIGTERM, | |
| 933 SIGUSR1, | |
| 934 SIGUSR2, | |
| 935 SIGWINCH, | |
| 936 SIGQUIT // Allow VMService to listen on SIGQUIT. | |
| 937 }; | 918 }; |
| 938 | 919 |
| 939 | 920 |
| 940 SignalInfo::~SignalInfo() { | 921 SignalInfo::~SignalInfo() { |
| 941 VOID_TEMP_FAILURE_RETRY(close(fd_)); | 922 VOID_TEMP_FAILURE_RETRY(close(fd_)); |
| 942 } | 923 } |
| 943 | 924 |
| 944 | 925 |
| 945 static void SignalHandler(int signal) { | 926 static void SignalHandler(int signal) { |
| 946 MutexLocker lock(signal_mutex); | 927 MutexLocker lock(signal_mutex); |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1034 sigaction(signal, &act, NULL); | 1015 sigaction(signal, &act, NULL); |
| 1035 } | 1016 } |
| 1036 } | 1017 } |
| 1037 | 1018 |
| 1038 } // namespace bin | 1019 } // namespace bin |
| 1039 } // namespace dart | 1020 } // namespace dart |
| 1040 | 1021 |
| 1041 #endif // defined(TARGET_OS_LINUX) | 1022 #endif // defined(TARGET_OS_LINUX) |
| 1042 | 1023 |
| 1043 #endif // !defined(DART_IO_DISABLED) | 1024 #endif // !defined(DART_IO_DISABLED) |
| OLD | NEW |