Skip to content

Commit

Permalink
pystate: implement _PyRuntime.multithreaded
Browse files Browse the repository at this point in the history
The _PyRuntime.multithreaded variable can be used to optimize for
single-threaded programs. It's zero if there is only one thread or if
the GIL is enabled.
  • Loading branch information
colesbury committed Apr 23, 2023
1 parent 7423dff commit 86efa7d
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 1 deletion.
4 changes: 4 additions & 0 deletions Include/internal/pycore_runtime.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
32 changes: 31 additions & 1 deletion Python/pystate.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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);
}
Expand Down

0 comments on commit 86efa7d

Please sign in to comment.