@@ -73,21 +73,16 @@ get_legacy_reftotal(void)
7373 interp->object_state.reftotal
7474
7575static inline void
76- reftotal_increment ( PyInterpreterState * interp )
76+ reftotal_add ( PyThreadState * tstate , Py_ssize_t n )
7777{
78- REFTOTAL (interp )++ ;
79- }
80-
81- static inline void
82- reftotal_decrement (PyInterpreterState * interp )
83- {
84- REFTOTAL (interp )-- ;
85- }
86-
87- static inline void
88- reftotal_add (PyInterpreterState * interp , Py_ssize_t n )
89- {
90- REFTOTAL (interp ) += n ;
78+ #ifdef Py_GIL_DISABLED
79+ _PyThreadStateImpl * tstate_impl = (_PyThreadStateImpl * )tstate ;
80+ // relaxed store to avoid data race with read in get_reftotal()
81+ Py_ssize_t reftotal = tstate_impl -> reftotal + n ;
82+ _Py_atomic_store_ssize_relaxed (& tstate_impl -> reftotal , reftotal );
83+ #else
84+ REFTOTAL (tstate -> interp ) += n ;
85+ #endif
9186}
9287
9388static inline Py_ssize_t get_global_reftotal (_PyRuntimeState * );
@@ -117,7 +112,15 @@ get_reftotal(PyInterpreterState *interp)
117112{
118113 /* For a single interpreter, we ignore the legacy _Py_RefTotal,
119114 since we can't determine which interpreter updated it. */
120- return REFTOTAL (interp );
115+ Py_ssize_t total = REFTOTAL (interp );
116+ #ifdef Py_GIL_DISABLED
117+ for (PyThreadState * p = interp -> threads .head ; p != NULL ; p = p -> next ) {
118+ /* This may race with other threads modifications to their reftotal */
119+ _PyThreadStateImpl * tstate_impl = (_PyThreadStateImpl * )p ;
120+ total += _Py_atomic_load_ssize_relaxed (& tstate_impl -> reftotal );
121+ }
122+ #endif
123+ return total ;
121124}
122125
123126static inline Py_ssize_t
@@ -129,7 +132,7 @@ get_global_reftotal(_PyRuntimeState *runtime)
129132 HEAD_LOCK (& _PyRuntime );
130133 PyInterpreterState * interp = PyInterpreterState_Head ();
131134 for (; interp != NULL ; interp = PyInterpreterState_Next (interp )) {
132- total += REFTOTAL (interp );
135+ total += get_reftotal (interp );
133136 }
134137 HEAD_UNLOCK (& _PyRuntime );
135138
@@ -222,32 +225,32 @@ _Py_NegativeRefcount(const char *filename, int lineno, PyObject *op)
222225void
223226_Py_INCREF_IncRefTotal (void )
224227{
225- reftotal_increment ( _PyInterpreterState_GET () );
228+ reftotal_add ( _PyThreadState_GET (), 1 );
226229}
227230
228231/* This is used strictly by Py_DECREF(). */
229232void
230233_Py_DECREF_DecRefTotal (void )
231234{
232- reftotal_decrement ( _PyInterpreterState_GET () );
235+ reftotal_add ( _PyThreadState_GET (), -1 );
233236}
234237
235238void
236- _Py_IncRefTotal (PyInterpreterState * interp )
239+ _Py_IncRefTotal (PyThreadState * tstate )
237240{
238- reftotal_increment ( interp );
241+ reftotal_add ( tstate , 1 );
239242}
240243
241244void
242- _Py_DecRefTotal (PyInterpreterState * interp )
245+ _Py_DecRefTotal (PyThreadState * tstate )
243246{
244- reftotal_decrement ( interp );
247+ reftotal_add ( tstate , -1 );
245248}
246249
247250void
248- _Py_AddRefTotal (PyInterpreterState * interp , Py_ssize_t n )
251+ _Py_AddRefTotal (PyThreadState * tstate , Py_ssize_t n )
249252{
250- reftotal_add (interp , n );
253+ reftotal_add (tstate , n );
251254}
252255
253256/* This includes the legacy total
@@ -267,7 +270,10 @@ _Py_GetLegacyRefTotal(void)
267270Py_ssize_t
268271_PyInterpreterState_GetRefTotal (PyInterpreterState * interp )
269272{
270- return get_reftotal (interp );
273+ HEAD_LOCK (& _PyRuntime );
274+ Py_ssize_t total = get_reftotal (interp );
275+ HEAD_UNLOCK (& _PyRuntime );
276+ return total ;
271277}
272278
273279#endif /* Py_REF_DEBUG */
@@ -345,7 +351,7 @@ _Py_DecRefSharedDebug(PyObject *o, const char *filename, int lineno)
345351
346352 if (should_queue ) {
347353#ifdef Py_REF_DEBUG
348- _Py_IncRefTotal (_PyInterpreterState_GET ());
354+ _Py_IncRefTotal (_PyThreadState_GET ());
349355#endif
350356 _Py_brc_queue_object (o );
351357 }
@@ -405,7 +411,7 @@ _Py_ExplicitMergeRefcount(PyObject *op, Py_ssize_t extra)
405411 & shared , new_shared ));
406412
407413#ifdef Py_REF_DEBUG
408- _Py_AddRefTotal (_PyInterpreterState_GET (), extra );
414+ _Py_AddRefTotal (_PyThreadState_GET (), extra );
409415#endif
410416
411417 _Py_atomic_store_uint32_relaxed (& op -> ob_ref_local , 0 );
@@ -2376,7 +2382,7 @@ void
23762382_Py_NewReference (PyObject * op )
23772383{
23782384#ifdef Py_REF_DEBUG
2379- reftotal_increment ( _PyInterpreterState_GET ());
2385+ _Py_IncRefTotal ( _PyThreadState_GET ());
23802386#endif
23812387 new_reference (op );
23822388}
0 commit comments