Fix interrupt handling

This commit is contained in:
Eelco Dolstra 2017-01-25 13:37:02 +01:00
parent 951357e5fb
commit 83ae6503e8
No known key found for this signature in database
GPG key ID: 8170B4726D7198DE
4 changed files with 41 additions and 13 deletions

View file

@ -97,6 +97,9 @@ static void opensslLockCallback(int mode, int type, const char * file, int line)
} }
static void sigHandler(int signo) { }
void initNix() void initNix()
{ {
/* Turn on buffering for cerr. */ /* Turn on buffering for cerr. */
@ -130,6 +133,10 @@ void initNix()
if (sigaction(SIGCHLD, &act, 0)) if (sigaction(SIGCHLD, &act, 0))
throw SysError("resetting SIGCHLD"); 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. */ /* Register a SIGSEGV handler to detect stack overflows. */
detectStackOverflow(); detectStackOverflow();
@ -253,6 +260,8 @@ void showManPage(const string & name)
int handleExceptions(const string & programName, std::function<void()> fun) int handleExceptions(const string & programName, std::function<void()> fun)
{ {
ReceiveInterrupts receiveInterrupts; // FIXME: need better place for this
string error = ANSI_RED "error:" ANSI_NORMAL " "; string error = ANSI_RED "error:" ANSI_NORMAL " ";
try { try {
try { try {

View file

@ -27,8 +27,7 @@ public:
fds[0].events = 0; fds[0].events = 0;
if (poll(fds, 1, -1) == -1) abort(); // can't happen if (poll(fds, 1, -1) == -1) abort(); // can't happen
assert(fds[0].revents & POLLHUP); assert(fds[0].revents & POLLHUP);
/* We got POLLHUP, so send an INT signal to the main thread. */ triggerInterrupt();
kill(getpid(), SIGINT);
}); });
}; };

View file

@ -1197,18 +1197,22 @@ static void signalHandlerThread(sigset_t set)
int signal = 0; int signal = 0;
sigwait(&set, &signal); sigwait(&set, &signal);
if (signal == SIGINT || signal == SIGTERM || signal == SIGHUP) { if (signal == SIGINT || signal == SIGTERM || signal == SIGHUP)
_isInterrupted = 1; triggerInterrupt();
}
}
{ void triggerInterrupt()
auto interruptCallbacks(_interruptCallbacks.lock()); {
for (auto & callback : *interruptCallbacks) { _isInterrupted = 1;
try {
callback(); {
} catch (...) { auto interruptCallbacks(_interruptCallbacks.lock());
ignoreException(); for (auto & callback : *interruptCallbacks) {
} try {
} callback();
} catch (...) {
ignoreException();
} }
} }
} }

View file

@ -433,5 +433,21 @@ struct InterruptCallback
std::unique_ptr<InterruptCallback> createInterruptCallback( std::unique_ptr<InterruptCallback> createInterruptCallback(
std::function<void()> callback); 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); }))
{ }
};
} }