}
-/* Bit flags for ob_gc_bits (in Py_GIL_DISABLED builds) */
+/* Bit flags for ob_gc_bits (in Py_GIL_DISABLED builds)
+ *
+ * Setting the bits requires a relaxed store. The per-object lock must also be
+ * held, except when the object is only visible to a single thread (e.g. during
+ * object initialization or destruction).
+ *
+ * Reading the bits requires using a relaxed load, but does not require holding
+ * the per-object lock.
+ */
#ifdef Py_GIL_DISABLED
# define _PyGC_BITS_TRACKED (1) // Tracked by the GC
# define _PyGC_BITS_FINALIZED (2) // tp_finalize was called
# define _PyGC_BITS_DEFERRED (64) // Use deferred reference counting
#endif
+#ifdef Py_GIL_DISABLED
+
+static inline void
+_PyObject_SET_GC_BITS(PyObject *op, uint8_t new_bits)
+{
+ uint8_t bits = _Py_atomic_load_uint8_relaxed(&op->ob_gc_bits);
+ _Py_atomic_store_uint8_relaxed(&op->ob_gc_bits, bits | new_bits);
+}
+
+static inline int
+_PyObject_HAS_GC_BITS(PyObject *op, uint8_t bits)
+{
+ return (_Py_atomic_load_uint8_relaxed(&op->ob_gc_bits) & bits) != 0;
+}
+
+static inline void
+_PyObject_CLEAR_GC_BITS(PyObject *op, uint8_t bits_to_clear)
+{
+ uint8_t bits = _Py_atomic_load_uint8_relaxed(&op->ob_gc_bits);
+ _Py_atomic_store_uint8_relaxed(&op->ob_gc_bits, bits & ~bits_to_clear);
+}
+
+#endif
+
/* True if the object is currently tracked by the GC. */
static inline int _PyObject_GC_IS_TRACKED(PyObject *op) {
#ifdef Py_GIL_DISABLED
- return (op->ob_gc_bits & _PyGC_BITS_TRACKED) != 0;
+ return _PyObject_HAS_GC_BITS(op, _PyGC_BITS_TRACKED);
#else
PyGC_Head *gc = _Py_AS_GC(op);
return (gc->_gc_next != 0);
* for calling _PyMem_FreeDelayed on the referenced
* memory. */
static inline int _PyObject_GC_IS_SHARED(PyObject *op) {
- return (op->ob_gc_bits & _PyGC_BITS_SHARED) != 0;
+ return _PyObject_HAS_GC_BITS(op, _PyGC_BITS_SHARED);
}
#define _PyObject_GC_IS_SHARED(op) _PyObject_GC_IS_SHARED(_Py_CAST(PyObject*, op))
static inline void _PyObject_GC_SET_SHARED(PyObject *op) {
- op->ob_gc_bits |= _PyGC_BITS_SHARED;
+ _PyObject_SET_GC_BITS(op, _PyGC_BITS_SHARED);
}
#define _PyObject_GC_SET_SHARED(op) _PyObject_GC_SET_SHARED(_Py_CAST(PyObject*, op))
* Objects with this bit that are GC objects will automatically
* delay-freed by PyObject_GC_Del. */
static inline int _PyObject_GC_IS_SHARED_INLINE(PyObject *op) {
- return (op->ob_gc_bits & _PyGC_BITS_SHARED_INLINE) != 0;
+ return _PyObject_HAS_GC_BITS(op, _PyGC_BITS_SHARED_INLINE);
}
#define _PyObject_GC_IS_SHARED_INLINE(op) \
_PyObject_GC_IS_SHARED_INLINE(_Py_CAST(PyObject*, op))
static inline void _PyObject_GC_SET_SHARED_INLINE(PyObject *op) {
- op->ob_gc_bits |= _PyGC_BITS_SHARED_INLINE;
+ _PyObject_SET_GC_BITS(op, _PyGC_BITS_SHARED_INLINE);
}
#define _PyObject_GC_SET_SHARED_INLINE(op) \
_PyObject_GC_SET_SHARED_INLINE(_Py_CAST(PyObject*, op))
static inline int _PyGC_FINALIZED(PyObject *op) {
#ifdef Py_GIL_DISABLED
- return (op->ob_gc_bits & _PyGC_BITS_FINALIZED) != 0;
+ return _PyObject_HAS_GC_BITS(op, _PyGC_BITS_FINALIZED);
#else
PyGC_Head *gc = _Py_AS_GC(op);
return ((gc->_gc_prev & _PyGC_PREV_MASK_FINALIZED) != 0);
}
static inline void _PyGC_SET_FINALIZED(PyObject *op) {
#ifdef Py_GIL_DISABLED
- op->ob_gc_bits |= _PyGC_BITS_FINALIZED;
+ _PyObject_SET_GC_BITS(op, _PyGC_BITS_FINALIZED);
#else
PyGC_Head *gc = _Py_AS_GC(op);
gc->_gc_prev |= _PyGC_PREV_MASK_FINALIZED;
}
static inline void _PyGC_CLEAR_FINALIZED(PyObject *op) {
#ifdef Py_GIL_DISABLED
- op->ob_gc_bits &= ~_PyGC_BITS_FINALIZED;
+ _PyObject_CLEAR_GC_BITS(op, _PyGC_BITS_FINALIZED);
#else
PyGC_Head *gc = _Py_AS_GC(op);
gc->_gc_prev &= ~_PyGC_PREV_MASK_FINALIZED;
_PyObject_HasDeferredRefcount(PyObject *op)
{
#ifdef Py_GIL_DISABLED
- return (op->ob_gc_bits & _PyGC_BITS_DEFERRED) != 0;
+ return _PyObject_HAS_GC_BITS(op, _PyGC_BITS_DEFERRED);
#else
return 0;
#endif
"object already tracked by the garbage collector",
filename, lineno, __func__);
#ifdef Py_GIL_DISABLED
- op->ob_gc_bits |= _PyGC_BITS_TRACKED;
+ _PyObject_SET_GC_BITS(op, _PyGC_BITS_TRACKED);
#else
PyGC_Head *gc = _Py_AS_GC(op);
_PyObject_ASSERT_FROM(op,
filename, lineno, __func__);
#ifdef Py_GIL_DISABLED
- op->ob_gc_bits &= ~_PyGC_BITS_TRACKED;
+ _PyObject_CLEAR_GC_BITS(op, _PyGC_BITS_TRACKED);
#else
PyGC_Head *gc = _Py_AS_GC(op);
PyGC_Head *prev = _PyGCHead_PREV(gc);