cedric pushed a commit to branch master.

http://git.enlightenment.org/core/efl.git/commit/?id=316dc52d2f758bba2263cd25b940d1e4457910fd

commit 316dc52d2f758bba2263cd25b940d1e4457910fd
Author: Jérémy Zurcher <jer...@asynk.ch>
Date:   Thu Jan 23 14:50:08 2014 +0900

    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
---
 src/lib/eina/eina_inline_lock_posix.x | 12 +++--
 src/lib/eina/eina_inline_lock_win32.x | 21 ++++++++-
 src/lib/eina/eina_inline_lock_wince.x | 25 +++++++++--
 src/lib/eina/eina_lock.h              |  4 ++
 src/lib/eina/eina_thread.c            | 85 +++++++++++++++++++++++++++++++++++
 src/tests/eina/eina_test_lock.c       | 40 +++++++++++++----
 6 files changed, 172 insertions(+), 15 deletions(-)

diff --git a/src/lib/eina/eina_inline_lock_posix.x 
b/src/lib/eina/eina_inline_lock_posix.x
index 5270f46..b9136fc 100644
--- a/src/lib/eina/eina_inline_lock_posix.x
+++ b/src/lib/eina/eina_inline_lock_posix.x
@@ -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)
 {
diff --git a/src/lib/eina/eina_inline_lock_win32.x 
b/src/lib/eina/eina_inline_lock_win32.x
index 6feb60d..3123ad6 100644
--- a/src/lib/eina/eina_inline_lock_win32.x
+++ b/src/lib/eina/eina_inline_lock_win32.x
@@ -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;
 }
 
diff --git a/src/lib/eina/eina_inline_lock_wince.x 
b/src/lib/eina/eina_inline_lock_wince.x
index 3b73256..3d96a84 100644
--- a/src/lib/eina/eina_inline_lock_wince.x
+++ b/src/lib/eina/eina_inline_lock_wince.x
@@ -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 
-eina_tls_new(Eina_TLS *key)
+static inline Eina_Bool
+eina_tls_cb_new(Eina_TLS *key, Eina_TLS_Delete_Cb delete_cb)
 {
-   if (TlsAlloc() == TLS_OUT_OF_INDEXES)
+   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);
 }
 
@@ -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;
 }
 
diff --git a/src/lib/eina/eina_lock.h b/src/lib/eina/eina_lock.h
index b0afa41..ac0c8b1 100644
--- a/src/lib/eina/eina_lock.h
+++ b/src/lib/eina/eina_lock.h
@@ -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) */
diff --git a/src/lib/eina/eina_thread.c b/src/lib/eina/eina_thread.c
index b4e07e7..5ba6c57 100644
--- a/src/lib/eina/eina_thread.c
+++ b/src/lib/eina/eina_thread.c
@@ -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);
diff --git a/src/tests/eina/eina_test_lock.c b/src/tests/eina/eina_test_lock.c
index 9bac304..7c6626e 100644
--- a/src/tests/eina/eina_test_lock.c
+++ b/src/tests/eina/eina_test_lock.c
@@ -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;
+
+   ptr = eina_tls_get(key);
+   fail_if(eina_tls_get(key) != NULL);
 
-   fail_if(!eina_tls_set(key, &mystack));
-   fail_if(eina_tls_get(key) != &mystack);
+   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);
 

-- 


Reply via email to