Chromium Code Reviews| Index: runtime/bin/process_linux.cc |
| diff --git a/runtime/bin/process_linux.cc b/runtime/bin/process_linux.cc |
| index 95d11cdce7dc2b8ee6a2aaf0ce1bcf12900d69de..8a28124bedee3c8de9af10ff67e1ee88708ec7bc 100644 |
| --- a/runtime/bin/process_linux.cc |
| +++ b/runtime/bin/process_linux.cc |
| @@ -18,6 +18,7 @@ |
| #include "bin/fdutils.h" |
| #include "bin/log.h" |
| +#include "bin/signal_blocker.h" |
| #include "bin/thread.h" |
| @@ -630,6 +631,152 @@ intptr_t Process::CurrentProcessId() { |
| return static_cast<intptr_t>(getpid()); |
| } |
| + |
| +static Mutex* signal_mutex = new Mutex(); |
| +static const int kSignalsCount = 5; |
| +static const int kSignals[kSignalsCount] = { |
| + SIGINT, |
| + SIGWINCH, |
| + SIGTERM, |
| + SIGUSR1, |
| + SIGUSR2 |
| +}; |
| + |
| + |
| +class SignalInfo { |
|
Søren Gjesse
2013/12/19 08:51:24
This class could should go into the platform indep
Anders Johnsen
2013/12/19 10:54:17
Done.
|
| + public: |
| + SignalInfo(int fd, int signal, SignalInfo* prev = NULL) |
| + : fd_(fd), |
| + signal_(signal), |
| + port_(Dart_GetMainPortId()), |
| + next_(NULL), |
| + prev_(prev) { |
| + if (prev_ != NULL) { |
| + prev_->next_ = this; |
| + } |
| + } |
| + |
| + ~SignalInfo() { |
| + VOID_TEMP_FAILURE_RETRY(close(fd_)); |
| + } |
| + |
| + void Unlink() { |
| + if (prev_ != NULL) { |
| + prev_->next_ = next_; |
| + } |
| + if (next_ != NULL) { |
| + next_->prev_ = prev_; |
| + } |
| + } |
| + |
| + int fd() const { return fd_; } |
| + int signal() const { return signal_; } |
| + Dart_Port port() const { return port_; } |
| + SignalInfo* next() const { return next_; } |
| + |
| + private: |
| + int fd_; |
| + int signal_; |
| + Dart_Port port_; |
|
Søren Gjesse
2013/12/19 08:51:24
Please add some documentation to the fields. Espec
Anders Johnsen
2013/12/19 10:54:17
Done.
|
| + SignalInfo* next_; |
| + SignalInfo* prev_; |
| +}; |
| + |
| + |
| +static SignalInfo* signal_handlers = NULL; |
| + |
| + |
| +static void SignalHandler(int signal) { |
| + MutexLocker lock(signal_mutex); |
| + const SignalInfo* handler = signal_handlers; |
| + while (handler != NULL) { |
| + if (handler->signal() == signal) { |
| + int value = 0; |
| + VOID_TEMP_FAILURE_RETRY(write(handler->fd(), &value, 1)); |
| + } |
| + handler = handler->next(); |
| + } |
| +} |
| + |
| + |
| +intptr_t Process::SetSignalHandler(intptr_t signal) { |
| + bool found = false; |
| + for (int i = 0; i < kSignalsCount; i++) { |
| + if (kSignals[i] == signal) { |
| + found = true; |
| + break; |
| + } |
| + } |
| + if (!found) return -1; |
| + int fds[2]; |
| + if (TEMP_FAILURE_RETRY_BLOCK_SIGNALS(pipe(fds)) != 0) { |
| + return -1; |
| + } |
| + if (!FDUtils::SetNonBlocking(fds[0])) { |
| + VOID_TEMP_FAILURE_RETRY_BLOCK_SIGNALS(close(fds[0])); |
| + VOID_TEMP_FAILURE_RETRY_BLOCK_SIGNALS(close(fds[1])); |
| + return -1; |
| + } |
| + ThreadSignalBlocker blocker(kSignalsCount, kSignals); |
| + MutexLocker lock(signal_mutex); |
| + SignalInfo* handler = signal_handlers; |
| + bool listen = true; |
| + while (handler != NULL) { |
| + if (handler->signal() == signal) { |
| + listen = false; |
| + break; |
| + } |
| + handler = handler->next(); |
| + } |
| + if (listen) { |
| + struct sigaction act; |
| + bzero(&act, sizeof(act)); |
| + act.sa_handler = SignalHandler; |
| + int status = TEMP_FAILURE_RETRY_BLOCK_SIGNALS( |
| + sigaction(signal, &act, NULL)); |
| + if (status < 0) { |
| + VOID_TEMP_FAILURE_RETRY_BLOCK_SIGNALS(close(fds[0])); |
| + VOID_TEMP_FAILURE_RETRY_BLOCK_SIGNALS(close(fds[1])); |
| + return -1; |
| + } |
| + } |
| + if (signal_handlers == NULL) { |
| + signal_handlers = new SignalInfo(fds[1], signal); |
| + } else { |
| + new SignalInfo(fds[1], signal, signal_handlers); |
| + } |
| + return fds[0]; |
| +} |
| + |
| + |
| +void Process::ClearSignalHandler(intptr_t signal) { |
| + ThreadSignalBlocker blocker(kSignalsCount, kSignals); |
| + MutexLocker lock(signal_mutex); |
| + SignalInfo* handler = signal_handlers; |
| + bool unlisten = true; |
| + while (handler != NULL) { |
| + bool remove = false; |
| + if (handler->signal() == signal) { |
| + if (handler->port() == Dart_GetMainPortId()) { |
| + if (signal_handlers == handler) signal_handlers = handler->next(); |
| + handler->Unlink(); |
| + remove = true; |
| + } else { |
| + unlisten = false; |
| + } |
| + } |
| + SignalInfo* next = handler->next(); |
| + if (remove) delete handler; |
| + handler = next; |
| + } |
| + if (unlisten) { |
| + struct sigaction act; |
| + bzero(&act, sizeof(act)); |
| + act.sa_handler = SIG_DFL; |
| + VOID_TEMP_FAILURE_RETRY_BLOCK_SIGNALS(sigaction(signal, &act, NULL)); |
| + } |
| +} |
| + |
| } // namespace bin |
| } // namespace dart |