diff --git a/Include/internal/pycore_weakref.h b/Include/internal/pycore_weakref.h index 4ed8928c0b92a8c..31c88cfb836e0f4 100644 --- a/Include/internal/pycore_weakref.h +++ b/Include/internal/pycore_weakref.h @@ -74,26 +74,27 @@ static inline PyObject* _PyWeakref_GET_REF(PyObject *ref_obj) assert(PyWeakref_Check(ref_obj)); PyWeakReference *ref = _Py_CAST(PyWeakReference*, ref_obj); - PyObject *obj = FT_ATOMIC_LOAD_PTR(ref->wr_object); +#ifdef Py_GIL_DISABLED + PyObject *obj = _Py_atomic_load_ptr(&ref->wr_object); if (obj == Py_None) { // clear_weakref() was called return NULL; } - - LOCK_WEAKREFS(obj); -#ifdef Py_GIL_DISABLED - if (ref->wr_object == Py_None) { + if (_Py_TryIncrefCompare(&ref->wr_object, obj)) { + return obj; + } + return NULL; +#else + PyObject *obj = ref->wr_object; + if (obj == Py_None) { // clear_weakref() was called - UNLOCK_WEAKREFS(obj); return NULL; } -#endif if (_Py_TryIncref(obj)) { - UNLOCK_WEAKREFS(obj); return obj; } - UNLOCK_WEAKREFS(obj); return NULL; +#endif } static inline int _PyWeakref_IS_DEAD(PyObject *ref_obj) @@ -108,8 +109,8 @@ static inline int _PyWeakref_IS_DEAD(PyObject *ref_obj) } else { LOCK_WEAKREFS(obj); - // See _PyWeakref_GET_REF() for the rationale of this test #ifdef Py_GIL_DISABLED + // The weakref may have been cleared before the lock was acquired. ret = (ref->wr_object == Py_None) || _is_dead(obj); #else ret = _is_dead(obj); diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-10-16-18-25-48.gh-issue-159564.WMRRFA.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-10-16-18-25-48.gh-issue-159564.WMRRFA.rst new file mode 100644 index 000000000000000..8e59f52fa4090ee --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-10-16-18-25-48.gh-issue-159564.WMRRFA.rst @@ -0,0 +1,3 @@ +Improve the performance and thread scaling of dereferencing weak references +in the :term:`free-threaded build`. Dereferencing a weak reference no longer +takes a lock. diff --git a/Objects/weakrefobject.c b/Objects/weakrefobject.c index db95bb926d5f733..576274ee4535d8d 100644 --- a/Objects/weakrefobject.c +++ b/Objects/weakrefobject.c @@ -84,9 +84,9 @@ clear_weakref_lock_held(PyWeakReference *self, PyObject **callback) /* If 'self' is the end of the list (and thus self->wr_next == NULL) then the weakref list itself (and thus the value of *list) will end up being set to NULL. */ - FT_ATOMIC_STORE_PTR(*list, self->wr_next); + FT_ATOMIC_STORE_PTR_RELEASE(*list, self->wr_next); } - FT_ATOMIC_STORE_PTR(self->wr_object, Py_None); + FT_ATOMIC_STORE_PTR_RELEASE(self->wr_object, Py_None); if (self->wr_prev != NULL) { self->wr_prev->wr_next = self->wr_next; }