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 /* On IRIX, pthread_atfork is declared in <unistd.h>, not in <pthread.h>. */
134 # if defined __sgi
135 # include <unistd.h>
136 # endif
137
138 # if USE_POSIX_THREADS_WEAK
139 /* Compilers other than GCC need to see the declaration of pthread_sigmask
140 before the "#pragma weak pthread_sigmask" below. */
141 # include <signal.h>
142 # endif
143
144 # ifdef __cplusplus
145 extern "C" {
146 # endif
147
148 # if PTHREAD_IN_USE_DETECTION_HARD
149
150 /* The pthread_in_use() detection needs to be done at runtime. */
151 # define pthread_in_use() \
152 glthread_in_use ()
153 extern int glthread_in_use (void);
154
155 # endif
156
157 # if USE_POSIX_THREADS_WEAK
158
159 /* Use weak references to the POSIX threads library. */
160
161 /* Weak references avoid dragging in external libraries if the other parts
162 of the program don't use them. Here we use them, because we don't want
163 every program that uses libintl to depend on libpthread. This assumes
164 that libpthread would not be loaded after libintl; i.e. if libintl is
165 loaded first, by an executable that does not depend on libpthread, and
166 then a module is dynamically loaded that depends on libpthread, libintl
167 will not be multithread-safe. */
168
169 /* The way to test at runtime whether libpthread is present is to test
170 whether a function pointer's value, such as &pthread_mutex_init, is
171 non-NULL. However, some versions of GCC have a bug through which, in
172 PIC mode, &foo != NULL always evaluates to true if there is a direct
173 call to foo(...) in the same function. To avoid this, we test the
174 address of a function in libpthread that we don't use. */
175
176 # ifndef pthread_sigmask /* Do not declare rpl_pthread_sigmask weak. */
177 # pragma weak pthread_sigmask
178 # endif
179
180 # pragma weak pthread_join
181 # ifndef pthread_self
182 # pragma weak pthread_self
183 # endif
184 # pragma weak pthread_exit
185 # if HAVE_PTHREAD_ATFORK
186 # pragma weak pthread_atfork
187 # endif
188
189 # if !PTHREAD_IN_USE_DETECTION_HARD
190 # pragma weak pthread_mutexattr_gettype
191 # define pthread_in_use() \
192 (pthread_mutexattr_gettype != NULL || c11_threads_in_use ())
193 # endif
194
195 # else
196
197 # if !PTHREAD_IN_USE_DETECTION_HARD
198 # define pthread_in_use() 1
199 # endif
200
201 # endif
202
203 /* -------------------------- gl_thread_t datatype -------------------------- */
204
205 /* This choice of gl_thread_t assumes that
206 pthread_equal (a, b) is equivalent to ((a) == (b)).
207 This is the case on all platforms in use in 2008. */
208 typedef pthread_t gl_thread_t;
209 # define glthread_create(THREADP, FUNC, ARG) \
210 (pthread_in_use () ? pthread_create (THREADP, NULL, FUNC, ARG) : ENOSYS)
211 # define glthread_sigmask(HOW, SET, OSET) \
212 (pthread_in_use () ? pthread_sigmask (HOW, SET, OSET) : 0)
213 # define glthread_join(THREAD, RETVALP) \
214 (pthread_in_use () ? pthread_join (THREAD, RETVALP) : 0)
215 # ifdef PTW32_VERSION
216 /* In pthreads-win32, pthread_t is a struct with a pointer field 'p' and
217 other fields. */
218 # define gl_thread_self() \
219 (pthread_in_use () ? pthread_self () : gl_null_thread)
220 # define gl_thread_self_pointer() \
221 (pthread_in_use () ? pthread_self ().p : NULL)
222 extern const gl_thread_t gl_null_thread;
223 # elif defined __MVS__
224 /* On IBM z/OS, pthread_t is a struct with an 8-byte '__' field.
225 The first three bytes of this field appear to uniquely identify a
226 pthread_t, though not necessarily representing a pointer. */
227 # define gl_thread_self() \
228 (pthread_in_use () ? pthread_self () : gl_null_thread)
229 # define gl_thread_self_pointer() \
230 (pthread_in_use () ? *((void **) pthread_self ().__) : NULL)
231 extern const gl_thread_t gl_null_thread;
232 # else
233 # define gl_thread_self() \
234 (pthread_in_use () ? pthread_self () : (pthread_t) 0)
235 # define gl_thread_self_pointer() \
236 (pthread_in_use () ? (void *) (pthread_t) pthread_self () : NULL)
237 # endif
238 # define gl_thread_exit(RETVAL) \
239 (void) (pthread_in_use () ? (pthread_exit (RETVAL), 0) : 0)
240
241 # if HAVE_PTHREAD_ATFORK
242 # define glthread_atfork(PREPARE_FUNC, PARENT_FUNC, CHILD_FUNC) \
243 (pthread_in_use () ? pthread_atfork (PREPARE_FUNC, PARENT_FUNC, CHILD_FUNC) : 0)
244 # else
245 # define glthread_atfork(PREPARE_FUNC, PARENT_FUNC, CHILD_FUNC) 0
246 # endif
247
248 # ifdef __cplusplus
249 }
250 # endif
251
252 #endif
253
254 /* ========================================================================= */
255
256 #if USE_WINDOWS_THREADS
257
258 # define WIN32_LEAN_AND_MEAN /* avoid including junk */
259 # include <windows.h>
260
261 # include "windows-thread.h"
262
263 # ifdef __cplusplus
264 extern "C" {
265 # endif
266
267 /* -------------------------- gl_thread_t datatype -------------------------- */
268
269 typedef glwthread_thread_t gl_thread_t;
270 # define glthread_create(THREADP, FUNC, ARG) \
271 glwthread_thread_create (THREADP, 0, FUNC, ARG)
272 # define glthread_sigmask(HOW, SET, OSET) \
273 /* unsupported */ 0
274 # define glthread_join(THREAD, RETVALP) \
275 glwthread_thread_join (THREAD, RETVALP)
276 # define gl_thread_self() \
277 glwthread_thread_self ()
278 # define gl_thread_self_pointer() \
279 gl_thread_self ()
280 # define gl_thread_exit(RETVAL) \
281 glwthread_thread_exit (RETVAL)
282 # define glthread_atfork(PREPARE_FUNC, PARENT_FUNC, CHILD_FUNC) 0
283
284 # ifdef __cplusplus
285 }
286 # endif
287
288 #endif
289
290 /* ========================================================================= */
291
292 #if !(USE_ISOC_THREADS || USE_POSIX_THREADS || USE_ISOC_AND_POSIX_THREADS || USE_WINDOWS_THREADS)
293
294 /* Provide dummy implementation if threads are not supported. */
295
296 typedef int gl_thread_t;
297 # define glthread_create(THREADP, FUNC, ARG) ENOSYS
298 # define glthread_sigmask(HOW, SET, OSET) 0
299 # define glthread_join(THREAD, RETVALP) 0
300 # define gl_thread_self() 0
301 # define gl_thread_self_pointer() \
302 ((void *) gl_thread_self ())
303 # define gl_thread_exit(RETVAL) (void)0
304 # define glthread_atfork(PREPARE_FUNC, PARENT_FUNC, CHILD_FUNC) 0
305
306 #endif
307
308 /* ========================================================================= */
309
310 /* Macros with built-in error handling. */
311
312 #ifdef __cplusplus
313 extern "C" {
314 #endif
315
316 extern gl_thread_t gl_thread_create (void *(*func) (void *arg), void *arg);
317 #define gl_thread_sigmask(HOW, SET, OSET) \
318 do \
319 { \
320 if (glthread_sigmask (HOW, SET, OSET)) \
321 abort (); \
322 } \
323 while (0)
324 #define gl_thread_join(THREAD, RETVAL) \
325 do \
326 { \
327 if (glthread_join (THREAD, RETVAL)) \
328 abort (); \
329 } \
330 while (0)
331 #define gl_thread_atfork(PREPARE, PARENT, CHILD) \
332 do \
333 { \
334 if (glthread_atfork (PREPARE, PARENT, CHILD)) \
335 abort (); \
336 } \
337 while (0)
338
339 #ifdef __cplusplus
340 }
341 #endif
342
343 #endif /* _GLTHREAD_THREAD_H */