aboutsummaryrefslogtreecommitdiff
path: root/pythonmod/pythonmod.c
diff options
context:
space:
mode:
Diffstat (limited to 'pythonmod/pythonmod.c')
-rw-r--r--pythonmod/pythonmod.c180
1 files changed, 132 insertions, 48 deletions
diff --git a/pythonmod/pythonmod.c b/pythonmod/pythonmod.c
index 7c7da548994a..628308612ac0 100644
--- a/pythonmod/pythonmod.c
+++ b/pythonmod/pythonmod.c
@@ -252,13 +252,24 @@ cleanup:
Py_XDECREF(exc_tb);
}
+/* we only want to unwind Python once at exit */
+static void
+pythonmod_atexit(void)
+{
+ log_assert(py_mod_count == 0);
+ log_assert(mainthr != NULL);
+
+ PyEval_RestoreThread(mainthr);
+ Py_Finalize();
+}
+
int pythonmod_init(struct module_env* env, int id)
{
int py_mod_idx = py_mod_count++;
/* Initialize module */
FILE* script_py = NULL;
- PyObject* py_init_arg, *res;
+ PyObject* py_init_arg = NULL, *res = NULL;
PyGILState_STATE gil;
int init_standard = 1, i = 0;
#if PY_MAJOR_VERSION < 3
@@ -292,24 +303,67 @@ int pythonmod_init(struct module_env* env, int id)
/* Initialize Python libraries */
if (py_mod_count==1 && !Py_IsInitialized())
{
+#if PY_VERSION_HEX >= 0x03080000
+ PyStatus status;
+ PyPreConfig preconfig;
+ PyConfig config;
+#endif
#if PY_MAJOR_VERSION >= 3
wchar_t progname[8];
mbstowcs(progname, "unbound", 8);
#else
char *progname = "unbound";
#endif
+#if PY_VERSION_HEX < 0x03080000
Py_SetProgramName(progname);
+#else
+ /* Python must be preinitialized, before the PyImport_AppendInittab
+ * call. */
+ PyPreConfig_InitPythonConfig(&preconfig);
+ status = Py_PreInitialize(&preconfig);
+ if(PyStatus_Exception(status)) {
+ log_err("python exception in Py_PreInitialize: %s%s%s",
+ (status.func?status.func:""), (status.func?": ":""),
+ (status.err_msg?status.err_msg:""));
+ return 0;
+ }
+#endif
Py_NoSiteFlag = 1;
#if PY_MAJOR_VERSION >= 3
PyImport_AppendInittab(SWIG_name, (void*)SWIG_init);
#endif
+#if PY_VERSION_HEX < 0x03080000
Py_Initialize();
+#else
+ PyConfig_InitPythonConfig(&config);
+ status = PyConfig_SetString(&config, &config.program_name, progname);
+ if(PyStatus_Exception(status)) {
+ log_err("python exception in PyConfig_SetString(.. program_name ..): %s%s%s",
+ (status.func?status.func:""), (status.func?": ":""),
+ (status.err_msg?status.err_msg:""));
+ PyConfig_Clear(&config);
+ return 0;
+ }
+ config.site_import = 0;
+ status = Py_InitializeFromConfig(&config);
+ if(PyStatus_Exception(status)) {
+ log_err("python exception in Py_InitializeFromConfig: %s%s%s",
+ (status.func?status.func:""), (status.func?": ":""),
+ (status.err_msg?status.err_msg:""));
+ PyConfig_Clear(&config);
+ return 0;
+ }
+ PyConfig_Clear(&config);
+#endif
#if PY_MAJOR_VERSION <= 2 || (PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION <= 6)
/* initthreads only for python 3.6 and older */
PyEval_InitThreads();
#endif
SWIG_init();
mainthr = PyEval_SaveThread();
+
+ /* register callback to unwind Python at exit */
+ atexit(pythonmod_atexit);
}
gil = PyGILState_Ensure();
@@ -317,6 +371,7 @@ int pythonmod_init(struct module_env* env, int id)
if (py_mod_count==1) {
/* Initialize Python */
if(PyRun_SimpleString("import sys \n") < 0 ) {
+ log_err("pythonmod: cannot initialize core module: unboundmodule.py");
goto python_init_fail;
}
PyRun_SimpleString("sys.path.append('.') \n");
@@ -328,24 +383,17 @@ int pythonmod_init(struct module_env* env, int id)
env->cfg->directory);
PyRun_SimpleString(wdir);
}
- /* Check if sysconfig is there and use that instead of distutils;
- * distutils.sysconfig is deprecated in Python 3.10. */
- if(PyRun_SimpleString("import sysconfig \n") < 0) {
- log_info("pythonmod: module sysconfig not available; "
- "falling back to distutils.sysconfig.");
- if(PyRun_SimpleString("import distutils.sysconfig \n") < 0
- || PyRun_SimpleString("sys.path.append("
- "distutils.sysconfig.get_python_lib(1,0)) \n") < 0) {
- goto python_init_fail;
- }
- } else {
- if(PyRun_SimpleString("sys.path.append("
- "sysconfig.get_path('platlib')) \n") < 0) {
- goto python_init_fail;
- }
+ if(PyRun_SimpleString("import site\n") < 0) {
+ log_err("pythonmod: cannot initialize core module: unboundmodule.py");
+ goto python_init_fail;
+ }
+ if(PyRun_SimpleString("sys.path.extend(site.getsitepackages())\n") < 0) {
+ log_err("pythonmod: cannot initialize core module: unboundmodule.py");
+ goto python_init_fail;
}
if(PyRun_SimpleString("from unboundmodule import *\n") < 0)
{
+ log_err("pythonmod: cannot initialize core module: unboundmodule.py");
goto python_init_fail;
}
}
@@ -362,18 +410,22 @@ int pythonmod_init(struct module_env* env, int id)
if (script_py == NULL)
{
log_err("pythonmod: can't open file %s for reading", pe->fname);
- PyGILState_Release(gil);
- return 0;
+ goto python_init_fail;
}
/* Load file */
pe->module = PyImport_AddModule("__main__");
+ Py_XINCREF(pe->module);
pe->dict = PyModule_GetDict(pe->module);
+ Py_XINCREF(pe->dict);
pe->data = PyDict_New();
- Py_XINCREF(pe->data);
- PyModule_AddObject(pe->module, "mod_env", pe->data);
-
- /* TODO: deallocation of pe->... if an error occurs */
+ Py_XINCREF(pe->data); /* reference will be stolen below */
+ if(PyModule_AddObject(pe->module, "mod_env", pe->data) < 0) {
+ log_err("pythonmod: could not add mod_env object");
+ Py_XDECREF(pe->data); /* 2 times, here and on python_init_fail; */
+ /* on failure the reference is not stolen */
+ goto python_init_fail;
+ }
if (PyRun_SimpleFile(script_py, pe->fname) < 0) {
#if PY_MAJOR_VERSION <= 2 || (PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION < 9)
@@ -404,18 +456,30 @@ int pythonmod_init(struct module_env* env, int id)
fstr = malloc(flen+1);
if(!fstr) {
log_err("malloc failure to print parse error");
- PyGILState_Release(gil);
+
+/* close the file */
+#if PY_MAJOR_VERSION < 3
+ Py_XDECREF(PyFileObject);
+#else
fclose(script_py);
- return 0;
+#endif
+
+ goto python_init_fail;
}
fseek(script_py, 0, SEEK_SET);
if(fread(fstr, flen, 1, script_py) < 1) {
log_err("file read failed to print parse error: %s: %s",
pe->fname, strerror(errno));
- PyGILState_Release(gil);
- fclose(script_py);
free(fstr);
- return 0;
+
+/* close the file */
+#if PY_MAJOR_VERSION < 3
+ Py_XDECREF(PyFileObject);
+#else
+ fclose(script_py);
+#endif
+
+ goto python_init_fail;
}
fstr[flen] = 0;
/* we compile the string, but do not run it, to stop side-effects */
@@ -423,17 +487,26 @@ int pythonmod_init(struct module_env* env, int id)
* that we are expecting */
(void)Py_CompileString(fstr, pe->fname, Py_file_input);
#endif
+
log_py_err();
- PyGILState_Release(gil);
+
+/* close the file */
+#if PY_MAJOR_VERSION < 3
+ Py_XDECREF(PyFileObject);
+#else
fclose(script_py);
+#endif
+
#if PY_MAJOR_VERSION <= 2 || (PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION < 9)
/* no cleanup needed for python before 3.9 */
#else
/* cleanup for python 3.9 and newer */
free(fstr);
#endif
- return 0;
+ goto python_init_fail;
}
+
+/* close the file */
#if PY_MAJOR_VERSION < 3
Py_XDECREF(PyFileObject);
#else
@@ -446,28 +519,28 @@ int pythonmod_init(struct module_env* env, int id)
if ((pe->func_init = PyDict_GetItemString(pe->dict, "init")) == NULL)
{
log_err("pythonmod: function init is missing in %s", pe->fname);
- PyGILState_Release(gil);
- return 0;
+ goto python_init_fail;
}
}
+ Py_XINCREF(pe->func_init);
if ((pe->func_deinit = PyDict_GetItemString(pe->dict, "deinit")) == NULL)
{
log_err("pythonmod: function deinit is missing in %s", pe->fname);
- PyGILState_Release(gil);
- return 0;
+ goto python_init_fail;
}
+ Py_XINCREF(pe->func_deinit);
if ((pe->func_operate = PyDict_GetItemString(pe->dict, "operate")) == NULL)
{
log_err("pythonmod: function operate is missing in %s", pe->fname);
- PyGILState_Release(gil);
- return 0;
+ goto python_init_fail;
}
+ Py_XINCREF(pe->func_operate);
if ((pe->func_inform = PyDict_GetItemString(pe->dict, "inform_super")) == NULL)
{
log_err("pythonmod: function inform_super is missing in %s", pe->fname);
- PyGILState_Release(gil);
- return 0;
+ goto python_init_fail;
}
+ Py_XINCREF(pe->func_inform);
if (init_standard)
{
@@ -483,26 +556,31 @@ int pythonmod_init(struct module_env* env, int id)
{
log_err("pythonmod: Exception occurred in function init");
log_py_err();
- Py_XDECREF(res);
- Py_XDECREF(py_init_arg);
- PyGILState_Release(gil);
- return 0;
+ goto python_init_fail;
}
Py_XDECREF(res);
Py_XDECREF(py_init_arg);
PyGILState_Release(gil);
-
return 1;
python_init_fail:
- log_err("pythonmod: cannot initialize core module: unboundmodule.py");
+ Py_XDECREF(pe->module);
+ Py_XDECREF(pe->dict);
+ Py_XDECREF(pe->data);
+ Py_XDECREF(pe->func_init);
+ Py_XDECREF(pe->func_deinit);
+ Py_XDECREF(pe->func_operate);
+ Py_XDECREF(pe->func_inform);
+ Py_XDECREF(res);
+ Py_XDECREF(py_init_arg);
PyGILState_Release(gil);
return 0;
}
void pythonmod_deinit(struct module_env* env, int id)
{
+ int cbtype;
struct pythonmod_env* pe = env->modinfo[id];
if(pe == NULL)
return;
@@ -522,18 +600,24 @@ void pythonmod_deinit(struct module_env* env, int id)
/* Free result if any */
Py_XDECREF(res);
/* Free shared data if any */
+ Py_XDECREF(pe->module);
+ Py_XDECREF(pe->dict);
Py_XDECREF(pe->data);
+ Py_XDECREF(pe->func_init);
+ Py_XDECREF(pe->func_deinit);
+ Py_XDECREF(pe->func_inform);
+ Py_XDECREF(pe->func_operate);
PyGILState_Release(gil);
- if(--py_mod_count==0) {
- PyEval_RestoreThread(mainthr);
- Py_Finalize();
- mainthr = NULL;
- }
+ py_mod_count--;
}
pe->fname = NULL;
free(pe);
+ /* iterate over all possible callback types and clean up each in turn */
+ for (cbtype = 0; cbtype < inplace_cb_types_total; cbtype++)
+ inplace_cb_delete(env, cbtype, id);
+
/* Module is deallocated in Python */
env->modinfo[id] = NULL;
}