166a50c13827e7ed058cc06b0481ab75ace9d678
[gnulib.git] / lib / glthread / thread.h
1 /* Creating and controlling threads.
2    Copyright (C) 2005-2013 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 2, 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 <http://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      <http://lists.gnu.org/archive/html/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 _GL_INLINE_HEADER_BEGIN
78 #ifndef _GLTHREAD_THREAD_INLINE
79 # define _GLTHREAD_THREAD_INLINE _GL_INLINE
80 #endif
81
82 /* ========================================================================= */
83
84 #if USE_POSIX_THREADS
85
86 /* Use the POSIX threads library.  */
87
88 # include <pthread.h>
89
90 # ifdef __cplusplus
91 extern "C" {
92 # endif
93
94 # if PTHREAD_IN_USE_DETECTION_HARD
95
96 /* The pthread_in_use() detection needs to be done at runtime.  */
97 #  define pthread_in_use() \
98      glthread_in_use ()
99 extern int glthread_in_use (void);
100
101 # endif
102
103 # if USE_POSIX_THREADS_WEAK
104
105 /* Use weak references to the POSIX threads library.  */
106
107 /* Weak references avoid dragging in external libraries if the other parts
108    of the program don't use them.  Here we use them, because we don't want
109    every program that uses libintl to depend on libpthread.  This assumes
110    that libpthread would not be loaded after libintl; i.e. if libintl is
111    loaded first, by an executable that does not depend on libpthread, and
112    then a module is dynamically loaded that depends on libpthread, libintl
113    will not be multithread-safe.  */
114
115 /* The way to test at runtime whether libpthread is present is to test
116    whether a function pointer's value, such as &pthread_mutex_init, is
117    non-NULL.  However, some versions of GCC have a bug through which, in
118    PIC mode, &foo != NULL always evaluates to true if there is a direct
119    call to foo(...) in the same function.  To avoid this, we test the
120    address of a function in libpthread that we don't use.  */
121
122 #  pragma weak pthread_create
123 #  pragma weak pthread_sigmask
124 #  pragma weak pthread_join
125 #  ifndef pthread_self
126 #   pragma weak pthread_self
127 #  endif
128 #  pragma weak pthread_exit
129 #  if HAVE_PTHREAD_ATFORK
130 #   pragma weak pthread_atfork
131 #  endif
132
133 #  if !PTHREAD_IN_USE_DETECTION_HARD
134 #   pragma weak pthread_cancel
135 #   define pthread_in_use() (pthread_cancel != NULL)
136 #  endif
137
138 # else
139
140 #  if !PTHREAD_IN_USE_DETECTION_HARD
141 #   define pthread_in_use() 1
142 #  endif
143
144 # endif
145
146 /* -------------------------- gl_thread_t datatype -------------------------- */
147
148 /* This choice of gl_thread_t assumes that
149      pthread_equal (a, b)  is equivalent to  ((a) == (b)).
150    This is the case on all platforms in use in 2008.  */
151 typedef pthread_t gl_thread_t;
152 # define glthread_create(THREADP, FUNC, ARG) \
153     (pthread_in_use () ? pthread_create (THREADP, NULL, FUNC, ARG) : ENOSYS)
154 # define glthread_sigmask(HOW, SET, OSET) \
155     (pthread_in_use () ? pthread_sigmask (HOW, SET, OSET) : 0)
156 # define glthread_join(THREAD, RETVALP) \
157     (pthread_in_use () ? pthread_join (THREAD, RETVALP) : 0)
158 # ifdef PTW32_VERSION
159    /* In pthreads-win32, pthread_t is a struct with a pointer field 'p' and
160       other fields.  */
161 #  define gl_thread_self() \
162      (pthread_in_use () ? pthread_self () : gl_null_thread)
163 #  define gl_thread_self_pointer() \
164      (pthread_in_use () ? pthread_self ().p : NULL)
165 extern const gl_thread_t gl_null_thread;
166 # else
167 #  define gl_thread_self() \
168      (pthread_in_use () ? pthread_self () : (pthread_t) NULL)
169 #  define gl_thread_self_pointer() \
170      (pthread_in_use () ? (void *) pthread_self () : NULL)
171 # endif
172 # define gl_thread_exit(RETVAL) \
173     (pthread_in_use () ? pthread_exit (RETVAL) : 0)
174
175 # if HAVE_PTHREAD_ATFORK
176 #  define glthread_atfork(PREPARE_FUNC, PARENT_FUNC, CHILD_FUNC) \
177      (pthread_in_use () ? pthread_atfork (PREPARE_FUNC, PARENT_FUNC, CHILD_FUNC) : 0)
178 # else
179 #  define glthread_atfork(PREPARE_FUNC, PARENT_FUNC, CHILD_FUNC) 0
180 # endif
181
182 # ifdef __cplusplus
183 }
184 # endif
185
186 #endif
187
188 /* ========================================================================= */
189
190 #if USE_PTH_THREADS
191
192 /* Use the GNU Pth threads library.  */
193
194 # include <pth.h>
195
196 # ifdef __cplusplus
197 extern "C" {
198 # endif
199
200 # if USE_PTH_THREADS_WEAK
201
202 /* Use weak references to the GNU Pth threads library.  */
203
204 #  pragma weak pth_spawn
205 #  pragma weak pth_sigmask
206 #  pragma weak pth_join
207 #  pragma weak pth_self
208 #  pragma weak pth_exit
209
210 #  pragma weak pth_cancel
211 #  define pth_in_use() (pth_cancel != NULL)
212
213 # else
214
215 #  define pth_in_use() 1
216
217 # endif
218 /* -------------------------- gl_thread_t datatype -------------------------- */
219
220 typedef pth_t gl_thread_t;
221 # define glthread_create(THREADP, FUNC, ARG) \
222     (pth_in_use () ? ((*(THREADP) = pth_spawn (NULL, FUNC, ARG)) ? 0 : errno) : 0)
223 # define glthread_sigmask(HOW, SET, OSET) \
224     (pth_in_use () && !pth_sigmask (HOW, SET, OSET) ? errno : 0)
225 # define glthread_join(THREAD, RETVALP) \
226     (pth_in_use () && !pth_join (THREAD, RETVALP) ? errno : 0)
227 # define gl_thread_self() \
228     (pth_in_use () ? (void *) pth_self () : NULL)
229 # define gl_thread_self_pointer() \
230     gl_thread_self ()
231 # define gl_thread_exit(RETVAL) \
232     (pth_in_use () ? pth_exit (RETVAL) : 0)
233 # define glthread_atfork(PREPARE_FUNC, PARENT_FUNC, CHILD_FUNC) 0
234
235 # ifdef __cplusplus
236 }
237 # endif
238
239 #endif
240
241 /* ========================================================================= */
242
243 #if USE_SOLARIS_THREADS
244
245 /* Use the old Solaris threads library.  */
246
247 # include <thread.h>
248 # include <synch.h>
249
250 # ifdef __cplusplus
251 extern "C" {
252 # endif
253
254 # if USE_SOLARIS_THREADS_WEAK
255
256 /* Use weak references to the old Solaris threads library.  */
257
258 #  pragma weak thr_create
259 #  pragma weak thr_join
260 #  pragma weak thr_self
261 #  pragma weak thr_exit
262
263 #  pragma weak thr_suspend
264 #  define thread_in_use() (thr_suspend != NULL)
265
266 # else
267
268 #  define thread_in_use() 1
269
270 # endif
271
272 /* -------------------------- gl_thread_t datatype -------------------------- */
273
274 typedef thread_t gl_thread_t;
275 # define glthread_create(THREADP, FUNC, ARG) \
276     (thread_in_use () ? thr_create (NULL, 0, FUNC, ARG, 0, THREADP) : 0)
277 # define glthread_sigmask(HOW, SET, OSET) \
278     (thread_in_use () ? sigprocmask (HOW, SET, OSET) : 0)
279 # define glthread_join(THREAD, RETVALP) \
280     (thread_in_use () ? thr_join (THREAD, NULL, RETVALP) : 0)
281 # define gl_thread_self() \
282     (thread_in_use () ? (void *) thr_self () : NULL)
283 # define gl_thread_self_pointer() \
284     gl_thread_self ()
285 # define gl_thread_exit(RETVAL) \
286     (thread_in_use () ? thr_exit (RETVAL) : 0)
287 # define glthread_atfork(PREPARE_FUNC, PARENT_FUNC, CHILD_FUNC) 0
288
289 # ifdef __cplusplus
290 }
291 # endif
292
293 #endif
294
295 /* ========================================================================= */
296
297 #if USE_WINDOWS_THREADS
298
299 # define WIN32_LEAN_AND_MEAN  /* avoid including junk */
300 # include <windows.h>
301
302 # ifdef __cplusplus
303 extern "C" {
304 # endif
305
306 /* -------------------------- gl_thread_t datatype -------------------------- */
307
308 /* The gl_thread_t is a pointer to a structure in memory.
309    Why not the thread handle?  If it were the thread handle, it would be hard
310    to implement gl_thread_self() (since GetCurrentThread () returns a pseudo-
311    handle, DuplicateHandle (GetCurrentThread ()) returns a handle that must be
312    closed afterwards, and there is no function for quickly retrieving a thread
313    handle from its id).
314    Why not the thread id?  I tried it.  It did not work: Sometimes ids appeared
315    that did not belong to running threads, and glthread_join failed with ESRCH.
316  */
317 typedef struct gl_thread_struct *gl_thread_t;
318 # define glthread_create(THREADP, FUNC, ARG) \
319     glthread_create_func (THREADP, FUNC, ARG)
320 # define glthread_sigmask(HOW, SET, OSET) \
321     /* unsupported */ 0
322 # define glthread_join(THREAD, RETVALP) \
323     glthread_join_func (THREAD, RETVALP)
324 # define gl_thread_self() \
325     gl_thread_self_func ()
326 # define gl_thread_self_pointer() \
327     gl_thread_self ()
328 # define gl_thread_exit(RETVAL) \
329     gl_thread_exit_func (RETVAL)
330 # define glthread_atfork(PREPARE_FUNC, PARENT_FUNC, CHILD_FUNC) 0
331 extern int glthread_create_func (gl_thread_t *threadp, void * (*func) (void *), void *arg);
332 extern int glthread_join_func (gl_thread_t thread, void **retvalp);
333 extern gl_thread_t gl_thread_self_func (void);
334 extern int gl_thread_exit_func (void *retval);
335
336 # ifdef __cplusplus
337 }
338 # endif
339
340 #endif
341
342 /* ========================================================================= */
343
344 #if !(USE_POSIX_THREADS || USE_PTH_THREADS || USE_SOLARIS_THREADS || USE_WINDOWS_THREADS)
345
346 /* Provide dummy implementation if threads are not supported.  */
347
348 typedef int gl_thread_t;
349 # define glthread_create(THREADP, FUNC, ARG) ENOSYS
350 # define glthread_sigmask(HOW, SET, OSET) 0
351 # define glthread_join(THREAD, RETVALP) 0
352 # define gl_thread_self() 0
353 # define gl_thread_self_pointer() \
354     ((void *) gl_thread_self ())
355 # define gl_thread_exit(RETVAL) 0
356 # define glthread_atfork(PREPARE_FUNC, PARENT_FUNC, CHILD_FUNC) 0
357
358 #endif
359
360 /* ========================================================================= */
361
362 /* Macros with built-in error handling.  */
363
364 #ifdef __cplusplus
365 extern "C" {
366 #endif
367
368 _GLTHREAD_THREAD_INLINE gl_thread_t
369 gl_thread_create (void *(*func) (void *arg), void *arg)
370 {
371   gl_thread_t thread;
372   int ret;
373
374   ret = glthread_create (&thread, func, arg);
375   if (ret != 0)
376     abort ();
377   return thread;
378 }
379 #define gl_thread_sigmask(HOW, SET, OSET)     \
380    do                                         \
381      {                                        \
382        if (glthread_sigmask (HOW, SET, OSET)) \
383          abort ();                            \
384      }                                        \
385    while (0)
386 #define gl_thread_join(THREAD, RETVAL)     \
387    do                                      \
388      {                                     \
389        if (glthread_join (THREAD, RETVAL)) \
390          abort ();                         \
391      }                                     \
392    while (0)
393 #define gl_thread_atfork(PREPARE, PARENT, CHILD)     \
394    do                                                \
395      {                                               \
396        if (glthread_atfork (PREPARE, PARENT, CHILD)) \
397          abort ();                                   \
398      }                                               \
399    while (0)
400
401 #ifdef __cplusplus
402 }
403 #endif
404
405 _GL_INLINE_HEADER_END
406
407 #endif /* _GLTHREAD_THREAD_H */