1 #ifndef Py_INTERNAL_WEAKREF_H 2 #define Py_INTERNAL_WEAKREF_H 3 #ifdef __cplusplus 4 extern "C" { 5 #endif 6 7 #ifndef Py_BUILD_CORE 8 # error "this header requires Py_BUILD_CORE define" 9 #endif 10 11 #include "pycore_critical_section.h" // Py_BEGIN_CRITICAL_SECTION() 12 #include "pycore_lock.h" 13 #include "pycore_object.h" // _Py_REF_IS_MERGED() 14 #include "pycore_pyatomic_ft_wrappers.h" 15 16 #ifdef Py_GIL_DISABLED 17 18 #define WEAKREF_LIST_LOCK(obj) \ 19 _PyInterpreterState_GET() \ 20 ->weakref_locks[((uintptr_t)obj) % NUM_WEAKREF_LIST_LOCKS] 21 22 // Lock using the referenced object 23 #define LOCK_WEAKREFS(obj) \ 24 PyMutex_LockFlags(&WEAKREF_LIST_LOCK(obj), _Py_LOCK_DONT_DETACH) 25 #define UNLOCK_WEAKREFS(obj) PyMutex_Unlock(&WEAKREF_LIST_LOCK(obj)) 26 27 // Lock using a weakref 28 #define LOCK_WEAKREFS_FOR_WR(wr) \ 29 PyMutex_LockFlags(wr->weakrefs_lock, _Py_LOCK_DONT_DETACH) 30 #define UNLOCK_WEAKREFS_FOR_WR(wr) PyMutex_Unlock(wr->weakrefs_lock) 31 32 #else 33 34 #define LOCK_WEAKREFS(obj) 35 #define UNLOCK_WEAKREFS(obj) 36 37 #define LOCK_WEAKREFS_FOR_WR(wr) 38 #define UNLOCK_WEAKREFS_FOR_WR(wr) 39 40 #endif 41 _is_dead(PyObject * obj)42static inline int _is_dead(PyObject *obj) 43 { 44 // Explanation for the Py_REFCNT() check: when a weakref's target is part 45 // of a long chain of deallocations which triggers the trashcan mechanism, 46 // clearing the weakrefs can be delayed long after the target's refcount 47 // has dropped to zero. In the meantime, code accessing the weakref will 48 // be able to "see" the target object even though it is supposed to be 49 // unreachable. See issue gh-60806. 50 #if defined(Py_GIL_DISABLED) 51 Py_ssize_t shared = _Py_atomic_load_ssize_relaxed(&obj->ob_ref_shared); 52 return shared == _Py_REF_SHARED(0, _Py_REF_MERGED); 53 #else 54 return (Py_REFCNT(obj) == 0); 55 #endif 56 } 57 _PyWeakref_GET_REF(PyObject * ref_obj)58static inline PyObject* _PyWeakref_GET_REF(PyObject *ref_obj) 59 { 60 assert(PyWeakref_Check(ref_obj)); 61 PyWeakReference *ref = _Py_CAST(PyWeakReference*, ref_obj); 62 63 PyObject *obj = FT_ATOMIC_LOAD_PTR(ref->wr_object); 64 if (obj == Py_None) { 65 // clear_weakref() was called 66 return NULL; 67 } 68 69 LOCK_WEAKREFS(obj); 70 #ifdef Py_GIL_DISABLED 71 if (ref->wr_object == Py_None) { 72 // clear_weakref() was called 73 UNLOCK_WEAKREFS(obj); 74 return NULL; 75 } 76 #endif 77 if (_Py_TryIncref(obj)) { 78 UNLOCK_WEAKREFS(obj); 79 return obj; 80 } 81 UNLOCK_WEAKREFS(obj); 82 return NULL; 83 } 84 _PyWeakref_IS_DEAD(PyObject * ref_obj)85static inline int _PyWeakref_IS_DEAD(PyObject *ref_obj) 86 { 87 assert(PyWeakref_Check(ref_obj)); 88 int ret = 0; 89 PyWeakReference *ref = _Py_CAST(PyWeakReference*, ref_obj); 90 PyObject *obj = FT_ATOMIC_LOAD_PTR(ref->wr_object); 91 if (obj == Py_None) { 92 // clear_weakref() was called 93 ret = 1; 94 } 95 else { 96 LOCK_WEAKREFS(obj); 97 // See _PyWeakref_GET_REF() for the rationale of this test 98 #ifdef Py_GIL_DISABLED 99 ret = (ref->wr_object == Py_None) || _is_dead(obj); 100 #else 101 ret = _is_dead(obj); 102 #endif 103 UNLOCK_WEAKREFS(obj); 104 } 105 return ret; 106 } 107 108 extern Py_ssize_t _PyWeakref_GetWeakrefCount(PyObject *obj); 109 110 // Clear all the weak references to obj but leave their callbacks uncalled and 111 // intact. 112 extern void _PyWeakref_ClearWeakRefsNoCallbacks(PyObject *obj); 113 114 PyAPI_FUNC(int) _PyWeakref_IsDead(PyObject *weakref); 115 116 #ifdef __cplusplus 117 } 118 #endif 119 #endif /* !Py_INTERNAL_WEAKREF_H */ 120