1 /* Creating and controlling ISO C 11 threads.
2 Copyright (C) 2005-2020 Free Software Foundation, Inc.
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)
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.
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/>. */
17 /* Written by Bruno Haible <bruno@clisp.org>, 2005, 2019.
18 Based on GCC's gthr-posix.h, gthr-posix95.h, gthr-win32.h. */
27 /* Provide workarounds. */
29 # if BROKEN_THRD_START_T
33 /* AIX 7.1..7.2 defines thrd_start_t incorrectly, namely as
34 'void * (*) (void *)' instead of 'int (*) (void *)'.
35 As a consequence, its thrd_join function never stores an exit code. */
37 /* The Thread-Specific Storage (TSS) key that allows to access each thread's
38 'struct thrd_with_exitcode *' pointer. */
39 static tss_t thrd_with_exitcode_key
;
41 /* Initializes thrd_with_exitcode_key.
42 This function must only be called once. */
44 do_init_thrd_with_exitcode_key (void)
46 if (tss_create (&thrd_with_exitcode_key
, NULL
) != thrd_success
)
50 /* Initializes thrd_with_exitcode_key. */
52 init_thrd_with_exitcode_key (void)
54 static once_flag once
= ONCE_FLAG_INIT
;
55 call_once (&once
, do_init_thrd_with_exitcode_key
);
60 struct thrd_with_exitcode t
;
63 thrd_t tid
; /* reserve memory for t.tid */
64 int detached
; /* reserve memory for t.detached */
65 thrd_start_t mainfunc
;
72 thrd_main_func (void *pmarg
)
74 /* Unpack the object that combines mainfunc and arg. */
75 main_arg_t
*main_arg
= (main_arg_t
*) pmarg
;
76 thrd_start_t mainfunc
= main_arg
->a
.mainfunc
;
77 void *arg
= main_arg
->a
.arg
;
79 if (tss_set (thrd_with_exitcode_key
, &main_arg
->t
) != thrd_success
)
82 /* Execute mainfunc, with arg as argument. */
84 int exitcode
= mainfunc (arg
);
85 /* Store the exitcode, for use by thrd_join(). */
86 main_arg
->t
.exitcode
= exitcode
;
87 if (main_arg
->t
.detached
)
89 /* Clean up the thread, like thrd_join would do. */
97 rpl_thrd_create (rpl_thrd_t
*threadp
, thrd_start_t mainfunc
, void *arg
)
100 init_thrd_with_exitcode_key ();
102 /* Combine mainfunc and arg in a single object.
103 A stack-allocated object does not work, because it would be out of
104 existence when thrd_create returns before pthread_main_func is
105 entered. So, allocate it in the heap. */
106 main_arg_t
*main_arg
= (main_arg_t
*) malloc (sizeof (main_arg_t
));
107 if (main_arg
== NULL
)
109 main_arg
->a
.mainfunc
= mainfunc
;
110 main_arg
->a
.arg
= arg
;
111 main_arg
->t
.detached
= 0;
114 thrd_create ((thrd_t
*) &main_arg
->t
.tid
, thrd_main_func
, main_arg
);
115 if (err
== thrd_success
)
116 *threadp
= &main_arg
->t
;
125 rpl_thrd_current (void)
128 init_thrd_with_exitcode_key ();
131 (struct thrd_with_exitcode
*) tss_get (thrd_with_exitcode_key
);
134 /* This happens only in threads that have not been created through
135 thrd_create(), such as the main thread. */
139 (struct thrd_with_exitcode
*)
140 malloc (sizeof (struct thrd_with_exitcode
));
143 /* Memory allocation failed. There is not much we can do. Have to
144 busy-loop, waiting for the availability of memory. */
149 thrd_sleep (&ts
, NULL
);
152 thread
->tid
= thrd_current ();
153 thread
->detached
= 0; /* This can lead to a memory leak. */
154 thread
->exitcode
= 0; /* just to be deterministic */
155 if (tss_set (thrd_with_exitcode_key
, thread
) != thrd_success
)
163 rpl_thrd_equal (rpl_thrd_t thread1
, rpl_thrd_t thread2
)
165 return thread1
== thread2
;
169 rpl_thrd_detach (rpl_thrd_t thread
)
172 if (thread
->detached
)
176 thrd_detach (thread
== rpl_thrd_current ()
177 ? /* thread->tid may not be initialized at this point. */
180 if (err
== thrd_success
)
181 thread
->detached
= 1;
187 rpl_thrd_join (rpl_thrd_t thread
, int *exitcodep
)
190 if (thread
== rpl_thrd_current () || thread
->detached
)
193 int err
= thrd_join (thread
->tid
, NULL
);
194 if (err
== thrd_success
)
196 if (exitcodep
!= NULL
)
197 *exitcodep
= thread
->exitcode
;
206 # if BROKEN_THRD_JOIN
208 /* On Solaris 11.4, thrd_join crashes when the second argument is NULL. */
210 rpl_thrd_join (thrd_t thread
, int *exitcodep
)
214 int err
= thrd_join (thread
, &exitcode
);
215 if (err
== 0 && exitcodep
!= NULL
)
216 *exitcodep
= exitcode
;
227 # if defined _WIN32 && ! defined __CYGWIN__
228 /* Use Windows threads. */
230 # define WIN32_LEAN_AND_MEAN /* avoid including junk */
231 # include <windows.h>
234 /* Use POSIX threads. */
236 # include <pthread.h>
241 /* The main functions passed to thrd_create and
242 pthread_create/glwthread_thread_create have different return types:
243 'int' vs. 'void *'. */
245 struct pthread_main_arg_t
247 thrd_start_t mainfunc
;
252 pthread_main_func (void *pmarg
)
254 /* Unpack the object that combines mainfunc and arg. */
255 struct pthread_main_arg_t
*pthread_main_arg
=
256 (struct pthread_main_arg_t
*) pmarg
;
257 thrd_start_t mainfunc
= pthread_main_arg
->mainfunc
;
258 void *arg
= pthread_main_arg
->arg
;
263 /* Execute mainfunc, with arg as argument. */
265 int exitcode
= mainfunc (arg
);
266 /* Note: When using Windows threads, this exit code is different from the
267 argument passed to ExitThread(), because the latter should never be 259,
268 see <https://docs.microsoft.com/de-de/windows/desktop/api/processthreadsapi/nf-processthreadsapi-getexitcodethread>,
269 whereas the exit code passed to thrd_exit() is not constrained. */
270 return (void *) (intptr_t) exitcode
;
274 # if defined _WIN32 && ! defined __CYGWIN__
275 /* Use Windows threads. */
278 thrd_create (thrd_t
*threadp
, thrd_start_t mainfunc
, void *arg
)
280 /* Combine mainfunc and arg in a single object.
281 A stack-allocated object does not work, because it would be out of
282 existence when thrd_create returns before pthread_main_func is
283 entered. So, allocate it in the heap. */
284 struct pthread_main_arg_t
*pthread_main_arg
=
285 (struct pthread_main_arg_t
*) malloc (sizeof (struct pthread_main_arg_t
));
286 if (pthread_main_arg
== NULL
)
288 pthread_main_arg
->mainfunc
= mainfunc
;
289 pthread_main_arg
->arg
= arg
;
292 int err
= glwthread_thread_create (threadp
, 0,
293 pthread_main_func
, pthread_main_arg
);
295 free (pthread_main_arg
);
296 return (err
== 0 ? thrd_success
:
297 err
== ENOMEM
/* || err == EAGAIN */ ? thrd_nomem
:
305 return glwthread_thread_self ();
309 thrd_equal (thrd_t thread1
, thrd_t thread2
)
311 return thread1
== thread2
;
321 thrd_detach (thrd_t thread
)
323 int err
= glwthread_thread_detach (thread
);
324 return (err
== 0 ? thrd_success
: thrd_error
);
328 thrd_join (thrd_t thread
, int *exitcodep
)
331 int err
= glwthread_thread_join (thread
, &exitptr
);
334 if (exitcodep
!= NULL
)
335 *exitcodep
= (int) (intptr_t) exitptr
;
343 thrd_exit (int exitcode
)
345 glwthread_thread_exit ((void *) (intptr_t) exitcode
);
349 /* Use POSIX threads. */
352 thrd_create (thrd_t
*threadp
, thrd_start_t mainfunc
, void *arg
)
354 /* Combine mainfunc and arg in a single object.
355 A stack-allocated object does not work, because it would be out of
356 existence when thrd_create returns before pthread_main_func is
357 entered. So, allocate it in the heap. */
358 struct pthread_main_arg_t
*pthread_main_arg
=
359 (struct pthread_main_arg_t
*) malloc (sizeof (struct pthread_main_arg_t
));
360 if (pthread_main_arg
== NULL
)
362 pthread_main_arg
->mainfunc
= mainfunc
;
363 pthread_main_arg
->arg
= arg
;
366 int err
= pthread_create (threadp
, NULL
,
367 pthread_main_func
, pthread_main_arg
);
369 free (pthread_main_arg
);
370 return (err
== 0 ? thrd_success
:
371 err
== ENOMEM
/* || err == EAGAIN */ ? thrd_nomem
:
379 return pthread_self ();
383 thrd_equal (thrd_t thread1
, thrd_t thread2
)
385 return pthread_equal (thread1
, thread2
);
395 thrd_detach (thrd_t thread
)
397 int err
= pthread_detach (thread
);
398 return (err
== 0 ? thrd_success
: thrd_error
);
402 thrd_join (thrd_t thread
, int *exitcodep
)
405 int err
= pthread_join (thread
, &exitptr
);
408 if (exitcodep
!= NULL
)
409 *exitcodep
= (int) (intptr_t) exitptr
;
417 thrd_exit (int exitcode
)
419 pthread_exit ((void *) (intptr_t) exitcode
);
425 thrd_sleep (const struct timespec
*duration
, struct timespec
*remaining
)
427 int ret
= nanosleep (duration
, remaining
);
428 return (ret
== 0 ? 0 : errno
== EINTR
? -1 : -2);