diff --git a/legacy/eina/src/include/eina_main.h b/legacy/eina/src/include/eina_main.h index c504bbb9d6..dc4f519606 100644 --- a/legacy/eina/src/include/eina_main.h +++ b/legacy/eina/src/include/eina_main.h @@ -35,6 +35,10 @@ EAPI int eina_init(void); EAPI int eina_shutdown(void); +EAPI int eina_threads_init(void); + +EAPI int eina_threads_shutdown(void); + /** * @} */ diff --git a/legacy/eina/src/include/eina_private.h b/legacy/eina/src/include/eina_private.h index ba4f01878d..e3ba4528fc 100644 --- a/legacy/eina/src/include/eina_private.h +++ b/legacy/eina/src/include/eina_private.h @@ -116,5 +116,12 @@ } \ } while(0); +#ifdef EFL_HAVE_PTHREAD +void eina_stringshare_threads_init(void); +void eina_stringshare_threads_shutdown(void); +void eina_log_threads_init(void); +void eina_log_threads_shutdown(void); +#endif + #endif /* EINA_PRIVATE_H_ */ diff --git a/legacy/eina/src/lib/eina_list.c b/legacy/eina/src/lib/eina_list.c index 4185d9d38a..12aa0b6d1d 100644 --- a/legacy/eina/src/lib/eina_list.c +++ b/legacy/eina/src/lib/eina_list.c @@ -1,3 +1,5 @@ +// vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 + /* EINA - EFL data type library * Copyright (C) 2002-2008 Carsten Haitzler, Gustavo Sverzut Barbieri, Tilman Sauerbeck, * Vincent Torri, Cedric Bail, Jorge Luis Zapata Muga, @@ -1590,15 +1592,15 @@ eina_list_merge(Eina_List *left, Eina_List *right) * @param right The head of the new right list. * @return The new left list * - * This function split @p list into two lists ( left and right ) after the node @p relative. @p Relative - * will become the last node of the left list. If @p list or @p right are NULL list is returns. + * This function split @p list into two lists ( left and right ) after the node @p relative. @p Relative + * will become the last node of the left list. If @p list or @p right are NULL list is returns. * If @p relative is NULL right is set to @p list and NULL is returns. * If @p relative is the last node of @p list list is returns and @p right is set to NULL. * * list does not exist anymore after the split. * */ -EAPI Eina_List * + EAPI Eina_List * eina_list_split_list(Eina_List *list, Eina_List *relative, Eina_List **right) { Eina_List *next; @@ -1610,12 +1612,12 @@ eina_list_split_list(Eina_List *list, Eina_List *relative, Eina_List **right) if (!list) return NULL; if (!relative) { - *right = list; - return NULL; + *right = list; + return NULL; } if (relative == eina_list_last(list)) return list; - next = eina_list_next(relative); + next = eina_list_next(relative); next->prev = NULL; next->accounting = _eina_list_mempool_accounting_new(next); next->accounting->last = list->accounting->last; @@ -1624,14 +1626,14 @@ eina_list_split_list(Eina_List *list, Eina_List *relative, Eina_List **right) itr = next; do { - itr->accounting = next->accounting; - next->accounting->count++; - itr = itr->next; + itr->accounting = next->accounting; + next->accounting->count++; + itr = itr->next; } - while (itr); + while (itr); relative->next = NULL; - list->accounting->last = relative; + list->accounting->last = relative; list->accounting->count = list->accounting->count - next->accounting->count; return list; diff --git a/legacy/eina/src/lib/eina_log.c b/legacy/eina/src/lib/eina_log.c index eb1c018d42..30c3be77ec 100644 --- a/legacy/eina/src/lib/eina_log.c +++ b/legacy/eina/src/lib/eina_log.c @@ -376,6 +376,7 @@ static pthread_t _main_thread; #ifdef EINA_PTHREAD_SPIN static pthread_spinlock_t _log_lock; #define LOCK() \ + if(_threads_enabled) \ do { \ if (0) \ fprintf(stderr, "+++LOG LOCKED! [%s, %lu]\n", \ @@ -384,6 +385,7 @@ static pthread_spinlock_t _log_lock; pthread_spin_lock(&_log_lock); \ } while (0) #define UNLOCK() \ + if(_threads_enabled) \ do { \ if (EINA_UNLIKELY(_threads_enabled)) \ pthread_spin_unlock(&_log_lock); \ @@ -396,8 +398,8 @@ static pthread_spinlock_t _log_lock; #define SHUTDOWN() pthread_spin_destroy(&_log_lock); #else static pthread_mutex_t _log_mutex = PTHREAD_MUTEX_INITIALIZER; -#define LOCK() pthread_mutex_lock(&_log_mutex); -#define UNLOCK() pthread_mutex_unlock(&_log_mutex); +#define LOCK() if(_threads_enabled) pthread_mutex_lock(&_log_mutex); +#define UNLOCK() if(_threads_enabled) pthread_mutex_unlock(&_log_mutex); #define INIT() do {} while (0) #define SHUTDOWN() do {} while (0) #endif @@ -700,7 +702,6 @@ eina_log_print_prefix_update(void) #undef S } - /* * Creates a colored domain name string. */ @@ -965,11 +966,6 @@ eina_log_init(void) assert((sizeof(_names)/sizeof(_names[0])) == EINA_LOG_LEVELS); assert((sizeof(_colors)/sizeof(_colors[0])) == EINA_LOG_LEVELS + 1); -#ifdef EFL_HAVE_PTHREAD - _main_thread = pthread_self(); - INIT(); -#endif - // Check if color is disabled if ((tmp = getenv(EINA_LOG_ENV_COLOR_DISABLE)) && (atoi(tmp) == 1)) _disable_color = EINA_TRUE; @@ -1056,14 +1052,48 @@ eina_log_shutdown(void) free(tmp); } -#ifdef EFL_HAVE_PTHREAD - SHUTDOWN(); - _threads_enabled = 0; -#endif - return EINA_TRUE; } + +#ifdef EFL_HAVE_PTHREAD + +/** + * @internal + * @brief Activate the log mutex. + * + * This function activate the mutex in the eina log module. It is called by + * eina_thread_init(). + * + * @see eina_thread_init() + */ +void +eina_log_threads_init(void) +{ + _main_thread = pthread_self(); + _threads_enabled = EINA_TRUE; + INIT(); +} + +/** + * @internal + * @brief Shut down the log mutex. + * + * This function shuts down the mutex in the log module. + * It is called by eina_thread_shutdown(). + * + * @see eina_thread_shutdown() + */ +void +eina_log_threads_shutdown(void) +{ + SHUTDOWN(); + _threads_enabled = EINA_FALSE; +} + +#endif + + /** * Enable logging module to handle threads. * @@ -1471,3 +1501,4 @@ eina_log_vprint(int domain, Eina_Log_Level level, const char *file, eina_log_print_unlocked(domain, level, file, fnc, line, fmt, args); UNLOCK(); } + diff --git a/legacy/eina/src/lib/eina_main.c b/legacy/eina/src/lib/eina_main.c index a75631a64a..0b8af5e0fb 100644 --- a/legacy/eina/src/lib/eina_main.c +++ b/legacy/eina/src/lib/eina_main.c @@ -48,6 +48,7 @@ */ static int _eina_main_count = 0; +static int _eina_main_thread_count = 0; static int _eina_log_dom = -1; #ifdef ERR @@ -60,6 +61,18 @@ static int _eina_log_dom = -1; #endif #define DBG(...) EINA_LOG_DOM_DBG(_eina_log_dom, __VA_ARGS__) +#ifdef EFL_HAVE_PTHREAD +#include +static Eina_Bool _threads_activated = EINA_FALSE; +static pthread_mutex_t _mutex = PTHREAD_MUTEX_INITIALIZER; +#define LOCK() if(_threads_activated) pthread_mutex_lock(&_mutex); +#define UNLOCK() if(_threads_activated) pthread_mutex_unlock(&_mutex); +#define UNLOCK_FORCE() pthread_mutex_unlock(&_mutex); +#else +#define LOCK() do {} while (0) +#define UNLOCK() do {} while (0) +#define UNLOCK_FORCE() do {} while (0) +#endif /* place module init/shutdown functions here to avoid other modules * calling them by mistake. @@ -220,6 +233,88 @@ eina_shutdown(void) return _eina_main_count; } + +/** + * @brief Initialize the mutexs of the Eina library. + * + * @return 1 or greater on success, 0 on error. + * + * This function sets up all the mutexs in all eina modules. It returns 0 on + * failure (that is, when one of the module fails to initialize), + * otherwise it returns the number of times it has already been + * called. + * + * When the mutexs are not used anymore, call eina_thread_shutdown() to shut down + * the mutexs. + */ +EAPI int +eina_threads_init(void) +{ +#ifdef EFL_HAVE_PTHREAD + int ret; + + LOCK(); + ++_eina_main_thread_count; + ret = _eina_main_thread_count; + + if(_eina_main_thread_count > 1) + { + UNLOCK(); + return ret; + } + + eina_stringshare_threads_init(); + eina_log_threads_init(); + _threads_activated = EINA_TRUE; + + return ret; +#else + return 0; +#endif +} + +/** + * @brief Shut down mutexs in the Eina library. + * + * @return 0 when all mutexs are completely shut down, 1 or + * greater otherwise. + * + * This function shuts down the mutexs in the Eina library. It returns 0 when it has + * been called the same number of times than eina_thread_init(). In that case + * it shut down all the mutexs. + * + * Once this function succeeds (that is, @c 0 is returned), you must + * not call any of the Eina function in a thread anymore. You must call + * eina_thread_init() again to use the Eina functions in a thread again. + */ +EAPI int +eina_threads_shutdown(void) +{ +#ifdef EFL_HAVE_PTHREAD + int ret; + + LOCK(); + ret = --_eina_main_thread_count; + if(_eina_main_thread_count > 0) + { + UNLOCK(); + return ret; + } + + eina_stringshare_threads_shutdown(); + eina_log_threads_shutdown(); + + _threads_activated = EINA_FALSE; + + UNLOCK_FORCE(); + + return ret; +#else + return 0; +#endif +} + + /** * @} */ diff --git a/legacy/eina/src/lib/eina_stringshare.c b/legacy/eina/src/lib/eina_stringshare.c index 50c3f86cad..8e445b6ff1 100644 --- a/legacy/eina/src/lib/eina_stringshare.c +++ b/legacy/eina/src/lib/eina_stringshare.c @@ -100,19 +100,23 @@ static const char EINA_MAGIC_STRINGSHARE_HEAD_STR[] = "Eina Stringshare Head"; static const char EINA_MAGIC_STRINGSHARE_NODE_STR[] = "Eina Stringshare Node"; -#define EINA_MAGIC_CHECK_STRINGSHARE_HEAD(d, ...) \ +#define EINA_MAGIC_CHECK_STRINGSHARE_HEAD(d, unlock, ...) \ do { \ if (!EINA_MAGIC_CHECK((d), EINA_MAGIC_STRINGSHARE_HEAD)) \ { \ EINA_MAGIC_FAIL((d), EINA_MAGIC_STRINGSHARE_HEAD); \ + unlock; \ return __VA_ARGS__; \ } \ } while (0); -#define EINA_MAGIC_CHECK_STRINGSHARE_NODE(d) \ +#define EINA_MAGIC_CHECK_STRINGSHARE_NODE(d, unlock) \ do { \ if (!EINA_MAGIC_CHECK((d), EINA_MAGIC_STRINGSHARE_NODE)) \ + { \ + unlock; \ EINA_MAGIC_FAIL((d), EINA_MAGIC_STRINGSHARE_NODE); \ + } \ } while (0); typedef struct _Eina_Stringshare Eina_Stringshare; @@ -170,6 +174,27 @@ static int _eina_stringshare_log_dom = -1; #endif #define DBG(...) EINA_LOG_DOM_DBG(_eina_stringshare_log_dom, __VA_ARGS__) + + +#ifdef EFL_HAVE_PTHREAD +#include +static Eina_Bool _threads_activated = EINA_FALSE; +//string < 4 +static pthread_mutex_t _mutex_small = PTHREAD_MUTEX_INITIALIZER; +//string >= 4 +static pthread_mutex_t _mutex_big = PTHREAD_MUTEX_INITIALIZER; +#define LOCK_SMALL() if(_threads_activated) pthread_mutex_lock(&_mutex_small); +#define UNLOCK_SMALL() if(_threads_activated) pthread_mutex_unlock(&_mutex_small); +#define LOCK_BIG() if(_threads_activated) pthread_mutex_lock(&_mutex_big); +#define UNLOCK_BIG() if(_threads_activated) pthread_mutex_unlock(&_mutex_big); +#else +#define LOCK_SMALL() do {} while (0) +#define UNLOCK_SMALL() do {} while (0) +#define LOCK_BIG() do {} while (0) +#define UNLOCK_BIG() do {} while (0) +#endif + + static const unsigned char _eina_stringshare_single[512] = { 0,0,1,0,2,0,3,0,4,0,5,0,6,0,7,0,8,0,9,0,10,0,11,0,12,0,13,0,14,0,15,0, 16,0,17,0,18,0,19,0,20,0,21,0,22,0,23,0,24,0,25,0,26,0,27,0,28,0,29,0,30,0, @@ -276,6 +301,9 @@ _eina_stringshare_population_stats(void) static void _eina_stringshare_population_add(int slen) { + LOCK_SMALL(); + LOCK_BIG(); + population.count++; if (population.count > population.max) population.max = population.count; @@ -286,14 +314,23 @@ _eina_stringshare_population_add(int slen) if (population_group[slen].count > population_group[slen].max) population_group[slen].max = population_group[slen].count; } + + UNLOCK_BIG(); + UNLOCK_SMALL(); } static void _eina_stringshare_population_del(int slen) { + LOCK_SMALL(); + LOCK_BIG(); + population.count--; if (slen < 4) population_group[slen].count--; + + UNLOCK_BIG(); + UNLOCK_SMALL(); } static void @@ -331,7 +368,7 @@ static void _eina_stringshare_population_head_del(__UNUSED__ Eina_Stringshare_He static int _eina_stringshare_cmp(const Eina_Stringshare_Head *ed, const int *hash, __UNUSED__ int length, __UNUSED__ void *data) { - EINA_MAGIC_CHECK_STRINGSHARE_HEAD(ed, 0); + EINA_MAGIC_CHECK_STRINGSHARE_HEAD(ed, , 0); return ed->hash - *hash; } @@ -339,8 +376,8 @@ _eina_stringshare_cmp(const Eina_Stringshare_Head *ed, const int *hash, __UNUSED static Eina_Rbtree_Direction _eina_stringshare_node(const Eina_Stringshare_Head *left, const Eina_Stringshare_Head *right, __UNUSED__ void *data) { - EINA_MAGIC_CHECK_STRINGSHARE_HEAD(left, 0); - EINA_MAGIC_CHECK_STRINGSHARE_HEAD(right, 0); + EINA_MAGIC_CHECK_STRINGSHARE_HEAD(left, , 0); + EINA_MAGIC_CHECK_STRINGSHARE_HEAD(right, , 0); if (left->hash - right->hash < 0) return EINA_RBTREE_LEFT; @@ -350,7 +387,7 @@ _eina_stringshare_node(const Eina_Stringshare_Head *left, const Eina_Stringshare static void _eina_stringshare_head_free(Eina_Stringshare_Head *ed, __UNUSED__ void *data) { - EINA_MAGIC_CHECK_STRINGSHARE_HEAD(ed); + EINA_MAGIC_CHECK_STRINGSHARE_HEAD(ed, ); while (ed->head) { @@ -879,6 +916,9 @@ eina_stringshare_shutdown(void) { unsigned int i; + LOCK_SMALL(); + LOCK_BIG(); + _eina_stringshare_population_stats(); /* remove any string still in the table */ @@ -893,9 +933,48 @@ eina_stringshare_shutdown(void) _eina_stringshare_small_shutdown(); eina_log_domain_unregister(_eina_stringshare_log_dom); _eina_stringshare_log_dom = -1; + + UNLOCK_BIG(); + UNLOCK_SMALL(); + + return EINA_TRUE; } +#ifdef EFL_HAVE_PTHREAD + +/** + * @internal + * @brief Activate the stringshare mutexs. + * + * This function activate the mutexs in the eina stringshare module. It is called by + * eina_thread_init(). + * + * @see eina_thread_init() + */ +void +eina_stringshare_threads_init(void) +{ + _threads_activated = EINA_TRUE; +} + +/** + * @internal + * @brief Shut down the stringshare mutexs. + * + * This function shuts down the mutexs in the stringshare module. + * It is called by eina_thread_shutdown(). + * + * @see eina_thread_shutdown() + */ +void +eina_stringshare_threads_shutdown(void) +{ + _threads_activated = EINA_FALSE; +} + +#endif + /** * @brief Retrieve an instance of a string for use in a program. * @@ -936,36 +1015,53 @@ eina_stringshare_add_length(const char *str, unsigned int slen) else if (slen == 1) return (const char *)_eina_stringshare_single + ((*str) << 1); else if (slen < 4) - return _eina_stringshare_small_add(str, slen); + { + LOCK_SMALL(); + const char *s = _eina_stringshare_small_add(str, slen); + UNLOCK_SMALL(); + return s; + } hash = eina_hash_superfast(str, slen); hash_num = hash & 0xFF; hash = (hash >> 8) & EINA_STRINGSHARE_MASK; + LOCK_BIG(); p_bucket = share->buckets + hash_num; + ed = _eina_stringshare_find_hash(*p_bucket, hash); if (!ed) - return _eina_stringshare_add_head(p_bucket, hash, str, slen); + { + const char *s = _eina_stringshare_add_head(p_bucket, hash, str, slen); + UNLOCK_BIG(); + return s; + } - EINA_MAGIC_CHECK_STRINGSHARE_HEAD(ed, NULL); + EINA_MAGIC_CHECK_STRINGSHARE_HEAD(ed, UNLOCK_BIG(), NULL); el = _eina_stringshare_head_find(ed, str, slen); if (el) { - EINA_MAGIC_CHECK_STRINGSHARE_NODE(el); + EINA_MAGIC_CHECK_STRINGSHARE_NODE(el, UNLOCK_BIG()); el->references++; + UNLOCK_BIG(); return el->str; } el = _eina_stringshare_node_alloc(slen); if (!el) - return NULL; + { + UNLOCK_BIG(); + return NULL; + } _eina_stringshare_node_init(el, str, slen); el->next = ed->head; ed->head = el; _eina_stringshare_population_head_add(ed); + UNLOCK_BIG(); + return el->str; } @@ -1014,7 +1110,7 @@ _eina_stringshare_node_from_str(const char *str) const size_t offset = (char *)&(t.str) - (char *)&t; node = (Eina_Stringshare_Node *)(str - offset); - EINA_MAGIC_CHECK_STRINGSHARE_NODE(node); + EINA_MAGIC_CHECK_STRINGSHARE_NODE(node, ); return node; } @@ -1047,18 +1143,27 @@ eina_stringshare_ref(const char *str) if (slen < 2) { _eina_stringshare_population_add(slen); + return str; } else if (slen < 4) { _eina_stringshare_population_add(slen); - return _eina_stringshare_small_add(str, slen); + + LOCK_SMALL(); + const char *s = _eina_stringshare_small_add(str, slen); + UNLOCK_SMALL(); + + return s; } + LOCK_BIG(); node = _eina_stringshare_node_from_str(str); node->references++; DBG("str=%p (%s) refs=%u", str, str, node->references); + UNLOCK_BIG(); + _eina_stringshare_population_add(node->length); return str; @@ -1102,15 +1207,20 @@ eina_stringshare_del(const char *str) return; else if (slen < 4) { + LOCK_SMALL(); _eina_stringshare_small_del(str, slen); + UNLOCK_SMALL(); return; } + LOCK_BIG(); + node = _eina_stringshare_node_from_str(str); if (node->references > 1) { node->references--; DBG("str=%p (%s) refs=%u", str, str, node->references); + UNLOCK_BIG(); return; } @@ -1127,7 +1237,7 @@ eina_stringshare_del(const char *str) if (!ed) goto on_error; - EINA_MAGIC_CHECK_STRINGSHARE_HEAD(ed); + EINA_MAGIC_CHECK_STRINGSHARE_HEAD(ed, UNLOCK_BIG()); if (!_eina_stringshare_head_remove_node(ed, node)) goto on_error; @@ -1140,9 +1250,12 @@ eina_stringshare_del(const char *str) else _eina_stringshare_population_head_del(ed); + UNLOCK_BIG(); + return; on_error: + UNLOCK_BIG(); /* possible segfault happened before here, but... */ CRITICAL("EEEK trying to del non-shared stringshare \"%s\"", str); } @@ -1231,7 +1344,10 @@ static Eina_Bool eina_iterator_array_check(const Eina_Rbtree *rbtree __UNUSED__, Eina_Stringshare_Head *head, struct dumpinfo *fdata) { Eina_Stringshare_Node *node; - + + LOCK_SMALL(); + LOCK_BIG(); + fdata->used += sizeof(Eina_Stringshare_Head); for (node = head->head; node; node = node->next) { @@ -1243,6 +1359,10 @@ eina_iterator_array_check(const Eina_Rbtree *rbtree __UNUSED__, Eina_Stringshare fdata->dups += node->references - 1; fdata->unique++; } + + UNLOCK_BIG(); + UNLOCK_SMALL(); + return EINA_TRUE; } @@ -1266,7 +1386,12 @@ eina_stringshare_dump(void) di.unique = 0; printf("DDD: len ref string\n"); printf("DDD:-------------------\n"); + + LOCK_SMALL(); _eina_stringshare_small_dump(&di); + UNLOCK_SMALL(); + + LOCK_BIG(); for (i = 0; i < EINA_STRINGSHARE_BUCKETS; i++) { if (!share->buckets[i]) continue; @@ -1294,8 +1419,11 @@ eina_stringshare_dump(void) for (i = 0; i < sizeof (population_group) / sizeof (population_group[0]); ++i) fprintf(stderr, "DDD: %i strings of length %i, max strings: %i\n", population_group[i].count, i, population_group[i].max); #endif + + UNLOCK_BIG(); } /** * @} */ +