diff --git a/Include/internal/pycore_runtime.h b/Include/internal/pycore_runtime.h index 6327c742d9..9b51c73551 100644 --- a/Include/internal/pycore_runtime.h +++ b/Include/internal/pycore_runtime.h @@ -83,6 +83,10 @@ typedef struct pyruntimestate { /* Is Python fully initialized? Set to 1 by Py_Initialize() */ int initialized; + /* Is there more than one thread? Set to 1 the first time another thread + is created ONLY IF the GIL is disabled. */ + int multithreaded; + /* Has Python started the process of stopping all threads? Protected by HEAD_LOCK() */ int stop_the_world_requested; diff --git a/Python/pystate.c b/Python/pystate.c index 63b55d68ca..80904ed317 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -1058,6 +1058,33 @@ init_threadstate(PyThreadState *tstate, tstate->_initialized = 1; } +static void +set_multithreaded(void) +{ + if (!_PyRuntime.preconfig.disable_gil) { + /* If the GIL is enabled, treat the program as single-threaded */ + return; + } + if (_Py_atomic_load_int(&_PyRuntime.multithreaded)) { + /* already set */ + return; + } + if (_PyThreadState_GET() != NULL) { + /* creating a new thread from the main thread. */ + _Py_atomic_store_int(&_PyRuntime.multithreaded, 1); + } + else { + /* If we don't have an active thread state, we might be creating a new + * thread from C and the main thread may not be aware of it yet. Pause + * it so that it stops doing non-thread safe things before setting + * multithreaded to 1. + */ + _PyRuntimeState_StopTheWorld(&_PyRuntime); + _Py_atomic_store_int(&_PyRuntime.multithreaded, 1); + _PyRuntimeState_StartTheWorld(&_PyRuntime); + } +} + static PyThreadState * new_threadstate(PyInterpreterState *interp, _PyEventRc *done_event) { @@ -1108,7 +1135,10 @@ new_threadstate(PyInterpreterState *interp, _PyEventRc *done_event) init_threadstate(tstate, interp, id, old_head, qsbr, done_event); HEAD_UNLOCK(runtime); - if (!used_newtstate) { + if (used_newtstate) {; + set_multithreaded(); + } + else { // Must be called with lock unlocked to avoid re-entrancy deadlock. PyMem_RawFree(new_tstate); }