1 /* Creating and controlling threads.
2 Copyright (C) 2005-2023 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 Based on GCC's gthr-posix.h, gthr-posix95.h, gthr-win32.h. */
19
20 /* This file contains primitives for creating and controlling threads.
21
22 Thread data type: gl_thread_t.
23
24 Creating a thread:
25 thread = gl_thread_create (func, arg);
26 Or with control of error handling:
27 err = glthread_create (&thread, func, arg);
28 extern int glthread_create (gl_thread_t *result,
29 void *(*func) (void *), void *arg);
30
31 Querying and changing the signal mask of a thread (not supported on all
32 platforms):
33 gl_thread_sigmask (how, newmask, oldmask);
34 Or with control of error handling:
35 err = glthread_sigmask (how, newmask, oldmask);
36 extern int glthread_sigmask (int how, const sigset_t *newmask, sigset_t *oldmask);
37
38 Waiting for termination of another thread:
39 gl_thread_join (thread, &return_value);
40 Or with control of error handling:
41 err = glthread_join (thread, &return_value);
42 extern int glthread_join (gl_thread_t thread, void **return_value_ptr);
43
44 Getting a reference to the current thread:
45 current = gl_thread_self ();
46 extern gl_thread_t gl_thread_self (void);
47
48 Getting a reference to the current thread as a pointer, for debugging:
49 ptr = gl_thread_self_pointer ();
50 extern void * gl_thread_self_pointer (void);
51
52 Terminating the current thread:
53 gl_thread_exit (return_value);
54 extern _Noreturn void gl_thread_exit (void *return_value);
55
56 Requesting custom code to be executed at fork() time (not supported on all
57 platforms):
58 gl_thread_atfork (prepare_func, parent_func, child_func);
59 Or with control of error handling:
60 err = glthread_atfork (prepare_func, parent_func, child_func);
61 extern int glthread_atfork (void (*prepare_func) (void),
62 void (*parent_func) (void),
63 void (*child_func) (void));
64 Note that even on platforms where this is supported, use of fork() and
65 threads together is problematic, see
66 <https://lists.gnu.org/r/bug-gnulib/2008-08/msg00062.html>
67 */
68
69
70 #ifndef _GLTHREAD_THREAD_H
71 #define _GLTHREAD_THREAD_H
72
73 /* This file uses _Noreturn, HAVE_THREADS_H, HAVE_PTHREAD_ATFORK. */
74 #if !_GL_CONFIG_H_INCLUDED
75 #error "Please include config.h first."
76 #endif
77
78 #include <errno.h>
79 #include <stdlib.h>
80
81 #if !defined c11_threads_in_use
82 # if HAVE_THREADS_H && USE_POSIX_THREADS_FROM_LIBC
83 # define c11_threads_in_use() 1
84 # elif HAVE_THREADS_H && USE_POSIX_THREADS_WEAK
85 # include <threads.h>
86 # pragma weak thrd_exit
87 # define c11_threads_in_use() (thrd_exit != NULL)
88 # else
89 # define c11_threads_in_use() 0
90 # endif
91 #endif
92
93 /* ========================================================================= */
94
95 #if USE_ISOC_THREADS
96
97 /* Use the ISO C threads library. */
98
99 # include <threads.h>
100
101 # ifdef __cplusplus
102 extern "C" {
103 # endif
104
105 /* -------------------------- gl_thread_t datatype -------------------------- */
106
107 typedef struct thrd_with_exitvalue *gl_thread_t;
108 extern int glthread_create (gl_thread_t *threadp,
109 void *(*func) (void *), void *arg);
110 # define glthread_sigmask(HOW, SET, OSET) \
111 pthread_sigmask (HOW, SET, OSET)
112 extern int glthread_join (gl_thread_t thread, void **return_value_ptr);
113 extern gl_thread_t gl_thread_self (void);
114 # define gl_thread_self_pointer() \
115 (void *) gl_thread_self ()
116 extern _Noreturn void gl_thread_exit (void *return_value);
117 # define glthread_atfork(PREPARE_FUNC, PARENT_FUNC, CHILD_FUNC) 0
118
119 # ifdef __cplusplus
120 }
121 # endif
122
123 #endif
124
125 /* ========================================================================= */
126
127 #if USE_POSIX_THREADS || USE_ISOC_AND_POSIX_THREADS
128
129 /* Use the POSIX threads library. */
130
131 # include <pthread.h>
132
133 /* Get intptr_t. */
134 # include <stdint.h>
135
136 /* On IRIX, pthread_atfork is declared in <unistd.h>, not in <pthread.h>. */
137 # if defined __sgi
138 # include <unistd.h>
139 # endif
140
141 # if USE_POSIX_THREADS_WEAK
142 /* Compilers other than GCC need to see the declaration of pthread_sigmask
143 before the "#pragma weak pthread_sigmask" below. */
144 # include <signal.h>
145 # endif
146
147 # ifdef __cplusplus
148 extern "C" {
149 # endif
150
151 # if PTHREAD_IN_USE_DETECTION_HARD
152
153 /* The pthread_in_use() detection needs to be done at runtime. */
154 # define pthread_in_use() \
155 glthread_in_use ()
156 extern int glthread_in_use (void);
157
158 # endif
159
160 # if USE_POSIX_THREADS_WEAK
161
162 /* Use weak references to the POSIX threads library. */
163
164 /* Weak references avoid dragging in external libraries if the other parts
165 of the program don't use them. Here we use them, because we don't want
166 every program that uses libintl to depend on libpthread. This assumes
167 that libpthread would not be loaded after libintl; i.e. if libintl is
168 loaded first, by an executable that does not depend on libpthread, and
169 then a module is dynamically loaded that depends on libpthread, libintl
170 will not be multithread-safe. */
171
172 /* The way to test at runtime whether libpthread is present is to test
173 whether a function pointer's value, such as &pthread_mutex_init, is
174 non-NULL. However, some versions of GCC have a bug through which, in
175 PIC mode, &foo != NULL always evaluates to true if there is a direct
176 call to foo(...) in the same function. To avoid this, we test the
177 address of a function in libpthread that we don't use. */
178
179 # ifndef pthread_sigmask /* Do not declare rpl_pthread_sigmask weak. */
180 # pragma weak pthread_sigmask
181 # endif
182
183 # pragma weak pthread_join
184 # ifndef pthread_self
185 # pragma weak pthread_self
186 # endif
187 # pragma weak pthread_exit
188 # if HAVE_PTHREAD_ATFORK
189 # pragma weak pthread_atfork
190 # endif
191
192 # if !PTHREAD_IN_USE_DETECTION_HARD
193 # pragma weak pthread_mutexattr_gettype
194 # define pthread_in_use() \
195 (pthread_mutexattr_gettype != NULL || c11_threads_in_use ())
196 # endif
197
198 # else
199
200 # if !PTHREAD_IN_USE_DETECTION_HARD
201 # define pthread_in_use() 1
202 # endif
203
204 # endif
205
206 /* -------------------------- gl_thread_t datatype -------------------------- */
207
208 /* This choice of gl_thread_t assumes that
209 pthread_equal (a, b) is equivalent to ((a) == (b)).
210 This is the case on all platforms in use in 2008. */
211 typedef pthread_t gl_thread_t;
212 # define glthread_create(THREADP, FUNC, ARG) \
213 (pthread_in_use () ? pthread_create (THREADP, NULL, FUNC, ARG) : ENOSYS)
214 # define glthread_sigmask(HOW, SET, OSET) \
215 (pthread_in_use () ? pthread_sigmask (HOW, SET, OSET) : 0)
216 # define glthread_join(THREAD, RETVALP) \
217 (pthread_in_use () ? pthread_join (THREAD, RETVALP) : 0)
218 # ifdef PTW32_VERSION
219 /* In pthreads-win32, pthread_t is a struct with a pointer field 'p' and
220 other fields. */
221 # define gl_thread_self() \
222 (pthread_in_use () ? pthread_self () : gl_null_thread)
223 # define gl_thread_self_pointer() \
224 (pthread_in_use () ? pthread_self ().p : NULL)
225 extern const gl_thread_t gl_null_thread;
226 # elif defined __MVS__
227 /* On IBM z/OS, pthread_t is a struct with an 8-byte '__' field.
228 The first three bytes of this field appear to uniquely identify a
229 pthread_t, though not necessarily representing a pointer. */
230 # define gl_thread_self() \
231 (pthread_in_use () ? pthread_self () : gl_null_thread)
232 # define gl_thread_self_pointer() \
233 (pthread_in_use () ? *((void **) pthread_self ().__) : NULL)
234 extern const gl_thread_t gl_null_thread;
235 # else
236 # define gl_thread_self() \
237 (pthread_in_use () ? pthread_self () : (pthread_t) 0)
238 # define gl_thread_self_pointer() \
239 (pthread_in_use () ? (void *) (intptr_t) (pthread_t) pthread_self () : NULL)
240 # endif
241 # define gl_thread_exit(RETVAL) \
242 (void) (pthread_in_use () ? (pthread_exit (RETVAL), 0) : 0)
243
244 # if HAVE_PTHREAD_ATFORK
245 # define glthread_atfork(PREPARE_FUNC, PARENT_FUNC, CHILD_FUNC) \
246 (pthread_in_use () ? pthread_atfork (PREPARE_FUNC, PARENT_FUNC, CHILD_FUNC) : 0)
247 # else
248 # define glthread_atfork(PREPARE_FUNC, PARENT_FUNC, CHILD_FUNC) 0
249 # endif
250
251 # ifdef __cplusplus
252 }
253 # endif
254
255 #endif
256
257 /* ========================================================================= */
258
259 #if USE_WINDOWS_THREADS
260
261 # define WIN32_LEAN_AND_MEAN /* avoid including junk */
262 # include <windows.h>
263
264 # include "windows-thread.h"
265
266 # ifdef __cplusplus
267 extern "C" {
268 # endif
269
270 /* -------------------------- gl_thread_t datatype -------------------------- */
271
272 typedef glwthread_thread_t gl_thread_t;
273 # define glthread_create(THREADP, FUNC, ARG) \
274 glwthread_thread_create (THREADP, 0, FUNC, ARG)
275 # define glthread_sigmask(HOW, SET, OSET) \
276 /* unsupported */ 0
277 # define glthread_join(THREAD, RETVALP) \
278 glwthread_thread_join (THREAD, RETVALP)
279 # define gl_thread_self() \
280 glwthread_thread_self ()
281 # define gl_thread_self_pointer() \
282 gl_thread_self ()
283 # define gl_thread_exit(RETVAL) \
284 glwthread_thread_exit (RETVAL)
285 # define glthread_atfork(PREPARE_FUNC, PARENT_FUNC, CHILD_FUNC) 0
286
287 # ifdef __cplusplus
288 }
289 # endif
290
291 #endif
292
293 /* ========================================================================= */
294
295 #if !(USE_ISOC_THREADS || USE_POSIX_THREADS || USE_ISOC_AND_POSIX_THREADS || USE_WINDOWS_THREADS)
296
297 /* Provide dummy implementation if threads are not supported. */
298
299 typedef int gl_thread_t;
300 # define glthread_create(THREADP, FUNC, ARG) ENOSYS
301 # define glthread_sigmask(HOW, SET, OSET) 0
302 # define glthread_join(THREAD, RETVALP) 0
303 # define gl_thread_self() 0
304 # define gl_thread_self_pointer() \
305 ((void *) gl_thread_self ())
306 # define gl_thread_exit(RETVAL) (void)0
307 # define glthread_atfork(PREPARE_FUNC, PARENT_FUNC, CHILD_FUNC) 0
308
309 #endif
310
311 /* ========================================================================= */
312
313 /* Macros with built-in error handling. */
314
315 #ifdef __cplusplus
316 extern "C" {
317 #endif
318
319 extern gl_thread_t gl_thread_create (void *(*func) (void *arg), void *arg);
320 #define gl_thread_sigmask(HOW, SET, OSET) \
321 do \
322 { \
323 if (glthread_sigmask (HOW, SET, OSET)) \
324 abort (); \
325 } \
326 while (0)
327 #define gl_thread_join(THREAD, RETVAL) \
328 do \
329 { \
330 if (glthread_join (THREAD, RETVAL)) \
331 abort (); \
332 } \
333 while (0)
334 #define gl_thread_atfork(PREPARE, PARENT, CHILD) \
335 do \
336 { \
337 if (glthread_atfork (PREPARE, PARENT, CHILD)) \
338 abort (); \
339 } \
340 while (0)
341
342 #ifdef __cplusplus
343 }
344 #endif
345
346 #endif /* _GLTHREAD_THREAD_H */