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 |