Eina : now eina stringshare is thread safe if eina_threads_init() is called. Eina log which was thread safe is now thread safe only if the previous functions is called

SVN revision: 43398
This commit is contained in:
Jonathan Atton 2009-11-01 19:50:18 +00:00
parent b2ac7c110a
commit 6ea6dc0856
6 changed files with 306 additions and 39 deletions

View File

@ -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);
/**
* @}
*/

View File

@ -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_ */

View File

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

View File

@ -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();
}

View File

@ -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 <pthread.h>
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
}
/**
* @}
*/

View File

@ -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 <pthread.h>
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();
}
/**
* @}
*/