1 /* Thread-local storage in multithreaded situations.
2    Copyright (C) 2005, 2007-2021 Free Software Foundation, Inc.
3 
4    This program is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 3 of the License, or
7    (at your option) 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
12    GNU General Public License for more details.
13 
14    You should have received a copy of the GNU 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_WEAK
51 #  include <threads.h>
52 #  pragma weak thrd_exit
53 #  define c11_threads_in_use() (thrd_exit != NULL)
54 # else
55 #  define c11_threads_in_use() 0
56 # endif
57 #endif
58 
59 /* ========================================================================= */
60 
61 #if USE_ISOC_THREADS || USE_ISOC_AND_POSIX_THREADS
62 
63 /* Use the ISO C threads library.  */
64 
65 # include <threads.h>
66 
67 /* ------------------------- gl_tls_key_t datatype ------------------------- */
68 
69 typedef tss_t gl_tls_key_t;
70 # define glthread_tls_key_init(KEY, DESTRUCTOR) \
71     (tss_create (KEY, DESTRUCTOR) != thrd_success ? EAGAIN : 0)
72 # define gl_tls_get(NAME) \
73     tss_get (NAME)
74 # define glthread_tls_set(KEY, POINTER) \
75     (tss_set (*(KEY), (POINTER)) != thrd_success ? ENOMEM : 0)
76 # define glthread_tls_key_destroy(KEY) \
77     (tss_delete (*(KEY)), 0)
78 
79 #endif
80 
81 /* ========================================================================= */
82 
83 #if USE_POSIX_THREADS
84 
85 /* Use the POSIX threads library.  */
86 
87 # include <pthread.h>
88 
89 # if PTHREAD_IN_USE_DETECTION_HARD
90 
91 /* The pthread_in_use() detection needs to be done at runtime.  */
92 #  define pthread_in_use() \
93      glthread_in_use ()
94 extern int glthread_in_use (void);
95 
96 # endif
97 
98 # if USE_POSIX_THREADS_WEAK
99 
100 /* Use weak references to the POSIX threads library.  */
101 
102 #  pragma weak pthread_key_create
103 #  pragma weak pthread_getspecific
104 #  pragma weak pthread_setspecific
105 #  pragma weak pthread_key_delete
106 #  ifndef pthread_self
107 #   pragma weak pthread_self
108 #  endif
109 
110 #  if !PTHREAD_IN_USE_DETECTION_HARD
111 #   pragma weak pthread_mutexattr_gettype
112 #   define pthread_in_use() \
113       (pthread_mutexattr_gettype != NULL || c11_threads_in_use ())
114 #  endif
115 
116 # else
117 
118 #  if !PTHREAD_IN_USE_DETECTION_HARD
119 #   define pthread_in_use() 1
120 #  endif
121 
122 # endif
123 
124 /* ------------------------- gl_tls_key_t datatype ------------------------- */
125 
126 typedef union
127         {
128           void *singlethread_value;
129           pthread_key_t key;
130         }
131         gl_tls_key_t;
132 # define glthread_tls_key_init(KEY, DESTRUCTOR) \
133     (pthread_in_use ()                              \
134      ? pthread_key_create (&(KEY)->key, DESTRUCTOR) \
135      : ((KEY)->singlethread_value = NULL, 0))
136 # define gl_tls_get(NAME) \
137     (pthread_in_use ()                  \
138      ? pthread_getspecific ((NAME).key) \
139      : (NAME).singlethread_value)
140 # define glthread_tls_set(KEY, POINTER) \
141     (pthread_in_use ()                             \
142      ? pthread_setspecific ((KEY)->key, (POINTER)) \
143      : ((KEY)->singlethread_value = (POINTER), 0))
144 # define glthread_tls_key_destroy(KEY) \
145     (pthread_in_use () ? pthread_key_delete ((KEY)->key) : 0)
146 
147 #endif
148 
149 /* ========================================================================= */
150 
151 #if USE_WINDOWS_THREADS
152 
153 # define WIN32_LEAN_AND_MEAN  /* avoid including junk */
154 # include <windows.h>
155 
156 # include "windows-tls.h"
157 
158 /* ------------------------- gl_tls_key_t datatype ------------------------- */
159 
160 typedef glwthread_tls_key_t gl_tls_key_t;
161 # define glthread_tls_key_init(KEY, DESTRUCTOR) \
162     glwthread_tls_key_create (KEY, DESTRUCTOR)
163 # define gl_tls_get(NAME) \
164     TlsGetValue (NAME)
165 # define glthread_tls_set(KEY, POINTER) \
166     (!TlsSetValue (*(KEY), POINTER) ? EINVAL : 0)
167 # define glthread_tls_key_destroy(KEY) \
168     glwthread_tls_key_delete (*(KEY))
169 
170 #endif
171 
172 /* ========================================================================= */
173 
174 #if !(USE_ISOC_THREADS || USE_POSIX_THREADS || USE_ISOC_AND_POSIX_THREADS || USE_WINDOWS_THREADS)
175 
176 /* Provide dummy implementation if threads are not supported.  */
177 
178 /* ------------------------- gl_tls_key_t datatype ------------------------- */
179 
180 typedef struct
181         {
182           void *singlethread_value;
183         }
184         gl_tls_key_t;
185 # define glthread_tls_key_init(KEY, DESTRUCTOR) \
186     ((KEY)->singlethread_value = NULL, \
187      (void) (DESTRUCTOR),              \
188      0)
189 # define gl_tls_get(NAME) \
190     (NAME).singlethread_value
191 # define glthread_tls_set(KEY, POINTER) \
192     ((KEY)->singlethread_value = (POINTER), 0)
193 # define glthread_tls_key_destroy(KEY) \
194     0
195 
196 #endif
197 
198 /* ========================================================================= */
199 
200 /* Macros with built-in error handling.  */
201 
202 /* ------------------------- gl_tls_key_t datatype ------------------------- */
203 
204 #define gl_tls_key_init(NAME, DESTRUCTOR) \
205    do                                                 \
206      {                                                \
207        if (glthread_tls_key_init (&NAME, DESTRUCTOR)) \
208          abort ();                                    \
209      }                                                \
210    while (0)
211 #define gl_tls_set(NAME, POINTER) \
212    do                                         \
213      {                                        \
214        if (glthread_tls_set (&NAME, POINTER)) \
215          abort ();                            \
216      }                                        \
217    while (0)
218 #define gl_tls_key_destroy(NAME) \
219    do                                        \
220      {                                       \
221        if (glthread_tls_key_destroy (&NAME)) \
222          abort ();                           \
223      }                                       \
224    while (0)
225 
226 /* ========================================================================= */
227 
228 #endif /* _TLS_H */
229