Merge tag 'release_3_0_12' into branch moonshot-fr-3.0.12-upgrade.
[freeradius.git] / src / include / threads.h
1 #ifndef FR_THREADS_H
2 #define FR_THREADS_H
3 /*
4  *   This library is free software; you can redistribute it and/or
5  *   modify it under the terms of the GNU Lesser General Public
6  *   License as published by the Free Software Foundation; either
7  *   version 2.1 of the License, or (at your option) any later version.
8  *
9  *   This library is distributed in the hope that it will be useful,
10  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  *   Lesser General Public License for more details.
13  *
14  *   You should have received a copy of the GNU Lesser General Public
15  *   License along with this library; if not, write to the Free Software
16  *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18
19 /**
20  * $Id$
21  *
22  * @file threads.h
23  * @brief Macros to abstract Thread Local Storage
24  *
25  * @copyright 2013  The FreeRADIUS server project
26  */
27 typedef void (*pthread_destructor_t)(void*);
28
29 #if !defined(HAVE_PTHREAD_H) && defined(WITH_THREADS)
30 #  error WITH_THREADS defined, but pthreads not available
31 #endif
32
33 /*
34  *      First figure whether we have compiler support this is usually the case except on OSX,
35  *      where we need to use pthreads.
36  */
37 #ifdef TLS_STORAGE_CLASS
38 #  define __THREAD TLS_STORAGE_CLASS
39 #endif
40
41 /*
42  *      Now we define three macros for initialisation, updating, and retrieving
43  */
44 #ifndef WITH_THREADS
45 #  define fr_thread_local_setup(_t, _n) static _t _n;\
46 static inline int __fr_thread_local_destructor_##_n(pthread_destructor_t *ctx)\
47 {\
48         pthread_destructor_t func = *ctx;\
49         func(_n);\
50         return 0;\
51 }\
52 static inline _t __fr_thread_local_init_##_n(pthread_destructor_t func)\
53 {\
54         static pthread_destructor_t *ctx;\
55         if (!ctx) {\
56                 ctx = talloc(talloc_autofree_context(), pthread_destructor_t);\
57                 talloc_set_destructor(ctx, __fr_thread_local_destructor_##_n);\
58                 *ctx = func;\
59         }\
60         return _n;\
61 }
62 #  define fr_thread_local_init(_n, _f) __fr_thread_local_init_##_n(_f)
63 #  define fr_thread_local_set(_n, _v) ((int)!((_n = _v) || 1))
64 #  define fr_thread_local_get(_n) _n
65 #elif defined(__THREAD)
66 #  include <pthread.h>
67 #  define fr_thread_local_setup(_t, _n) static __THREAD _t _n;\
68 static pthread_key_t __fr_thread_local_key_##_n;\
69 static pthread_once_t __fr_thread_local_once_##_n = PTHREAD_ONCE_INIT;\
70 static pthread_destructor_t __fr_thread_local_destructor_##_n = NULL;\
71 static void __fr_thread_local_destroy_##_n(UNUSED void *unused)\
72 {\
73         __fr_thread_local_destructor_##_n(_n);\
74 }\
75 static void __fr_thread_local_key_init_##_n(void)\
76 {\
77         (void) pthread_key_create(&__fr_thread_local_key_##_n, __fr_thread_local_destroy_##_n);\
78 }\
79 static _t __fr_thread_local_init_##_n(pthread_destructor_t func)\
80 {\
81         __fr_thread_local_destructor_##_n = func;\
82         if (_n) return _n; \
83         (void) pthread_once(&__fr_thread_local_once_##_n, __fr_thread_local_key_init_##_n);\
84         (void) pthread_setspecific(__fr_thread_local_key_##_n, &(_n));\
85         return _n;\
86 }
87 #  define fr_thread_local_init(_n, _f)  __fr_thread_local_init_##_n(_f)
88 #  define fr_thread_local_set(_n, _v) ((int)!((_n = _v) || 1))
89 #  define fr_thread_local_get(_n) _n
90 #elif defined(HAVE_PTHREAD_H)
91 #  include <pthread.h>
92 #  define fr_thread_local_setup(_t, _n) \
93 static pthread_key_t __fr_thread_local_key_##_n;\
94 static pthread_once_t __fr_thread_local_once_##_n = PTHREAD_ONCE_INIT;\
95 static pthread_destructor_t __fr_thread_local_destructor_##_n = NULL;\
96 static void __fr_thread_local_destroy_##_n(UNUSED void *unused)\
97 {\
98         __fr_thread_local_destructor_##_n(_n);\
99 }\
100 static void __fr_thread_local_key_init_##_n(void)\
101 {\
102         (void) pthread_key_create(&__fr_thread_local_key_##_n, __fr_thread_local_destroy_##_n);\
103         (void) pthread_setspecific(__fr_thread_local_key_##_n, &(_n));\
104 }\
105 static _t __fr_thread_local_init_##_n(pthread_destructor_t func)\
106 {\
107         __fr_thread_local_destructor_##_n = func;\
108         if (_n) return _n; \
109         (void) pthread_once(&__fr_thread_local_once_##_n, __fr_thread_local_key_init_##_n);\
110         return _n;\
111 }
112 #  define fr_thread_local_init(_n, _f)                  __fr_thread_local_init_##_n(_f)
113 #  define fr_thread_local_set(_n, _v)                   __fr_thread_local_set_##_n(_v)
114 #  define fr_thread_local_get(_n)                       __fr_thread_local_get_##_n()
115 #endif
116 #endif