| 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 "bin/process.h" | 5 #include "bin/process.h" |
| 6 | 6 |
| 7 #include <errno.h> | 7 #include <errno.h> |
| 8 #include <fcntl.h> | 8 #include <fcntl.h> |
| 9 #include <poll.h> | 9 #include <poll.h> |
| 10 #include <signal.h> | 10 #include <signal.h> |
| 11 #include <stdio.h> | 11 #include <stdio.h> |
| 12 #include <stdlib.h> | 12 #include <stdlib.h> |
| 13 #include <string.h> | 13 #include <string.h> |
| 14 #include <unistd.h> | 14 #include <unistd.h> |
| 15 | 15 |
| 16 #include "bin/fdutils.h" | 16 #include "bin/fdutils.h" |
| 17 #include "bin/thread.h" | 17 #include "bin/thread.h" |
| 18 | 18 |
| 19 | 19 |
| 20 // ProcessInfo is used to map a process id to the file descriptor for | 20 // ProcessInfo is used to map a process id to the file descriptor for |
| 21 // the pipe used to communicate the exit code of the process to Dart. | 21 // the pipe used to communicate the exit code of the process to Dart. |
| 22 // ProcessInfo objects are kept in the static singly-linked | 22 // ProcessInfo objects are kept in the static singly-linked |
| 23 // ProcessInfoList. | 23 // ProcessInfoList. |
| 24 class ProcessInfo { | 24 class ProcessInfo { |
| 25 public: | 25 public: |
| 26 ProcessInfo(pid_t pid, intptr_t fd) : pid_(pid), fd_(fd) { } | 26 ProcessInfo(pid_t pid, intptr_t fd) : pid_(pid), fd_(fd) { } |
| 27 ~ProcessInfo() { | |
| 28 int closed = TEMP_FAILURE_RETRY(close(fd_)); | |
| 29 if (closed != 0) { | |
| 30 FATAL("Failed to close process exit code pipe"); | |
| 31 } | |
| 32 } | |
| 33 pid_t pid() { return pid_; } | 27 pid_t pid() { return pid_; } |
| 34 intptr_t fd() { return fd_; } | 28 intptr_t fd() { return fd_; } |
| 35 ProcessInfo* next() { return next_; } | 29 ProcessInfo* next() { return next_; } |
| 36 void set_next(ProcessInfo* info) { next_ = info; } | 30 void set_next(ProcessInfo* info) { next_ = info; } |
| 37 | 31 |
| 38 private: | 32 private: |
| 39 pid_t pid_; | 33 pid_t pid_; |
| 40 intptr_t fd_; | 34 intptr_t fd_; |
| 41 ProcessInfo* next_; | 35 ProcessInfo* next_; |
| 42 }; | 36 }; |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 99 ProcessInfo* ProcessInfoList::active_processes_ = NULL; | 93 ProcessInfo* ProcessInfoList::active_processes_ = NULL; |
| 100 dart::Mutex ProcessInfoList::mutex_; | 94 dart::Mutex ProcessInfoList::mutex_; |
| 101 | 95 |
| 102 | 96 |
| 103 // The exit code handler sets up a separate thread which is signalled | 97 // The exit code handler sets up a separate thread which is signalled |
| 104 // on SIGCHLD. That separate thread can then get the exit code from | 98 // on SIGCHLD. That separate thread can then get the exit code from |
| 105 // processes that have exited and communicate it to Dart through the | 99 // processes that have exited and communicate it to Dart through the |
| 106 // event loop. | 100 // event loop. |
| 107 class ExitCodeHandler { | 101 class ExitCodeHandler { |
| 108 public: | 102 public: |
| 109 static const uint8_t kTerminateByte = 1; | |
| 110 | |
| 111 // Ensure that the ExitCodeHandler has been initialized. | 103 // Ensure that the ExitCodeHandler has been initialized. |
| 112 static bool EnsureInitialized() { | 104 static bool EnsureInitialized() { |
| 113 // Multiple isolates could be starting processes at the same | 105 // Multiple isolates could be starting processes at the same |
| 114 // time. Make sure that only one of them initializes the | 106 // time. Make sure that only one of them initializes the |
| 115 // ExitCodeHandler. | 107 // ExitCodeHandler. |
| 116 MutexLocker locker(&mutex_); | 108 MutexLocker locker(&mutex_); |
| 117 if (initialized_) { | 109 if (initialized_) { |
| 118 return true; | 110 return true; |
| 119 } | 111 } |
| 120 | 112 |
| (...skipping 15 matching lines...) Expand all Loading... |
| 136 initialized_ = true; | 128 initialized_ = true; |
| 137 return true; | 129 return true; |
| 138 } | 130 } |
| 139 | 131 |
| 140 // Get the write end of the pipe. | 132 // Get the write end of the pipe. |
| 141 static int WakeUpFd() { | 133 static int WakeUpFd() { |
| 142 ASSERT(initialized_); | 134 ASSERT(initialized_); |
| 143 return sig_chld_fds_[1]; | 135 return sig_chld_fds_[1]; |
| 144 } | 136 } |
| 145 | 137 |
| 146 static void Terminate() { | |
| 147 MutexLocker locker(&mutex_); | |
| 148 if (!initialized_) { | |
| 149 return; | |
| 150 } | |
| 151 char data = ExitCodeHandler::kTerminateByte; | |
| 152 ssize_t result = TEMP_FAILURE_RETRY(write(WakeUpFd(), &data, 1)); | |
| 153 if (result < 1) { | |
| 154 perror("Failed to write to wake-up fd in SIGCHLD handler"); | |
| 155 } | |
| 156 } | |
| 157 | |
| 158 private: | 138 private: |
| 159 // GetProcessExitCodes is called on a separate thread when a SIGCHLD | 139 // GetProcessExitCodes is called on a separate thread when a SIGCHLD |
| 160 // signal is received to retrieve the exit codes and post them to | 140 // signal is received to retrieve the exit codes and post them to |
| 161 // dart. | 141 // dart. |
| 162 static void GetProcessExitCodes() { | 142 static void GetProcessExitCodes() { |
| 163 pid_t pid = 0; | 143 pid_t pid = 0; |
| 164 int status = 0; | 144 int status = 0; |
| 165 while ((pid = TEMP_FAILURE_RETRY(waitpid(-1, &status, WNOHANG))) > 0) { | 145 while ((pid = TEMP_FAILURE_RETRY(waitpid(-1, &status, WNOHANG))) > 0) { |
| 166 int exit_code = 0; | 146 int exit_code = 0; |
| 167 int negative = 0; | 147 int negative = 0; |
| 168 if (WIFEXITED(status)) { | 148 if (WIFEXITED(status)) { |
| 169 exit_code = WEXITSTATUS(status); | 149 exit_code = WEXITSTATUS(status); |
| 170 } | 150 } |
| 171 if (WIFSIGNALED(status)) { | 151 if (WIFSIGNALED(status)) { |
| 172 exit_code = WTERMSIG(status); | 152 exit_code = WTERMSIG(status); |
| 173 negative = 1; | 153 negative = 1; |
| 174 } | 154 } |
| 175 intptr_t exit_code_fd = ProcessInfoList::LookupProcessExitFd(pid); | 155 intptr_t exit_code_fd = ProcessInfoList::LookupProcessExitFd(pid); |
| 176 if (exit_code_fd != 0) { | 156 if (exit_code_fd != 0) { |
| 177 int message[2] = { exit_code, negative }; | 157 int message[3] = { pid, exit_code, negative }; |
| 178 ssize_t result = | 158 ssize_t result = |
| 179 FDUtils::WriteToBlocking(exit_code_fd, &message, sizeof(message)); | 159 FDUtils::WriteToBlocking(exit_code_fd, &message, sizeof(message)); |
| 180 if (result != sizeof(message) && errno != EPIPE) { | 160 if (result != sizeof(message) && errno != EPIPE) { |
| 181 perror("ExitHandler notification failed"); | 161 perror("ExitHandler notification failed"); |
| 182 } | 162 } |
| 183 ProcessInfoList::RemoveProcess(pid); | 163 TEMP_FAILURE_RETRY(close(exit_code_fd)); |
| 184 } | 164 } |
| 185 } | 165 } |
| 186 } | 166 } |
| 187 | 167 |
| 188 | 168 |
| 189 // Entry point for the separate exit code handler thread started by | 169 // Entry point for the separate exit code handler thread started by |
| 190 // the ExitCodeHandler. | 170 // the ExitCodeHandler. |
| 191 static void ExitCodeHandlerEntry(uword param) { | 171 static void ExitCodeHandlerEntry(uword param) { |
| 192 struct pollfd pollfds; | 172 struct pollfd pollfds; |
| 193 pollfds.fd = param; | 173 pollfds.fd = param; |
| 194 pollfds.events |= POLLIN; | 174 pollfds.events |= POLLIN; |
| 195 while (true) { | 175 while (true) { |
| 196 int result = TEMP_FAILURE_RETRY(poll(&pollfds, 1, -1)); | 176 int result = TEMP_FAILURE_RETRY(poll(&pollfds, 1, -1)); |
| 197 if (result == -1) { | 177 if (result == -1) { |
| 198 ASSERT(EAGAIN == EWOULDBLOCK); | 178 ASSERT(EAGAIN == EWOULDBLOCK); |
| 199 if (errno != EWOULDBLOCK) { | 179 if (errno != EWOULDBLOCK) { |
| 200 perror("ExitCodeHandler poll failed"); | 180 perror("ExitCodeHandler poll failed"); |
| 201 } | 181 } |
| 202 } else { | 182 } else { |
| 203 // Read the byte from the wake-up fd. | 183 // Read the byte from the wake-up fd. |
| 204 ASSERT(result = 1); | 184 ASSERT(result = 1); |
| 205 intptr_t data = 0; | 185 intptr_t data = 0; |
| 206 ssize_t read_bytes = FDUtils::ReadFromBlocking(pollfds.fd, &data, 1); | 186 ssize_t read_bytes = FDUtils::ReadFromBlocking(pollfds.fd, &data, 1); |
| 207 if (read_bytes < 1) { | 187 if (read_bytes < 1) { |
| 208 perror("Failed to read from wake-up fd in exit-code handler"); | 188 perror("Failed to read from wake-up fd in exit-code handler"); |
| 209 } | 189 } |
| 210 // Check if the ExitCodeHandler has been terminated. | |
| 211 if (data == ExitCodeHandler::kTerminateByte) { | |
| 212 return; | |
| 213 } | |
| 214 // Get the exit code from all processes that have died. | 190 // Get the exit code from all processes that have died. |
| 215 GetProcessExitCodes(); | 191 GetProcessExitCodes(); |
| 216 } | 192 } |
| 217 } | 193 } |
| 218 } | 194 } |
| 219 | 195 |
| 220 static dart::Mutex mutex_; | 196 static dart::Mutex mutex_; |
| 221 static bool initialized_; | 197 static bool initialized_; |
| 222 static int sig_chld_fds_[2]; | 198 static int sig_chld_fds_[2]; |
| 223 }; | 199 }; |
| (...skipping 280 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 504 | 480 |
| 505 bool Process::Kill(intptr_t id) { | 481 bool Process::Kill(intptr_t id) { |
| 506 int result = TEMP_FAILURE_RETRY(kill(id, SIGKILL)); | 482 int result = TEMP_FAILURE_RETRY(kill(id, SIGKILL)); |
| 507 if (result == -1) { | 483 if (result == -1) { |
| 508 return false; | 484 return false; |
| 509 } | 485 } |
| 510 return true; | 486 return true; |
| 511 } | 487 } |
| 512 | 488 |
| 513 | 489 |
| 514 void Process::TerminateExitCodeHandler() { | 490 void Process::Exit(intptr_t id) { |
| 515 ExitCodeHandler::Terminate(); | 491 ProcessInfoList::RemoveProcess(id); |
| 516 } | 492 } |
| OLD | NEW |