1 /* Creating and controlling threads.
2 Copyright (C) 2005-2018 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, 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
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 Based on GCC's gthr-posix.h, gthr-posix95.h, gthr-solaris.h,
19 gthr-win32.h. */
20
21 /* This file contains primitives for creating and controlling threads.
22
23 Thread data type: gl_thread_t.
24
25 Creating a thread:
26 thread = gl_thread_create (func, arg);
27 Or with control of error handling:
28 err = glthread_create (&thread, func, arg);
29 extern int glthread_create (gl_thread_t *result,
30 void *(*func) (void *), void *arg);
31
32 Querying and changing the signal mask of a thread (not supported on all
33 platforms):
34 gl_thread_sigmask (how, newmask, oldmask);
35 Or with control of error handling:
36 err = glthread_sigmask (how, newmask, oldmask);
37 extern int glthread_sigmask (int how, const sigset_t *newmask, sigset_t *oldmask);
38
39 Waiting for termination of another thread:
40 gl_thread_join (thread, &return_value);
41 Or with control of error handling:
42 err = glthread_join (thread, &return_value);
43 extern int glthread_join (gl_thread_t thread, void **return_value_ptr);
44
45 Getting a reference to the current thread:
46 current = gl_thread_self ();
47 extern gl_thread_t gl_thread_self (void);
48
49 Getting a reference to the current thread as a pointer, for debugging:
50 ptr = gl_thread_self_pointer ();
51 extern void * gl_thread_self_pointer (void);
52
53 Terminating the current thread:
54 gl_thread_exit (return_value);
55 extern _Noreturn void gl_thread_exit (void *return_value);
56
57 Requesting custom code to be executed at fork() time (not supported on all
58 platforms):
59 gl_thread_atfork (prepare_func, parent_func, child_func);
60 Or with control of error handling:
61 err = glthread_atfork (prepare_func, parent_func, child_func);
62 extern int glthread_atfork (void (*prepare_func) (void),
63 void (*parent_func) (void),
64 void (*child_func) (void));
65 Note that even on platforms where this is supported, use of fork() and
66 threads together is problematic, see
67 <https://lists.gnu.org/r/bug-gnulib/2008-08/msg00062.html>
68 */
69
70
71 #ifndef _GLTHREAD_THREAD_H
72 #define _GLTHREAD_THREAD_H
73
74 #include <errno.h>
75 #include <stdlib.h>
76
77 #ifndef _GL_INLINE_HEADER_BEGIN
78 #error "Please include config.h first."
79 #endif
80 _GL_INLINE_HEADER_BEGIN
81 #ifndef _GLTHREAD_THREAD_INLINE
82 # define _GLTHREAD_THREAD_INLINE _GL_INLINE
83 #endif
84
85 /* ========================================================================= */
86
87 #if USE_POSIX_THREADS
88
89 /* Use the POSIX threads library. */
90
91 # include <pthread.h>
92
93 /* On IRIX, pthread_atfork is declared in <unistd.h>, not in <pthread.h>. */
94 # if defined __sgi
95 # include <unistd.h>
96 # endif
97
98 # if USE_POSIX_THREADS_WEAK
99 /* Compilers other than GCC need to see the declaration of pthread_sigmask
100 before the "#pragma weak pthread_sigmask" below. */
101 # include <signal.h>
102 # endif
103
104 # ifdef __cplusplus
105 extern "C" {
106 # endif
107
108 # if PTHREAD_IN_USE_DETECTION_HARD
109
110 /* The pthread_in_use() detection needs to be done at runtime. */
111 # define pthread_in_use() \
112 glthread_in_use ()
113 extern int glthread_in_use (void);
114
115 # endif
116
117 # if USE_POSIX_THREADS_WEAK
118
119 /* Use weak references to the POSIX threads library. */
120
121 /* Weak references avoid dragging in external libraries if the other parts
122 of the program don't use them. Here we use them, because we don't want
123 every program that uses libintl to depend on libpthread. This assumes
124 that libpthread would not be loaded after libintl; i.e. if libintl is
125 loaded first, by an executable that does not depend on libpthread, and
126 then a module is dynamically loaded that depends on libpthread, libintl
127 will not be multithread-safe. */
128
129 /* The way to test at runtime whether libpthread is present is to test
130 whether a function pointer's value, such as &pthread_mutex_init, is
131 non-NULL. However, some versions of GCC have a bug through which, in
132 PIC mode, &foo != NULL always evaluates to true if there is a direct
133 call to foo(...) in the same function. To avoid this, we test the
134 address of a function in libpthread that we don't use. */
135
136 # pragma weak pthread_create
137
138 # ifndef pthread_sigmask /* Do not declare rpl_pthread_sigmask weak. */
139 # pragma weak pthread_sigmask
140 # endif
141
142 # pragma weak pthread_join
143 # ifndef pthread_self
144 # pragma weak pthread_self
145 # endif
146 # pragma weak pthread_exit
147 # if HAVE_PTHREAD_ATFORK
148 # pragma weak pthread_atfork
149 # endif
150
151 # if !PTHREAD_IN_USE_DETECTION_HARD
152 # pragma weak pthread_mutexattr_gettype
153 # define pthread_in_use() (pthread_mutexattr_gettype != NULL)
154 # endif
155
156 # else
157
158 # if !PTHREAD_IN_USE_DETECTION_HARD
159 # define pthread_in_use() 1
160 # endif
161
162 # endif
163
164 /* -------------------------- gl_thread_t datatype -------------------------- */
165
166 /* This choice of gl_thread_t assumes that
167 pthread_equal (a, b) is equivalent to ((a) == (b)).
168 This is the case on all platforms in use in 2008. */
169 typedef pthread_t gl_thread_t;
170 # define glthread_create(THREADP, FUNC, ARG) \
171 (pthread_in_use () ? pthread_create (THREADP, NULL, FUNC, ARG) : ENOSYS)
172 # define glthread_sigmask(HOW, SET, OSET) \
173 (pthread_in_use () ? pthread_sigmask (HOW, SET, OSET) : 0)
174 # define glthread_join(THREAD, RETVALP) \
175 (pthread_in_use () ? pthread_join (THREAD, RETVALP) : 0)
176 # ifdef PTW32_VERSION
177 /* In pthreads-win32, pthread_t is a struct with a pointer field 'p' and
178 other fields. */
179 # define gl_thread_self() \
180 (pthread_in_use () ? pthread_self () : gl_null_thread)
181 # define gl_thread_self_pointer() \
182 (pthread_in_use () ? pthread_self ().p : NULL)
183 extern const gl_thread_t gl_null_thread;
184 # elif defined __MVS__
185 /* On IBM z/OS, pthread_t is a struct with an 8-byte '__' field.
186 The first three bytes of this field appear to uniquely identify a
187 pthread_t, though not necessarily representing a pointer. */
188 # define gl_thread_self() \
189 (pthread_in_use () ? pthread_self () : gl_null_thread)
190 # define gl_thread_self_pointer() \
191 (pthread_in_use () ? *((void **) pthread_self ().__) : NULL)
192 extern const gl_thread_t gl_null_thread;
193 # else
194 # define gl_thread_self() \
195 (pthread_in_use () ? pthread_self () : (pthread_t) NULL)
196 # define gl_thread_self_pointer() \
197 (pthread_in_use () ? (void *) pthread_self () : NULL)
198 # endif
199 # define gl_thread_exit(RETVAL) \
200 (pthread_in_use () ? pthread_exit (RETVAL) : 0)
201
202 # if HAVE_PTHREAD_ATFORK
203 # define glthread_atfork(PREPARE_FUNC, PARENT_FUNC, CHILD_FUNC) \
204 (pthread_in_use () ? pthread_atfork (PREPARE_FUNC, PARENT_FUNC, CHILD_FUNC) : 0)
205 # else
206 # define glthread_atfork(PREPARE_FUNC, PARENT_FUNC, CHILD_FUNC) 0
207 # endif
208
209 # ifdef __cplusplus
210 }
211 # endif
212
213 #endif
214
215 /* ========================================================================= */
216
217 #if USE_PTH_THREADS
218
219 /* Use the GNU Pth threads library. */
220
221 # include <pth.h>
222
223 # ifdef __cplusplus
224 extern "C" {
225 # endif
226
227 # if USE_PTH_THREADS_WEAK
228
229 /* Use weak references to the GNU Pth threads library. */
230
231 # pragma weak pth_init
232 # pragma weak pth_spawn
233 # pragma weak pth_sigmask
234 # pragma weak pth_join
235 # pragma weak pth_self
236 # pragma weak pth_exit
237
238 # pragma weak pth_cancel
239 # define pth_in_use() (pth_cancel != NULL)
240
241 # else
242
243 # define pth_in_use() 1
244
245 # endif
246 /* -------------------------- gl_thread_t datatype -------------------------- */
247
248 typedef pth_t gl_thread_t;
249 # define glthread_create(THREADP, FUNC, ARG) \
250 (pth_in_use () ? (pth_init (), ((*(THREADP) = pth_spawn (NULL, FUNC, ARG)) ? 0 : errno)) : 0)
251 # define glthread_sigmask(HOW, SET, OSET) \
252 (pth_in_use () ? (pth_init (), (pth_sigmask (HOW, SET, OSET) ? 0 : errno)) : 0)
253 # define glthread_join(THREAD, RETVALP) \
254 (pth_in_use () ? (pth_init (), (pth_join (THREAD, RETVALP) ? 0 : errno)) : 0)
255 # define gl_thread_self() \
256 (pth_in_use () ? (pth_init (), (void *) pth_self ()) : NULL)
257 # define gl_thread_self_pointer() \
258 gl_thread_self ()
259 # define gl_thread_exit(RETVAL) \
260 (pth_in_use () ? (pth_init (), pth_exit (RETVAL)) : 0)
261 # define glthread_atfork(PREPARE_FUNC, PARENT_FUNC, CHILD_FUNC) 0
262
263 # ifdef __cplusplus
264 }
265 # endif
266
267 #endif
268
269 /* ========================================================================= */
270
271 #if USE_SOLARIS_THREADS
272
273 /* Use the old Solaris threads library. */
274
275 # include <thread.h>
276 # include <synch.h>
277
278 # ifdef __cplusplus
279 extern "C" {
280 # endif
281
282 # if USE_SOLARIS_THREADS_WEAK
283
284 /* Use weak references to the old Solaris threads library. */
285
286 # pragma weak thr_create
287 # pragma weak thr_join
288 # pragma weak thr_self
289 # pragma weak thr_exit
290
291 # pragma weak thr_suspend
292 # define thread_in_use() (thr_suspend != NULL)
293
294 # else
295
296 # define thread_in_use() 1
297
298 # endif
299
300 /* -------------------------- gl_thread_t datatype -------------------------- */
301
302 typedef thread_t gl_thread_t;
303 # define glthread_create(THREADP, FUNC, ARG) \
304 (thread_in_use () ? thr_create (NULL, 0, FUNC, ARG, 0, THREADP) : 0)
305 # define glthread_sigmask(HOW, SET, OSET) \
306 (thread_in_use () ? sigprocmask (HOW, SET, OSET) : 0)
307 # define glthread_join(THREAD, RETVALP) \
308 (thread_in_use () ? thr_join (THREAD, NULL, RETVALP) : 0)
309 # define gl_thread_self() \
310 (thread_in_use () ? (void *) thr_self () : NULL)
311 # define gl_thread_self_pointer() \
312 gl_thread_self ()
313 # define gl_thread_exit(RETVAL) \
314 (thread_in_use () ? thr_exit (RETVAL) : 0)
315 # define glthread_atfork(PREPARE_FUNC, PARENT_FUNC, CHILD_FUNC) 0
316
317 # ifdef __cplusplus
318 }
319 # endif
320
321 #endif
322
323 /* ========================================================================= */
324
325 #if USE_WINDOWS_THREADS
326
327 # define WIN32_LEAN_AND_MEAN /* avoid including junk */
328 # include <windows.h>
329
330 # ifdef __cplusplus
331 extern "C" {
332 # endif
333
334 /* -------------------------- gl_thread_t datatype -------------------------- */
335
336 /* The gl_thread_t is a pointer to a structure in memory.
337 Why not the thread handle? If it were the thread handle, it would be hard
338 to implement gl_thread_self() (since GetCurrentThread () returns a pseudo-
339 handle, DuplicateHandle (GetCurrentThread ()) returns a handle that must be
340 closed afterwards, and there is no function for quickly retrieving a thread
341 handle from its id).
342 Why not the thread id? I tried it. It did not work: Sometimes ids appeared
343 that did not belong to running threads, and glthread_join failed with ESRCH.
344 */
345 typedef struct gl_thread_struct *gl_thread_t;
346 # define glthread_create(THREADP, FUNC, ARG) \
347 glthread_create_func (THREADP, FUNC, ARG)
348 # define glthread_sigmask(HOW, SET, OSET) \
349 /* unsupported */ 0
350 # define glthread_join(THREAD, RETVALP) \
351 glthread_join_func (THREAD, RETVALP)
352 # define gl_thread_self() \
353 gl_thread_self_func ()
354 # define gl_thread_self_pointer() \
355 gl_thread_self ()
356 # define gl_thread_exit(RETVAL) \
357 gl_thread_exit_func (RETVAL)
358 # define glthread_atfork(PREPARE_FUNC, PARENT_FUNC, CHILD_FUNC) 0
359 extern int glthread_create_func (gl_thread_t *threadp, void * (*func) (void *), void *arg);
360 extern int glthread_join_func (gl_thread_t thread, void **retvalp);
361 extern gl_thread_t gl_thread_self_func (void);
362 extern int gl_thread_exit_func (void *retval);
363
364 # ifdef __cplusplus
365 }
366 # endif
367
368 #endif
369
370 /* ========================================================================= */
371
372 #if !(USE_POSIX_THREADS || USE_PTH_THREADS || USE_SOLARIS_THREADS || USE_WINDOWS_THREADS)
373
374 /* Provide dummy implementation if threads are not supported. */
375
376 typedef int gl_thread_t;
377 # define glthread_create(THREADP, FUNC, ARG) ENOSYS
378 # define glthread_sigmask(HOW, SET, OSET) 0
379 # define glthread_join(THREAD, RETVALP) 0
380 # define gl_thread_self() 0
381 # define gl_thread_self_pointer() \
382 ((void *) gl_thread_self ())
383 # define gl_thread_exit(RETVAL) 0
384 # define glthread_atfork(PREPARE_FUNC, PARENT_FUNC, CHILD_FUNC) 0
385
386 #endif
387
388 /* ========================================================================= */
389
390 /* Macros with built-in error handling. */
391
392 #ifdef __cplusplus
393 extern "C" {
394 #endif
395
396 _GLTHREAD_THREAD_INLINE gl_thread_t
gl_thread_create(void * (* func)(void * arg),void * arg)397 gl_thread_create (void *(*func) (void *arg), void *arg)
398 {
399 gl_thread_t thread;
400 int ret;
401
402 ret = glthread_create (&thread, func, arg);
403 if (ret != 0)
404 abort ();
405 return thread;
406 }
407 #define gl_thread_sigmask(HOW, SET, OSET) \
408 do \
409 { \
410 if (glthread_sigmask (HOW, SET, OSET)) \
411 abort (); \
412 } \
413 while (0)
414 #define gl_thread_join(THREAD, RETVAL) \
415 do \
416 { \
417 if (glthread_join (THREAD, RETVAL)) \
418 abort (); \
419 } \
420 while (0)
421 #define gl_thread_atfork(PREPARE, PARENT, CHILD) \
422 do \
423 { \
424 if (glthread_atfork (PREPARE, PARENT, CHILD)) \
425 abort (); \
426 } \
427 while (0)
428
429 #ifdef __cplusplus
430 }
431 #endif
432
433 _GL_INLINE_HEADER_END
434
435 #endif /* _GLTHREAD_THREAD_H */
436