Add support for registering destructors for TLS
authorArran Cudbard-Bell <a.cudbardb@freeradius.org>
Thu, 18 Jul 2013 12:13:06 +0000 (13:13 +0100)
committerArran Cudbard-Bell <a.cudbardb@freeradius.org>
Thu, 18 Jul 2013 12:17:20 +0000 (13:17 +0100)
src/include/threads.h

index 7b4df45..57c781e 100644 (file)
  *
  * @copyright 2013  The FreeRADIUS server project
  */
+typedef void (*pthread_destructor_t)(void*);
 
 /*
  *     First figure whether we have compiler support this is usually the case except on OSX,
- *     where we need to use pthreads.  
+ *     where we need to use pthreads.
  */
 #ifdef HAVE_THREAD_TLS
 /*
  *     Now we define three macros for initialisation, updating, and retrieving
  */
 #ifndef WITH_THREADS
-#  define fr_thread_local_init(_x, _n) static _x _n
+#  define fr_thread_local_setup(_x, _n)        static _x _n
+/*
+ *  @todo we really need to put destructors in a global array and call them on server exit
+ */
+#  define fr_thread_local_init(_n, _f) _n
 #  define fr_thread_local_set(_n, _v) ((int)!((_n = _v) || 1))
 #  define fr_thread_local_get(_n) _n
+#elif !defined(HAVE_PTHREAD_H)
+#error WITH_THREADS defined, but pthreads not available
 #elif defined(__THREAD)
-#  define fr_thread_local_init(_x, _n) static __THREAD _x _n
+#  include <pthread.h>
+#  define fr_thread_local_setup(_t, _n) static __THREAD _t _n;\
+static pthread_key_t __fr_thread_local_key_##_n;\
+static pthread_once_t __fr_thread_local_once_##_n = PTHREAD_ONCE_INIT;\
+static pthread_destructor_t __fr_thread_local_destructor_##_n = NULL;\
+static inline void __fr_thread_local_key_init_##_n(void)\
+{\
+       (void) pthread_key_create(&__fr_thread_local_key_##_n, __fr_thread_local_destructor_##_n);\
+}\
+static inline _t __fr_thread_local_init_##_n(pthread_destructor_t func)\
+{\
+       __fr_thread_local_destructor_##_n = func;\
+       (void) pthread_once(&__fr_thread_local_once_##_n, __fr_thread_local_key_init_##_n);\
+       return _n;\
+}
+#  define fr_thread_local_init(_n, _f) __fr_thread_local_init_##_n(_f)
 #  define fr_thread_local_set(_n, _v) ((int)!((_n = _v) || 1))
 #  define fr_thread_local_get(_n) _n
 #elif defined(HAVE_PTHREAD_H)
 #  include <pthread.h>
-#  define fr_thread_local_init(_t, _n) \
+#  define fr_thread_local_setup(_t, _n) \
 static pthread_key_t __fr_thread_local_key_##_n;\
 static pthread_once_t __fr_thread_local_once_##_n = PTHREAD_ONCE_INIT;\
-static void __fr_thread_local_key_init_##_n(void)\
+static pthread_destructor_t __fr_thread_local_destructor_##_n = NULL; \
+static inline void __fr_thread_local_key_init_##_n(void)\
 {\
-       (void) pthread_key_create(&__fr_thread_local_key_##_n, NULL);\
+       (void) pthread_key_create(&__fr_thread_local_key_##_n, __fr_thread_local_destructor_##_n);\
 }\
-static _t __fr_thread_local_get_##_n(void)\
+static inline _t __fr_thread_local_init_##_n(pthread_destructor_t func)\
 {\
+       __fr_thread_local_destructor_##_n = func;
        (void) pthread_once(&__fr_thread_local_once_##_n, __fr_thread_local_key_init_##_n);\
        return pthread_getspecific(__fr_thread_local_key_##_n);\
 }\
-static int __fr_thread_local_set_##_n(_t val)\
+static inline _t __fr_thread_local_get_##_n(void)\
+{\
+       return pthread_getspecific(__fr_thread_local_key_##_n);\
+}\
+static inline int __fr_thread_local_set_##_n(_t val)\
 {\
-       (void) pthread_once(&__fr_thread_local_once_##_n, __fr_thread_local_key_init_##_n);\
        return pthread_setspecific(__fr_thread_local_key_##_n, val);\
 }
-#  define fr_thread_local_set(_n, _v)  __fr_thread_local_set_##_n(_v)
-#  define fr_thread_local_get(_n)      __fr_thread_local_get_##_n()
-#else
-# error WITH_THREADS defined, but no Thread Local Storage (TLS) available
+#  define fr_thread_local_init(_n, _f)                 __fr_thread_local_init_##_n(_f)
+#  define fr_thread_local_set(_n, _v)                  __fr_thread_local_set_##_n(_v)
+#  define fr_thread_local_get(_n)                      __fr_thread_local_get_##_n()
 #endif