Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit f3e7eb4

Browse files
gh-99113: Add PyInterpreterConfig.own_gil (gh-104204)
We also add PyInterpreterState.ceval.own_gil to record if the interpreter actually has its own GIL. Note that for now we don't actually respect own_gil; all interpreters still share the one GIL. However, PyInterpreterState.ceval.own_gil does reflect PyInterpreterConfig.own_gil. That lie is a temporary one that we will fix when the GIL really becomes per-interpreter.
1 parent 66558d2 commit f3e7eb4

File tree

11 files changed

+80
-19
lines changed

11 files changed

+80
-19
lines changed

Include/cpython/initconfig.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,7 @@ typedef struct {
252252
int allow_threads;
253253
int allow_daemon_threads;
254254
int check_multi_interp_extensions;
255+
int own_gil;
255256
} PyInterpreterConfig;
256257

257258
#define _PyInterpreterConfig_INIT \
@@ -262,6 +263,7 @@ typedef struct {
262263
.allow_threads = 1, \
263264
.allow_daemon_threads = 0, \
264265
.check_multi_interp_extensions = 1, \
266+
.own_gil = 1, \
265267
}
266268

267269
#define _PyInterpreterConfig_LEGACY_INIT \
@@ -272,6 +274,7 @@ typedef struct {
272274
.allow_threads = 1, \
273275
.allow_daemon_threads = 1, \
274276
.check_multi_interp_extensions = 0, \
277+
.own_gil = 0, \
275278
}
276279

277280
/* --- Helper functions --------------------------------------- */

Include/internal/pycore_ceval.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ _PyEval_Vector(PyThreadState *tstate,
9797
PyObject *kwnames);
9898

9999
extern int _PyEval_ThreadsInitialized(void);
100-
extern PyStatus _PyEval_InitGIL(PyThreadState *tstate);
100+
extern PyStatus _PyEval_InitGIL(PyThreadState *tstate, int own_gil);
101101
extern void _PyEval_FiniGIL(PyInterpreterState *interp);
102102

103103
extern void _PyEval_ReleaseLock(PyThreadState *tstate);

Include/internal/pycore_ceval_state.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ struct _pending_calls {
8686
struct _ceval_state {
8787
int recursion_limit;
8888
struct _gil_runtime_state *gil;
89+
int own_gil;
8990
/* This single variable consolidates all requests to break out of
9091
the fast path in the eval loop. */
9192
_Py_atomic_int eval_breaker;

Lib/test/test_capi/test_misc.py

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1401,23 +1401,37 @@ def test_configured_settings(self):
14011401
DAEMON_THREADS = 1<<11
14021402
FORK = 1<<15
14031403
EXEC = 1<<16
1404-
1405-
features = ['obmalloc', 'fork', 'exec', 'threads', 'daemon_threads',
1406-
'extensions']
1404+
ALL_FLAGS = (OBMALLOC | FORK | EXEC | THREADS | DAEMON_THREADS
1405+
| EXTENSIONS);
1406+
1407+
features = [
1408+
'obmalloc',
1409+
'fork',
1410+
'exec',
1411+
'threads',
1412+
'daemon_threads',
1413+
'extensions',
1414+
'own_gil',
1415+
]
14071416
kwlist = [f'allow_{n}' for n in features]
14081417
kwlist[0] = 'use_main_obmalloc'
1409-
kwlist[-1] = 'check_multi_interp_extensions'
1418+
kwlist[-2] = 'check_multi_interp_extensions'
1419+
kwlist[-1] = 'own_gil'
14101420

14111421
# expected to work
14121422
for config, expected in {
1413-
(True, True, True, True, True, True):
1414-
OBMALLOC | FORK | EXEC | THREADS | DAEMON_THREADS | EXTENSIONS,
1415-
(True, False, False, False, False, False): OBMALLOC,
1416-
(False, False, False, True, False, True): THREADS | EXTENSIONS,
1423+
(True, True, True, True, True, True, True):
1424+
(ALL_FLAGS, True),
1425+
(True, False, False, False, False, False, False):
1426+
(OBMALLOC, False),
1427+
(False, False, False, True, False, True, False):
1428+
(THREADS | EXTENSIONS, False),
14171429
}.items():
14181430
kwargs = dict(zip(kwlist, config))
1431+
exp_flags, exp_gil = expected
14191432
expected = {
1420-
'feature_flags': expected,
1433+
'feature_flags': exp_flags,
1434+
'own_gil': exp_gil,
14211435
}
14221436
with self.subTest(config):
14231437
r, w = os.pipe()
@@ -1437,7 +1451,7 @@ def test_configured_settings(self):
14371451

14381452
# expected to fail
14391453
for config in [
1440-
(False, False, False, False, False, False),
1454+
(False, False, False, False, False, False, False),
14411455
]:
14421456
kwargs = dict(zip(kwlist, config))
14431457
with self.subTest(config):
@@ -1473,6 +1487,7 @@ def test_overridden_setting_extensions_subinterp_check(self):
14731487
'allow_exec': True,
14741488
'allow_threads': True,
14751489
'allow_daemon_threads': True,
1490+
'own_gil': False,
14761491
}
14771492

14781493
def check(enabled, override):
@@ -1483,6 +1498,7 @@ def check(enabled, override):
14831498
flags = BASE_FLAGS | EXTENSIONS if enabled else BASE_FLAGS
14841499
settings = {
14851500
'feature_flags': flags,
1501+
'own_gil': False,
14861502
}
14871503

14881504
expected = {

Lib/test/test_embed.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1666,6 +1666,7 @@ def test_init_main_interpreter_settings(self):
16661666
# All optional features should be enabled.
16671667
'feature_flags':
16681668
OBMALLOC | FORK | EXEC | THREADS | DAEMON_THREADS,
1669+
'own_gil': True,
16691670
}
16701671
out, err = self.run_embedded_interpreter(
16711672
'test_init_main_interpreter_settings',

Lib/test/test_import/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1640,6 +1640,7 @@ class SubinterpImportTests(unittest.TestCase):
16401640
)
16411641
ISOLATED = dict(
16421642
use_main_obmalloc=False,
1643+
own_gil=True,
16431644
)
16441645
NOT_ISOLATED = {k: not v for k, v in ISOLATED.items()}
16451646

Lib/test/test_threading.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1349,6 +1349,7 @@ def func():
13491349
allow_threads={allowed},
13501350
allow_daemon_threads={daemon_allowed},
13511351
check_multi_interp_extensions=False,
1352+
own_gil=False,
13521353
)
13531354
""")
13541355
with test.support.SuppressCrashReport():

Modules/_testcapimodule.c

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1488,6 +1488,7 @@ run_in_subinterp_with_config(PyObject *self, PyObject *args, PyObject *kwargs)
14881488
int allow_threads = -1;
14891489
int allow_daemon_threads = -1;
14901490
int check_multi_interp_extensions = -1;
1491+
int own_gil = -1;
14911492
int r;
14921493
PyThreadState *substate, *mainstate;
14931494
/* only initialise 'cflags.cf_flags' to test backwards compatibility */
@@ -1500,13 +1501,15 @@ run_in_subinterp_with_config(PyObject *self, PyObject *args, PyObject *kwargs)
15001501
"allow_threads",
15011502
"allow_daemon_threads",
15021503
"check_multi_interp_extensions",
1504+
"own_gil",
15031505
NULL};
15041506
if (!PyArg_ParseTupleAndKeywords(args, kwargs,
1505-
"s$pppppp:run_in_subinterp_with_config", kwlist,
1507+
"s$ppppppp:run_in_subinterp_with_config", kwlist,
15061508
&code, &use_main_obmalloc,
15071509
&allow_fork, &allow_exec,
15081510
&allow_threads, &allow_daemon_threads,
1509-
&check_multi_interp_extensions)) {
1511+
&check_multi_interp_extensions,
1512+
&own_gil)) {
15101513
return NULL;
15111514
}
15121515
if (use_main_obmalloc < 0) {
@@ -1525,6 +1528,10 @@ run_in_subinterp_with_config(PyObject *self, PyObject *args, PyObject *kwargs)
15251528
PyErr_SetString(PyExc_ValueError, "missing allow_threads");
15261529
return NULL;
15271530
}
1531+
if (own_gil < 0) {
1532+
PyErr_SetString(PyExc_ValueError, "missing own_gil");
1533+
return NULL;
1534+
}
15281535
if (allow_daemon_threads < 0) {
15291536
PyErr_SetString(PyExc_ValueError, "missing allow_daemon_threads");
15301537
return NULL;
@@ -1545,6 +1552,7 @@ run_in_subinterp_with_config(PyObject *self, PyObject *args, PyObject *kwargs)
15451552
.allow_threads = allow_threads,
15461553
.allow_daemon_threads = allow_daemon_threads,
15471554
.check_multi_interp_extensions = check_multi_interp_extensions,
1555+
.own_gil = own_gil,
15481556
};
15491557
PyStatus status = Py_NewInterpreterFromConfig(&substate, &config);
15501558
if (PyStatus_Exception(status)) {

Modules/_testinternalcapi.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -729,6 +729,13 @@ get_interp_settings(PyObject *self, PyObject *args)
729729
return NULL;
730730
}
731731

732+
/* "own GIL" */
733+
PyObject *own_gil = interp->ceval.own_gil ? Py_True : Py_False;
734+
if (PyDict_SetItemString(settings, "own_gil", own_gil) != 0) {
735+
Py_DECREF(settings);
736+
return NULL;
737+
}
738+
732739
return settings;
733740
}
734741

Python/ceval_gil.c

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -500,9 +500,18 @@ PyEval_ThreadsInitialized(void)
500500
}
501501

502502
PyStatus
503-
_PyEval_InitGIL(PyThreadState *tstate)
503+
_PyEval_InitGIL(PyThreadState *tstate, int own_gil)
504504
{
505505
assert(tstate->interp->ceval.gil == NULL);
506+
if (!own_gil) {
507+
PyInterpreterState *main_interp = _PyInterpreterState_Main();
508+
assert(tstate->interp != main_interp);
509+
struct _gil_runtime_state *gil = main_interp->ceval.gil;
510+
assert(gil_created(gil));
511+
tstate->interp->ceval.gil = gil;
512+
tstate->interp->ceval.own_gil = 0;
513+
return _PyStatus_OK();
514+
}
506515

507516
/* XXX per-interpreter GIL */
508517
struct _gil_runtime_state *gil = &tstate->interp->runtime->ceval.gil;
@@ -512,15 +521,19 @@ _PyEval_InitGIL(PyThreadState *tstate)
512521
and destroy it. */
513522
assert(gil_created(gil));
514523
tstate->interp->ceval.gil = gil;
524+
// XXX For now we lie.
525+
tstate->interp->ceval.own_gil = 1;
515526
return _PyStatus_OK();
516527
}
528+
assert(own_gil);
517529

518530
assert(!gil_created(gil));
519531

520532
PyThread_init_thread();
521533
create_gil(gil);
522534
assert(gil_created(gil));
523535
tstate->interp->ceval.gil = gil;
536+
tstate->interp->ceval.own_gil = 1;
524537
take_gil(tstate);
525538
return _PyStatus_OK();
526539
}
@@ -530,6 +543,14 @@ _PyEval_FiniGIL(PyInterpreterState *interp)
530543
{
531544
if (interp->ceval.gil == NULL) {
532545
/* It was already finalized (or hasn't been initialized yet). */
546+
assert(!interp->ceval.own_gil);
547+
return;
548+
}
549+
else if (!interp->ceval.own_gil) {
550+
PyInterpreterState *main_interp = _PyInterpreterState_Main();
551+
assert(interp != main_interp);
552+
assert(interp->ceval.gil == main_interp->ceval.gil);
553+
interp->ceval.gil = NULL;
533554
return;
534555
}
535556

Python/pylifecycle.c

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -585,7 +585,7 @@ init_interp_settings(PyInterpreterState *interp,
585585

586586

587587
static PyStatus
588-
init_interp_create_gil(PyThreadState *tstate)
588+
init_interp_create_gil(PyThreadState *tstate, int own_gil)
589589
{
590590
PyStatus status;
591591

@@ -600,7 +600,7 @@ init_interp_create_gil(PyThreadState *tstate)
600600
}
601601

602602
/* Create the GIL and take it */
603-
status = _PyEval_InitGIL(tstate);
603+
status = _PyEval_InitGIL(tstate, own_gil);
604604
if (_PyStatus_EXCEPTION(status)) {
605605
return status;
606606
}
@@ -632,7 +632,9 @@ pycore_create_interpreter(_PyRuntimeState *runtime,
632632
return status;
633633
}
634634

635-
const PyInterpreterConfig config = _PyInterpreterConfig_LEGACY_INIT;
635+
PyInterpreterConfig config = _PyInterpreterConfig_LEGACY_INIT;
636+
// The main interpreter always has its own GIL.
637+
config.own_gil = 1;
636638
status = init_interp_settings(interp, &config);
637639
if (_PyStatus_EXCEPTION(status)) {
638640
return status;
@@ -645,7 +647,7 @@ pycore_create_interpreter(_PyRuntimeState *runtime,
645647
_PyThreadState_Bind(tstate);
646648
(void) PyThreadState_Swap(tstate);
647649

648-
status = init_interp_create_gil(tstate);
650+
status = init_interp_create_gil(tstate, config.own_gil);
649651
if (_PyStatus_EXCEPTION(status)) {
650652
return status;
651653
}
@@ -2047,7 +2049,7 @@ new_interpreter(PyThreadState **tstate_p, const PyInterpreterConfig *config)
20472049
goto error;
20482050
}
20492051

2050-
status = init_interp_create_gil(tstate);
2052+
status = init_interp_create_gil(tstate, config->own_gil);
20512053
if (_PyStatus_EXCEPTION(status)) {
20522054
goto error;
20532055
}

0 commit comments

Comments
 (0)