| /* PyInterpreterConfig API */ | |
| #include "Python.h" | |
| #include "pycore_interp.h" // Py_RTFLAGS | |
| #include "pycore_pylifecycle.h" | |
| #include <stdbool.h> | |
| #include "config_common.h" | |
| static const char * | |
| gil_flag_to_str(int flag) | |
| { | |
| switch (flag) { | |
| case PyInterpreterConfig_DEFAULT_GIL: | |
| return "default"; | |
| case PyInterpreterConfig_SHARED_GIL: | |
| return "shared"; | |
| case PyInterpreterConfig_OWN_GIL: | |
| return "own"; | |
| default: | |
| PyErr_SetString(PyExc_SystemError, | |
| "invalid interpreter config 'gil' value"); | |
| return NULL; | |
| } | |
| } | |
| static int | |
| gil_flag_from_str(const char *str, int *p_flag) | |
| { | |
| int flag; | |
| if (str == NULL) { | |
| flag = PyInterpreterConfig_DEFAULT_GIL; | |
| } | |
| else if (strcmp(str, "default") == 0) { | |
| flag = PyInterpreterConfig_DEFAULT_GIL; | |
| } | |
| else if (strcmp(str, "shared") == 0) { | |
| flag = PyInterpreterConfig_SHARED_GIL; | |
| } | |
| else if (strcmp(str, "own") == 0) { | |
| flag = PyInterpreterConfig_OWN_GIL; | |
| } | |
| else { | |
| PyErr_Format(PyExc_ValueError, | |
| "unsupported interpreter config .gil value '%s'", str); | |
| return -1; | |
| } | |
| *p_flag = flag; | |
| return 0; | |
| } | |
| PyObject * | |
| _PyInterpreterConfig_AsDict(PyInterpreterConfig *config) | |
| { | |
| PyObject *dict = PyDict_New(); | |
| if (dict == NULL) { | |
| return NULL; | |
| } | |
| #define ADD(NAME, OBJ) \ | |
| do { \ | |
| int res = PyDict_SetItemString(dict, NAME, (OBJ)); \ | |
| Py_DECREF(OBJ); \ | |
| if (res < 0) { \ | |
| goto error; \ | |
| } \ | |
| } while (0) | |
| #define ADD_BOOL(FIELD) \ | |
| ADD(#FIELD, Py_NewRef(config->FIELD ? Py_True : Py_False)) | |
| #define ADD_STR(FIELD, STR) \ | |
| do { \ | |
| if (STR == NULL) { \ | |
| goto error; \ | |
| } \ | |
| PyObject *obj = PyUnicode_FromString(STR); \ | |
| if (obj == NULL) { \ | |
| goto error; \ | |
| } \ | |
| ADD(#FIELD, obj); \ | |
| } while (0) | |
| ADD_BOOL(use_main_obmalloc); | |
| ADD_BOOL(allow_fork); | |
| ADD_BOOL(allow_exec); | |
| ADD_BOOL(allow_threads); | |
| ADD_BOOL(allow_daemon_threads); | |
| ADD_BOOL(check_multi_interp_extensions); | |
| ADD_STR(gil, gil_flag_to_str(config->gil)); | |
| #undef ADD_STR | |
| #undef ADD_BOOL | |
| #undef ADD | |
| return dict; | |
| error: | |
| Py_DECREF(dict); | |
| return NULL; | |
| } | |
| static int | |
| _config_dict_get_bool(PyObject *dict, const char *name, int *p_flag) | |
| { | |
| PyObject *item; | |
| if (_config_dict_get(dict, name, &item) < 0) { | |
| return -1; | |
| } | |
| // For now we keep things strict, rather than using PyObject_IsTrue(). | |
| int flag = item == Py_True; | |
| if (!flag && item != Py_False) { | |
| Py_DECREF(item); | |
| config_dict_invalid_type(name); | |
| return -1; | |
| } | |
| Py_DECREF(item); | |
| *p_flag = flag; | |
| return 0; | |
| } | |
| static int | |
| _config_dict_copy_str(PyObject *dict, const char *name, | |
| char *buf, size_t bufsize) | |
| { | |
| PyObject *item; | |
| if (_config_dict_get(dict, name, &item) < 0) { | |
| return -1; | |
| } | |
| if (!PyUnicode_Check(item)) { | |
| Py_DECREF(item); | |
| config_dict_invalid_type(name); | |
| return -1; | |
| } | |
| strncpy(buf, PyUnicode_AsUTF8(item), bufsize-1); | |
| buf[bufsize-1] = '\0'; | |
| Py_DECREF(item); | |
| return 0; | |
| } | |
| static int | |
| interp_config_from_dict(PyObject *origdict, PyInterpreterConfig *config, | |
| bool missing_allowed) | |
| { | |
| PyObject *dict = PyDict_New(); | |
| if (dict == NULL) { | |
| return -1; | |
| } | |
| if (PyDict_Update(dict, origdict) < 0) { | |
| goto error; | |
| } | |
| #define CHECK(NAME) \ | |
| do { \ | |
| if (PyErr_Occurred()) { \ | |
| goto error; \ | |
| } \ | |
| else { \ | |
| if (!missing_allowed) { \ | |
| (void)config_dict_get(dict, NAME); \ | |
| assert(PyErr_Occurred()); \ | |
| goto error; \ | |
| } \ | |
| } \ | |
| } while (0) | |
| #define COPY_BOOL(FIELD) \ | |
| do { \ | |
| int flag; \ | |
| if (_config_dict_get_bool(dict, #FIELD, &flag) < 0) { \ | |
| CHECK(#FIELD); \ | |
| } \ | |
| else { \ | |
| config->FIELD = flag; \ | |
| (void)PyDict_PopString(dict, #FIELD, NULL); \ | |
| } \ | |
| } while (0) | |
| COPY_BOOL(use_main_obmalloc); | |
| COPY_BOOL(allow_fork); | |
| COPY_BOOL(allow_exec); | |
| COPY_BOOL(allow_threads); | |
| COPY_BOOL(allow_daemon_threads); | |
| COPY_BOOL(check_multi_interp_extensions); | |
| // PyInterpreterConfig.gil | |
| char buf[20]; | |
| if (_config_dict_copy_str(dict, "gil", buf, 20) < 0) { | |
| CHECK("gil"); | |
| } | |
| else { | |
| int flag; | |
| if (gil_flag_from_str(buf, &flag) < 0) { | |
| goto error; | |
| } | |
| config->gil = flag; | |
| (void)PyDict_PopString(dict, "gil", NULL); | |
| } | |
| #undef COPY_BOOL | |
| #undef CHECK | |
| Py_ssize_t unused = PyDict_GET_SIZE(dict); | |
| if (unused == 1) { | |
| PyErr_Format(PyExc_ValueError, | |
| "config dict has 1 extra item (%R)", dict); | |
| goto error; | |
| } | |
| else if (unused > 0) { | |
| PyErr_Format(PyExc_ValueError, | |
| "config dict has %zd extra items (%R)", unused, dict); | |
| goto error; | |
| } | |
| Py_DECREF(dict); | |
| return 0; | |
| error: | |
| Py_DECREF(dict); | |
| return -1; | |
| } | |
| int | |
| _PyInterpreterConfig_InitFromDict(PyInterpreterConfig *config, PyObject *dict) | |
| { | |
| if (!PyDict_Check(dict)) { | |
| PyErr_SetString(PyExc_TypeError, "dict expected"); | |
| return -1; | |
| } | |
| if (interp_config_from_dict(dict, config, false) < 0) { | |
| return -1; | |
| } | |
| return 0; | |
| } | |
| int | |
| _PyInterpreterConfig_UpdateFromDict(PyInterpreterConfig *config, PyObject *dict) | |
| { | |
| if (!PyDict_Check(dict)) { | |
| PyErr_SetString(PyExc_TypeError, "dict expected"); | |
| return -1; | |
| } | |
| if (interp_config_from_dict(dict, config, true) < 0) { | |
| return -1; | |
| } | |
| return 0; | |
| } | |
| int | |
| _PyInterpreterConfig_InitFromState(PyInterpreterConfig *config, | |
| PyInterpreterState *interp) | |
| { | |
| // Populate the config by re-constructing the values from the interpreter. | |
| *config = (PyInterpreterConfig){ | |
| #define FLAG(flag) \ | |
| (interp->feature_flags & Py_RTFLAGS_ ## flag) | |
| .use_main_obmalloc = FLAG(USE_MAIN_OBMALLOC), | |
| .allow_fork = FLAG(FORK), | |
| .allow_exec = FLAG(EXEC), | |
| .allow_threads = FLAG(THREADS), | |
| .allow_daemon_threads = FLAG(DAEMON_THREADS), | |
| .check_multi_interp_extensions = FLAG(MULTI_INTERP_EXTENSIONS), | |
| #undef FLAG | |
| .gil = interp->ceval.own_gil | |
| ? PyInterpreterConfig_OWN_GIL | |
| : PyInterpreterConfig_SHARED_GIL, | |
| }; | |
| return 0; | |
| } |