diff options
Diffstat (limited to 'pcilib')
-rw-r--r-- | pcilib/kmem.c | 6 | ||||
-rw-r--r-- | pcilib/kmem.h | 6 | ||||
-rw-r--r-- | pcilib/locking.c | 6 | ||||
-rw-r--r-- | pcilib/py.c | 211 |
4 files changed, 121 insertions, 108 deletions
diff --git a/pcilib/kmem.c b/pcilib/kmem.c index b103126..e1d60c5 100644 --- a/pcilib/kmem.c +++ b/pcilib/kmem.c @@ -29,7 +29,7 @@ int pcilib_clean_kernel_memory(pcilib_t *ctx, pcilib_kmem_use_t use, pcilib_kmem static int pcilib_free_kernel_buffer(pcilib_t *ctx, pcilib_kmem_list_t *kbuf, size_t i, pcilib_kmem_flags_t flags) { kmem_handle_t kh = {0}; - if (kbuf->buf.blocks[i].ua) munmap(kbuf->buf.blocks[i].ua, kbuf->buf.blocks[i].size + kbuf->buf.blocks[i].alignment_offset); + if (kbuf->buf.blocks[i].ua) munmap((void*)kbuf->buf.blocks[i].ua, kbuf->buf.blocks[i].size + kbuf->buf.blocks[i].alignment_offset); kh.handle_id = kbuf->buf.blocks[i].handle_id; kh.pa = kbuf->buf.blocks[i].pa; kh.flags = flags; @@ -361,7 +361,7 @@ int pcilib_kmem_sync_block(pcilib_t *ctx, pcilib_kmem_handle_t *k, pcilib_kmem_s return 0; } -void* volatile pcilib_kmem_get_ua(pcilib_t *ctx, pcilib_kmem_handle_t *k) { +volatile void *pcilib_kmem_get_ua(pcilib_t *ctx, pcilib_kmem_handle_t *k) { pcilib_kmem_list_t *kbuf = (pcilib_kmem_list_t*)k; return kbuf->buf.addr.ua + kbuf->buf.addr.alignment_offset + kbuf->buf.addr.mmap_offset; } @@ -380,7 +380,7 @@ uintptr_t pcilib_kmem_get_ba(pcilib_t *ctx, pcilib_kmem_handle_t *k) { return 0; } -void* volatile pcilib_kmem_get_block_ua(pcilib_t *ctx, pcilib_kmem_handle_t *k, size_t block) { +volatile void *pcilib_kmem_get_block_ua(pcilib_t *ctx, pcilib_kmem_handle_t *k, size_t block) { pcilib_kmem_list_t *kbuf = (pcilib_kmem_list_t*)k; return kbuf->buf.blocks[block].ua + kbuf->buf.blocks[block].alignment_offset + kbuf->buf.blocks[block].mmap_offset; } diff --git a/pcilib/kmem.h b/pcilib/kmem.h index 1d63e3b..e8d2827 100644 --- a/pcilib/kmem.h +++ b/pcilib/kmem.h @@ -68,7 +68,7 @@ typedef struct { uintptr_t pa; /**< physical address of buffer */ uintptr_t ba; /**< bus address of buffer (if it is mapped for DMA operations) */ - void* volatile ua; /**< pointer to buffer in the process address space */ + volatile void *ua; /**< pointer to buffer in the process address space */ size_t size; /**< size of the buffer in bytes */ size_t alignment_offset; /**< we may request alignment of allocated buffers. To enusre proper alignment the larger buffer will be allocated and the offset will specify the first position in the buffer fullfilling alignment request */ @@ -205,7 +205,7 @@ int pcilib_kmem_sync_block(pcilib_t *ctx, pcilib_kmem_handle_t *k, pcilib_kmem_s * @param[in] k - kernel memory handle returned from pcilib_alloc_kernel_memory() call * @return - user-space pointer */ -void* volatile pcilib_kmem_get_ua(pcilib_t *ctx, pcilib_kmem_handle_t *k); +volatile void *pcilib_kmem_get_ua(pcilib_t *ctx, pcilib_kmem_handle_t *k); /** * Get a physical address of a single-buffer kernel memory @@ -233,7 +233,7 @@ uintptr_t pcilib_kmem_get_ba(pcilib_t *ctx, pcilib_kmem_handle_t *k); * @param[in] block - specifies the buffer within the kernel memory (buffers are numbered from 0) * @return - user-space pointer */ -void* volatile pcilib_kmem_get_block_ua(pcilib_t *ctx, pcilib_kmem_handle_t *k, size_t block); +volatile void *pcilib_kmem_get_block_ua(pcilib_t *ctx, pcilib_kmem_handle_t *k, size_t block); /** * Get a physical address of the specified kernel memory buffer diff --git a/pcilib/locking.c b/pcilib/locking.c index 71f204e..6ae4365 100644 --- a/pcilib/locking.c +++ b/pcilib/locking.c @@ -43,7 +43,7 @@ int pcilib_init_locking(pcilib_t* ctx) { if ((reused & PCILIB_KMEM_REUSE_REUSED) == 0) { for (i = 0; i < PCILIB_LOCK_PAGES; i++) { - void *addr = pcilib_kmem_get_block_ua(ctx, ctx->locks.kmem, i); + void *addr = (void*)pcilib_kmem_get_block_ua(ctx, ctx->locks.kmem, i); memset(addr, 0, PCILIB_KMEM_PAGE_SIZE); } } @@ -95,7 +95,7 @@ void pcilib_unlock_global(pcilib_t *ctx) { pcilib_lock_t *pcilib_get_lock_by_id(pcilib_t *ctx, pcilib_lock_id_t id) { int page = id / PCILIB_LOCKS_PER_PAGE; int offset = id - page * PCILIB_LOCKS_PER_PAGE; - void *addr = pcilib_kmem_get_block_ua(ctx, ctx->locks.kmem, page); + volatile void *addr = pcilib_kmem_get_block_ua(ctx, ctx->locks.kmem, page); pcilib_lock_t *lock = (pcilib_lock_t*)(addr + offset * PCILIB_LOCK_SIZE); return lock; @@ -308,7 +308,7 @@ int pcilib_destroy_all_locks(pcilib_t *ctx, int force) { } for (i = 0; i < PCILIB_LOCK_PAGES; i++) { - void *addr = pcilib_kmem_get_block_ua(ctx, ctx->locks.kmem, i); + void *addr = (void*)pcilib_kmem_get_block_ua(ctx, ctx->locks.kmem, i); memset(addr, 0, PCILIB_KMEM_PAGE_SIZE); } diff --git a/pcilib/py.c b/pcilib/py.c index 94d7ed8..03e9d8d 100644 --- a/pcilib/py.c +++ b/pcilib/py.c @@ -3,10 +3,9 @@ #ifdef HAVE_PYTHON # include <Python.h> -#if PY_MAJOR_VERSION >= 3 -#include <pthread.h> -#endif /* PY_MAJOR_VERSION >= 3 */ - +# if PY_MAJOR_VERSION >= 3 +# include <pthread.h> +# endif /* PY_MAJOR_VERSION >= 3 */ #endif /* HAVE_PYTHON */ #include <stdio.h> @@ -22,7 +21,7 @@ #include "error.h" #ifdef HAVE_PYTHON -#define PCILIB_PYTHON_WRAPPER "pcipywrap" +# define PCILIB_PYTHON_WRAPPER "pcipywrap" typedef struct pcilib_script_s pcilib_script_t; @@ -32,14 +31,6 @@ 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 */ @@ -47,9 +38,11 @@ struct pcilib_py_s { 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 */ +# if PY_MAJOR_VERSION >= 3 + pthread_t pth; + pthread_cond_t cond; + pthread_mutex_t lock; +# endif /* PY_MAJOR_VERSION > 3 */ }; #endif /* HAVE_PYTHON */ @@ -72,7 +65,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); @@ -82,7 +75,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); @@ -92,7 +85,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 */ @@ -133,26 +126,47 @@ void pcilib_log_python_error(const char *file, int line, pcilib_log_flags_t flag } #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(); +# if PY_MAJOR_VERSION >= 3 +/** + * Python3 specially treats the main thread intializing Python. It crashes if + * the Lock is released and any Python code is executed under the GIL compaling + * that GIL is not locked. Python3 assumes that the main thread most of the time + * holds the Lock, only shortly giving it away to other threads and re-obtaining + * it hereafter. This is not possible to do with GILs, but instead (probably) + * PyEval_{Save,Restore}Thread() should be used. On other hand, the other threads + * are working fine with GILs. This makes things complicated as we need to know + * if we are running in main thread or not. + * To simplify matters, during initalization we start a new thread which will + * performa actual initialization of Python and, hence, act as main thread. + * We only intialize here. No python code is executed afterwards. So we don't + * need to care about special locking mechanisms in main thread. Instead all + * our user threads can use GILs normally. + * See more details here: + * http://stackoverflow.com/questions/24499393/cpython-locking-the-gil-in-the-main-thread + * http://stackoverflow.com/questions/15470367/pyeval-initthreads-in-python-3-how-when-to-call-it-the-saga-continues-ad-naus + */ +static void *pcilib_py_run_init_thread(void *arg) { + pcilib_py_t *py = (pcilib_py_t*)(arg); + + Py_Initialize(); + PyEval_InitThreads(); + PyEval_ReleaseLock(); + + // Ensure that main thread waiting for our signal + pthread_lock(&(py->lock)); - //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; + // Inform the parent thread that initialization is finished + pthread_cond_signal(&(py->cond)); + + // Wait untill cleanup is requested + pthread_cond_wait(&(py->cond), &(py->lock)); + pthread_unlock(&(py->lock))); + + Py_Finalize(); + + return NULL; } -#endif /* PY_MAJOR_VERSION < 3 */ +# endif /* PY_MAJOR_VERSION < 3 */ #endif /* HAVE_PYTHON */ int pcilib_init_py(pcilib_t *ctx) { @@ -161,28 +175,42 @@ int pcilib_init_py(pcilib_t *ctx) { if (!ctx->py) return PCILIB_ERROR_MEMORY; memset(ctx->py, 0, sizeof(pcilib_py_t)); - if(!Py_IsInitialized()) { -#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; + if (!Py_IsInitialized()) { +# if 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(); +# else /* PY_MAJOR_VERSION < 3 */ + err = pthread_mutex_init(&(ctx->py.lock)); + if (err) return PCILIB_ERROR_FAILED; + + err = pthread_cond_init(&(ctx->py.cond)); + if (err) { + pthread_mutex_destroy(&(ctx->py.lock)); + return PCILIB_ERROR_FAILED; + } + + err = pthread_mutex_lock(&(ctx->py.lock)); + if (err) { + pthread_cond_destroy(&(ctx->py.lock)); + pthread_mutex_destroy(&(ctx->py.lock)); + return PCILIB_ERROR_FAILED; + } + + // Create initalizer thread and wait until it releases the Lock + err = pthread_create(&(ctx->py.pth), NULL, pcilib_py_run_init_thread, &(ctx->py)); + if (err) { + pthread_mutex_unlock(&(ctx->py.lock)); + pthread_cond_destroy(&(ctx->py.cond)); + pthread_mutex_destroy(&(ctx->py.lock)); + return PCILIB_ERROR_FAILED; + } + + // Wait until initialized and keep the lock afterwards until free executed + pthread_cond_wait(&(ctx->py.cond), (ctx->py.lock)); +# endif /* PY_MAJOR_VERSION < 3 */ + ctx->py->finalyze = 1; } @@ -190,22 +218,22 @@ int pcilib_init_py(pcilib_t *ctx) { ctx->py->main_module = PyImport_AddModule("__parser__"); if (!ctx->py->main_module) { - pcilib_python_warning("Error importing python parser"); PyGILState_Release(gstate); + pcilib_python_warning("Error importing python parser"); 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); + pcilib_python_warning("Error locating global python dictionary"); return PCILIB_ERROR_FAILED; } PyObject *pywrap = PyImport_ImportModule(PCILIB_PYTHON_WRAPPER); if (!pywrap) { - pcilib_python_warning("Error importing pcilib python wrapper"); PyGILState_Release(gstate); + pcilib_python_warning("Error importing pcilib python wrapper"); return PCILIB_ERROR_FAILED; } @@ -216,8 +244,8 @@ int pcilib_init_py(pcilib_t *ctx) { Py_XDECREF(mod_name); if (!ctx->py->pcilib_pywrap) { - pcilib_python_warning("Error initializing python wrapper"); PyGILState_Release(gstate); + pcilib_python_warning("Error initializing python wrapper"); return PCILIB_ERROR_FAILED; } @@ -253,15 +281,15 @@ int pcilib_py_add_script_dir(pcilib_t *ctx, const char *dir) { pypath = PySys_GetObject("path"); if (!pypath) { - pcilib_python_warning("Can't get python path"); PyGILState_Release(gstate); + pcilib_python_warning("Can't get python path"); return PCILIB_ERROR_FAILED; } pynewdir = PyUnicode_FromString(script_dir); if (!pynewdir) { - pcilib_python_warning("Can't create python string"); PyGILState_Release(gstate); + pcilib_python_warning("Can't create python string"); return PCILIB_ERROR_MEMORY; } @@ -290,13 +318,12 @@ int pcilib_py_add_script_dir(pcilib_t *ctx, const char *dir) { if (pyret) Py_DECREF(pyret); Py_DECREF(pynewdir); + PyGILState_Release(gstate); + 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; @@ -305,14 +332,13 @@ 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) { + PyGILState_STATE gstate; + if (ctx->py->finalyze) finalyze = 1; + + gstate = PyGILState_Ensure(); if (ctx->py->script_hash) { pcilib_script_t *script, *script_tmp; @@ -325,12 +351,11 @@ void pcilib_free_py(pcilib_t *ctx) { ctx->py->script_hash = NULL; } - if (ctx->py->pcilib_pywrap) { - gstate = PyGILState_Ensure(); + if (ctx->py->pcilib_pywrap) Py_DECREF(ctx->py->pcilib_pywrap); - PyGILState_Release(gstate); - } - + + PyGILState_Release(gstate); + free(ctx->py); ctx->py = NULL; @@ -339,26 +364,16 @@ void pcilib_free_py(pcilib_t *ctx) { 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); + // singal python init thread to stop and wait it to finish + pthread_cond_signal(&(ctx->py.cond)); + pthread_mutex_unlock(&(ctx->py.lock)); + pthread_join(ctx->py.pth, NULL); + // destroy synchronization primitives + pthread_cond_destroy(&(ctx->py.cond)); + pthread_mutex_destroy(&(ctx->py.lock)); #else /* PY_MAJOR_VERSION < 3 */ - Py_Finalize(); - #endif /* PY_MAJOR_VERSION < 3 */ } @@ -388,14 +403,12 @@ int pcilib_py_load_script(pcilib_t *ctx, const char *script_name) { 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); + pcilib_python_error("Error importing script (%s)", script_name); return PCILIB_ERROR_FAILED; } - PyGILState_Release(gstate); module = (pcilib_script_t*)malloc(sizeof(pcilib_script_t)); @@ -433,8 +446,8 @@ int pcilib_py_get_transform_script_properties(pcilib_t *ctx, const char *script_ dict = PyModule_GetDict(module->module); if (!dict) { - pcilib_python_error("Error getting dictionary for script (%s)", script_name); PyGILState_Release(gstate); + pcilib_python_error("Error getting dictionary for script (%s)", script_name); return PCILIB_ERROR_FAILED; } |