@@ -9,7 +9,35 @@ extern "C" {
9
9
#endif
10
10
11
11
#include "pycore_critical_section.h" // Py_BEGIN_CRITICAL_SECTION()
12
+ #include "pycore_lock.h"
12
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
13
41
14
42
static inline int _is_dead (PyObject * obj )
15
43
{
@@ -30,53 +58,64 @@ static inline int _is_dead(PyObject *obj)
30
58
static inline PyObject * _PyWeakref_GET_REF (PyObject * ref_obj )
31
59
{
32
60
assert (PyWeakref_Check (ref_obj ));
33
- PyObject * ret = NULL ;
34
- Py_BEGIN_CRITICAL_SECTION (ref_obj );
35
61
PyWeakReference * ref = _Py_CAST (PyWeakReference * , ref_obj );
36
- PyObject * obj = ref -> wr_object ;
37
62
63
+ PyObject * obj = FT_ATOMIC_LOAD_PTR (ref -> wr_object );
38
64
if (obj == Py_None ) {
39
65
// clear_weakref() was called
40
- goto end ;
66
+ return NULL ;
41
67
}
42
68
43
- if (_is_dead (obj )) {
44
- goto end ;
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 ;
45
75
}
46
- #if !defined(Py_GIL_DISABLED )
47
- assert (Py_REFCNT (obj ) > 0 );
48
76
#endif
49
- ret = Py_NewRef (obj );
50
- end :
51
- Py_END_CRITICAL_SECTION ();
52
- return ret ;
77
+ if (_Py_TryIncref (obj )) {
78
+ UNLOCK_WEAKREFS (obj );
79
+ return obj ;
80
+ }
81
+ UNLOCK_WEAKREFS (obj );
82
+ return NULL ;
53
83
}
54
84
55
85
static inline int _PyWeakref_IS_DEAD (PyObject * ref_obj )
56
86
{
57
87
assert (PyWeakref_Check (ref_obj ));
58
88
int ret = 0 ;
59
- Py_BEGIN_CRITICAL_SECTION (ref_obj );
60
89
PyWeakReference * ref = _Py_CAST (PyWeakReference * , ref_obj );
61
- PyObject * obj = ref -> wr_object ;
90
+ PyObject * obj = FT_ATOMIC_LOAD_PTR ( ref -> wr_object ) ;
62
91
if (obj == Py_None ) {
63
92
// clear_weakref() was called
64
93
ret = 1 ;
65
94
}
66
95
else {
96
+ LOCK_WEAKREFS (obj );
67
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
68
101
ret = _is_dead (obj );
102
+ #endif
103
+ UNLOCK_WEAKREFS (obj );
69
104
}
70
- Py_END_CRITICAL_SECTION ();
71
105
return ret ;
72
106
}
73
107
74
- extern Py_ssize_t _PyWeakref_GetWeakrefCount (PyWeakReference * head );
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_ClearWeakRefsExceptCallbacks (PyObject * obj );
75
113
76
114
extern void _PyWeakref_ClearRef (PyWeakReference * self );
77
115
116
+ PyAPI_FUNC (int ) _PyWeakref_IsDead (PyObject * weakref );
117
+
78
118
#ifdef __cplusplus
79
119
}
80
120
#endif
81
121
#endif /* !Py_INTERNAL_WEAKREF_H */
82
-
0 commit comments