Where Online Learning is simpler!
The C and C++ Include Header Files
cat -n /usr/include/python3.14/internal/pycore_weakref.h
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" // PyMutex_LockFlags() 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 #define FT_CLEAR_WEAKREFS(obj, weakref_list) \ 33 do { \ 34 assert(Py_REFCNT(obj) == 0); \ 35 PyObject_ClearWeakRefs(obj); \ 36 } while (0) 37 38 #else 39 40 #define LOCK_WEAKREFS(obj) 41 #define UNLOCK_WEAKREFS(obj) 42 43 #define LOCK_WEAKREFS_FOR_WR(wr) 44 #define UNLOCK_WEAKREFS_FOR_WR(wr) 45 46 #define FT_CLEAR_WEAKREFS(obj, weakref_list) \ 47 do { \ 48 assert(Py_REFCNT(obj) == 0); \ 49 if (weakref_list != NULL) { \ 50 PyObject_ClearWeakRefs(obj); \ 51 } \ 52 } while (0) 53 54 #endif 55 56 static inline int _is_dead(PyObject *obj) 57 { 58 // Explanation for the Py_REFCNT() check: when a weakref's target is part 59 // of a long chain of deallocations which triggers the trashcan mechanism, 60 // clearing the weakrefs can be delayed long after the target's refcount 61 // has dropped to zero. In the meantime, code accessing the weakref will 62 // be able to "see" the target object even though it is supposed to be 63 // unreachable. See issue gh-60806. 64 #if defined(Py_GIL_DISABLED) 65 Py_ssize_t shared = _Py_atomic_load_ssize_relaxed(&obj->ob_ref_shared); 66 return shared == _Py_REF_SHARED(0, _Py_REF_MERGED); 67 #else 68 return (Py_REFCNT(obj) == 0); 69 #endif 70 } 71 72 static inline PyObject* _PyWeakref_GET_REF(PyObject *ref_obj) 73 { 74 assert(PyWeakref_Check(ref_obj)); 75 PyWeakReference *ref = _Py_CAST(PyWeakReference*, ref_obj); 76 77 PyObject *obj = FT_ATOMIC_LOAD_PTR(ref->wr_object); 78 if (obj == Py_None) { 79 // clear_weakref() was called 80 return NULL; 81 } 82 83 LOCK_WEAKREFS(obj); 84 #ifdef Py_GIL_DISABLED 85 if (ref->wr_object == Py_None) { 86 // clear_weakref() was called 87 UNLOCK_WEAKREFS(obj); 88 return NULL; 89 } 90 #endif 91 if (_Py_TryIncref(obj)) { 92 UNLOCK_WEAKREFS(obj); 93 return obj; 94 } 95 UNLOCK_WEAKREFS(obj); 96 return NULL; 97 } 98 99 static inline int _PyWeakref_IS_DEAD(PyObject *ref_obj) 100 { 101 assert(PyWeakref_Check(ref_obj)); 102 int ret = 0; 103 PyWeakReference *ref = _Py_CAST(PyWeakReference*, ref_obj); 104 PyObject *obj = FT_ATOMIC_LOAD_PTR(ref->wr_object); 105 if (obj == Py_None) { 106 // clear_weakref() was called 107 ret = 1; 108 } 109 else { 110 LOCK_WEAKREFS(obj); 111 // See _PyWeakref_GET_REF() for the rationale of this test 112 #ifdef Py_GIL_DISABLED 113 ret = (ref->wr_object == Py_None) || _is_dead(obj); 114 #else 115 ret = _is_dead(obj); 116 #endif 117 UNLOCK_WEAKREFS(obj); 118 } 119 return ret; 120 } 121 122 extern Py_ssize_t _PyWeakref_GetWeakrefCount(PyObject *obj); 123 124 // Clear all the weak references to obj but leave their callbacks uncalled and 125 // intact. 126 extern void _PyWeakref_ClearWeakRefsNoCallbacks(PyObject *obj); 127 128 PyAPI_FUNC(int) _PyWeakref_IsDead(PyObject *weakref); 129 130 #ifdef __cplusplus 131 } 132 #endif 133 #endif /* !Py_INTERNAL_WEAKREF_H */