diff options
| author | Cy Schubert <cy@FreeBSD.org> | 2023-09-18 19:59:52 +0000 |
|---|---|---|
| committer | Cy Schubert <cy@FreeBSD.org> | 2023-09-18 19:59:52 +0000 |
| commit | 401770e05c71ecb5ae61a59d316069b4b78bf622 (patch) | |
| tree | a66e3d57ff5dde81aaa0fdc4c2d86c8b7a525ae0 /pythonmod/pythonmod.c | |
| parent | 7699e1386a16236002b26107ffd2dcbde375e197 (diff) | |
Diffstat (limited to 'pythonmod/pythonmod.c')
| -rw-r--r-- | pythonmod/pythonmod.c | 180 |
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; } |
