diff options
author | Eelco Dolstra <edolstra@gmail.com> | 2017-01-25T12·37+0100 |
---|---|---|
committer | Eelco Dolstra <edolstra@gmail.com> | 2017-01-26T19·40+0100 |
commit | 83ae6503e87c7f5237fb0f1602793c126436495a (patch) | |
tree | e439570378a11b6ec6d1ef381aed4b5e1613c5bb | |
parent | 951357e5fb4cd0804e729866f204b635add926a3 (diff) |
Fix interrupt handling
-rw-r--r-- | src/libmain/shared.cc | 9 | ||||
-rw-r--r-- | src/libutil/monitor-fd.hh | 3 | ||||
-rw-r--r-- | src/libutil/util.cc | 28 | ||||
-rw-r--r-- | src/libutil/util.hh | 16 |
4 files changed, 42 insertions, 14 deletions
diff --git a/src/libmain/shared.cc b/src/libmain/shared.cc index 12f083c7f794..d564e03853e0 100644 --- a/src/libmain/shared.cc +++ b/src/libmain/shared.cc @@ -97,6 +97,9 @@ static void opensslLockCallback(int mode, int type, const char * file, int line) } +static void sigHandler(int signo) { } + + void initNix() { /* Turn on buffering for cerr. */ @@ -130,6 +133,10 @@ void initNix() if (sigaction(SIGCHLD, &act, 0)) throw SysError("resetting SIGCHLD"); + /* Install a dummy SIGUSR1 handler for use with pthread_kill(). */ + act.sa_handler = sigHandler; + if (sigaction(SIGUSR1, &act, 0)) throw SysError("handling SIGUSR1"); + /* Register a SIGSEGV handler to detect stack overflows. */ detectStackOverflow(); @@ -253,6 +260,8 @@ void showManPage(const string & name) int handleExceptions(const string & programName, std::function<void()> fun) { + ReceiveInterrupts receiveInterrupts; // FIXME: need better place for this + string error = ANSI_RED "error:" ANSI_NORMAL " "; try { try { diff --git a/src/libutil/monitor-fd.hh b/src/libutil/monitor-fd.hh index 6f01ccd91a43..e0ec66c01803 100644 --- a/src/libutil/monitor-fd.hh +++ b/src/libutil/monitor-fd.hh @@ -27,8 +27,7 @@ public: fds[0].events = 0; if (poll(fds, 1, -1) == -1) abort(); // can't happen assert(fds[0].revents & POLLHUP); - /* We got POLLHUP, so send an INT signal to the main thread. */ - kill(getpid(), SIGINT); + triggerInterrupt(); }); }; diff --git a/src/libutil/util.cc b/src/libutil/util.cc index 52608ac2a016..ca4edc2cd6c4 100644 --- a/src/libutil/util.cc +++ b/src/libutil/util.cc @@ -1197,18 +1197,22 @@ static void signalHandlerThread(sigset_t set) int signal = 0; sigwait(&set, &signal); - if (signal == SIGINT || signal == SIGTERM || signal == SIGHUP) { - _isInterrupted = 1; - - { - auto interruptCallbacks(_interruptCallbacks.lock()); - for (auto & callback : *interruptCallbacks) { - try { - callback(); - } catch (...) { - ignoreException(); - } - } + if (signal == SIGINT || signal == SIGTERM || signal == SIGHUP) + triggerInterrupt(); + } +} + +void triggerInterrupt() +{ + _isInterrupted = 1; + + { + auto interruptCallbacks(_interruptCallbacks.lock()); + for (auto & callback : *interruptCallbacks) { + try { + callback(); + } catch (...) { + ignoreException(); } } } diff --git a/src/libutil/util.hh b/src/libutil/util.hh index b68d48582b34..07141ffed6b5 100644 --- a/src/libutil/util.hh +++ b/src/libutil/util.hh @@ -433,5 +433,21 @@ struct InterruptCallback std::unique_ptr<InterruptCallback> createInterruptCallback( std::function<void()> callback); +void triggerInterrupt(); + +/* A RAII class that causes the current thread to receive SIGUSR1 when + the signal handler thread receives SIGINT. That is, this allows + SIGINT to be multiplexed to multiple threads. */ +struct ReceiveInterrupts +{ + pthread_t target; + std::unique_ptr<InterruptCallback> callback; + + ReceiveInterrupts() + : target(pthread_self()) + , callback(createInterruptCallback([&]() { pthread_kill(target, SIGUSR1); })) + { } +}; + } |