about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorEelco Dolstra <edolstra@gmail.com>2017-01-25T12·37+0100
committerEelco Dolstra <edolstra@gmail.com>2017-01-26T19·40+0100
commit83ae6503e87c7f5237fb0f1602793c126436495a (patch)
treee439570378a11b6ec6d1ef381aed4b5e1613c5bb /src
parent951357e5fb4cd0804e729866f204b635add926a3 (diff)
Fix interrupt handling
Diffstat (limited to 'src')
-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 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); }))
+    { }
+};
+
 
 }