10000 gh-101659: Isolate "obmalloc" State to Each Interpreter by ericsnowcurrently · Pull Request #101660 · python/cpython · GitHub
[go: up one dir, main page]

Skip to content

gh-101659: Isolate "obmalloc" State to Each Interpreter #101660

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 58 commits into from
Apr 24, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
07a09d4
Pass PyInterpreterState to pymalloc_*().
ericsnowcurrently Oct 6, 2022
ca75048
Move the object arenas to the interpreter state.
ericsnowcurrently Oct 7, 2022
4ee199b
Drop an errant #define.
ericsnowcurrently Feb 7, 2023
2768fa4
Leave dump_debug_stats in the global state.
ericsnowcurrently Feb 7, 2023
bf9425f
Dynamically initialize obmalloc for subinterpreters.
ericsnowcurrently Feb 9, 2023
d5da34b
Merge branch 'main' into per-interpreter-alloc
ericsnowcurrently Mar 9, 2023
6c3111c
Pass around struct _obmalloc_state* instead of PyInterpeterState*.
ericsnowcurrently Mar 8, 2023
4dc087d
Add _PyInterpreterConfig.use_main_obmalloc.
ericsnowcurrently Mar 9, 2023
1ae33a0
Add a comment about why per-interpreter obmalloc requires multi-phase…
ericsnowcurrently Mar 9, 2023
5b54d63
Add a TODO comment.
ericsnowcurrently Mar 9, 2023
9f4f8f3
Optionally use the main interpreter's obmalloc state.
ericsnowcurrently Mar 9, 2023
aa10204
Pass use_main_obmalloc to run_in_subinterp() in test_import.
ericsnowcurrently Mar 9, 2023
69d9a2d
_Py_GetAllocatedBlocks() -> _Py_GetGlobalAllocatedBlocks().
ericsnowcurrently Mar 10, 2023
25378f8
Errors from _Py_NewInterpreterFromConfig() are no longer fatal.
ericsnowcurrently Mar 10, 2023
1c5b109
Chain the exceptions.
ericsnowcurrently Mar 13, 2023
f36426b
Swap out the failed tstate.
ericsnowcurrently Mar 10, 2023
54b9f09
Remaining static builtin types must be fixed.
ericsnowcurrently Mar 13, 2023
2358a42
Add PyInterpreterState.sysdict_copy.
ericsnowcurrently Mar 13, 2023
b6502e1
Set m_copy to None for sys and builtins.
ericsnowcurrently Mar 13, 2023
678e67b
Add _PyIO_InitTypes().
ericsnowcurrently Mar 13, 2023
69a5829
Fix test_capi.
ericsnowcurrently Mar 13, 2023
3feb408
Avoid allocation for shared exceptions.
ericsnowcurrently Mar 13, 2023
05806fc
Fix the ChannelID tp_name.
ericsnowcurrently Mar 13, 2023
b1cd7bb
Merge branch 'main' into per-interpreter-alloc
ericsnowcurrently Mar 29, 2023
4feb2b7
Do not include the total from interpreters sharing with main.
ericsnowcurrently Mar 29, 2023
136ad2f
Add _PyRuntime.obmalloc.interpreter_leaks.
ericsnowcurrently Mar 29, 2023
e19bb37
Track leaked blocks across init/fini cycles.
ericsnowcurrently Mar 29, 2023
6c51997
Clean up assumptions around runtime fini.
ericsnowcurrently Mar 29, 2023
f0fcaf6
Merge branch 'main' into per-interpreter-alloc
ericsnowcurrently Mar 29, 2023
0ff65ff
Add stubs for when WITH_PYMALLOC isn't defined.
ericsnowcurrently Mar 30, 2023
7db8d4a
Decref the key in the right interpreter in _extensions_cache_set().
ericsnowcurrently Mar 31, 2023
38bee89
Don't test against sys (for now).
ericsnowcurrently Mar 31, 2023
375a8f2
Clean up SubinterpImportTests.
ericsnowcurrently Mar 31, 2023
b0a9e11
Ensure we are testing against the right type of extension.
ericsnowcurrently Mar 31, 2023
5e5d5d5
Add a test that uses an isolated interpreter.
ericsnowcurrently Mar 31, 2023
25809ce
Fix is_core_module().
ericsnowcurrently Apr 4, 2023
616d3dd
Merge branch 'main' into per-interpreter-alloc
ericsnowcurrently Apr 4, 2023
43a836b
Ignore last_final_leaks.
ericsnowcurrently Apr 4, 2023
1841b55
Fix a typo.
ericsnowcurrently Apr 4, 2023
299527e
Merge branch 'main' into per-interpreter-alloc
ericsnowcurrently Apr 4, 2023
0091e48
Add a note about global state owned by the module.
ericsnowcurrently Apr 5, 2023
9f74f7b
Factor out GLOBAL_MALLOC() and GLOBAL_FREE().
ericsnowcurrently Apr 5, 2023
10c3589
Switch to the raw allocator.
ericsnowcurrently Apr 5, 2023
ff727ec
Merge branch 'channels-raw-allocator' into per-interpreter-alloc
ericsnowcurrently Apr 5, 2023
593430b
Use the raw allocator for _PyCrossInterpreterData_InitWithSize().
ericsnowcurrently Apr 5, 2023
f5ae710
atexit_callback -> atexit_py_callback.
ericsnowcurrently Apr 5, 2023
e6d4776
Add pycore_atexit.h.
ericsnowcurrently Apr 5, 2023
c719f02
Add _Py_AtExit().
ericsnowcurrently Apr 5, 2023
47c302d
Add a TODO comment.
ericsnowcurrently Apr 5, 2023
aaeaaa6
Move _Py_AtExit() to the public API.
ericsnowcurrently Apr 5, 2023
b5396e4
Test a constraint.
ericsnowcurrently Apr 5, 2023
448b48a
Add an atexit callback for _xxinterpchannels.
ericsnowcurrently Apr 5, 2023
c86f738
Implement the callback.
ericsnowcurrently Apr 5, 2023
1827feb
Drop the _PyCrossInterpreterData_Clear() call in _xxinterpchannels.
ericsnowcurrently Apr 5, 2023
82b395c
Drop the _PyCrossInterpreterData_Clear() call in _xxsubinterpreters.
8000 ericsnowcurrently Apr 5, 2023
df77a64
Merge branch 'atexit-c-callback' into per-interpreter-alloc
ericsnowcurrently Apr 6, 2023
22758a3
Merge branch 'main' into per-interpreter-alloc
ericsnowcurrently Apr 6, 2023
0fd74a9
Merge branch 'main' into per-interpreter-alloc
ericsnowcurrently Apr 24, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Add _PyInterpreterConfig.use_main_obmalloc.
  • Loading branch information
ericsnowcurrently committed Mar 9, 2023
commit 4dc087dea276b3f5c0b8b98b79614661c777971d
3 changes: 3 additions & 0 deletions Include/cpython/initconfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@ PyAPI_FUNC(PyStatus) PyConfig_SetWideStringList(PyConfig *config,
/* --- PyInterpreterConfig ------------------------------------ */

typedef struct {
int use_main_obmalloc;
int allow_fork;
int allow_exec;
int allow_threads;
Expand All @@ -253,6 +254,7 @@ typedef struct {

#define _PyInterpreterConfig_INIT \
{ \
.use_main_obmalloc = 0, \
.allow_fork = 0, \
.allow_exec = 0, \
.allow_threads = 1, \
Expand All @@ -262,6 +264,7 @@ typedef struct {

#define _PyInterpreterConfig_LEGACY_INIT \
{ \
.use_main_obmalloc = 1, \
.allow_fork = 1, \
.allow_exec = 1, \
.allow_threads = 1, \
Expand Down
4 changes: 4 additions & 0 deletions Include/cpython/pystate.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ is available in a given context. For example, forking the process
might not be allowed in the current interpreter (i.e. os.fork() would fail).
*/

/* Set if the interpreter share obmalloc runtime state
with the main interpreter. */
#define Py_RTFLAGS_USE_MAIN_OBMALLOC (1UL << 5)

/* Set if import should check a module for subinterpreter support. */
#define Py_RTFLAGS_MULTI_INTERP_EXTENSIONS (1UL << 8)

Expand Down
17 changes: 11 additions & 6 deletions Lib/test/test_capi/test_misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -1215,20 +1215,23 @@ def test_configured_settings(self):
"""
import json

OBMALLOC = 1<<5
EXTENSIONS = 1<<8
THREADS = 1<<10
DAEMON_THREADS = 1<<11
FORK = 1<<15
EXEC = 1<<16

features = ['fork', 'exec', 'threads', 'daemon_threads', 'extensions']
features = ['obmalloc', 'fork', 'exec', 'threads', 'daemon_threads',
'extensions']
kwlist = [f'allow_{n}' for n in features]
kwlist[0] = 'use_main_obmalloc'
kwlist[-1] = 'check_multi_interp_extensions'
for config, expected in {
(True, True, True, True, True):
FORK | EXEC | THREADS | DAEMON_THREADS | EXTENSIONS,
(False, False, False, False, False): 0,
(False, False, True, False, True): THREADS | EXTENSIONS,
(True, True, True, True, True, True):
OBMALLOC | FORK | EXEC | THREADS | DAEMON_THREADS | EXTENSIONS,
(False, False, False, False, False, False): 0,
(False, False, False, True, False, True): THREADS | EXTENSIONS,
}.items():
kwargs = dict(zip(kwlist, config))
expected = {
Expand Down Expand Up @@ -1261,13 +1264,15 @@ def test_overridden_setting_extensions_subinterp_check(self):
"""
import json

OBMALLOC = 1<<5
EXTENSIONS = 1<<8
THREADS = 1<<10
DAEMON_THREADS = 1<<11
FORK = 1<<15
EXEC = 1<<16
BASE_FLAGS = FORK | EXEC | THREADS | DAEMON_THREADS
BASE_FLAGS = OBMALLOC | FORK | EXEC | THREADS | DAEMON_THREADS
base_kwargs = {
'use_main_obmalloc': True,
'allow_fork': True,
'allow_exec': True,
'allow_threads': True,
Expand Down
3 changes: 2 additions & 1 deletion Lib/test/test_embed.py
Original file line number Diff line number Diff line change
Expand Up @@ -1656,6 +1656,7 @@ def test_init_use_frozen_modules(self):
api=API_PYTHON, env=env)

def test_init_main_interpreter_settings(self):
OBMALLOC = 1<<5
EXTENSIONS = 1<<8
THREADS = 1<<10
DAEMON_THREADS = 1<<11
Expand All @@ -1664,7 +1665,7 @@ def test_init_main_interpreter_settings(self):
expected = {
# All optional features should be enabled.
'feature_flags':
FORK | EXEC | THREADS | DAEMON_THREADS,
OBMALLOC | FORK | EXEC | THREADS | DAEMON_THREADS,
}
out, err = self.run_embedded_interpreter(
'test_init_main_interpreter_settings',
Expand Down
1 change: 1 addition & 0 deletions Lib/test/test_threading.py
Original file line number Diff line number Diff line change
Expand Up @@ -1343,6 +1343,7 @@ def func():
import test.support
test.support.run_in_subinterp_with_config(
{subinterp_code!r},
use_main_obmalloc=True,
allow_fork=True,
allow_exec=True,
allow_threads={allowed},
Expand Down
12 changes: 10 additions & 2 deletions Modules/_testcapimodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -1482,6 +1482,7 @@ static PyObject *
run_in_subinterp_with_config(PyObject *self, PyObject *args, PyObject *kwargs)
{
const char *code;
int use_main_obmalloc = -1;
int allow_fork = -1;
int allow_exec = -1;
int allow_threads = -1;
Expand All @@ -1493,19 +1494,25 @@ run_in_subinterp_with_config(PyObject *self, PyObject *args, PyObject *kwargs)
PyCompilerFlags cflags = {0};

static char *kwlist[] = {"code",
"use_main_obmalloc",
"allow_fork",
"allow_exec",
"allow_threads",
"allow_daemon_threads",
"check_multi_interp_extensions",
NULL};
if (!PyArg_ParseTupleAndKeywords(args, kwargs,
"s$ppppp:run_in_subinterp_with_config", kwlist,
&code, &allow_fork, &allow_exec,
"s$pppppp:run_in_subinterp_with_config", kwlist,
&code, &use_main_obmalloc,
&allow_fork, &allow_exec,
&allow_threads, &allow_daemon_threads,
&check_multi_interp_extensions)) {
return NULL;
}
if (use_main_obmalloc < 0) {
PyErr_SetString(PyExc_ValueError, "missing use_main_obmalloc");
return NULL;
}
if (allow_fork < 0) {
PyErr_SetString(PyExc_ValueError, "missing allow_fork");
return NULL;
Expand All @@ -1532,6 +1539,7 @@ run_in_subinterp_with_config(PyObject *self, PyObject *args, PyObject *kwargs)
PyThreadState_Swap(NULL);

const _PyInterpreterConfig config = {
.use_main_obmalloc = use_main_obmalloc,
.allow_fork = allow_fork,
.allow_exec = allow_exec,
.allow_threads = allow_threads,
Expand Down
22 changes: 19 additions & 3 deletions Python/pylifecycle.c
Original file line number Diff line number Diff line change
Expand Up @@ -546,11 +546,19 @@ pycore_init_runtime(_PyRuntimeState *runtime,
}


static void
static PyStatus
init_interp_settings(PyInterpreterState *interp, const _PyInterpreterConfig *config)
{
assert(interp->feature_flags == 0);

if (config->use_main_obmalloc) {
interp->feature_flags |= Py_RTFLAGS_USE_MAIN_OBMALLOC;
}
else if (!config->check_multi_interp_extensions) {
return _PyStatus_ERR("per-interpreter obmalloc does not support "
"single-phase init extension modules");
}

if (config->allow_fork) {
interp->feature_flags |= Py_RTFLAGS_FORK;
}
Expand All @@ -569,6 +577,8 @@ init_interp_settings(PyInterpreterState *interp, const _PyInterpreterConfig *con
if (config->check_multi_interp_extensions) {
interp->feature_flags |= Py_RTFLAGS_MULTI_INTERP_EXTENSIONS;
}

return _PyStatus_OK();
}


Expand Down Expand Up @@ -621,7 +631,10 @@ pycore_create_interpreter(_PyRuntimeState *runtime,
}

const _PyInterpreterConfig config = _PyInterpreterConfig_LEGACY_INIT;
init_interp_settings(interp, &config);
status = init_interp_settings(interp, &config);
if (_PyStatus_EXCEPTION(status)) {
return status;
}

PyThreadState *tstate = _PyThreadState_New(interp);
if (tstate == NULL) {
Expand Down Expand Up @@ -2031,7 +2044,10 @@ new_interpreter(PyThreadState **tstate_p, const _PyInterpreterConfig *config)
goto error;
}

init_interp_settings(interp, config);
status = init_interp_settings(interp, config);
if (_PyStatus_EXCEPTION(status)) {
goto error;
}

status = init_interp_create_gil(tstate);
if (_PyStatus_EXCEPTION(status)) {
Expand Down
0