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:
parent
4f34c40398
commit
ab3ce1cc13
4 changed files with 12 additions and 14 deletions
|
@ -24,15 +24,9 @@
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
|
|
||||||
volatile sig_atomic_t blockInt = 0;
|
|
||||||
|
|
||||||
|
|
||||||
static void sigintHandler(int signo)
|
static void sigintHandler(int signo)
|
||||||
{
|
{
|
||||||
if (!blockInt) {
|
|
||||||
_isInterrupted = 1;
|
_isInterrupted = 1;
|
||||||
blockInt = 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -287,8 +281,7 @@ int handleExceptions(const string & programName, std::function<void()> fun)
|
||||||
condition is discharged before we reach printMsg()
|
condition is discharged before we reach printMsg()
|
||||||
below, since otherwise it will throw an (uncaught)
|
below, since otherwise it will throw an (uncaught)
|
||||||
exception. */
|
exception. */
|
||||||
blockInt = 1; /* ignore further SIGINTs */
|
interruptThrown = true;
|
||||||
_isInterrupted = 0;
|
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
} catch (Exit & e) {
|
} catch (Exit & e) {
|
||||||
|
|
|
@ -55,9 +55,10 @@ void ThreadPool::process()
|
||||||
work();
|
work();
|
||||||
} catch (std::exception & e) {
|
} catch (std::exception & e) {
|
||||||
auto state_(state.lock());
|
auto state_(state.lock());
|
||||||
if (state_->exception)
|
if (state_->exception) {
|
||||||
|
if (!dynamic_cast<Interrupted*>(&e))
|
||||||
printMsg(lvlError, format("error: %s") % e.what());
|
printMsg(lvlError, format("error: %s") % e.what());
|
||||||
else {
|
} else {
|
||||||
state_->exception = std::current_exception();
|
state_->exception = std::current_exception();
|
||||||
wakeup.notify_all();
|
wakeup.notify_all();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1062,13 +1062,15 @@ void restoreSIGPIPE()
|
||||||
|
|
||||||
volatile sig_atomic_t _isInterrupted = 0;
|
volatile sig_atomic_t _isInterrupted = 0;
|
||||||
|
|
||||||
|
thread_local bool interruptThrown = false;
|
||||||
|
|
||||||
void _interrupted()
|
void _interrupted()
|
||||||
{
|
{
|
||||||
/* Block user interrupts while an exception is being handled.
|
/* Block user interrupts while an exception is being handled.
|
||||||
Throwing an exception while another exception is being handled
|
Throwing an exception while another exception is being handled
|
||||||
kills the program! */
|
kills the program! */
|
||||||
if (!std::uncaught_exception()) {
|
if (!interruptThrown && !std::uncaught_exception()) {
|
||||||
_isInterrupted = 0;
|
interruptThrown = true;
|
||||||
throw Interrupted("interrupted by the user");
|
throw Interrupted("interrupted by the user");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -316,6 +316,8 @@ void restoreSIGPIPE();
|
||||||
|
|
||||||
extern volatile sig_atomic_t _isInterrupted;
|
extern volatile sig_atomic_t _isInterrupted;
|
||||||
|
|
||||||
|
extern thread_local bool interruptThrown;
|
||||||
|
|
||||||
void _interrupted();
|
void _interrupted();
|
||||||
|
|
||||||
void inline checkInterrupt()
|
void inline checkInterrupt()
|
||||||
|
|
Loading…
Reference in a new issue