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