From 4436081e5bdb6683d5aa76edcd4bb5703dde7e4b Mon Sep 17 00:00:00 2001 From: Mike Blumenkrantz Date: Fri, 23 Jul 2010 15:33:22 +0000 Subject: [PATCH] add threadsafe global data to threads, allowing for communication between threads and other threads and threads and main loop SVN revision: 50453 --- legacy/ecore/src/lib/ecore/Ecore.h | 19 +++- legacy/ecore/src/lib/ecore/ecore_thread.c | 128 +++++++++++++++++++++- 2 files changed, 139 insertions(+), 8 deletions(-) diff --git a/legacy/ecore/src/lib/ecore/Ecore.h b/legacy/ecore/src/lib/ecore/Ecore.h index 06347ed5d1..7573a60e29 100644 --- a/legacy/ecore/src/lib/ecore/Ecore.h +++ b/legacy/ecore/src/lib/ecore/Ecore.h @@ -347,12 +347,6 @@ extern "C" { void (*func_cancel)(void *data), const void *data, Eina_Bool try_no_queue); - EAPI Eina_Bool ecore_thread_pool_data_add(Ecore_Thread *thread, const char *key, - const void *value, Eina_Bool direct); - EAPI void *ecore_thread_pool_data_set(Ecore_Thread *thread, const char *key, - const void *value); - EAPI void *ecore_thread_pool_data_find(Ecore_Thread *thread, const char *key); - EAPI Eina_Bool ecore_thread_pool_data_del(Ecore_Thread *thread, const char *key); EAPI Eina_Bool ecore_thread_cancel(Ecore_Thread *thread); EAPI Eina_Bool ecore_thread_check(Ecore_Thread *thread); EAPI Eina_Bool ecore_thread_notify(Ecore_Thread *thread, const void *msg_data); @@ -365,6 +359,19 @@ extern "C" { EAPI void ecore_thread_max_reset(void); EAPI int ecore_thread_available_get(void); + EAPI Eina_Bool ecore_thread_pool_data_add(Ecore_Thread *thread, const char *key, + const void *value, Eina_Bool direct); + EAPI void *ecore_thread_pool_data_set(Ecore_Thread *thread, const char *key, + const void *value); + EAPI void *ecore_thread_pool_data_find(Ecore_Thread *thread, const char *key); + EAPI Eina_Bool ecore_thread_pool_data_del(Ecore_Thread *thread, const char *key); + + EAPI Eina_Bool ecore_thread_global_data_add(const char *key, const void *value, + Eina_Bool direct); + EAPI void *ecore_thread_global_data_set(const char *key, const void *value); + EAPI void *ecore_thread_global_data_find(const char *key); + EAPI Eina_Bool ecore_thread_global_data_del(const char *key); + EAPI double ecore_time_get(void); EAPI double ecore_loop_time_get(void); diff --git a/legacy/ecore/src/lib/ecore/ecore_thread.c b/legacy/ecore/src/lib/ecore/ecore_thread.c index 667c505b26..19d262c2dc 100644 --- a/legacy/ecore/src/lib/ecore/ecore_thread.c +++ b/legacy/ecore/src/lib/ecore/ecore_thread.c @@ -61,14 +61,15 @@ static int ECORE_THREAD_PIPE_DEL = 0; #ifdef EFL_HAVE_PTHREAD static int _ecore_thread_count = 0; -static Eina_Hash *_ecore_thread_global_hash = NULL; + static Eina_List *_ecore_active_job_threads = NULL; static Eina_List *_ecore_pending_job_threads = NULL; static Eina_List *_ecore_pending_job_threads_long = NULL; static Ecore_Event_Handler *del_handler = NULL; - static pthread_mutex_t _ecore_pending_job_threads_mutex = PTHREAD_MUTEX_INITIALIZER; +static Eina_Hash *_ecore_thread_global_hash = NULL; +static pthread_rwlock_t _ecore_thread_global_hash_lock = PTHREAD_RWLOCK_INITIALIZER; static void _ecore_thread_pipe_free(void *data __UNUSED__, void *event) { @@ -923,6 +924,129 @@ ecore_thread_pool_data_del(Ecore_Thread *thread, const char *key) #endif } +/** + * @brief Add data to the global data + * @param key The name string to add the data with + * @param value The data to add + * @param direct If true, this will not copy the key string (like eina_hash_direct_add) + * @return EINA_TRUE on success, EINA_FALSE on failure + * This adds data to the global thread data, and will return EINA_FALSE in any case but success. + * All data added to global should be manually freed to avoid stale pointers in the global thread data. + */ +EAPI Eina_Bool +ecore_thread_global_data_add(const char *key, const void *value, Eina_Bool direct) +{ + Eina_Bool ret; + if ((!key) || (!value)) + return EINA_FALSE; +#ifdef EFL_HAVE_PTHREAD + pthread_rwlock_wrlock(&_ecore_thread_global_hash_lock); + if (!_ecore_thread_global_hash) + _ecore_thread_global_hash = eina_hash_string_small_new(NULL); + pthread_rwlock_unlock(&_ecore_thread_global_hash_lock); + + if (!_ecore_thread_global_hash) + return EINA_FALSE; + pthread_rwlock_wrlock(&_ecore_thread_global_hash_lock); + if (direct) + ret = eina_hash_direct_add(_ecore_thread_global_hash, key, value); + else + ret = eina_hash_add(_ecore_thread_global_hash, key, value); + pthread_rwlock_unlock(&_ecore_thread_global_hash_lock); + return ret; +#else + return EINA_TRUE; +#endif +} + +/** + * @brief Add data to the global data + * @param key The name string to add the data with + * @param value The data to add + * @return EINA_TRUE on success, EINA_FALSE on failure + * This adds data to the global thread data and returns NULL, or replaces the previous data + * associated with @p key and returning the previous data if it existed. To see if an error occurred, + * one must use eina_error_get. + * All data added to global should be manually freed to avoid stale pointers in the global thread data. + */ +EAPI void * +ecore_thread_global_data_set(const char *key, const void *value) +{ + void *ret; + if ((!key) || (!value)) + return NULL; +#ifdef EFL_HAVE_PTHREAD + pthread_rwlock_wrlock(&_ecore_thread_global_hash_lock); + if (!_ecore_thread_global_hash) + _ecore_thread_global_hash = eina_hash_string_small_new(NULL); + pthread_rwlock_unlock(&_ecore_thread_global_hash_lock); + + if (!_ecore_thread_global_hash) + return NULL; + + pthread_rwlock_wrlock(&_ecore_thread_global_hash_lock); + ret = eina_hash_set(_ecore_thread_global_hash, key, value); + pthread_rwlock_unlock(&_ecore_thread_global_hash_lock); + return ret; +#else + return NULL; +#endif +} + +/** + * @brief Find data in the global data + * @param key The name string the data is associated with + * @return The value, or NULL on error + * This finds data in the global data that has been previously added with @ref ecore_thread_global_data_add + * This function will return NULL in any case but success. + */ + +EAPI void * +ecore_thread_global_data_find(const char *key) +{ + void *ret; + if (!key) + return NULL; +#ifdef EFL_HAVE_PTHREAD + if (!_ecore_thread_global_hash) return NULL; + + pthread_rwlock_rdlock(&_ecore_thread_global_hash_lock); + ret = eina_hash_find(_ecore_thread_global_hash, key); + pthread_rwlock_unlock(&_ecore_thread_global_hash_lock); + return ret; +#else + return NULL; +#endif +} + +/** + * @brief Delete data from the global data + * @param key The name string the data is associated with + * @return EINA_TRUE on success, EINA_FALSE on failure + * This deletes the data pointer from the global data which was previously added with @ref ecore_thread_global_data_add + * This function will return EINA_FALSE in any case but success. + * Note that this WILL NOT free the data, it merely removes it from the global set. + */ +EAPI Eina_Bool +ecore_thread_global_data_del(const char *key) +{ + Eina_Bool ret; + if (!key) + return EINA_FALSE; +#ifdef EFL_HAVE_PTHREAD + if (!_ecore_thread_global_hash) + return EINA_FALSE; + + pthread_rwlock_wrlock(&_ecore_thread_global_hash_lock); + ret = eina_hash_del_by_key(_ecore_thread_global_hash, key); + pthread_rwlock_unlock(&_ecore_thread_global_hash_lock); + return ret; +#else + return EINA_TRUE; +#endif +} + + /** * @} */