fadce76fb0e442ef4a73101e11bea1b3825ddbd8
[gnulib.git] / lib / tls.h
1 /* Thread-local storage in multithreaded situations.
2    Copyright (C) 2005 Free Software Foundation, Inc.
3
4    This program is free software; you can redistribute it and/or modify it
5    under the terms of the GNU Library General Public License as published
6    by the Free Software Foundation; either version 2, or (at your option)
7    any later version.
8
9    This program 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    Library General Public License for more details.
13
14    You should have received a copy of the GNU Library General Public
15    License along with this program; if not, write to the Free Software
16    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
17    USA.  */
18
19 /* Written by Bruno Haible <bruno@clisp.org>, 2005.  */
20
21 /* This file contains thread-local storage primitives for use with a given
22    thread library.  It does not contain primitives for creating threads or
23    for other multithreading primitives.
24
25    Type:                      gl_tls_key_t
26    Initialization:            gl_tls_key_init (name, destructor);
27    Getting per-thread value:  gl_tls_get (name)
28    Setting per-thread value:  gl_tls_set (name, pointer);
29    De-initialization:         gl_tls_key_destroy (name);
30
31    A per-thread value is of type 'void *'.
32
33    A destructor is a function pointer of type 'void (*) (void *)', called
34    when a thread exits, and taking the last per-thread value as argument.  It
35    is unspecified whether the destructor function is called when the last
36    per-thread value is NULL.  On some platforms, the destructor function is
37    not called at all.
38 */
39
40
41 #ifndef _TLS_H
42 #define _TLS_H
43
44 /* ========================================================================= */
45
46 #if USE_POSIX_THREADS
47
48 /* Use the POSIX threads library.  */
49
50 # include <pthread.h>
51 # include <stdlib.h>
52
53 # if PTHREAD_IN_USE_DETECTION_HARD
54
55 /* The pthread_in_use() detection needs to be done at runtime.  */
56 #  define pthread_in_use() \
57      glthread_in_use ()
58 extern int glthread_in_use (void);
59
60 # endif
61
62 # if USE_POSIX_THREADS_WEAK
63
64 /* Use weak references to the POSIX threads library.  */
65
66 #  pragma weak pthread_key_create
67 #  pragma weak pthread_getspecific
68 #  pragma weak pthread_setspecific
69 #  pragma weak pthread_key_delete
70 #  ifndef pthread_self
71 #   pragma weak pthread_self
72 #  endif
73
74 #  if !PTHREAD_IN_USE_DETECTION_HARD
75 #   pragma weak pthread_cancel
76 #   define pthread_in_use() (pthread_cancel != NULL)
77 #  endif
78
79 # else
80
81 #  if !PTHREAD_IN_USE_DETECTION_HARD
82 #   define pthread_in_use() 1
83 #  endif
84
85 # endif
86
87 /* ------------------------- gl_tls_key_t datatype ------------------------- */
88
89 typedef union
90         {
91           void *singlethread_value;
92           pthread_key_t key;
93         }
94         gl_tls_key_t;
95 # define gl_tls_key_init(NAME, DESTRUCTOR) \
96     do                                                             \
97       {                                                            \
98         if (pthread_in_use ())                                     \
99           {                                                        \
100             if (pthread_key_create (&(NAME).key, DESTRUCTOR) != 0) \
101               abort ();                                            \
102           }                                                        \
103         else                                                       \
104           (NAME).singlethread_value = NULL;                        \
105       }                                                            \
106     while (0)
107 # define gl_tls_get(NAME) \
108     (pthread_in_use ()                  \
109      ? pthread_getspecific ((NAME).key) \
110      : (NAME).singlethread_value)
111 # define gl_tls_set(NAME, POINTER) \
112     do                                                            \
113       {                                                           \
114         if (pthread_in_use ())                                    \
115           {                                                       \
116             if (pthread_setspecific ((NAME).key, (POINTER)) != 0) \
117               abort ();                                           \
118           }                                                       \
119         else                                                      \
120           (NAME).singlethread_value = (POINTER);                  \
121       }                                                           \
122     while (0)
123 # define gl_tls_key_destroy(NAME) \
124     if (pthread_in_use () && pthread_key_delete ((NAME).key) != 0) \
125       abort ()
126
127 #endif
128
129 /* ========================================================================= */
130
131 #if USE_PTH_THREADS
132
133 /* Use the GNU Pth threads library.  */
134
135 # include <pth.h>
136 # include <stdlib.h>
137
138 # if USE_PTH_THREADS_WEAK
139
140 /* Use weak references to the GNU Pth threads library.  */
141
142 #  pragma weak pth_key_create
143 #  pragma weak pth_key_getdata
144 #  pragma weak pth_key_setdata
145 #  pragma weak pth_key_delete
146
147 #  pragma weak pth_cancel
148 #  define pth_in_use() (pth_cancel != NULL)
149
150 # else
151
152 #  define pth_in_use() 1
153
154 # endif
155
156 /* ------------------------- gl_tls_key_t datatype ------------------------- */
157
158 typedef union
159         {
160           void *singlethread_value;
161           pth_key_t key;
162         }
163         gl_tls_key_t;
164 # define gl_tls_key_init(NAME, DESTRUCTOR) \
165     do                                                     \
166       {                                                    \
167         if (pth_in_use ())                                 \
168           {                                                \
169             if (!pth_key_create (&(NAME).key, DESTRUCTOR)) \
170               abort ();                                    \
171           }                                                \
172         else                                               \
173           (NAME).singlethread_value = NULL;                \
174       }                                                    \
175     while (0)
176 # define gl_tls_get(NAME) \
177     (pth_in_use ()                  \
178      ? pth_key_getdata ((NAME).key) \
179      : (NAME).singlethread_value)
180 # define gl_tls_set(NAME, POINTER) \
181     do                                                    \
182       {                                                   \
183         if (pth_in_use ())                                \
184           {                                               \
185             if (!pth_key_setdata ((NAME).key, (POINTER))) \
186               abort ();                                   \
187           }                                               \
188         else                                              \
189           (NAME).singlethread_value = (POINTER);          \
190       }                                                   \
191     while (0)
192 # define gl_tls_key_destroy(NAME) \
193     if (pth_in_use () && !pth_key_delete ((NAME).key)) \
194       abort ()
195
196 #endif
197
198 /* ========================================================================= */
199
200 #if USE_SOLARIS_THREADS
201
202 /* Use the old Solaris threads library.  */
203
204 # include <thread.h>
205 # include <stdlib.h>
206
207 # if USE_SOLARIS_THREADS_WEAK
208
209 /* Use weak references to the old Solaris threads library.  */
210
211 #  pragma weak thr_keycreate
212 #  pragma weak thr_getspecific
213 #  pragma weak thr_setspecific
214
215 #  pragma weak thr_suspend
216 #  define thread_in_use() (thr_suspend != NULL)
217
218 # else
219
220 #  define thread_in_use() 1
221
222 # endif
223
224 /* ------------------------- gl_tls_key_t datatype ------------------------- */
225
226 typedef union
227         {
228           void *singlethread_value;
229           thread_key_t key;
230         }
231         gl_tls_key_t;
232 # define gl_tls_key_init(NAME, DESTRUCTOR) \
233     do                                                        \
234       {                                                       \
235         if (thread_in_use ())                                 \
236           {                                                   \
237             if (thr_keycreate (&(NAME).key, DESTRUCTOR) != 0) \
238               abort ();                                       \
239           }                                                   \
240         else                                                  \
241           (NAME).singlethread_value = NULL;                   \
242       }                                                       \
243     while (0)
244 # define gl_tls_get(NAME) \
245     (thread_in_use ()                \
246      ? glthread_tls_get ((NAME).key) \
247      : (NAME).singlethread_value)
248 extern void *glthread_tls_get (thread_key_t key);
249 # define gl_tls_set(NAME, POINTER) \
250     do                                                        \
251       {                                                       \
252         if (thread_in_use ())                                 \
253           {                                                   \
254             if (thr_setspecific ((NAME).key, (POINTER)) != 0) \
255               abort ();                                       \
256           }                                                   \
257         else                                                  \
258           (NAME).singlethread_value = (POINTER);              \
259       }                                                       \
260     while (0)
261 # define gl_tls_key_destroy(NAME) \
262     /* Unsupported.  */ \
263     (void)0
264
265 #endif
266
267 /* ========================================================================= */
268
269 #if USE_WIN32_THREADS
270
271 # include <windows.h>
272
273 /* ------------------------- gl_tls_key_t datatype ------------------------- */
274
275 typedef DWORD gl_tls_key_t;
276 # define gl_tls_key_init(NAME, DESTRUCTOR) \
277     /* The destructor is unsupported.  */    \
278     if (((NAME) = TlsAlloc ()) == (DWORD)-1) \
279       abort ()
280 # define gl_tls_get(NAME) \
281     TlsGetValue (NAME)
282 # define gl_tls_set(NAME, POINTER) \
283     if (!TlsSetValue (NAME, POINTER)) \
284       abort ()
285 # define gl_tls_key_destroy(NAME) \
286     if (!TlsFree (NAME)) \
287       abort ()
288
289 #endif
290
291 /* ========================================================================= */
292
293 #if !(USE_POSIX_THREADS || USE_PTH_THREADS || USE_SOLARIS_THREADS || USE_WIN32_THREADS)
294
295 /* Provide dummy implementation if threads are not supported.  */
296
297 /* ------------------------- gl_tls_key_t datatype ------------------------- */
298
299 typedef struct
300         {
301           void *singlethread_value;
302         }
303         gl_tls_key_t;
304 # define gl_tls_key_init(NAME, DESTRUCTOR) \
305     (NAME).singlethread_value = NULL
306 # define gl_tls_get(NAME) \
307     (NAME).singlethread_value
308 # define gl_tls_set(NAME, POINTER) \
309     (NAME).singlethread_value = (POINTER)
310 # define gl_tls_key_destroy(NAME) \
311     (void)0
312
313 #endif
314
315 /* ========================================================================= */
316
317 #endif /* _TLS_H */