Improve SIGINT handling in multi-threaded programs

The flag remembering whether an Interrupted exception was thrown is
now thread-local. Thus, all threads will (eventually) throw
Interrupted. Previously, one thread would throw Interrupted, and then
the other threads wouldn't see that they were supposed to quit.
This commit is contained in:
Eelco Dolstra 2016-03-29 15:08:24 +02:00
parent 4f34c40398
commit ab3ce1cc13
4 changed files with 12 additions and 14 deletions

View file

@ -24,15 +24,9 @@
namespace nix {
volatile sig_atomic_t blockInt = 0;
static void sigintHandler(int signo)
{
if (!blockInt) {
_isInterrupted = 1;
blockInt = 1;
}
}
@ -287,8 +281,7 @@ int handleExceptions(const string & programName, std::function<void()> fun)
condition is discharged before we reach printMsg()
below, since otherwise it will throw an (uncaught)
exception. */
blockInt = 1; /* ignore further SIGINTs */
_isInterrupted = 0;
interruptThrown = true;
throw;
}
} catch (Exit & e) {

View file

@ -55,9 +55,10 @@ void ThreadPool::process()
work();
} catch (std::exception & e) {
auto state_(state.lock());
if (state_->exception)
if (state_->exception) {
if (!dynamic_cast<Interrupted*>(&e))
printMsg(lvlError, format("error: %s") % e.what());
else {
} else {
state_->exception = std::current_exception();
wakeup.notify_all();
}

View file

@ -1062,13 +1062,15 @@ void restoreSIGPIPE()
volatile sig_atomic_t _isInterrupted = 0;
thread_local bool interruptThrown = false;
void _interrupted()
{
/* Block user interrupts while an exception is being handled.
Throwing an exception while another exception is being handled
kills the program! */
if (!std::uncaught_exception()) {
_isInterrupted = 0;
if (!interruptThrown && !std::uncaught_exception()) {
interruptThrown = true;
throw Interrupted("interrupted by the user");
}
}

View file

@ -316,6 +316,8 @@ void restoreSIGPIPE();
extern volatile sig_atomic_t _isInterrupted;
extern thread_local bool interruptThrown;
void _interrupted();
void inline checkInterrupt()