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) { | ||||||
|                         printMsg(lvlError, format("error: %s") % e.what()); |                         if (!dynamic_cast<Interrupted*>(&e)) | ||||||
|                     else { |                             printMsg(lvlError, format("error: %s") % e.what()); | ||||||
|  |                     } 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…
	
	Add table
		Add a link
		
	
		Reference in a new issue