about summary refs log tree commit diff
path: root/src/libutil/util.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/libutil/util.cc')
-rw-r--r--src/libutil/util.cc54
1 files changed, 31 insertions, 23 deletions
diff --git a/src/libutil/util.cc b/src/libutil/util.cc
index e9457582810a..6c4c5c969d86 100644
--- a/src/libutil/util.cc
+++ b/src/libutil/util.cc
@@ -860,6 +860,8 @@ string runProgram(Path program, bool searchPath, const Strings & args,
         Strings args_(args);
         args_.push_front(program);
 
+        restoreSignals();
+
         if (searchPath)
             execvp(program.c_str(), stringsToCharPtrs(args_).data());
         else
@@ -909,16 +911,6 @@ void closeOnExec(int fd)
 }
 
 
-void restoreSIGPIPE()
-{
-    struct sigaction act;
-    act.sa_handler = SIG_DFL;
-    act.sa_flags = 0;
-    sigemptyset(&act.sa_mask);
-    if (sigaction(SIGPIPE, &act, 0)) throw SysError("resetting SIGPIPE");
-}
-
-
 //////////////////////////////////////////////////////////////////////
 
 
@@ -1197,36 +1189,52 @@ 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();
             }
         }
     }
 }
 
+static sigset_t savedSignalMask;
+
 void startSignalHandlerThread()
 {
+    if (sigprocmask(SIG_BLOCK, nullptr, &savedSignalMask))
+        throw SysError("quering signal mask");
+
     sigset_t set;
     sigemptyset(&set);
     sigaddset(&set, SIGINT);
     sigaddset(&set, SIGTERM);
     sigaddset(&set, SIGHUP);
+    sigaddset(&set, SIGPIPE);
     if (pthread_sigmask(SIG_BLOCK, &set, nullptr))
         throw SysError("blocking signals");
 
     std::thread(signalHandlerThread, set).detach();
 }
 
+void restoreSignals()
+{
+    if (sigprocmask(SIG_SETMASK, &savedSignalMask, nullptr))
+        throw SysError("restoring signals");
+}
+
 /* RAII helper to automatically deregister a callback. */
 struct InterruptCallbackImpl : InterruptCallback
 {
@@ -1246,7 +1254,7 @@ std::unique_ptr<InterruptCallback> createInterruptCallback(std::function<void()>
     res->it = interruptCallbacks->end();
     res->it--;
 
-    return res;
+    return std::unique_ptr<InterruptCallback>(res.release());
 }
 
 }