Skip to content

Commit

Permalink
Actually make the GIL per-interpreter!
Browse files Browse the repository at this point in the history
  • Loading branch information
ericsnowcurrently committed May 6, 2023
1 parent 3104796 commit 0f39f69
Show file tree
Hide file tree
Showing 7 changed files with 20 additions and 52 deletions.
3 changes: 1 addition & 2 deletions Include/internal/pycore_ceval.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,7 @@ struct _ceval_runtime_state;


extern void _Py_FinishPendingCalls(PyThreadState *tstate);
extern void _PyEval_InitRuntimeState(struct _ceval_runtime_state *);
extern void _PyEval_InitState(struct _ceval_state *, PyThread_type_lock);
extern void _PyEval_InitState(PyInterpreterState *, PyThread_type_lock);
extern void _PyEval_FiniState(struct _ceval_state *ceval);
PyAPI_FUNC(void) _PyEval_SignalReceived(PyInterpreterState *interp);
PyAPI_FUNC(int) _PyEval_AddPendingCall(
Expand Down
3 changes: 0 additions & 3 deletions Include/internal/pycore_ceval_state.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,6 @@ struct _ceval_runtime_state {
the main thread of the main interpreter can handle signals: see
_Py_ThreadCanHandleSignals(). */
_Py_atomic_int signals_pending;

/* This is (only) used indirectly through PyInterpreterState.ceval.gil. */
struct _gil_runtime_state gil;
};

#ifdef PY_HAVE_PERF_TRAMPOLINE
Expand Down
3 changes: 3 additions & 0 deletions Include/internal/pycore_interp.h
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,9 @@ struct _is {
basis. Also see _PyRuntimeState regarding the various mutex fields.
*/

/* The per-interpreter GIL, which might not be used. */
struct _gil_runtime_state _gil;

/* the initial PyInterpreterState.threads.head */
PyThreadState _initial_thread;
};
Expand Down
2 changes: 0 additions & 2 deletions Include/internal/pycore_runtime.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,6 @@ struct _getargs_runtime_state {
struct _PyArg_Parser *static_parsers;
};

/* ceval state */

/* GIL state */

struct _gilstate_runtime_state {
Expand Down
55 changes: 13 additions & 42 deletions Python/ceval_gil.c
Original file line number Diff line number Diff line change
Expand Up @@ -464,17 +464,15 @@ take_gil(PyThreadState *tstate)

void _PyEval_SetSwitchInterval(unsigned long microseconds)
{
/* XXX per-interpreter GIL */
PyInterpreterState *interp = _PyInterpreterState_Main();
PyInterpreterState *interp = _PyInterpreterState_Get();
struct _gil_runtime_state *gil = interp->ceval.gil;
assert(gil != NULL);
gil->interval = microseconds;
}

unsigned long _PyEval_GetSwitchInterval(void)
{
/* XXX per-interpreter GIL */
PyInterpreterState *interp = _PyInterpreterState_Main();
PyInterpreterState *interp = _PyInterpreterState_Get();
struct _gil_runtime_state *gil = interp->ceval.gil;
assert(gil != NULL);
return gil->interval;
Expand All @@ -484,7 +482,9 @@ unsigned long _PyEval_GetSwitchInterval(void)
int
_PyEval_ThreadsInitialized(void)
{
/* XXX per-interpreter GIL */
/* XXX This is only needed for an assert in PyGILState_Ensure(),
* which currently does not work with subinterpreters.
* Thus we only use the main interpreter. */
PyInterpreterState *interp = _PyInterpreterState_Main();
if (interp == NULL) {
return 0;
Expand Down Expand Up @@ -532,27 +532,16 @@ _PyEval_InitGIL(PyThreadState *tstate, int own_gil)
assert(tstate->interp->ceval.gil == NULL);
int locked;
if (!own_gil) {
/* The interpreter will share the main interpreter's instead. */
PyInterpreterState *main_interp = _PyInterpreterState_Main();
assert(tstate->interp != main_interp);
struct _gil_runtime_state *gil = main_interp->ceval.gil;
init_shared_gil(tstate->interp, gil);
locked = current_thread_holds_gil(gil, tstate);
}
/* XXX per-interpreter GIL */
else if (!_Py_IsMainInterpreter(tstate->interp)) {
/* Currently, the GIL is shared by all interpreters,
and only the main interpreter is responsible to create
and destroy it. */
struct _gil_runtime_state *main_gil = _PyInterpreterState_Main()->ceval.gil;
init_shared_gil(tstate->interp, main_gil);
// XXX For now we lie.
tstate->interp->ceval.own_gil = 1;
locked = current_thread_holds_gil(main_gil, tstate);
}
else {
PyThread_init_thread();
// XXX per-interpreter GIL: switch to interp->_gil.
init_own_gil(tstate->interp, &tstate->interp->runtime->ceval.gil);
init_own_gil(tstate->interp, &tstate->interp->_gil);
locked = 0;
}
if (!locked) {
Expand All @@ -565,30 +554,20 @@ _PyEval_InitGIL(PyThreadState *tstate, int own_gil)
void
_PyEval_FiniGIL(PyInterpreterState *interp)
{
if (interp->ceval.gil == NULL) {
struct _gil_runtime_state *gil = interp->ceval.gil;
if (gil == NULL) {
/* It was already finalized (or hasn't been initialized yet). */
assert(!interp->ceval.own_gil);
return;
}
else if (!interp->ceval.own_gil) {
PyInterpreterState *main_interp = _PyInterpreterState_Main();
assert(interp != main_interp);
assert(main_interp != NULL && interp != main_interp);
assert(interp->ceval.gil == main_interp->ceval.gil);
interp->ceval.gil = NULL;
return;
}

/* XXX per-interpreter GIL */
struct _gil_runtime_state *gil = &interp->runtime->ceval.gil;
if (!_Py_IsMainInterpreter(interp)) {
/* Currently, the GIL is shared by all interpreters,
and only the main interpreter is responsible to create
and destroy it. */
assert(interp->ceval.gil == gil);
interp->ceval.gil = NULL;
return;
}

if (!gil_created(gil)) {
/* First Py_InitializeFromConfig() call: the GIL doesn't exist
yet: do nothing. */
Expand Down Expand Up @@ -972,21 +951,13 @@ Py_MakePendingCalls(void)
return 0;
}

/* The interpreter's recursion limit */

void
_PyEval_InitRuntimeState(struct _ceval_runtime_state *ceval)
_PyEval_InitState(PyInterpreterState *interp, PyThread_type_lock pending_lock)
{
/* XXX per-interpreter GIL */
_gil_initialize(&ceval->gil);
}
_gil_initialize(&interp->_gil);

void
_PyEval_InitState(struct _ceval_state *ceval, PyThread_type_lock pending_lock)
{
struct _pending_calls *pending = &ceval->pending;
struct _pending_calls *pending = &interp->ceval.pending;
assert(pending->lock == NULL);

pending->lock = pending_lock;
}

Expand Down
2 changes: 2 additions & 0 deletions Python/pylifecycle.c
Original file line number Diff line number Diff line change
Expand Up @@ -2039,6 +2039,8 @@ new_interpreter(PyThreadState **tstate_p, const PyInterpreterConfig *config)
/* Copy the current interpreter config into the new interpreter */
const PyConfig *src_config;
if (save_tstate != NULL) {
// XXX Might new_interpreter() have been called without the GIL held?
_PyEval_ReleaseLock(save_tstate);
src_config = _PyInterpreterState_GetConfig(save_tstate->interp);
}
else
Expand Down
4 changes: 1 addition & 3 deletions Python/pystate.c
Original file line number Diff line number Diff line change
Expand Up @@ -425,8 +425,6 @@ init_runtime(_PyRuntimeState *runtime,
runtime->open_code_userdata = open_code_userdata;
runtime->audit_hook_head = audit_hook_head;

_PyEval_InitRuntimeState(&runtime->ceval);

PyPreConfig_InitPythonConfig(&runtime->preconfig);

PyThread_type_lock *lockptrs[NUMLOCKS] = {
Expand Down Expand Up @@ -682,7 +680,7 @@ init_interpreter(PyInterpreterState *interp,
memcpy(&interp->obmalloc.pools.used, temp, sizeof(temp));
}

_PyEval_InitState(&interp->ceval, pending_lock);
_PyEval_InitState(interp, pending_lock);
_PyGC_InitState(&interp->gc);
PyConfig_InitPythonConfig(&interp->config);
_PyType_InitCache(interp);
Expand Down

0 comments on commit 0f39f69

Please sign in to comment.