#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", \
pthread_spin_lock(&_log_lock); \
} while (0)
#define UNLOCK() \
+ if(_threads_enabled) \
do { \
if (EINA_UNLIKELY(_threads_enabled)) \
pthread_spin_unlock(&_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
#undef S
}
-
/*
* Creates a colored domain name string.
*/
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;
free(tmp);
}
+ return EINA_TRUE;
+}
+
+
#ifdef EFL_HAVE_PTHREAD
- SHUTDOWN();
- _threads_enabled = 0;
-#endif
- return EINA_TRUE;
+/**
+ * @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.
*
eina_log_print_unlocked(domain, level, file, fnc, line, fmt, args);
UNLOCK();
}
+
*/
static int _eina_main_count = 0;
+static int _eina_main_thread_count = 0;
static int _eina_log_dom = -1;
#ifdef ERR
#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.
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
+}
+
+
/**
* @}
*/
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;
#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,
static void
_eina_stringshare_population_add(int slen)
{
+ LOCK_SMALL();
+ LOCK_BIG();
+
population.count++;
if (population.count > population.max)
population.max = population.count;
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
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;
}
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;
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)
{
{
unsigned int i;
+ LOCK_SMALL();
+ LOCK_BIG();
+
_eina_stringshare_population_stats();
/* remove any string still in the table */
_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.
*
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;
}
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;
}
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;
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;
}
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;
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);
}
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)
{
fdata->dups += node->references - 1;
fdata->unique++;
}
+
+ UNLOCK_BIG();
+ UNLOCK_SMALL();
+
return EINA_TRUE;
}
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;
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();
}
/**
* @}
*/
+