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