1 /* Thread-local storage in multithreaded situations.
2    Copyright (C) 2005, 2007-2021 Free Software Foundation, Inc.
3 
4    This file is free software: you can redistribute it and/or modify
5    it under the terms of the GNU Lesser General Public License as
6    published by the Free Software Foundation; either version 2.1 of the
7    License, or (at your option) any later version.
8 
9    This file 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
12    GNU Lesser General Public License for more details.
13 
14    You should have received a copy of the GNU Lesser General Public License
15    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
16 
17 /* Written by Bruno Haible <bruno@clisp.org>, 2005.  */
18 
19 /* This file contains thread-local storage primitives for use with a given
20    thread library.  It does not contain primitives for creating threads or
21    for other multithreading primitives.
22 
23      Type:                      gl_tls_key_t
24      Initialization:            gl_tls_key_init (name, destructor);
25      Getting per-thread value:  gl_tls_get (name)
26      Setting per-thread value:  gl_tls_set (name, pointer);
27      De-initialization:         gl_tls_key_destroy (name);
28    Equivalent functions with control of error handling:
29      Initialization:            err = glthread_tls_key_init (&name, destructor);
30      Setting per-thread value:  err = glthread_tls_set (&name, pointer);
31      De-initialization:         err = glthread_tls_key_destroy (&name);
32 
33    A per-thread value is of type 'void *'.
34 
35    A destructor is a function pointer of type 'void (*) (void *)', called
36    when a thread exits, and taking the last per-thread value as argument.  It
37    is unspecified whether the destructor function is called when the last
38    per-thread value is NULL.  On some platforms, the destructor function is
39    not called at all.
40 */
41 
42 
43 #ifndef _TLS_H
44 #define _TLS_H
45 
46 #include <errno.h>
47 #include <stdlib.h>
48 
49 #if !defined c11_threads_in_use
50 # if HAVE_THREADS_H && USE_POSIX_THREADS_FROM_LIBC
51 #  define c11_threads_in_use() 1
52 # elif HAVE_THREADS_H && USE_POSIX_THREADS_WEAK
53 #  include <threads.h>
54 #  pragma weak thrd_exit
55 #  define c11_threads_in_use() (thrd_exit != NULL)
56 # else
57 #  define c11_threads_in_use() 0
58 # endif
59 #endif
60 
61 /* ========================================================================= */
62 
63 #if USE_ISOC_THREADS || USE_ISOC_AND_POSIX_THREADS
64 
65 /* Use the ISO C threads library.  */
66 
67 # include <threads.h>
68 
69 /* ------------------------- gl_tls_key_t datatype ------------------------- */
70 
71 typedef tss_t gl_tls_key_t;
72 # define glthread_tls_key_init(KEY, DESTRUCTOR) \
73     (tss_create (KEY, DESTRUCTOR) != thrd_success ? EAGAIN : 0)
74 # define gl_tls_get(NAME) \
75     tss_get (NAME)
76 # define glthread_tls_set(KEY, POINTER) \
77     (tss_set (*(KEY), (POINTER)) != thrd_success ? ENOMEM : 0)
78 # define glthread_tls_key_destroy(KEY) \
79     (tss_delete (*(KEY)), 0)
80 
81 #endif
82 
83 /* ========================================================================= */
84 
85 #if USE_POSIX_THREADS
86 
87 /* Use the POSIX threads library.  */
88 
89 # include <pthread.h>
90 
91 # if PTHREAD_IN_USE_DETECTION_HARD
92 
93 /* The pthread_in_use() detection needs to be done at runtime.  */
94 #  define pthread_in_use() \
95      glthread_in_use ()
96 extern int glthread_in_use (void);
97 
98 # endif
99 
100 # if USE_POSIX_THREADS_WEAK
101 
102 /* Use weak references to the POSIX threads library.  */
103 
104 #  pragma weak pthread_key_create
105 #  pragma weak pthread_getspecific
106 #  pragma weak pthread_setspecific
107 #  pragma weak pthread_key_delete
108 #  ifndef pthread_self
109 #   pragma weak pthread_self
110 #  endif
111 
112 #  if !PTHREAD_IN_USE_DETECTION_HARD
113 #   pragma weak pthread_mutexattr_gettype
114 #   define pthread_in_use() \
115       (pthread_mutexattr_gettype != NULL || c11_threads_in_use ())
116 #  endif
117 
118 # else
119 
120 #  if !PTHREAD_IN_USE_DETECTION_HARD
121 #   define pthread_in_use() 1
122 #  endif
123 
124 # endif
125 
126 /* ------------------------- gl_tls_key_t datatype ------------------------- */
127 
128 typedef union
129         {
130           void *singlethread_value;
131           pthread_key_t key;
132         }
133         gl_tls_key_t;
134 # define glthread_tls_key_init(KEY, DESTRUCTOR) \
135     (pthread_in_use ()                              \
136      ? pthread_key_create (&(KEY)->key, DESTRUCTOR) \
137      : ((KEY)->singlethread_value = NULL, 0))
138 # define gl_tls_get(NAME) \
139     (pthread_in_use ()                  \
140      ? pthread_getspecific ((NAME).key) \
141      : (NAME).singlethread_value)
142 # define glthread_tls_set(KEY, POINTER) \
143     (pthread_in_use ()                             \
144      ? pthread_setspecific ((KEY)->key, (POINTER)) \
145      : ((KEY)->singlethread_value = (POINTER), 0))
146 # define glthread_tls_key_destroy(KEY) \
147     (pthread_in_use () ? pthread_key_delete ((KEY)->key) : 0)
148 
149 #endif
150 
151 /* ========================================================================= */
152 
153 #if USE_WINDOWS_THREADS
154 
155 # define WIN32_LEAN_AND_MEAN  /* avoid including junk */
156 # include <windows.h>
157 
158 # include "windows-tls.h"
159 
160 /* ------------------------- gl_tls_key_t datatype ------------------------- */
161 
162 typedef glwthread_tls_key_t gl_tls_key_t;
163 # define glthread_tls_key_init(KEY, DESTRUCTOR) \
164     glwthread_tls_key_create (KEY, DESTRUCTOR)
165 # define gl_tls_get(NAME) \
166     TlsGetValue (NAME)
167 # define glthread_tls_set(KEY, POINTER) \
168     (!TlsSetValue (*(KEY), POINTER) ? EINVAL : 0)
169 # define glthread_tls_key_destroy(KEY) \
170     glwthread_tls_key_delete (*(KEY))
171 
172 #endif
173 
174 /* ========================================================================= */
175 
176 #if !(USE_ISOC_THREADS || USE_POSIX_THREADS || USE_ISOC_AND_POSIX_THREADS || USE_WINDOWS_THREADS)
177 
178 /* Provide dummy implementation if threads are not supported.  */
179 
180 /* ------------------------- gl_tls_key_t datatype ------------------------- */
181 
182 typedef struct
183         {
184           void *singlethread_value;
185         }
186         gl_tls_key_t;
187 # define glthread_tls_key_init(KEY, DESTRUCTOR) \
188     ((KEY)->singlethread_value = NULL, \
189      (void) (DESTRUCTOR),              \
190      0)
191 # define gl_tls_get(NAME) \
192     (NAME).singlethread_value
193 # define glthread_tls_set(KEY, POINTER) \
194     ((KEY)->singlethread_value = (POINTER), 0)
195 # define glthread_tls_key_destroy(KEY) \
196     0
197 
198 #endif
199 
200 /* ========================================================================= */
201 
202 /* Macros with built-in error handling.  */
203 
204 /* ------------------------- gl_tls_key_t datatype ------------------------- */
205 
206 #define gl_tls_key_init(NAME, DESTRUCTOR) \
207    do                                                 \
208      {                                                \
209        if (glthread_tls_key_init (&NAME, DESTRUCTOR)) \
210          abort ();                                    \
211      }                                                \
212    while (0)
213 #define gl_tls_set(NAME, POINTER) \
214    do                                         \
215      {                                        \
216        if (glthread_tls_set (&NAME, POINTER)) \
217          abort ();                            \
218      }                                        \
219    while (0)
220 #define gl_tls_key_destroy(NAME) \
221    do                                        \
222      {                                       \
223        if (glthread_tls_key_destroy (&NAME)) \
224          abort ();                           \
225      }                                       \
226    while (0)
227 
228 /* ========================================================================= */
229 
230 #endif /* _TLS_H */
231