Index: runtime/bin/process_macos.cc |
diff --git a/runtime/bin/process_macos.cc b/runtime/bin/process_macos.cc |
index edb222af3fb11acc7037a1f9a813ba374529ea63..ae0f37e749462c0aba80502078bb43b03eb8b5d8 100644 |
--- a/runtime/bin/process_macos.cc |
+++ b/runtime/bin/process_macos.cc |
@@ -18,6 +18,7 @@ |
#include "bin/fdutils.h" |
#include "bin/log.h" |
+#include "bin/signal_blocker.h" |
#include "bin/thread.h" |
extern char **environ; |
@@ -622,8 +623,44 @@ bool Process::Wait(intptr_t pid, |
} |
+static int SignalMap(intptr_t id) { |
+ switch (static_cast<ProcessSignals>(id)) { |
+ case kSighup: return SIGHUP; |
+ case kSigint: return SIGINT; |
+ case kSigquit: return SIGQUIT; |
+ case kSigill: return SIGILL; |
+ case kSigtrap: return SIGTRAP; |
+ case kSigabrt: return SIGABRT; |
+ case kSigbus: return SIGBUS; |
+ case kSigfpe: return SIGFPE; |
+ case kSigkill: return SIGKILL; |
+ case kSigusr1: return SIGUSR1; |
+ case kSigsegv: return SIGSEGV; |
+ case kSigusr2: return SIGUSR2; |
+ case kSigpipe: return SIGPIPE; |
+ case kSigalrm: return SIGALRM; |
+ case kSigterm: return SIGTERM; |
+ case kSigchld: return SIGCHLD; |
+ case kSigcont: return SIGCONT; |
+ case kSigstop: return SIGSTOP; |
+ case kSigtstp: return SIGTSTP; |
+ case kSigttin: return SIGTTIN; |
+ case kSigttou: return SIGTTOU; |
+ case kSigurg: return SIGURG; |
+ case kSigxcpu: return SIGXCPU; |
+ case kSigxfsz: return SIGXFSZ; |
+ case kSigvtalrm: return SIGVTALRM; |
+ case kSigprof: return SIGPROF; |
+ case kSigwinch: return SIGWINCH; |
+ case kSigpoll: return -1; |
+ case kSigsys: return SIGSYS; |
+ } |
+ return -1; |
+} |
+ |
+ |
bool Process::Kill(intptr_t id, int signal) { |
- return (TEMP_FAILURE_RETRY(kill(id, signal)) != -1); |
+ return (TEMP_FAILURE_RETRY(kill(id, SignalMap(signal))) != -1); |
} |
@@ -636,6 +673,119 @@ intptr_t Process::CurrentProcessId() { |
return static_cast<intptr_t>(getpid()); |
} |
+ |
+static Mutex* signal_mutex = new Mutex(); |
+static SignalInfo* signal_handlers = NULL; |
+static const int kSignalsCount = 5; |
+static const int kSignals[kSignalsCount] = { |
+ SIGINT, |
+ SIGWINCH, |
+ SIGTERM, |
+ SIGUSR1, |
+ SIGUSR2 |
+}; |
+ |
+ |
+SignalInfo::~SignalInfo() { |
+ VOID_TEMP_FAILURE_RETRY(close(fd_)); |
+} |
+ |
+ |
+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) { |
+ signal = SignalMap(signal); |
+ if (signal == -1) return -1; |
+ 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) { |
+ signal = SignalMap(signal); |
+ if (signal == -1) return; |
+ 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 |