8000 Allow disabling the GIL with `PYTHON_GIL=0` · python/cpython@9e03999 · GitHub
[go: up one dir, main page]

Skip to content
8000

Commit 9e03999

Browse files
committed
Allow disabling the GIL with PYTHON_GIL=0
In free-threaded builds, running with `PYTHON_GIL=0` will now disable the GIL. Follow-up issues track work to re-enable the GIL when loading an incompatible extension, and to disable the GIL by default. In order to support re-enabling the GIL at runtime, all GIL-related data structures are initialized as usual, and disabling the GIL simply sets a flag that causes `take_gil()` and `drop_gil()` to return early. With `PYTHON_GIL=0` set, I spot-checked a few tests and small programs that don't use threads. They all seem to run fine, and very basic threaded programs work, sometimes. Trying to run the full test suite crashes pretty quickly, in `test_asyncio`.
1 parent 72714c0 commit 9e03999

File tree

6 files changed

+58
-0
lines changed

6 files changed

+58
-0
lines changed

Include/cpython/initconfig.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,9 @@ typedef struct PyConfig {
181181
int int_max_str_digits;
182182

183183
int cpu_count;
184+
#ifdef Py_GIL_DISABLED
185+
int enable_gil;
186+
#endif
184187

185188
/* --- Path configuration inputs ------------ */
186189
int pathconfig_warnings;

Include/internal/pycore_gil.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@ extern "C" {
2020
#define FORCE_SWITCHING
2121

2222
struct _gil_runtime_state {
23+
#ifdef Py_GIL_DISABLED
24+
/* Whether or not this GIL is being used. Can change from 0 to 1 at runtime
25+
if, for example, a module that requires the GIL is loaded. */
26+
int enabled;
27+
#endif
2328
/* microseconds (the Python API uses seconds, though) */
2429
unsigned long interval;
2530
/* Last PyThreadState holding / having held the GIL. This helps us

Include/internal/pycore_initconfig.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,18 @@ typedef enum {
153153
_PyConfig_INIT_ISOLATED = 3
154154
} _PyConfigInitEnum;
155155

156+
typedef enum {
157+
/* For now, this means the GIL is enabled.
158+
159+
gh-116329: This will eventually change to "the GIL is disabled but can
160+
be reenabled by loading an incompatible extension module." */
161+
_PyConfig_GIL_DEFAULT,
162+
163+
/* The GIL has been forced off or on, and will not be affected by module loading. */
164+
_PyConfig_GIL_DISABLE,
165+
_PyConfig_GIL_ENABLE,
166+
} _PyConfigGILEnum;
167+
156168
// Export for '_testembed' program
157169
PyAPI_FUNC(void) _PyConfig_InitCompatConfig(PyConfig *config);
158170

Lib/test/test_embed.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -452,6 +452,7 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase):
452452
'hash_seed': 0,
453453
'int_max_str_digits': sys.int_info.default_max_str_digits,
454454
'cpu_count': -1,
455+
'enable_gil': 0,
455456
'faulthandler': 0,
456457
'tracemalloc': 0,
457458
'perf_profiling': 0,

Python/ceval_gil.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,11 @@ drop_gil(PyInterpreterState *interp, PyThreadState *tstate)
219219
// XXX assert(tstate == NULL || !tstate->_status.cleared);
220220

221221
struct _gil_runtime_state *gil = ceval->gil;
222+
#ifdef Py_GIL_DISABLED
223+
if (!gil->enabled) {
224+
return;
225+
}
226+
#endif
222227
if (!_Py_atomic_load_ptr_relaxed(&gil->locked)) {
223228
Py_FatalError("drop_gil: GIL is not locked");
224229
}
@@ -294,6 +299,11 @@ take_gil(PyThreadState *tstate)
294299
assert(_PyThreadState_CheckConsistency(tstate));
295300
PyInterpreterState *interp = tstate->interp;
296301
struct _gil_runtime_state *gil = interp->ceval.gil;
302+
#ifdef Py_GIL_DISABLED
303+
if (!gil->enabled) {
304+
return;
305+
}
306+
#endif
297307

298308
/* Check that _PyEval_InitThreads() was called to create the lock */
299309
assert(gil_created(gil));
@@ -438,6 +448,11 @@ static void
438448
init_own_gil(PyInterpreterState *interp, struct _gil_runtime_state *gil)
439449
{
440450
assert(!gil_created(gil));
451+
#ifdef Py_GIL_DISABLED
452+
// gh-116329: Once it is safe to do so, change this condition to
453+
// (enable_gil == _PyConfig_GIL_ENABLE), so the GIL is disabled by default.
454+
gil->enabled = _PyInterpreterState_GetConfig(interp)->enable_gil != _PyConfig_GIL_DISABLE;
455+
#endif
441456
create_gil(gil);
442457
assert(gil_created(gil));
443458
interp->ceval.gil = gil;

Python/initconfig.c

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,9 @@ static const PyConfigSpec PYCONFIG_SPEC[] = {
9393
SPEC(safe_path, UINT),
9494
SPEC(int_max_str_digits, INT),
9595
SPEC(cpu_count, INT),
96+
#ifdef Py_GIL_DISABLED
97+
SPEC(enable_gil, INT),
98+
#endif
9699
SPEC(pathconfig_warnings, UINT),
97100
SPEC(program_name, WSTR),
98101
SPEC(pythonpath_env, WSTR_OPT),
@@ -276,6 +279,9 @@ static const char usage_envvars[] =
276279
"PYTHON_CPU_COUNT: Overrides the return value of os.process_cpu_count(),\n"
277280
" os.cpu_count(), and multiprocessing.cpu_count() if set to\n"
278281
" a positive integer.\n"
282+
#ifdef Py_GIL_DISABLED
283+
"PYTHON_GIL : When set to 0, disables the GIL.\n"
284+
#endif
279285
"PYTHONDEVMODE : enable the development mode.\n"
280286
"PYTHONPYCACHEPREFIX: root directory for bytecode cache (pyc) files.\n"
281287
"PYTHONWARNDEFAULTENCODING: enable opt-in EncodingWarning for 'encoding=None'.\n"
@@ -860,6 +866,9 @@ _PyConfig_InitCompatConfig(PyConfig *config)
860866
config->_is_python_build = 0;
861867
config->code_debug_ranges = 1;
862868
config->cpu_count = -1;
869+
#ifdef Py_GIL_DISABLED
870+
config->enable_gil = _PyConfig_GIL_DEFAULT;
871+
#endif
863872
}
864873

865874

@@ -1642,6 +1651,19 @@ config_read_env_vars(PyConfig *config)
16421651
config->safe_path = 1;
16431652
}
16441653

1654+
const char *gil = config_get_env(config, "PYTHON_GIL");
1655+
if (gil != NULL) {
1656+
#ifdef Py_GIL_DISABLED
1657+
if (strcmp(gil, "0") == 0) {
1658+
config->enable_gil = _PyConfig_GIL_DISABLE;
1659+
} else if (strcmp(gil, "1") != 0) {
1660+
return _PyStatus_ERR("PYTHON_GIL must be \"0\" or \"1\"");
1661+
}
1662+
#else
1663+
return _PyStatus_ERR("PYTHON_GIL is not supported by this build");
1664+
#endif
1665+
}
1666+
16451667
return _PyStatus_OK();
16461668
}
16471669

0 commit comments

Comments
 (0)
0