@@ -37,7 +37,15 @@ static inline PyObject* _Py_FROM_GC(PyGC_Head *gc) {
37
37
}
38
38
39
39
40
- /* Bit flags for ob_gc_bits (in Py_GIL_DISABLED builds) */
40
+ /* Bit flags for ob_gc_bits (in Py_GIL_DISABLED builds)
41
+ *
42
+ * Setting the bits requires a relaxed store. The per-object lock must also be
43
+ * held, except when the object is only visible to a single thread (e.g. during
44
+ * object initialization or destruction).
45
+ *
46
+ * Reading the bits requires using a relaxed load, but does not require holding
47
+ * the per-object lock.
48
+ */
41
49
#ifdef Py_GIL_DISABLED
42
50
# define _PyGC_BITS_TRACKED (1) // Tracked by the GC
43
51
# define _PyGC_BITS_FINALIZED (2) // tp_finalize was called
@@ -48,10 +56,34 @@ static inline PyObject* _Py_FROM_GC(PyGC_Head *gc) {
48
56
# define _PyGC_BITS_DEFERRED (64) // Use deferred reference counting
49
57
#endif
50
58
59
+ #ifdef Py_GIL_DISABLED
60
+
61
+ static inline void
62
+ _PyObject_SET_GC_BITS (PyObject * op , uint8_t new_bits )
63
+ {
64
+ uint8_t bits = _Py_atomic_load_uint8_relaxed (& op -> ob_gc_bits );
65
+ _Py_atomic_store_uint8_relaxed (& op -> ob_gc_bits , bits | new_bits );
66
+ }
67
+
68
+ static inline int
69
+ _PyObject_HAS_GC_BITS (PyObject * op , uint8_t bits )
70
+ {
71
+ return (_Py_atomic_load_uint8_relaxed (& op -> ob_gc_bits ) & bits ) != 0 ;
72
+ }
73
+
74
+ static inline void
75
+ _PyObject_CLEAR_GC_BITS (PyObject * op , uint8_t bits_to_clear )
76
+ {
77
+ uint8_t bits = _Py_atomic_load_uint8_relaxed (& op -> ob_gc_bits );
78
+ _Py_atomic_store_uint8_relaxed (& op -> ob_gc_bits , bits & ~bits_to_clear );
79
+ }
80
+
81
+ #endif
82
+
51
83
/* True if the object is currently tracked by the GC. */
52
84
static inline int _PyObject_GC_IS_TRACKED (PyObject * op ) {
53
85
#ifdef Py_GIL_DISABLED
54
- return (op -> ob_gc_bits & _PyGC_BITS_TRACKED ) != 0 ;
86
+ return _PyObject_HAS_GC_BITS (op , _PyGC_BITS_TRACKED );
55
87
#else
56
88
PyGC_Head * gc = _Py_AS_GC (op );
57
89
return (gc -> _gc_next != 0 );
@@ -80,12 +112,12 @@ static inline int _PyObject_GC_MAY_BE_TRACKED(PyObject *obj) {
80
112
* for calling _PyMem_FreeDelayed on the referenced
81
113
* memory. */
82
114
static inline int _PyObject_GC_IS_SHARED (PyObject * op ) {
83
- return (op -> ob_gc_bits & _PyGC_BITS_SHARED ) != 0 ;
115
+ return _PyObject_HAS_GC_BITS (op , _PyGC_BITS_SHARED );
84
116
}
85
117
#define _PyObject_GC_IS_SHARED (op ) _PyObject_GC_IS_SHARED(_Py_CAST(PyObject*, op))
86
118
87
119
static inline void _PyObject_GC_SET_SHARED (PyObject * op ) {
88
- op -> ob_gc_bits |= _PyGC_BITS_SHARED ;
120
+ _PyObject_SET_GC_BITS ( op , _PyGC_BITS_SHARED ) ;
89
121
}
90
122
#define _PyObject_GC_SET_SHARED (op ) _PyObject_GC_SET_SHARED(_Py_CAST(PyObject*, op))
91
123
@@ -95,13 +127,13 @@ static inline void _PyObject_GC_SET_SHARED(PyObject *op) {
95
127
* Objects with this bit that are GC objects will automatically
96
128
* delay-freed by PyObject_GC_Del. */
97
129
static inline int _PyObject_GC_IS_SHARED_INLINE (PyObject * op ) {
98
- return (op -> ob_gc_bits & _PyGC_BITS_SHARED_INLINE ) != 0 ;
130
+ return _PyObject_HAS_GC_BITS (op , _PyGC_BITS_SHARED_INLINE );
99
131
}
100
132
#define _PyObject_GC_IS_SHARED_INLINE (op ) \
101
133
_PyObject_GC_IS_SHARED_INLINE(_Py_CAST(PyObject*, op))
102
134
103
135
static inline void _PyObject_GC_SET_SHARED_INLINE (PyObject * op ) {
104
- op -> ob_gc_bits |= _PyGC_BITS_SHARED_INLINE ;
136
+ _PyObject_SET_GC_BITS ( op , _PyGC_BITS_SHARED_INLINE ) ;
105
137
}
106
138
#define _PyObject_GC_SET_SHARED_INLINE (op ) \
107
139
_PyObject_GC_SET_SHARED_INLINE(_Py_CAST(PyObject*, op))
@@ -178,23 +210,23 @@ static inline void _PyGCHead_SET_PREV(PyGC_Head *gc, PyGC_Head *prev) {
178
210
179
211
static inline int _PyGC_FINALIZED (PyObject * op ) {
180
212
#ifdef Py_GIL_DISABLED
181
- return (op -> ob_gc_bits & _PyGC_BITS_FINALIZED ) != 0 ;
213
+ return _PyObject_HAS_GC_BITS (op , _PyGC_BITS_FINALIZED );
182
214
#else
183
215
PyGC_Head * gc = _Py_AS_GC (op );
184
216
return ((gc -> _gc_prev & _PyGC_PREV_MASK_FINALIZED ) != 0 );
185
217
#endif
186
218
}
187
219
static inline void _PyGC_SET_FINALIZED (PyObject * op ) {
188
220
#ifdef Py_GIL_DISABLED
189
- op -> ob_gc_bits |= _PyGC_BITS_FINALIZED ;
221
+ _PyObject_SET_GC_BITS ( op , _PyGC_BITS_FINALIZED ) ;
190
222
#else
191
223
PyGC_Head * gc = _Py_AS_GC (op );
192
224
gc -> _gc_prev |= _PyGC_PREV_MASK_FINALIZED ;
193
225
#endif
194
226
}
195
227
static inline void _PyGC_CLEAR_FINALIZED (PyObject * op ) {
196
228
#ifdef Py_GIL_DISABLED
197
- op -> ob_gc_bits &= ~ _PyGC_BITS_FINALIZED ;
229
+ _PyObject_CLEAR_GC_BITS ( op , _PyGC_BITS_FINALIZED ) ;
198
230
#else
199
231
PyGC_Head * gc = _Py_AS_GC (op );
200
232
gc -> _gc_prev &= ~_PyGC_PREV_MASK_FINALIZED ;
0 commit comments