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