mirror of
https://github.com/NixOS/nix
synced 2025-06-27 00:11:17 +02:00
Handle SIGINT etc. via a sigwait() signal handler thread
This allows other threads to install callbacks that run in a regular, non-signal context. In particular, we can use this to signal the downloader thread to quit. Closes #1183.
This commit is contained in:
parent
c0d55f9183
commit
cc3b93c991
4 changed files with 101 additions and 28 deletions
|
@ -2,14 +2,16 @@
|
|||
|
||||
#include "util.hh"
|
||||
#include "affinity.hh"
|
||||
#include "sync.hh"
|
||||
|
||||
#include <iostream>
|
||||
#include <cctype>
|
||||
#include <cerrno>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <sstream>
|
||||
#include <cstring>
|
||||
#include <cctype>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <thread>
|
||||
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
@ -933,7 +935,7 @@ void restoreSIGPIPE()
|
|||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
volatile sig_atomic_t _isInterrupted = 0;
|
||||
bool _isInterrupted = false;
|
||||
|
||||
thread_local bool interruptThrown = false;
|
||||
|
||||
|
@ -1200,4 +1202,64 @@ void callFailure(const std::function<void(std::exception_ptr exc)> & failure, st
|
|||
}
|
||||
|
||||
|
||||
static Sync<std::list<std::function<void()>>> _interruptCallbacks;
|
||||
|
||||
static void signalHandlerThread(sigset_t set)
|
||||
{
|
||||
while (true) {
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void startSignalHandlerThread()
|
||||
{
|
||||
sigset_t set;
|
||||
sigemptyset(&set);
|
||||
sigaddset(&set, SIGINT);
|
||||
sigaddset(&set, SIGTERM);
|
||||
sigaddset(&set, SIGHUP);
|
||||
if (pthread_sigmask(SIG_BLOCK, &set, nullptr))
|
||||
throw SysError("blocking signals");
|
||||
|
||||
std::thread(signalHandlerThread, set).detach();
|
||||
}
|
||||
|
||||
/* RAII helper to automatically deregister a callback. */
|
||||
struct InterruptCallbackImpl : InterruptCallback
|
||||
{
|
||||
std::list<std::function<void()>>::iterator it;
|
||||
~InterruptCallbackImpl() override
|
||||
{
|
||||
_interruptCallbacks.lock()->erase(it);
|
||||
}
|
||||
};
|
||||
|
||||
std::unique_ptr<InterruptCallback> createInterruptCallback(std::function<void()> callback)
|
||||
{
|
||||
auto interruptCallbacks(_interruptCallbacks.lock());
|
||||
interruptCallbacks->push_back(callback);
|
||||
|
||||
auto res = std::make_unique<InterruptCallbackImpl>();
|
||||
res->it = interruptCallbacks->end();
|
||||
res->it--;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue