Skip to content

Commit dc8140b

Browse files
colesburydiegorusso
authored andcommitted
pythongh-110481: Fix biased reference counting queue initialization. (python#117271)
The biased reference counting queue must be initialized from the bound (active) thread because it uses `_Py_ThreadId()` as the key in a hash table.
1 parent 8f572b4 commit dc8140b

File tree

2 files changed

+18
-6
lines changed

2 files changed

+18
-6
lines changed

Python/brc.c

+12-2
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,8 @@ _Py_brc_merge_refcounts(PyThreadState *tstate)
119119
struct _brc_thread_state *brc = &((_PyThreadStateImpl *)tstate)->brc;
120120
struct _brc_bucket *bucket = get_bucket(tstate->interp, brc->tid);
121121

122+
assert(brc->tid == _Py_ThreadId());
123+
122124
// Append all objects into a local stack. We don't want to hold the lock
123125
// while calling destructors.
124126
PyMutex_Lock(&bucket->mutex);
@@ -142,11 +144,12 @@ void
142144
_Py_brc_init_thread(PyThreadState *tstate)
143145
{
144146
struct _brc_thread_state *brc = &((_PyThreadStateImpl *)tstate)->brc;
145-
brc->tid = _Py_ThreadId();
147+
uintptr_t tid = _Py_ThreadId();
146148

147149
// Add ourself to the hashtable
148-
struct _brc_bucket *bucket = get_bucket(tstate->interp, brc->tid);
150+
struct _brc_bucket *bucket = get_bucket(tstate->interp, tid);
149151
PyMutex_Lock(&bucket->mutex);
152+
brc->tid = tid;
150153
llist_insert_tail(&bucket->root, &brc->bucket_node);
151154
PyMutex_Unlock(&bucket->mutex);
152155
}
@@ -155,6 +158,13 @@ void
155158
_Py_brc_remove_thread(PyThreadState *tstate)
156159
{
157160
struct _brc_thread_state *brc = &((_PyThreadStateImpl *)tstate)->brc;
161+
if (brc->tid == 0) {
162+
// The thread state may have been created, but never bound to a native
163+
// thread and therefore never added to the hashtable.
164+
assert(tstate->_status.bound == 0);
165+
return;
166+
}
167+
158168
struct _brc_bucket *bucket = get_bucket(tstate->interp, brc->tid);
159169

160170
// We need to fully process any objects to merge before removing ourself

Python/pystate.c

+6-4
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,12 @@ bind_tstate(PyThreadState *tstate)
261261
tstate->native_thread_id = PyThread_get_thread_native_id();
262262
#endif
263263

264+
#ifdef Py_GIL_DISABLED
265+
// Initialize biased reference counting inter-thread queue. Note that this
266+
// needs to be initialized from the active thread.
267+
_Py_brc_init_thread(tstate);
268+
#endif
269+
264270
// mimalloc state needs to be initialized from the active thread.
265271
tstate_mimalloc_bind(tstate);
266272

@@ -1412,10 +1418,6 @@ init_threadstate(_PyThreadStateImpl *_tstate,
14121418
tstate->what_event = -1;
14131419
tstate->previous_executor = NULL;
14141420

1415-
#ifdef Py_GIL_DISABLED
1416-
// Initialize biased reference counting inter-thread queue
1417-
_Py_brc_init_thread(tstate);
1418-
#endif
14191421
llist_init(&_tstate->mem_free_queue);
14201422

14211423
if (interp->stoptheworld.requested || _PyRuntime.stoptheworld.requested) {

0 commit comments

Comments
 (0)