d35be0dbebab32b3fadc860ba93af63643018960
[platform/upstream/libunistring.git] / tests / glthread / thread.h
1 /* Creating and controlling threads.
2    Copyright (C) 2005-2010 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, 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 /* This choice of gl_thread_t assumes that
141      pthread_equal (a, b)  is equivalent to  ((a) == (b)).
142    This is the case on all platforms in use in 2008.  */
143 typedef pthread_t gl_thread_t;
144 # define glthread_create(THREADP, FUNC, ARG) \
145     (pthread_in_use () ? pthread_create (THREADP, NULL, FUNC, ARG) : ENOSYS)
146 # define glthread_sigmask(HOW, SET, OSET) \
147     (pthread_in_use () ? pthread_sigmask (HOW, SET, OSET) : 0)
148 # define glthread_join(THREAD, RETVALP) \
149     (pthread_in_use () ? pthread_join (THREAD, RETVALP) : 0)
150 # define gl_thread_self() \
151     (pthread_in_use () ? (void *) pthread_self () : NULL)
152 # define gl_thread_exit(RETVAL) \
153     (pthread_in_use () ? pthread_exit (RETVAL) : 0)
154
155 # if HAVE_PTHREAD_ATFORK
156 #  define glthread_atfork(PREPARE_FUNC, PARENT_FUNC, CHILD_FUNC) \
157      (pthread_in_use () ? pthread_atfork (PREPARE_FUNC, PARENT_FUNC, CHILD_FUNC) : 0)
158 # else
159 #  define glthread_atfork(PREPARE_FUNC, PARENT_FUNC, CHILD_FUNC) 0
160 # endif
161
162 # ifdef __cplusplus
163 }
164 # endif
165
166 #endif
167
168 /* ========================================================================= */
169
170 #if USE_PTH_THREADS
171
172 /* Use the GNU Pth threads library.  */
173
174 # include <pth.h>
175
176 # ifdef __cplusplus
177 extern "C" {
178 # endif
179
180 # if USE_PTH_THREADS_WEAK
181
182 /* Use weak references to the GNU Pth threads library.  */
183
184 #  pragma weak pth_spawn
185 #  pragma weak pth_sigmask
186 #  pragma weak pth_join
187 #  pragma weak pth_self
188 #  pragma weak pth_exit
189
190 #  pragma weak pth_cancel
191 #  define pth_in_use() (pth_cancel != NULL)
192
193 # else
194
195 #  define pth_in_use() 1
196
197 # endif
198 /* -------------------------- gl_thread_t datatype -------------------------- */
199
200 typedef pth_t gl_thread_t;
201 # define glthread_create(THREADP, FUNC, ARG) \
202     (pth_in_use () ? ((*(THREADP) = pth_spawn (NULL, FUNC, ARG)) ? 0 : errno) : 0)
203 # define glthread_sigmask(HOW, SET, OSET) \
204     (pth_in_use () && !pth_sigmask (HOW, SET, OSET) ? errno : 0)
205 # define glthread_join(THREAD, RETVALP) \
206     (pth_in_use () && !pth_join (THREAD, RETVALP) ? errno : 0)
207 # define gl_thread_self() \
208     (pth_in_use () ? (void *) pth_self () : 0)
209 # define gl_thread_exit(RETVAL) \
210     (pth_in_use () ? pth_exit (RETVAL) : 0)
211 # define glthread_atfork(PREPARE_FUNC, PARENT_FUNC, CHILD_FUNC) 0
212
213 # ifdef __cplusplus
214 }
215 # endif
216
217 #endif
218
219 /* ========================================================================= */
220
221 #if USE_SOLARIS_THREADS
222
223 /* Use the old Solaris threads library.  */
224
225 # include <thread.h>
226 # include <synch.h>
227
228 # ifdef __cplusplus
229 extern "C" {
230 # endif
231
232 # if USE_SOLARIS_THREADS_WEAK
233
234 /* Use weak references to the old Solaris threads library.  */
235
236 #  pragma weak thr_create
237 #  pragma weak thr_join
238 #  pragma weak thr_self
239 #  pragma weak thr_exit
240
241 #  pragma weak thr_suspend
242 #  define thread_in_use() (thr_suspend != NULL)
243
244 # else
245
246 #  define thread_in_use() 1
247
248 # endif
249
250 /* -------------------------- gl_thread_t datatype -------------------------- */
251
252 typedef thread_t gl_thread_t;
253 # define glthread_create(THREADP, FUNC, ARG) \
254     (thread_in_use () ? thr_create (NULL, 0, FUNC, ARG, 0, THREADP) : 0)
255 # define glthread_sigmask(HOW, SET, OSET) \
256     (thread_in_use () ? sigprocmask (HOW, SET, OSET) : 0)
257 # define glthread_join(THREAD, RETVALP) \
258     (thread_in_use () ? thr_join (THREAD, NULL, RETVALP) : 0)
259 # define gl_thread_self() \
260     (thread_in_use () ? (void *) thr_self () : 0)
261 # define gl_thread_exit(RETVAL) \
262     (thread_in_use () ? thr_exit (RETVAL) : 0)
263 # define glthread_atfork(PREPARE_FUNC, PARENT_FUNC, CHILD_FUNC) 0
264
265 # ifdef __cplusplus
266 }
267 # endif
268
269 #endif
270
271 /* ========================================================================= */
272
273 #if USE_WIN32_THREADS
274
275 # include <windows.h>
276
277 # ifdef __cplusplus
278 extern "C" {
279 # endif
280
281 /* -------------------------- gl_thread_t datatype -------------------------- */
282
283 /* The gl_thread_t is a pointer to a structure in memory.
284    Why not the thread handle?  If it were the thread handle, it would be hard
285    to implement gl_thread_self() (since GetCurrentThread () returns a pseudo-
286    handle, DuplicateHandle (GetCurrentThread ()) returns a handle that must be
287    closed afterwards, and there is no function for quickly retrieving a thread
288    handle from its id).
289    Why not the thread id?  I tried it.  It did not work: Sometimes ids appeared
290    that did not belong to running threads, and glthread_join failed with ESRCH.
291  */
292 typedef struct gl_thread_struct *gl_thread_t;
293 # define glthread_create(THREADP, FUNC, ARG) \
294     glthread_create_func (THREADP, FUNC, ARG)
295 # define glthread_sigmask(HOW, SET, OSET) \
296     /* unsupported */ 0
297 # define glthread_join(THREAD, RETVALP) \
298     glthread_join_func (THREAD, RETVALP)
299 # define gl_thread_self() \
300     gl_thread_self_func ()
301 # define gl_thread_exit(RETVAL) \
302     gl_thread_exit_func (RETVAL)
303 # define glthread_atfork(PREPARE_FUNC, PARENT_FUNC, CHILD_FUNC) 0
304 extern int glthread_create_func (gl_thread_t *threadp, void * (*func) (void *), void *arg);
305 extern int glthread_join_func (gl_thread_t thread, void **retvalp);
306 extern gl_thread_t gl_thread_self_func (void);
307 extern int gl_thread_exit_func (void *retval);
308
309 # ifdef __cplusplus
310 }
311 # endif
312
313 #endif
314
315 /* ========================================================================= */
316
317 #if !(USE_POSIX_THREADS || USE_PTH_THREADS || USE_SOLARIS_THREADS || USE_WIN32_THREADS)
318
319 /* Provide dummy implementation if threads are not supported.  */
320
321 typedef int gl_thread_t;
322 # define glthread_create(THREADP, FUNC, ARG) ENOSYS
323 # define glthread_sigmask(HOW, SET, OSET) 0
324 # define glthread_join(THREAD, RETVALP) 0
325 # define gl_thread_self() NULL
326 # define gl_thread_exit(RETVAL) 0
327 # define glthread_atfork(PREPARE_FUNC, PARENT_FUNC, CHILD_FUNC) 0
328
329 #endif
330
331 /* ========================================================================= */
332
333 /* Macros with built-in error handling.  */
334
335 #ifdef __cplusplus
336 extern "C" {
337 #endif
338
339 static inline gl_thread_t
340 gl_thread_create (void *(*func) (void *arg), void *arg)
341 {
342   gl_thread_t thread;
343   int ret;
344
345   ret = glthread_create (&thread, func, arg);
346   if (ret != 0)
347     abort ();
348   return thread;
349 }
350 #define gl_thread_sigmask(HOW, SET, OSET)     \
351    do                                         \
352      {                                        \
353        if (glthread_sigmask (HOW, SET, OSET)) \
354          abort ();                            \
355      }                                        \
356    while (0)
357 #define gl_thread_join(THREAD, RETVAL)     \
358    do                                      \
359      {                                     \
360        if (glthread_join (THREAD, RETVAL)) \
361          abort ();                         \
362      }                                     \
363    while (0)
364 #define gl_thread_atfork(PREPARE, PARENT, CHILD)     \
365    do                                                \
366      {                                               \
367        if (glthread_atfork (PREPARE, PARENT, CHILD)) \
368          abort ();                                   \
369      }                                               \
370    while (0)
371
372 #ifdef __cplusplus
373 }
374 #endif
375
376 #endif /* _GLTHREAD_THREAD_H */