Make gl_create_thread easier to use.
[gnulib.git] / lib / glthread / thread.h
1 /* Creating and controlling threads.
2    Copyright (C) 2005-2008 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, write to the Free Software Foundation,
16    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
17
18 /* Written by Bruno Haible <bruno@clisp.org>, 2005.
19    Based on GCC's gthr-posix.h, gthr-posix95.h, gthr-solaris.h,
20    gthr-win32.h.  */
21
22 /* This file contains primitives for creating and controlling threads.
23
24    Thread data type: gl_thread_t.
25
26    Creating a thread:
27        thread = gl_thread_create (func, arg);
28    Or with control of error handling:
29        err = glthread_create (&thread, func, arg);
30        extern int glthread_create (gl_thread_t *result,
31                                    void *(*func) (void *), void *arg);
32
33    Querying and changing the signal mask of a thread (not supported on all
34    platforms):
35        gl_thread_sigmask (how, newmask, oldmask);
36    Or with control of error handling:
37        err = glthread_sigmask (how, newmask, oldmask);
38        extern int glthread_sigmask (int how, const sigset_t *newmask, sigset_t *oldmask);
39
40    Waiting for termination of another thread:
41        gl_thread_join (thread, &return_value);
42    Or with control of error handling:
43        err = glthread_join (thread, &return_value);
44        extern int glthread_join (gl_thread_t thread, void **return_value_ptr);
45
46    Getting a reference to the current thread:
47        current = gl_thread_self ();
48        extern gl_thread_t gl_thread_self (void);
49
50    Terminating the current thread:
51        gl_thread_exit (return_value);
52        extern void gl_thread_exit (void *return_value) __attribute__ ((noreturn));
53
54    Requesting custom code to be executed at fork() time(not supported on all
55    platforms):
56        gl_thread_atfork (prepare_func, parent_func, child_func);
57    Or with control of error handling:
58        err = glthread_atfork (prepare_func, parent_func, child_func);
59        extern int glthread_atfork (void (*prepare_func) (void),
60                                    void (*parent_func) (void),
61                                    void (*child_func) (void));
62    Note that even on platforms where this is supported, use of fork() and
63    threads together is problematic, see
64      <http://lists.gnu.org/archive/html/bug-gnulib/2008-08/msg00062.html>
65  */
66
67
68 #ifndef _GLTHREAD_THREAD_H
69 #define _GLTHREAD_THREAD_H
70
71 #include <errno.h>
72 #include <stdlib.h>
73
74 /* ========================================================================= */
75
76 #if USE_POSIX_THREADS
77
78 /* Use the POSIX threads library.  */
79
80 # include <pthread.h>
81
82 # ifdef __cplusplus
83 extern "C" {
84 # endif
85
86 # if PTHREAD_IN_USE_DETECTION_HARD
87
88 /* The pthread_in_use() detection needs to be done at runtime.  */
89 #  define pthread_in_use() \
90      glthread_in_use ()
91 extern int glthread_in_use (void);
92
93 # endif
94
95 # if USE_POSIX_THREADS_WEAK
96
97 /* Use weak references to the POSIX threads library.  */
98
99 /* Weak references avoid dragging in external libraries if the other parts
100    of the program don't use them.  Here we use them, because we don't want
101    every program that uses libintl to depend on libpthread.  This assumes
102    that libpthread would not be loaded after libintl; i.e. if libintl is
103    loaded first, by an executable that does not depend on libpthread, and
104    then a module is dynamically loaded that depends on libpthread, libintl
105    will not be multithread-safe.  */
106
107 /* The way to test at runtime whether libpthread is present is to test
108    whether a function pointer's value, such as &pthread_mutex_init, is
109    non-NULL.  However, some versions of GCC have a bug through which, in
110    PIC mode, &foo != NULL always evaluates to true if there is a direct
111    call to foo(...) in the same function.  To avoid this, we test the
112    address of a function in libpthread that we don't use.  */
113
114 #  pragma weak pthread_create
115 #  pragma weak pthread_sigmask
116 #  pragma weak pthread_join
117 #  ifndef pthread_self
118 #   pragma weak pthread_self
119 #  endif
120 #  pragma weak pthread_exit
121 #  if HAVE_PTHREAD_ATFORK
122 #   pragma weak pthread_atfork
123 #  endif
124
125 #  if !PTHREAD_IN_USE_DETECTION_HARD
126 #   pragma weak pthread_cancel
127 #   define pthread_in_use() (pthread_cancel != NULL)
128 #  endif
129
130 # else
131
132 #  if !PTHREAD_IN_USE_DETECTION_HARD
133 #   define pthread_in_use() 1
134 #  endif
135
136 # endif
137
138 /* -------------------------- gl_thread_t datatype -------------------------- */
139
140 typedef pthread_t gl_thread_t;
141 # define glthread_create(THREADP, FUNC, ARG) \
142     (pthread_in_use () ? pthread_create (THREADP, NULL, FUNC, ARG) : ENOSYS)
143 # define glthread_sigmask(HOW, SET, OSET) \
144     (pthread_in_use () ? pthread_sigmask (HOW, SET, OSET) : 0)
145 # define glthread_join(THREAD, RETVALP) \
146     (pthread_in_use () ? pthread_join (THREAD, RETVALP) : 0)
147 # define gl_thread_self() \
148     (pthread_in_use () ? (void *) pthread_self () : NULL)
149 # define gl_thread_exit(RETVAL) \
150     (pthread_in_use () ? pthread_exit (RETVAL) : 0)
151
152 # if HAVE_PTHREAD_ATFORK
153 #  define glthread_atfork(PREPARE_FUNC, PARENT_FUNC, CHILD_FUNC) \
154      (pthread_in_use () ? pthread_atfork (PREPARE_FUNC, PARENT_FUNC, CHILD_FUNC) : 0)
155 # else
156 #  define glthread_atfork(PREPARE_FUNC, PARENT_FUNC, CHILD_FUNC) 0
157 # endif
158
159 #endif
160
161 /* ========================================================================= */
162
163 #if USE_PTH_THREADS
164
165 /* Use the GNU Pth threads library.  */
166
167 # include <pth.h>
168
169 # ifdef __cplusplus
170 extern "C" {
171 # endif
172
173 # if USE_PTH_THREADS_WEAK
174
175 /* Use weak references to the GNU Pth threads library.  */
176
177 #  pragma weak pth_spawn
178 #  pragma weak pth_sigmask
179 #  pragma weak pth_join
180 #  pragma weak pth_self
181 #  pragma weak pth_exit
182
183 #  pragma weak pth_cancel
184 #  define pth_in_use() (pth_cancel != NULL)
185
186 # else
187
188 #  define pth_in_use() 1
189
190 # endif
191 /* -------------------------- gl_thread_t datatype -------------------------- */
192
193 typedef pth_t gl_thread_t;
194 # define glthread_create(THREADP, FUNC, ARG) \
195     (pth_in_use () ? ((*(THREADP) = pth_spawn (NULL, FUNC, ARG)) ? 0 : errno) : 0)
196 # define glthread_sigmask(HOW, SET, OSET) \
197     (pth_in_use () && !pth_sigmask (HOW, SET, OSET) ? errno : 0)
198 # define glthread_join(THREAD, RETVALP) \
199     (pth_in_use () && !pth_join (THREAD, RETVALP) ? errno : 0)
200 # define gl_thread_self() \
201     (pth_in_use () ? (void *) pth_self () : 0)
202 # define gl_thread_exit(RETVAL) \
203     (pth_in_use () ? pth_exit (RETVAL) : 0)
204 # define glthread_atfork(PREPARE_FUNC, PARENT_FUNC, CHILD_FUNC) 0
205
206 #endif
207
208 /* ========================================================================= */
209
210 #if USE_SOLARIS_THREADS
211
212 /* Use the old Solaris threads library.  */
213
214 # include <thread.h>
215 # include <synch.h>
216
217 # ifdef __cplusplus
218 extern "C" {
219 # endif
220
221 # if USE_SOLARIS_THREADS_WEAK
222
223 /* Use weak references to the old Solaris threads library.  */
224
225 #  pragma weak thr_create
226 #  pragma weak thr_join
227 #  pragma weak thr_self
228 #  pragma weak thr_exit
229
230 #  pragma weak thr_suspend
231 #  define thread_in_use() (thr_suspend != NULL)
232
233 # else
234
235 #  define thread_in_use() 1
236
237 # endif
238
239 /* -------------------------- gl_thread_t datatype -------------------------- */
240
241 typedef thread_t gl_thread_t;
242 # define glthread_create(THREADP, FUNC, ARG) \
243     (thread_in_use () ? thr_create (NULL, 0, FUNC, ARG, 0, THREADP) : 0)
244 # define glthread_sigmask(HOW, SET, OSET) \
245     (pthread_in_use () ? sigprocmask (HOW, SET, OSET) : 0)
246 # define glthread_join(THREAD, RETVALP) \
247     (pthread_in_use () ? thr_join (THREAD, NULL, RETVALP) : 0)
248 # define gl_thread_self() \
249     (pthread_in_use () ? (void *) thr_self () : 0)
250 # define gl_thread_exit(RETVAL) \
251     (pthread_in_use () ? thr_exit (RETVAL) : 0)
252 # define glthread_atfork(PREPARE_FUNC, PARENT_FUNC, CHILD_FUNC) 0
253 #endif
254
255
256 /* ========================================================================= */
257
258 #if !(USE_POSIX_THREADS || USE_PTH_THREADS || USE_SOLARIS_THREADS || USE_WIN32_THREADS)
259
260 /* Provide dummy implementation if threads are not supported.  */
261
262 typedef int gl_thread_t;
263 # define glthread_create(THREADP, FUNC, ARG) ENOSYS
264 # define glthread_sigmask(HOW, SET, OSET) 0
265 # define glthread_join(THREAD, RETVALP) 0
266 # define gl_thread_self() NULL
267 # define gl_thread_exit(RETVAL) 0
268 # define glthread_atfork(PREPARE_FUNC, PARENT_FUNC, CHILD_FUNC) 0
269
270 #endif
271
272
273 /* ========================================================================= */
274
275 /* Macros with built-in error handling.  */
276
277 static inline gl_thread_t
278 gl_thread_create (void *(*func) (void *arg), void *arg)
279 {
280   gl_thread_t thread;
281   int ret;
282
283   ret = glthread_create (&thread, func, arg);
284   if (ret != 0)
285     abort ();
286   return thread;
287 }
288 #define gl_thread_sigmask(HOW, SET, OSET)     \
289    do                                         \
290      {                                        \
291        if (glthread_sigmask (HOW, SET, OSET)) \
292          abort ();                            \
293      }                                        \
294    while (0)
295 #define gl_thread_join(THREAD, RETVAL)     \
296    do                                      \
297      {                                     \
298        if (glthread_join (THREAD, RETVAL)) \
299          abort ();                         \
300      }                                     \
301    while (0)
302 #define gl_thread_atfork(PREPARE, PARENT, CHILD)     \
303    do                                                \
304      {                                               \
305        if (glthread_atfork (PREPARE, PARENT, CHILD)) \
306          abort ();                                   \
307      }                                               \
308    while (0)
309
310 #endif /* _GLTHREAD_THREAD_H */