eina_tls: add eina_tls_cb_new(Eina_TLS *key, Eina_TLS_Delete_Cb delete_cb)

Summary:
   delete_cb is called at thread exit for each Eina_TLS keys used by the thread

Details:
   posix:
      pthread_key_create(key, delete_cb); does it
   win32/wince:
      eina_tls_free/new un/registers key&&cb into a static eina_list.
      eina_tls_set add the key to an eina_list in Eina_Thread_Win3.
      this list is cleared and callbacks are called in _eina_thread_join()

Test Plan: win32/wince has to be tested, I have no setup to do it.

Reviewers: cedric

CC: cedric

Differential Revision: https://phab.enlightenment.org/D489
This commit is contained in:
Jérémy Zurcher 2014-01-23 14:50:08 +09:00 committed by Cedric BAIL
parent 1d7d554348
commit 316dc52d2f
6 changed files with 173 additions and 16 deletions

View File

@ -495,14 +495,20 @@ eina_rwlock_release(Eina_RWLock *mutex)
return EINA_LOCK_SUCCEED;
}
static inline Eina_Bool
eina_tls_new(Eina_TLS *key)
static inline Eina_Bool
eina_tls_cb_new(Eina_TLS *key, Eina_TLS_Delete_Cb delete_cb)
{
if (pthread_key_create(key, NULL) != 0)
if (pthread_key_create(key, delete_cb) != 0)
return EINA_FALSE;
return EINA_TRUE;
}
static inline Eina_Bool
eina_tls_new(Eina_TLS *key)
{
return eina_tls_cb_new(key, NULL);
}
static inline void
eina_tls_free(Eina_TLS key)
{

View File

@ -71,6 +71,9 @@ struct _Eina_RWLock
EAPI extern Eina_Bool _eina_threads_activated;
EAPI extern Eina_Bool _eina_thread_tls_cb_register(Eina_TLS key, Eina_TLS_Delete_Cb cb);
EAPI extern Eina_Bool _eina_thread_tls_cb_unregister(Eina_TLS key);
EAPI extern Eina_Bool _eina_thread_tls_key_add(Eina_TLS key);
static inline Eina_Bool
@ -481,16 +484,31 @@ eina_rwlock_release(Eina_RWLock *mutex)
}
static inline Eina_Bool
eina_tls_new(Eina_TLS *key)
eina_tls_cb_new(Eina_TLS *key, Eina_TLS_Delete_Cb delete_cb)
{
if ((*key = TlsAlloc()) == TLS_OUT_OF_INDEXES)
return EINA_FALSE;
if (delete_cb)
{
if (!_eina_thread_tls_cb_register(*key, delete_cb))
{
TlsFree(key);
return EINA_FALSE;
}
}
return EINA_TRUE;
}
static inline Eina_Bool
eina_tls_new(Eina_TLS *key)
{
return eina_tls_cb_new(key, NULL);
}
static inline void
eina_tls_free(Eina_TLS key)
{
_eina_thread_tls_cb_unregister(key);
TlsFree(key);
}
@ -505,6 +523,7 @@ eina_tls_set(Eina_TLS key, const void *data)
{
if (TlsSetValue(key, (LPVOID)data) == 0)
return EINA_FALSE;
_eina_thread_tls_key_add(key);
return EINA_TRUE;
}

View File

@ -26,6 +26,9 @@
#undef WIN32_LEAN_AND_MEAN
EAPI extern Eina_Bool _threads_activated;
EAPI extern Eina_Bool _eina_thread_tls_cb_register(Eina_TLS key, Eina_TLS_Delete_Cb cb);
EAPI extern Eina_Bool _eina_thread_tls_cb_unregister(Eina_TLS key);
EAPI extern Eina_Bool _eina_thread_tls_key_add(Eina_TLS key);
typedef HANDLE Eina_Lock;
typedef Eina_Lock Eina_Spinlock;
@ -151,17 +154,32 @@ eina_rwlock_release(Eina_RWLock *mutex)
return eina_lock_release(mutex);
}
static inline Eina_Bool
static inline Eina_Bool
eina_tls_cb_new(Eina_TLS *key, Eina_TLS_Delete_Cb delete_cb)
{
if ((*key = TlsAlloc()) == TLS_OUT_OF_INDEXES)
return EINA_FALSE;
if (delete_cb)
{
if (!_eina_thread_tls_cb_register(*key, delete_cb))
{
TlsFree(key);
return EINA_FALSE;
}
}
return EINA_TRUE;
}
static inline Eina_Bool
eina_tls_new(Eina_TLS *key)
{
if (TlsAlloc() == TLS_OUT_OF_INDEXES)
return EINA_FALSE;
return EINA_TRUE;
return eina_tls_cb_new(key, NULL);
}
static inline void
eina_tls_free(Eina_TLS key)
{
_eina_thread_tls_cb_unregister(key);
TlsFree(key);
}
@ -176,6 +194,7 @@ eina_tls_set(Eina_TLS key, const void *data)
{
if (TlsSetValue(key, (LPVOID)data) == 0)
return EINA_FALSE;
_eina_thread_tls_key_add(key);
return EINA_TRUE;
}

View File

@ -42,6 +42,8 @@ typedef enum
EINA_LOCK_DEADLOCK
} Eina_Lock_Result;
typedef void (*Eina_TLS_Delete_Cb)(void *ptr);
#ifdef _WIN32_WCE
# include "eina_inline_lock_wince.x"
#elif defined(_WIN32)
@ -91,6 +93,8 @@ static inline Eina_Lock_Result eina_rwlock_release(Eina_RWLock *mutex);
/** @relates static Eina_Bool eina_tls_new(pthread_key_t *key) */
static inline Eina_Bool eina_tls_new(Eina_TLS *key);
/** @relates static Eina_Bool eina_tls_cb_new(pthread_key_t *key, Eina_TLS_Delete_Cb delete_cb) */
static inline Eina_Bool eina_tls_cb_new(Eina_TLS *key, Eina_TLS_Delete_Cb delete_cb);
/** @relates static void eina_tls_free(pthread_key_t key) */
static inline void eina_tls_free(Eina_TLS key);
/** @relates static void eina_tls_get(pthread_key_t key) */

View File

@ -27,6 +27,7 @@
#include "eina_sched.h"
#ifdef _WIN32
# include "eina_list.h"
# include "eina_lock.h"
#endif
/* undefs EINA_ARG_NONULL() so NULL checks are not compiled out! */
@ -38,6 +39,12 @@
# include <windows.h>
# undef WIN32_LEAN_AND_MEAN
typedef struct _Eina_TLS_Cbs_Win32 Eina_TLS_Cbs_Win32;
struct _Eina_TLS_Cbs_Win32
{
Eina_TLS key;
Eina_TLS_Delete_Cb cb;
};
typedef struct _Eina_Thread_Win32 Eina_Thread_Win32;
struct _Eina_Thread_Win32
{
@ -45,6 +52,7 @@ struct _Eina_Thread_Win32
void *(*func)(void *data);
void *data;
void *ret;
Eina_List *tls_keys;
Eina_Thread index;
};
@ -54,6 +62,81 @@ struct _Eina_Thread_Win32
static unsigned long int _current_index = 1; /* start from one as the main loop == 0 */
static Eina_List *_thread_pool = NULL;
static Eina_List *_thread_running = NULL;
static Eina_List *_tls_keys_cbs = NULL;
static inline Eina_TLS_Cbs_Win32 *
_eina_thread_tls_cb_find(Eina_TLS key)
{
Eina_TLS_Cbs_Win32 *cb;
Eina_List *l;
EINA_LIST_FOREACH(_tls_keys_cbs, l, cb)
if (cb->key == key)
return cb;
return NULL;
}
static inline void
_eina_thread_tls_keys_clean(Eina_Thread_Win32 *tw)
{
void *data;
Eina_TLS_Cbs_Win32 *cb;
EINA_LIST_FREE(tw->tls_keys, data)
{
Eina_TLS key = data;
cb = _eina_thread_tls_cb_find(key);
if (cb)
cb->cb(eina_tls_get(key));
}
tw->tls_keys = NULL;
}
EAPI Eina_Bool
_eina_thread_tls_cb_register(Eina_TLS key, Eina_TLS_Delete_Cb cb)
{
Eina_TLS_Cbs_Win32 *tls_cb = malloc(sizeof(Eina_TLS_Cbs_Win32));
if (!cb) return EINA_FALSE;
tls_cb->key = key;
tls_cb->cb = cb;
_tls_keys_cbs = eina_list_append(_tls_keys_cbs, tls_cb);
return EINA_TRUE;
}
EAPI Eina_Bool
_eina_thread_tls_cb_unregister(Eina_TLS key)
{
Eina_TLS_Cbs_Win32 *cb = _eina_thread_tls_cb_find(key);
if (!cb) return EINA_FALSE;
_tls_keys_cbs = eina_list_remove(_tls_keys_cbs, cb);
free(cb);
return EINA_TRUE;
}
EAPI Eina_Bool
_eina_thread_tls_key_add(Eina_TLS key)
{
HANDLE t;
Eina_Thread_Win32 *tw;
Eina_List *l;
t = GetCurrentThread();
EINA_LIST_FOREACH(_thread_running, l, tw)
if (tw->thread == t)
{
void *data = key;
if (!eina_list_data_find(tw->tls_keys, data))
tw->tls_keys = eina_list_append(tw->tls_keys, data);
return EINA_TRUE;
}
return EINA_FALSE;
}
static Eina_Thread_Win32 *
_eina_thread_win32_find(Eina_Thread index)
@ -123,6 +206,7 @@ _eina_thread_create(Eina_Thread *t,
tw->func = func;
tw->data = (void *)data;
tw->tls_keys = NULL;
tw->thread = CreateThread(NULL, 0, _eina_thread_win32_cb, tw, 0, NULL);
if (!tw->thread) goto on_error;
@ -159,6 +243,7 @@ _eina_thread_join(Eina_Thread t)
tw->thread = NULL;
tw->func = NULL;
tw->data = NULL;
_eina_thread_tls_keys_clean(tw);
_thread_running = eina_list_remove(_thread_running, tw);
_thread_pool = eina_list_append(_thread_pool, _thread_pool);

View File

@ -77,33 +77,57 @@ START_TEST(eina_test_spinlock)
END_TEST
static Eina_TLS key;
static int _eina_tls_free_count = 0;
static void *
_eina_test_tls_alloc(int v)
{
int *ptr = malloc(sizeof(int));
*ptr = v;
return ptr;
}
static void
_eina_test_tls_free(void *ptr)
{
_eina_tls_free_count++;
free(ptr);
}
static void *
_eina_test_tls_thread(void *data EINA_UNUSED, Eina_Thread t EINA_UNUSED)
{
unsigned int mystack = 21;
int *ptr;
fail_if(!eina_tls_set(key, &mystack));
fail_if(eina_tls_get(key) != &mystack);
ptr = eina_tls_get(key);
fail_if(eina_tls_get(key) != NULL);
fail_if(!eina_tls_set(key, _eina_test_tls_alloc(24)));
ptr = eina_tls_get(key);
fail_if(eina_tls_get(key) == NULL);
fail_if(*ptr != 24);
return NULL;
}
START_TEST(eina_test_tls)
{
unsigned int ft = 42;
fail_if(!eina_init());
fail_if(!eina_tls_new(&key));
fail_if(!eina_tls_cb_new(&key, _eina_test_tls_free));
fail_if(!eina_tls_set(key, &ft));
fail_if(!eina_tls_set(key, _eina_test_tls_alloc(42)));
fail_if(!eina_thread_create(&thread, EINA_THREAD_NORMAL, 0, _eina_test_tls_thread, NULL));
eina_thread_join(thread);
fail_if(_eina_tls_free_count != 1);
fail_if(eina_tls_get(key) != &ft);
int *ptr = eina_tls_get(key);
fail_if(eina_tls_get(key) == NULL);
fail_if(*ptr != 42);
eina_tls_free(key);