@@ -74,21 +74,16 @@ get_legacy_reftotal(void)
74
74
interp->object_state.reftotal
75
75
76
76
static inline void
77
- reftotal_increment ( PyInterpreterState * interp )
77
+ reftotal_add ( PyThreadState * tstate , Py_ssize_t n )
78
78
{
79
- REFTOTAL (interp )++ ;
80
- }
81
-
82
- static inline void
83
- reftotal_decrement (PyInterpreterState * interp )
84
- {
85
- REFTOTAL (interp )-- ;
86
- }
87
-
88
- static inline void
89
- reftotal_add (PyInterpreterState * interp , Py_ssize_t n )
90
- {
91
- REFTOTAL (interp ) += n ;
79
+ #ifdef Py_GIL_DISABLED
80
+ _PyThreadStateImpl * tstate_impl = (_PyThreadStateImpl * )tstate ;
81
+ // relaxed store to avoid data race with read in get_reftotal()
82
+ Py_ssize_t reftotal = tstate_impl -> reftotal + n ;
83
+ _Py_atomic_store_ssize_relaxed (& tstate_impl -> reftotal , reftotal );
84
+ #else
85
+ REFTOTAL (tstate -> interp ) += n ;
86
+ #endif
92
87
}
93
88
94
89
static inline Py_ssize_t get_global_reftotal (_PyRuntimeState * );
@@ -118,7 +113,15 @@ get_reftotal(PyInterpreterState *interp)
118
113
{
119
114
/* For a single interpreter, we ignore the legacy _Py_RefTotal,
120
115
since we can't determine which interpreter updated it. */
121
- return REFTOTAL (interp );
116
+ Py_ssize_t total = REFTOTAL (interp );
117
+ #ifdef Py_GIL_DISABLED
118
+ for (PyThreadState * p = interp -> threads .head ; p != NULL ; p = p -> next ) {
119
+ /* This may race with other threads modifications to their reftotal */
120
+ _PyThreadStateImpl * tstate_impl = (_PyThreadStateImpl * )p ;
121
+ total += _Py_atomic_load_ssize_relaxed (& tstate_impl -> reftotal );
122
+ }
123
+ #endif
124
+ return total ;
122
125
}
123
126
124
127
static inline Py_ssize_t
@@ -130,7 +133,7 @@ get_global_reftotal(_PyRuntimeState *runtime)
130
133
HEAD_LOCK (& _PyRuntime );
131
134
PyInterpreterState * interp = PyInterpreterState_Head ();
132
135
for (; interp != NULL ; interp = PyInterpreterState_Next (interp )) {
133
- total += REFTOTAL (interp );
136
+ total += get_reftotal (interp );
134
137
}
135
138
HEAD_UNLOCK (& _PyRuntime );
136
139
@@ -223,32 +226,32 @@ _Py_NegativeRefcount(const char *filename, int lineno, PyObject *op)
223
226
void
224
227
_Py_INCREF_IncRefTotal (void )
225
228
{
226
- reftotal_increment ( _PyInterpreterState_GET () );
229
+ reftotal_add ( _PyThreadState_GET (), 1 );
227
230
}
228
231
229
232
/* This is used strictly by Py_DECREF(). */
230
233
void
231
234
_Py_DECREF_DecRefTotal (void )
232
235
{
233
- reftotal_decrement ( _PyInterpreterState_GET () );
236
+ reftotal_add ( _PyThreadState_GET (), -1 );
234
237
}
235
238
236
239
void
237
- _Py_IncRefTotal (PyInterpreterState * interp )
240
+ _Py_IncRefTotal (PyThreadState * tstate )
238
241
{
239
- reftotal_increment ( interp );
242
+ reftotal_add ( tstate , 1 );
240
243
}
241
244
242
245
void
243
- _Py_DecRefTotal (PyInterpreterState * interp )
246
+ _Py_DecRefTotal (PyThreadState * tstate )
244
247
{
245
- reftotal_decrement ( interp );
248
+ reftotal_add ( tstate , -1 );
246
249
}
247
250
248
251
void
249
- _Py_AddRefTotal (PyInterpreterState * interp , Py_ssize_t n )
252
+ _Py_AddRefTotal (PyThreadState * tstate , Py_ssize_t n )
250
253
{
251
- reftotal_add (interp , n );
254
+ reftotal_add (tstate , n );
252
255
}
253
256
254
257
/* This includes the legacy total
@@ -268,7 +271,10 @@ _Py_GetLegacyRefTotal(void)
268
271
Py_ssize_t
269
272
_PyInterpreterState_GetRefTotal (PyInterpreterState * interp )
270
273
{
271
- return get_reftotal (interp );
274
+ HEAD_LOCK (& _PyRuntime );
275
+ Py_ssize_t total = get_reftotal (interp );
276
+ HEAD_UNLOCK (& _PyRuntime );
277
+ return total ;
272
278
}
273
279
274
280
#endif /* Py_REF_DEBUG */
@@ -346,7 +352,7 @@ _Py_DecRefSharedDebug(PyObject *o, const char *filename, int lineno)
346
352
347
353
if (should_queue ) {
348
354
#ifdef Py_REF_DEBUG
349
- _Py_IncRefTotal (_PyInterpreterState_GET ());
355
+ _Py_IncRefTotal (_PyThreadState_GET ());
350
356
#endif
351
357
_Py_brc_queue_object (o );
352
358
}
@@ -406,7 +412,7 @@ _Py_ExplicitMergeRefcount(PyObject *op, Py_ssize_t extra)
406
412
& shared , new_shared ));
407
413
408
414
#ifdef Py_REF_DEBUG
409
- _Py_AddRefTotal (_PyInterpreterState_GET (), extra );
415
+ _Py_AddRefTotal (_PyThreadState_GET (), extra );
410
416
#endif
411
417
412
418
_Py_atomic_store_uint32_relaxed (& op -> ob_ref_local , 0 );
@@ -2374,7 +2380,7 @@ void
2374
2380
_Py_NewReference (PyObject * op )
2375
2381
{
2376
2382
#ifdef Py_REF_DEBUG
2377
- reftotal_increment ( _PyInterpreterState_GET ());
2383
+ _Py_IncRefTotal ( _PyThreadState_GET ());
2378
2384
#endif
2379
2385
new_reference (op );
2380
2386
}
0 commit comments