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