Skip to content

Commit 115e4d2

Browse files
committed
fix tsan
1 parent 5f357f3 commit 115e4d2

File tree

2 files changed

+26
-4
lines changed

2 files changed

+26
-4
lines changed

Include/internal/pycore_interp_structs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -793,6 +793,7 @@ struct _is {
793793
int finalizing;
794794

795795
uintptr_t last_restart_version;
796+
Py_ssize_t _owners;
796797
struct pythreads {
797798
uint64_t next_unique_id;
798799
/* The linked list of threads, newest first. */

Python/pystate.c

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -485,6 +485,23 @@ free_interpreter(PyInterpreterState *interp)
485485
}
486486
}
487487

488+
static void
489+
_finalize_and_free_interpreter(PyInterpreterState *interp)
490+
{
491+
_Py_qsbr_fini(interp);
492+
_PyObject_FiniState(interp);
493+
free_interpreter(interp);
494+
}
495+
496+
static inline void
497+
_interp_release_owner(PyInterpreterState *interp)
498+
{
499+
Py_ssize_t prev = _Py_atomic_add_ssize(&interp->_owners, -1);
500+
if (prev == 1) {
501+
_finalize_and_free_interpreter(interp);
502+
}
503+
}
504+
488505
#ifndef NDEBUG
489506
static inline int check_interpreter_whence(long);
490507
#endif
@@ -534,6 +551,7 @@ init_interpreter(PyInterpreterState *interp,
534551
interp->id = id;
535552

536553
interp->id_refcount = 0;
554+
interp->_owners = 1;
537555

538556
assert(runtime->interpreters.head == interp);
539557
assert(next != NULL || (interp == runtime->interpreters.main));
@@ -955,11 +973,9 @@ PyInterpreterState_Delete(PyInterpreterState *interp)
955973
}
956974
HEAD_UNLOCK(runtime);
957975

958-
_Py_qsbr_fini(interp);
959-
960-
_PyObject_FiniState(interp);
976+
interp->finalizing = 1;
961977

962-
free_interpreter(interp);
978+
_interp_release_owner(interp);
963979
}
964980

965981

@@ -1412,6 +1428,7 @@ static void
14121428
free_threadstate(_PyThreadStateImpl *tstate)
14131429
{
14141430
PyInterpreterState *interp = tstate->base.interp;
1431+
14151432
// The initial thread state of the interpreter is allocated
14161433
// as part of the interpreter state so should not be freed.
14171434
if (tstate == &interp->_initial_thread) {
@@ -1423,6 +1440,8 @@ free_threadstate(_PyThreadStateImpl *tstate)
14231440
else {
14241441
PyMem_RawFree(tstate);
14251442
}
1443+
1444+
_interp_release_owner(interp);
14261445
}
14271446

14281447
static void
@@ -1549,6 +1568,8 @@ new_threadstate(PyInterpreterState *interp, int whence)
15491568
uint64_t id = interp->threads.next_unique_id;
15501569
init_threadstate(tstate, interp, id, whence);
15511570

1571+
_Py_atomic_add_ssize(&interp->_owners, 1);
1572+
15521573
// Add the new thread state to the interpreter.
15531574
PyThreadState *old_head = interp->threads.head;
15541575
add_threadstate(interp, (PyThreadState *)tstate, old_head);

0 commit comments

Comments
 (0)