aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEelco Dolstra <edolstra@gmail.com>2017-01-25 13:37:02 +0100
committerEelco Dolstra <edolstra@gmail.com>2017-01-26 20:40:33 +0100
commit83ae6503e87c7f5237fb0f1602793c126436495a (patch)
treee439570378a11b6ec6d1ef381aed4b5e1613c5bb
parent951357e5fb4cd0804e729866f204b635add926a3 (diff)
Fix interrupt handling
-rw-r--r--src/libmain/shared.cc9
-rw-r--r--src/libutil/monitor-fd.hh3
-rw-r--r--src/libutil/util.cc28
-rw-r--r--src/libutil/util.hh16
4 files changed, 42 insertions, 14 deletions
diff --git a/src/libmain/shared.cc b/src/libmain/shared.cc
index 12f083c7f..d564e0385 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 6f01ccd91..e0ec66c01 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 52608ac2a..ca4edc2cd 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 b68d48582..07141ffed 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); }))
+ { }
+};
+
}