From 4b4dc3c70ef19a29386c2b3e8284687851094eb9 Mon Sep 17 00:00:00 2001 From: Vasilii Chernov Date: Fri, 4 Mar 2016 09:31:42 +0100 Subject: Fix python3 initialization from pcilib_t --- apps/test_multithread.c | 2 + pcilib/py.c | 150 ++++++++++++++++++++++++++++++++++++++++++------ pywrap/test_pcilib.py | 2 +- 3 files changed, 135 insertions(+), 19 deletions(-) diff --git a/apps/test_multithread.c b/apps/test_multithread.c index f6afae7..a041655 100644 --- a/apps/test_multithread.c +++ b/apps/test_multithread.c @@ -9,6 +9,7 @@ const char* prop = "/registers/fpga/reg1"; char* reg; int stop = 0; +/* void *get_prop(void *arg) { pcilib_t *ctx = (pcilib_t*)arg; @@ -34,6 +35,7 @@ void *get_prop(void *arg) } return NULL; } +*/ void *read_reg(void *arg) { diff --git a/pcilib/py.c b/pcilib/py.c index bec7d08..94d7ed8 100644 --- a/pcilib/py.c +++ b/pcilib/py.c @@ -2,6 +2,11 @@ #ifdef HAVE_PYTHON # include + +#if PY_MAJOR_VERSION >= 3 +#include +#endif /* PY_MAJOR_VERSION >= 3 */ + #endif /* HAVE_PYTHON */ #include @@ -27,12 +32,24 @@ struct pcilib_script_s { UT_hash_handle hh; /**< hash */ }; +#if PY_MAJOR_VERSION >= 3 +typedef struct pcilib_py_s_thread_control { + pthread_t pth; + pthread_cond_t cond_finished; + pthread_mutex_t cond_finished_lock; +} pcilib_py_s_thread_control; +#endif /* PY_MAJOR_VERSION < 3 */ + struct pcilib_py_s { int finalyze; /**< Indicates, that we are initialized from wrapper and should not destroy Python resources in destructor */ PyObject *main_module; /**< Main interpreter */ PyObject *global_dict; /**< Dictionary of main interpreter */ PyObject *pcilib_pywrap; /**< pcilib wrapper module */ pcilib_script_t *script_hash; /**< Hash with loaded scripts */ + +#if PY_MAJOR_VERSION >= 3 + pcilib_py_s_thread_control *thr_ctl; /**< Controller for Python main loop thread for Python 3 */ +#endif /* PY_MAJOR_VERSION < 3 */ }; #endif /* HAVE_PYTHON */ @@ -55,7 +72,7 @@ void pcilib_log_python_error(const char *file, int line, pcilib_log_flags_t flag PyErr_NormalizeException(&pytype, &pyval, &pytraceback); if (pyval) pystr = PyObject_Str(pyval); -# if PY_MAJOR_VERSION >= 3 +#if PY_MAJOR_VERSION >= 3 if (pytype) { if (PyUnicode_Check(pytype)) type = PyUnicode_AsUTF8(pytype); @@ -65,7 +82,7 @@ void pcilib_log_python_error(const char *file, int line, pcilib_log_flags_t flag if (pystr) { val = PyUnicode_AsUTF8(pystr); } -# else /* PY_MAJOR_VERSION >= 3 */ +#else /* PY_MAJOR_VERSION >= 3 */ if (pytype) { if (PyString_Check(pytype)) type = PyString_AsString(pytype); @@ -75,7 +92,7 @@ void pcilib_log_python_error(const char *file, int line, pcilib_log_flags_t flag if (pystr) { val = PyString_AsString(pystr); } -# endif /*PY_MAJOR_VERSION >= 3*/ +#endif /*PY_MAJOR_VERSION >= 3*/ } PyGILState_Release(gstate); #endif /* HAVE_PYTHON */ @@ -115,39 +132,80 @@ void pcilib_log_python_error(const char *file, int line, pcilib_log_flags_t flag #endif /* HAVE_PYTHON */ } - +#ifdef HAVE_PYTHON +#if PY_MAJOR_VERSION >= 3 +void *pcilib_py_run_side_thread(void *arg) { + pcilib_t *ctx = (pcilib_t*)(arg); + //Initializing python + Py_Initialize(); + PyEval_InitThreads(); + PyEval_ReleaseLock(); + + //send initialization finish signal + pthread_cond_signal(&(ctx->py->thr_ctl->cond_finished)); + pthread_mutex_unlock(&(ctx->py->thr_ctl->cond_finished_lock)); + pthread_mutex_destroy(&(ctx->py->thr_ctl->cond_finished_lock)); + + //wait untill finish signal + pthread_mutex_lock(&(ctx->py->thr_ctl->cond_finished_lock)); + pthread_cond_wait(&(ctx->py->thr_ctl->cond_finished), + &(ctx->py->thr_ctl->cond_finished_lock)); + return NULL; +} +#endif /* PY_MAJOR_VERSION < 3 */ +#endif /* HAVE_PYTHON */ int pcilib_init_py(pcilib_t *ctx) { #ifdef HAVE_PYTHON ctx->py = (pcilib_py_t*)malloc(sizeof(pcilib_py_t)); if (!ctx->py) return PCILIB_ERROR_MEMORY; - memset(ctx->py, 0, sizeof(pcilib_py_t)); if(!Py_IsInitialized()) { - Py_Initialize(); - - // Since python is being initializing from c programm, it needs to initialize threads to work properly with c threads - PyEval_InitThreads(); - PyEval_ReleaseLock(); - ctx->py->finalyze = 1; - } - +#if PY_MAJOR_VERSION >= 3 + //create thread controller + ctx->py->thr_ctl = malloc(sizeof(pcilib_py_s_thread_control)); + if(!ctx->py->thr_ctl) return PCILIB_ERROR_MEMORY; + memset(ctx->py->thr_ctl, 0, sizeof(pcilib_py_s_thread_control)); + + //create side thread with python main loop + pthread_create(&(ctx->py->thr_ctl->pth), NULL, pcilib_py_run_side_thread, ctx); + pthread_mutex_lock(&(ctx->py->thr_ctl->cond_finished_lock)); + + //wait until Python initializes + pthread_cond_wait(&(ctx->py->thr_ctl->cond_finished), + &(ctx->py->thr_ctl->cond_finished_lock)); + +#else /* PY_MAJOR_VERSION < 3 */ + Py_Initialize(); + // Since python is being initializing from c programm, it needs to initialize threads to work properly with c threads + PyEval_InitThreads(); + PyEval_ReleaseLock(); +#endif /* PY_MAJOR_VERSION < 3 */ + ctx->py->finalyze = 1; + } + + + PyGILState_STATE gstate = PyGILState_Ensure(); + ctx->py->main_module = PyImport_AddModule("__parser__"); if (!ctx->py->main_module) { pcilib_python_warning("Error importing python parser"); + PyGILState_Release(gstate); return PCILIB_ERROR_FAILED; } ctx->py->global_dict = PyModule_GetDict(ctx->py->main_module); if (!ctx->py->global_dict) { pcilib_python_warning("Error locating global python dictionary"); + PyGILState_Release(gstate); return PCILIB_ERROR_FAILED; } PyObject *pywrap = PyImport_ImportModule(PCILIB_PYTHON_WRAPPER); if (!pywrap) { pcilib_python_warning("Error importing pcilib python wrapper"); + PyGILState_Release(gstate); return PCILIB_ERROR_FAILED; } @@ -159,8 +217,11 @@ int pcilib_init_py(pcilib_t *ctx) { if (!ctx->py->pcilib_pywrap) { pcilib_python_warning("Error initializing python wrapper"); + PyGILState_Release(gstate); return PCILIB_ERROR_FAILED; } + + PyGILState_Release(gstate); #endif /* HAVE_PYTHON */ return 0; @@ -187,20 +248,24 @@ int pcilib_py_add_script_dir(pcilib_t *ctx, const char *dir) { if (!script_dir) return PCILIB_ERROR_MEMORY; sprintf(script_dir, "%s/%s", model_dir, dir); } + + PyGILState_STATE gstate = PyGILState_Ensure(); pypath = PySys_GetObject("path"); if (!pypath) { pcilib_python_warning("Can't get python path"); + PyGILState_Release(gstate); return PCILIB_ERROR_FAILED; } pynewdir = PyUnicode_FromString(script_dir); if (!pynewdir) { pcilib_python_warning("Can't create python string"); + PyGILState_Release(gstate); return PCILIB_ERROR_MEMORY; } - // Checking if the directory already in the path? + // Checking if the directory already in the path? pydict = PyDict_New(); if (pydict) { pystr = PyUnicode_FromString("cur"); @@ -227,8 +292,11 @@ int pcilib_py_add_script_dir(pcilib_t *ctx, const char *dir) { if (err) { pcilib_python_warning("Can't add directory (%s) to python path", script_dir); + PyGILState_Release(gstate); return err; } + + PyGILState_Release(gstate); #endif /* HAVE_PYTHON */ return 0; @@ -237,7 +305,12 @@ int pcilib_py_add_script_dir(pcilib_t *ctx, const char *dir) { void pcilib_free_py(pcilib_t *ctx) { #ifdef HAVE_PYTHON int finalyze = 0; - + PyGILState_STATE gstate; + +#if PY_MAJOR_VERSION >= 3 + pcilib_py_s_thread_control *thr_ctl = ctx->py->thr_ctl; +#endif /* PY_MAJOR_VERSION < 3 */ + if (ctx->py) { if (ctx->py->finalyze) finalyze = 1; @@ -252,15 +325,44 @@ void pcilib_free_py(pcilib_t *ctx) { ctx->py->script_hash = NULL; } - if (ctx->py->pcilib_pywrap) + if (ctx->py->pcilib_pywrap) { + gstate = PyGILState_Ensure(); Py_DECREF(ctx->py->pcilib_pywrap); + PyGILState_Release(gstate); + } + free(ctx->py); ctx->py = NULL; } - if (finalyze) - Py_Finalize(); + + if (finalyze) { +#if PY_MAJOR_VERSION >= 3 + + //stop python side thread + pthread_cond_signal(&(thr_ctl->cond_finished)); + pthread_mutex_unlock(&(thr_ctl->cond_finished_lock)); + pthread_join(thr_ctl->pth, NULL); + + //free python + //must be finalized in main thread to correctly stop python threading + PyGILState_Ensure(); + Py_Finalize(); + + //destroy thread controllers + pthread_mutex_destroy(&(thr_ctl->cond_finished_lock)); + pthread_cond_destroy(&(thr_ctl->cond_finished)); + free(thr_ctl); + +#else /* PY_MAJOR_VERSION < 3 */ + + Py_Finalize(); + +#endif /* PY_MAJOR_VERSION < 3 */ + } + + #endif /* HAVE_PYTHON */ } @@ -268,6 +370,7 @@ int pcilib_py_load_script(pcilib_t *ctx, const char *script_name) { #ifdef HAVE_PYTHON PyObject* pymodule; pcilib_script_t *module = NULL; + PyGILState_STATE gstate; if (!ctx->py) return 0; @@ -284,11 +387,16 @@ int pcilib_py_load_script(pcilib_t *ctx, const char *script_name) { HASH_FIND_STR(ctx->py->script_hash, script_name, module); if (module) return 0; + gstate = PyGILState_Ensure(); + pymodule = PyImport_ImportModule(module_name); if (!pymodule) { pcilib_python_error("Error importing script (%s)", script_name); + PyGILState_Release(gstate); return PCILIB_ERROR_FAILED; } + + PyGILState_Release(gstate); module = (pcilib_script_t*)malloc(sizeof(pcilib_script_t)); if (!module) return PCILIB_ERROR_MEMORY; @@ -307,6 +415,7 @@ int pcilib_py_get_transform_script_properties(pcilib_t *ctx, const char *script_ PyObject *dict; PyObject *pystr; pcilib_script_t *module; + PyGILState_STATE gstate; if (!ctx->py) { if (mode_ret) *mode_ret = mode; @@ -319,10 +428,13 @@ int pcilib_py_get_transform_script_properties(pcilib_t *ctx, const char *script_ pcilib_error("Script (%s) is not loaded yet", script_name); return PCILIB_ERROR_NOTFOUND; } + + gstate = PyGILState_Ensure(); dict = PyModule_GetDict(module->module); if (!dict) { pcilib_python_error("Error getting dictionary for script (%s)", script_name); + PyGILState_Release(gstate); return PCILIB_ERROR_FAILED; } @@ -337,6 +449,8 @@ int pcilib_py_get_transform_script_properties(pcilib_t *ctx, const char *script_ if (PyDict_Contains(dict, pystr)) mode |= PCILIB_ACCESS_W; Py_DECREF(pystr); } + + PyGILState_Release(gstate); #endif /* HAVE_PYTHON */ if (mode_ret) *mode_ret = mode; diff --git a/pywrap/test_pcilib.py b/pywrap/test_pcilib.py index 398d975..74eee4a 100644 --- a/pywrap/test_pcilib.py +++ b/pywrap/test_pcilib.py @@ -82,7 +82,7 @@ class test_pcilib(): def testMemoryLeak(self): try: while(1): - val = long(random.randint(0, 8096)) + val = random.randint(0, 8096) self.pcilib = pcilib.pcilib(self.device, self.model) print(self.pcilib.get_property_list(self.branch)) print(self.pcilib.get_register_info(self.register)) -- cgit v1.2.3