mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 05:31:20 +00:00 
			
		
		
		
	[3.14] gh-137433: Fix deadlock with stop-the-world and daemon threads (gh-137735) (GH-138965)
There was a deadlock originally seen by Memray when a daemon thread
enabled or disabled profiling while the interpreter was shutting down.
I think this could also happen with garbage collection, but I haven't
seen that in practice.
The daemon thread could be hung while trying acquire the global rwmutex
that prevents overlapping global and per-interpreter stop-the-world events.
Since it already held the main interpreter's stop-the-world lock, it
also deadlocked the main thread, which is trying to perform interpreter
finalization.
Swap the order of lock acquisition to prevent this deadlock.
Additionally, refactor `_PyParkingLot_Park` so that the global buckets
hashtable is left in a clean state if the thread is hung in
`PyEval_AcquireThread`.
(cherry picked from commit 90fe3250f8)
Co-authored-by: Sam Gross <colesbury@gmail.com>
			
			
This commit is contained in:
		
							parent
							
								
									db8b943259
								
							
						
					
					
						commit
						e09f33e5bf
					
				
					 4 changed files with 51 additions and 4 deletions
				
			
		|  | @ -1381,6 +1381,33 @@ def test_native_id_after_fork(self): | |||
|         self.assertEqual(len(native_ids), 2) | ||||
|         self.assertNotEqual(native_ids[0], native_ids[1]) | ||||
| 
 | ||||
|     def test_stop_the_world_during_finalization(self): | ||||
|         # gh-137433: Test functions that trigger a stop-the-world in the free | ||||
|         # threading build concurrent with interpreter finalization. | ||||
|         script = """if True: | ||||
|             import gc | ||||
|             import sys | ||||
|             import threading | ||||
|             NUM_THREADS = 5 | ||||
|             b = threading.Barrier(NUM_THREADS + 1) | ||||
|             def run_in_bg(): | ||||
|                 b.wait() | ||||
|                 while True: | ||||
|                     sys.setprofile(None) | ||||
|                     gc.collect() | ||||
| 
 | ||||
|             for _ in range(NUM_THREADS): | ||||
|                 t = threading.Thread(target=run_in_bg, daemon=True) | ||||
|                 t.start() | ||||
| 
 | ||||
|             b.wait() | ||||
|             print("Exiting...") | ||||
|         """ | ||||
|         rc, out, err = assert_python_ok('-c', script) | ||||
|         self.assertEqual(rc, 0) | ||||
|         self.assertEqual(err, b"") | ||||
|         self.assertEqual(out.strip(), b"Exiting...") | ||||
| 
 | ||||
| class ThreadJoinOnShutdown(BaseTestCase): | ||||
| 
 | ||||
|     def _run_and_join(self, script): | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Miss Islington (bot)
						Miss Islington (bot)