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