mirror of https://github.com/python/cpython.git
267 lines
8.0 KiB
C
267 lines
8.0 KiB
C
|
/* PyInterpreterConfig API */
|
||
|
|
||
|
#include "Python.h"
|
||
|
#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 %d extra items (%R)", unused, dict);
|
||
|
goto error;
|
||
|
}
|
||
|
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;
|
||
|
}
|