diff options
Diffstat (limited to 'src/libutil')
-rw-r--r-- | src/libutil/monitor-fd.hh | 3 | ||||
-rw-r--r-- | src/libutil/serialise.hh | 15 | ||||
-rw-r--r-- | src/libutil/util.cc | 54 | ||||
-rw-r--r-- | src/libutil/util.hh | 23 |
4 files changed, 66 insertions, 29 deletions
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/serialise.hh b/src/libutil/serialise.hh index f12f02543bc0..5646d08c1314 100644 --- a/src/libutil/serialise.hh +++ b/src/libutil/serialise.hh @@ -139,6 +139,21 @@ struct StringSource : Source }; +/* Adapter class of a Source that saves all data read to `s'. */ +struct SavingSourceAdapter : Source +{ + Source & orig; + string s; + SavingSourceAdapter(Source & orig) : orig(orig) { } + size_t read(unsigned char * data, size_t len) + { + size_t n = orig.read(data, len); + s.append((const char *) data, n); + return n; + } +}; + + void writePadding(size_t len, Sink & sink); void writeString(const unsigned char * buf, size_t len, Sink & sink); 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()); } } diff --git a/src/libutil/util.hh b/src/libutil/util.hh index b68d48582b34..cfaaf1486e9e 100644 --- a/src/libutil/util.hh +++ b/src/libutil/util.hh @@ -256,10 +256,6 @@ void closeMostFDs(const set<int> & exceptions); /* Set the close-on-exec flag for the given file descriptor. */ void closeOnExec(int fd); -/* Restore default handling of SIGPIPE, otherwise some programs will - randomly say "Broken pipe". */ -void restoreSIGPIPE(); - /* User interruption. */ @@ -423,6 +419,9 @@ void callSuccess( on the current thread (and thus any threads created by it). */ void startSignalHandlerThread(); +/* Restore default signal handling. */ +void restoreSignals(); + struct InterruptCallback { virtual ~InterruptCallback() { }; @@ -433,5 +432,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); })) + { } +}; + } |