Skip to content

Commit b478d5e

Browse files
committed
fix tsan
1 parent 6a74e94 commit b478d5e

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
@@ -787,6 +787,7 @@ struct _is {
787787
int finalizing;
788788

789789
uintptr_t last_restart_version;
790+
Py_ssize_t _owners;
790791
struct pythreads {
791792
uint64_t next_unique_id;
792793
/* The linked list of threads, newest first. */

Python/pystate.c

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -488,6 +488,23 @@ free_interpreter(PyInterpreterState *interp)
488488
}
489489
}
490490

491+
static void
492+
_finalize_and_free_interpreter(PyInterpreterState *interp)
493+
{
494+
_Py_qsbr_fini(interp);
495+
_PyObject_FiniState(interp);
496+
free_interpreter(interp);
497+
}
498+
499+
static inline void
500+
_interp_release_owner(PyInterpreterState *interp)
501+
{
502+
Py_ssize_t prev = _Py_atomic_add_ssize(&interp->_owners, -1);
503+
if (prev == 1) {
504+
_finalize_and_free_interpreter(interp);
505+
}
506+
}
507+
491508
#ifndef NDEBUG
492509
static inline int check_interpreter_whence(long);
493510
#endif
@@ -537,6 +554,7 @@ init_interpreter(PyInterpreterState *interp,
537554
interp->id = id;
538555

539556
interp->id_refcount = 0;
557+
interp->_owners = 1;
540558

541559
assert(runtime->interpreters.head == interp);
542560
assert(next != NULL || (interp == runtime->interpreters.main));
@@ -958,11 +976,9 @@ PyInterpreterState_Delete(PyInterpreterState *interp)
958976
}
959977
HEAD_UNLOCK(runtime);
960978

961-
_Py_qsbr_fini(interp);
962-
963-
_PyObject_FiniState(interp);
979+
interp->finalizing = 1;
964980

965-
free_interpreter(interp);
981+
_interp_release_owner(interp);
966982
}
967983

968984

@@ -1415,6 +1431,7 @@ static void
14151431
free_threadstate(_PyThreadStateImpl *tstate)
14161432
{
14171433
PyInterpreterState *interp = tstate->base.interp;
1434+
14181435
// The initial thread state of the interpreter is allocated
14191436
// as part of the interpreter state so should not be freed.
14201437
if (tstate == &interp->_initial_thread) {
@@ -1426,6 +1443,8 @@ free_threadstate(_PyThreadStateImpl *tstate)
14261443
else {
14271444
PyMem_RawFree(tstate);
14281445
}
1446+
1447+
_interp_release_owner(interp);
14291448
}
14301449

14311450
static void
@@ -1552,6 +1571,8 @@ new_threadstate(PyInterpreterState *interp, int whence)
15521571
uint64_t id = interp->threads.next_unique_id;
15531572
init_threadstate(tstate, interp, id, whence);
15541573

1574+
_Py_atomic_add_ssize(&interp->_owners, 1);
1575+
15551576
// Add the new thread state to the interpreter.
15561577
PyThreadState *old_head = interp->threads.head;
15571578
add_threadstate(interp, (PyThreadState *)tstate, old_head);

0 commit comments

Comments
 (0)