Skip to content

Commit c22323c

Browse files
authored
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`.
1 parent df93f5d commit c22323c

File tree

2 files changed

+9
-4
lines changed

2 files changed

+9
-4
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix deadlock involving ``_PyType_Lookup()`` cache in the free-threaded build
2+
when the GIL is dynamically enabled at runtime.

Objects/typeobject.c

+7-4
Original file line numberDiff line numberDiff line change
@@ -5169,7 +5169,7 @@ is_dunder_name(PyObject *name)
51695169
return 0;
51705170
}
51715171

5172-
static void
5172+
static PyObject *
51735173
update_cache(struct type_cache_entry *entry, PyObject *name, unsigned int version_tag, PyObject *value)
51745174
{
51755175
_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
51805180
// exact unicode object or Py_None so it's safe to do so.
51815181
PyObject *old_name = entry->name;
51825182
_Py_atomic_store_ptr_relaxed(&entry->name, Py_NewRef(name));
5183-
Py_DECREF(old_name);
5183+
return old_name;
51845184
}
51855185

51865186
#if Py_GIL_DISABLED
@@ -5200,10 +5200,12 @@ update_cache_gil_disabled(struct type_cache_entry *entry, PyObject *name,
52005200
return;
52015201
}
52025202

5203-
update_cache(entry, name, version_tag, value);
5203+
PyObject *old_value = update_cache(entry, name, version_tag, value);
52045204

52055205
// Then update sequence to the next valid value
52065206
_PySeqLock_UnlockWrite(&entry->sequence);
5207+
5208+
Py_DECREF(old_value);
52075209
}
52085210

52095211
#endif
@@ -5315,7 +5317,8 @@ _PyType_LookupRef(PyTypeObject *type, PyObject *name)
53155317
#if Py_GIL_DISABLED
53165318
update_cache_gil_disabled(entry, name, version, res);
53175319
#else
5318-
update_cache(entry, name, version, res);
5320+
PyObject *old_value = update_cache(entry, name, version, res);
5321+
Py_DECREF(old_value);
53195322
#endif
53205323
}
53215324
return res;

0 commit comments

Comments
 (0)