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;      } | 
