mirror of
				https://github.com/python/cpython.git
				synced 2025-11-03 15:11:34 +00:00 
			
		
		
		
	gh-119525: Fix deadlock with _PyType_Lookup and the GIL (#119527)
				
					
				
			The deadlock only affected the free-threaded build and only occurred when the GIL was enabled at runtime. The `Py_DECREF(old_name)` call might temporarily release the GIL while holding the type seqlock. Another thread may spin trying to acquire the seqlock while holding the GIL. The deadlock occurred roughly 1 in ~1,000 runs of `pool_in_threads.py` from `test_multiprocessing_pool_circular_import`.
This commit is contained in:
		
							parent
							
								
									df93f5d4bf
								
							
						
					
					
						commit
						c22323cd1c
					
				
					 2 changed files with 9 additions and 4 deletions
				
			
		| 
						 | 
				
			
			@ -0,0 +1,2 @@
 | 
			
		|||
Fix deadlock involving ``_PyType_Lookup()`` cache in the free-threaded build
 | 
			
		||||
when the GIL is dynamically enabled at runtime.
 | 
			
		||||
| 
						 | 
				
			
			@ -5169,7 +5169,7 @@ is_dunder_name(PyObject *name)
 | 
			
		|||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
static PyObject *
 | 
			
		||||
update_cache(struct type_cache_entry *entry, PyObject *name, unsigned int version_tag, PyObject *value)
 | 
			
		||||
{
 | 
			
		||||
    _Py_atomic_store_uint32_relaxed(&entry->version, version_tag);
 | 
			
		||||
| 
						 | 
				
			
			@ -5180,7 +5180,7 @@ update_cache(struct type_cache_entry *entry, PyObject *name, unsigned int versio
 | 
			
		|||
    // exact unicode object or Py_None so it's safe to do so.
 | 
			
		||||
    PyObject *old_name = entry->name;
 | 
			
		||||
    _Py_atomic_store_ptr_relaxed(&entry->name, Py_NewRef(name));
 | 
			
		||||
    Py_DECREF(old_name);
 | 
			
		||||
    return old_name;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if Py_GIL_DISABLED
 | 
			
		||||
| 
						 | 
				
			
			@ -5200,10 +5200,12 @@ update_cache_gil_disabled(struct type_cache_entry *entry, PyObject *name,
 | 
			
		|||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    update_cache(entry, name, version_tag, value);
 | 
			
		||||
    PyObject *old_value = update_cache(entry, name, version_tag, value);
 | 
			
		||||
 | 
			
		||||
    // Then update sequence to the next valid value
 | 
			
		||||
    _PySeqLock_UnlockWrite(&entry->sequence);
 | 
			
		||||
 | 
			
		||||
    Py_DECREF(old_value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -5315,7 +5317,8 @@ _PyType_LookupRef(PyTypeObject *type, PyObject *name)
 | 
			
		|||
#if Py_GIL_DISABLED
 | 
			
		||||
        update_cache_gil_disabled(entry, name, version, res);
 | 
			
		||||
#else
 | 
			
		||||
        update_cache(entry, name, version, res);
 | 
			
		||||
        PyObject *old_value = update_cache(entry, name, version, res);
 | 
			
		||||
        Py_DECREF(old_value);
 | 
			
		||||
#endif
 | 
			
		||||
    }
 | 
			
		||||
    return res;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue