Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-11-19 09:50:52

0001 #ifndef Py_INTERNAL_WEAKREF_H
0002 #define Py_INTERNAL_WEAKREF_H
0003 #ifdef __cplusplus
0004 extern "C" {
0005 #endif
0006 
0007 #ifndef Py_BUILD_CORE
0008 #  error "this header requires Py_BUILD_CORE define"
0009 #endif
0010 
0011 #include "pycore_critical_section.h" // Py_BEGIN_CRITICAL_SECTION()
0012 #include "pycore_lock.h"
0013 #include "pycore_object.h"           // _Py_REF_IS_MERGED()
0014 #include "pycore_pyatomic_ft_wrappers.h"
0015 
0016 #ifdef Py_GIL_DISABLED
0017 
0018 #define WEAKREF_LIST_LOCK(obj) \
0019     _PyInterpreterState_GET()  \
0020         ->weakref_locks[((uintptr_t)obj) % NUM_WEAKREF_LIST_LOCKS]
0021 
0022 // Lock using the referenced object
0023 #define LOCK_WEAKREFS(obj) \
0024     PyMutex_LockFlags(&WEAKREF_LIST_LOCK(obj), _Py_LOCK_DONT_DETACH)
0025 #define UNLOCK_WEAKREFS(obj) PyMutex_Unlock(&WEAKREF_LIST_LOCK(obj))
0026 
0027 // Lock using a weakref
0028 #define LOCK_WEAKREFS_FOR_WR(wr) \
0029     PyMutex_LockFlags(wr->weakrefs_lock, _Py_LOCK_DONT_DETACH)
0030 #define UNLOCK_WEAKREFS_FOR_WR(wr) PyMutex_Unlock(wr->weakrefs_lock)
0031 
0032 #else
0033 
0034 #define LOCK_WEAKREFS(obj)
0035 #define UNLOCK_WEAKREFS(obj)
0036 
0037 #define LOCK_WEAKREFS_FOR_WR(wr)
0038 #define UNLOCK_WEAKREFS_FOR_WR(wr)
0039 
0040 #endif
0041 
0042 static inline int _is_dead(PyObject *obj)
0043 {
0044     // Explanation for the Py_REFCNT() check: when a weakref's target is part
0045     // of a long chain of deallocations which triggers the trashcan mechanism,
0046     // clearing the weakrefs can be delayed long after the target's refcount
0047     // has dropped to zero.  In the meantime, code accessing the weakref will
0048     // be able to "see" the target object even though it is supposed to be
0049     // unreachable.  See issue gh-60806.
0050 #if defined(Py_GIL_DISABLED)
0051     Py_ssize_t shared = _Py_atomic_load_ssize_relaxed(&obj->ob_ref_shared);
0052     return shared == _Py_REF_SHARED(0, _Py_REF_MERGED);
0053 #else
0054     return (Py_REFCNT(obj) == 0);
0055 #endif
0056 }
0057 
0058 static inline PyObject* _PyWeakref_GET_REF(PyObject *ref_obj)
0059 {
0060     assert(PyWeakref_Check(ref_obj));
0061     PyWeakReference *ref = _Py_CAST(PyWeakReference*, ref_obj);
0062 
0063     PyObject *obj = FT_ATOMIC_LOAD_PTR(ref->wr_object);
0064     if (obj == Py_None) {
0065         // clear_weakref() was called
0066         return NULL;
0067     }
0068 
0069     LOCK_WEAKREFS(obj);
0070 #ifdef Py_GIL_DISABLED
0071     if (ref->wr_object == Py_None) {
0072         // clear_weakref() was called
0073         UNLOCK_WEAKREFS(obj);
0074         return NULL;
0075     }
0076 #endif
0077     if (_Py_TryIncref(obj)) {
0078         UNLOCK_WEAKREFS(obj);
0079         return obj;
0080     }
0081     UNLOCK_WEAKREFS(obj);
0082     return NULL;
0083 }
0084 
0085 static inline int _PyWeakref_IS_DEAD(PyObject *ref_obj)
0086 {
0087     assert(PyWeakref_Check(ref_obj));
0088     int ret = 0;
0089     PyWeakReference *ref = _Py_CAST(PyWeakReference*, ref_obj);
0090     PyObject *obj = FT_ATOMIC_LOAD_PTR(ref->wr_object);
0091     if (obj == Py_None) {
0092         // clear_weakref() was called
0093         ret = 1;
0094     }
0095     else {
0096         LOCK_WEAKREFS(obj);
0097         // See _PyWeakref_GET_REF() for the rationale of this test
0098 #ifdef Py_GIL_DISABLED
0099         ret = (ref->wr_object == Py_None) || _is_dead(obj);
0100 #else
0101         ret = _is_dead(obj);
0102 #endif
0103         UNLOCK_WEAKREFS(obj);
0104     }
0105     return ret;
0106 }
0107 
0108 extern Py_ssize_t _PyWeakref_GetWeakrefCount(PyObject *obj);
0109 
0110 // Clear all the weak references to obj but leave their callbacks uncalled and
0111 // intact.
0112 extern void _PyWeakref_ClearWeakRefsNoCallbacks(PyObject *obj);
0113 
0114 PyAPI_FUNC(int) _PyWeakref_IsDead(PyObject *weakref);
0115 
0116 #ifdef __cplusplus
0117 }
0118 #endif
0119 #endif /* !Py_INTERNAL_WEAKREF_H */