| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 8bcfd31 commit 252346a
14 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1004,6 +1004,8 @@ Private provisional API: | |||
| 1004 | 1004 | ||
| 1005 | 1005 | * :c:member:`PyConfig._init_main`: if set to 0, | |
| 1006 | 1006 | :c:func:`Py_InitializeFromConfig` stops at the "Core" initialization phase. | |
| 1007 | + * :c:member:`PyConfig._isolated_interpreter`: if non-zero, | ||
| 1008 | + disallow threads, subprocesses and fork. | ||
| 1007 | 1009 | ||
| 1008 | 1010 | .. c:function:: PyStatus _Py_InitializeMain(void) | |
| 1009 | 1011 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -409,6 +409,10 @@ typedef struct { | |||
| 409 | 409 | ||
| 410 | 410 | /* If equal to 0, stop Python initialization before the "main" phase */ | |
| 411 | 411 | int _init_main; | |
| 412 | + | ||
| 413 | + /* If non-zero, disallow threads, subprocesses, and fork. | ||
| 414 | + Default: 0. */ | ||
| 415 | + int _isolated_interpreter; | ||
| 412 | 416 | } PyConfig; | |
| 413 | 417 | ||
| 414 | 418 | PyAPI_FUNC(void) PyConfig_InitPythonConfig(PyConfig *config); | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -65,6 +65,8 @@ PyAPI_FUNC(int) _Py_CoerceLegacyLocale(int warn); | |||
| 65 | 65 | PyAPI_FUNC(int) _Py_LegacyLocaleDetected(int warn); | |
| 66 | 66 | PyAPI_FUNC(char *) _Py_SetLocaleFromEnv(int category); | |
| 67 | 67 | ||
| 68 | + PyAPI_FUNC(PyThreadState *) _Py_NewInterpreter(int isolated_subinterpreter); | ||
| 69 | + | ||
| 68 | 70 | #ifdef __cplusplus | |
| 69 | 71 | } | |
| 70 | 72 | #endif | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -794,6 +794,7 @@ def f(): | |||
| 794 | 794 | self.assertEqual(out, 'it worked!') | |
| 795 | 795 | ||
| 796 | 796 | def test_create_thread(self): | |
| 797 | + subinterp = interpreters.create(isolated=False) | ||
| 797 | 798 | script, file = _captured_script(""" | |
| 798 | 799 | import threading | |
| 799 | 800 | def f(): | |
@@ -804,7 +805,7 @@ def f(): | |||
| 804 | 805 | t.join() | |
| 805 | 806 | """) | |
| 806 | 807 | with file: | |
| 807 | - interpreters.run_string(self.id, script) | ||
| 808 | + interpreters.run_string(subinterp, script) | ||
| 808 | 809 | out = file.read() | |
| 809 | 810 | ||
| 810 | 811 | self.assertEqual(out, 'it worked!') | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -406,6 +406,7 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase): | |||
| 406 | 406 | 'check_hash_pycs_mode': 'default', | |
| 407 | 407 | 'pathconfig_warnings': 1, | |
| 408 | 408 | '_init_main': 1, | |
| 409 | + '_isolated_interpreter': 0, | ||
| 409 | 410 | } | |
| 410 | 411 | if MS_WINDOWS: | |
| 411 | 412 | CONFIG_COMPAT.update({ | |
@@ -766,6 +767,8 @@ def test_init_from_config(self): | |||
| 766 | 767 | ||
| 767 | 768 | 'check_hash_pycs_mode': 'always', | |
| 768 | 769 | 'pathconfig_warnings': 0, | |
| 770 | + | ||
| 771 | + '_isolated_interpreter': 1, | ||
| 769 | 772 | } | |
| 770 | 773 | self.check_all_configs("test_init_from_config", config, preconfig, | |
| 771 | 774 | api=API_COMPAT) | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,3 @@ | |||
| 1 | + Add ``isolated=True`` keyword-only parameter to | ||
| 2 | + ``_xxsubinterpreters.create()``. An isolated subinterpreter cannot spawn | ||
| 3 | + threads, spawn a child process or call ``os.fork()``. | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -663,6 +663,14 @@ subprocess_fork_exec(PyObject* self, PyObject *args) | |||
| 663 | 663 | return NULL; | |
| 664 | 664 | } | |
| 665 | 665 | ||
| 666 | + PyInterpreterState *interp = PyInterpreterState_Get(); | ||
| 667 | + const PyConfig *config = _PyInterpreterState_GetConfig(interp); | ||
| 668 | + if (config->_isolated_interpreter) { | ||
| 669 | + PyErr_SetString(PyExc_RuntimeError, | ||
| 670 | + "subprocess not supported for isolated subinterpreters"); | ||
| 671 | + return NULL; | ||
| 672 | + } | ||
| 673 | + | ||
| 666 | 674 | /* We need to call gc.disable() when we'll be calling preexec_fn */ | |
| 667 | 675 | if (preexec_fn != Py_None) { | |
| 668 | 676 | PyObject *result; | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1085,6 +1085,14 @@ thread_PyThread_start_new_thread(PyObject *self, PyObject *fargs) | |||
| 1085 | 1085 | "optional 3rd arg must be a dictionary"); | |
| 1086 | 1086 | return NULL; | |
| 1087 | 1087 | } | |
| 1088 | + | ||
| 1089 | + PyInterpreterState *interp = _PyInterpreterState_GET(); | ||
| 1090 | + if (interp->config._isolated_interpreter) { | ||
| 1091 | + PyErr_SetString(PyExc_RuntimeError, | ||
| 1092 | + "thread is not supported for isolated subinterpreters"); | ||
| 1093 | + return NULL; | ||
| 1094 | + } | ||
| 1095 | + | ||
| 1088 | 1096 | boot = PyMem_NEW(struct bootstate, 1); | |
| 1089 | 1097 | if (boot == NULL) | |
| 1090 | 1098 | return PyErr_NoMemory(); | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1080,6 +1080,14 @@ _winapi_CreateProcess_impl(PyObject *module, | |||
| 1080 | 1080 | return NULL; | |
| 1081 | 1081 | } | |
| 1082 | 1082 | ||
| 1083 | + PyInterpreterState *interp = PyInterpreterState_Get(); | ||
| 1084 | + const PyConfig *config = _PyInterpreterState_GetConfig(interp); | ||
| 1085 | + if (config->_isolated_interpreter) { | ||
| 1086 | + PyErr_SetString(PyExc_RuntimeError, | ||
| 1087 | + "subprocess not supported for isolated subinterpreters"); | ||
| 1088 | + return NULL; | ||
| 1089 | + } | ||
| 1090 | + | ||
| 1083 | 1091 | ZeroMemory(&si, sizeof(si)); | |
| 1084 | 1092 | si.StartupInfo.cb = sizeof(si); | |
| 1085 | 1093 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1999,16 +1999,20 @@ _global_channels(void) { | |||
| 1999 | 1999 | } | |
| 2000 | 2000 | ||
| 2001 | 2001 | static PyObject * | |
| 2002 | - interp_create(PyObject *self, PyObject *args) | ||
| 2002 | + interp_create(PyObject *self, PyObject *args, PyObject *kwds) | ||
| 2003 | 2003 | { | |
| 2004 | - if (!PyArg_UnpackTuple(args, "create", 0, 0)) { | ||
| 2004 | + | ||
| 2005 | + static char *kwlist[] = {"isolated", NULL}; | ||
| 2006 | + int isolated = 1; | ||
| 2007 | + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|$i:create", kwlist, | ||
| 2008 | + &isolated)) { | ||
| 2005 | 2009 | return NULL; | |
| 2006 | 2010 | } | |
| 2007 | 2011 | ||
| 2008 | 2012 | // Create and initialize the new interpreter. | |
| 2009 | 2013 | PyThreadState *save_tstate = PyThreadState_Swap(NULL); | |
| 2010 | 2014 | // XXX Possible GILState issues? | |
| 2011 | - PyThreadState *tstate = Py_NewInterpreter(); | ||
| 2015 | + PyThreadState *tstate = _Py_NewInterpreter(isolated); | ||
| 2012 | 2016 | PyThreadState_Swap(save_tstate); | |
| 2013 | 2017 | if (tstate == NULL) { | |
| 2014 | 2018 | /* Since no new thread state was created, there is no exception to | |
@@ -2547,8 +2551,8 @@ channel__channel_id(PyObject *self, PyObject *args, PyObject *kwds) | |||
| 2547 | 2551 | } | |
| 2548 | 2552 | ||
| 2549 | 2553 | static PyMethodDef module_functions[] = { | |
| 2550 | - {"create", (PyCFunction)interp_create, | ||
| 2551 | - METH_VARARGS, create_doc}, | ||
| 2554 | + {"create", (PyCFunction)(void(*)(void))interp_create, | ||
| 2555 | + METH_VARARGS | METH_KEYWORDS, create_doc}, | ||
| 2552 | 2556 | {"destroy", (PyCFunction)(void(*)(void))interp_destroy, | |
| 2553 | 2557 | METH_VARARGS | METH_KEYWORDS, destroy_doc}, | |
| 2554 | 2558 | {"list_all", interp_list_all, | |
| Back | FazBrowse Home | New Git URL |
0 commit comments