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 { | ||||
| 
 | ||||
| 
 | ||||
| volatile sig_atomic_t blockInt = 0; | ||||
| 
 | ||||
| 
 | ||||
| static void sigintHandler(int signo) | ||||
| { | ||||
|     if (!blockInt) { | ||||
|         _isInterrupted = 1; | ||||
|         blockInt = 1; | ||||
|     } | ||||
|     _isInterrupted = 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) { | ||||
|  |  | |||
|  | @ -55,9 +55,10 @@ void ThreadPool::process() | |||
|                     work(); | ||||
|                 } catch (std::exception & e) { | ||||
|                     auto state_(state.lock()); | ||||
|                     if (state_->exception) | ||||
|                         printMsg(lvlError, format("error: %s") % e.what()); | ||||
|                     else { | ||||
|                     if (state_->exception) { | ||||
|                         if (!dynamic_cast<Interrupted*>(&e)) | ||||
|                             printMsg(lvlError, format("error: %s") % e.what()); | ||||
|                     } else { | ||||
|                         state_->exception = std::current_exception(); | ||||
|                         wakeup.notify_all(); | ||||
|                     } | ||||
|  |  | |||
|  | @ -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"); | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -316,6 +316,8 @@ void restoreSIGPIPE(); | |||
| 
 | ||||
| extern volatile sig_atomic_t _isInterrupted; | ||||
| 
 | ||||
| extern thread_local bool interruptThrown; | ||||
| 
 | ||||
| void _interrupted(); | ||||
| 
 | ||||
| void inline checkInterrupt() | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue