1 /* Creating and controlling 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.
18 Based on GCC's gthr-posix.h, gthr-posix95.h, gthr-win32.h. */
23 # define _GLTHREAD_THREAD_INLINE _GL_EXTERN_INLINE
24 #include "glthread/thread.h"
27 #include "glthread/lock.h"
29 /* ========================================================================= */
33 struct thrd_with_exitvalue
36 void * volatile exitvalue
;
39 /* The Thread-Specific Storage (TSS) key that allows to access each thread's
40 'struct thrd_with_exitvalue *' pointer. */
41 static tss_t thrd_with_exitvalue_key
;
43 /* Initializes thrd_with_exitvalue_key.
44 This function must only be called once. */
46 do_init_thrd_with_exitvalue_key (void)
48 if (tss_create (&thrd_with_exitvalue_key
, NULL
) != thrd_success
)
52 /* Initializes thrd_with_exitvalue_key. */
54 init_thrd_with_exitvalue_key (void)
56 static once_flag once
= ONCE_FLAG_INIT
;
57 call_once (&once
, do_init_thrd_with_exitvalue_key
);
62 struct thrd_with_exitvalue t
;
65 thrd_t tid
; /* reserve memory for t.tid */
66 void *(*mainfunc
) (void *);
73 thrd_main_func (void *pmarg
)
75 /* Unpack the object that combines mainfunc and arg. */
76 main_arg_t
*main_arg
= (main_arg_t
*) pmarg
;
77 void *(*mainfunc
) (void *) = main_arg
->a
.mainfunc
;
78 void *arg
= main_arg
->a
.arg
;
80 if (tss_set (thrd_with_exitvalue_key
, &main_arg
->t
) != thrd_success
)
83 /* Execute mainfunc, with arg as argument. */
85 void *exitvalue
= mainfunc (arg
);
86 /* Store the exitvalue, for use by glthread_join(). */
87 main_arg
->t
.exitvalue
= exitvalue
;
93 glthread_create (gl_thread_t
*threadp
, void *(*mainfunc
) (void *), void *arg
)
95 init_thrd_with_exitvalue_key ();
97 /* Combine mainfunc and arg in a single object.
98 A stack-allocated object does not work, because it would be out of
99 existence when thrd_create returns before thrd_main_func is
100 entered. So, allocate it in the heap. */
101 main_arg_t
*main_arg
= (main_arg_t
*) malloc (sizeof (main_arg_t
));
102 if (main_arg
== NULL
)
104 main_arg
->a
.mainfunc
= mainfunc
;
105 main_arg
->a
.arg
= arg
;
106 switch (thrd_create ((thrd_t
*) &main_arg
->t
.tid
, thrd_main_func
, main_arg
))
117 *threadp
= &main_arg
->t
;
123 gl_thread_self (void)
125 init_thrd_with_exitvalue_key ();
128 (struct thrd_with_exitvalue
*) tss_get (thrd_with_exitvalue_key
);
131 /* This happens only in threads that have not been created through
132 glthread_create(), such as the main thread. */
136 (struct thrd_with_exitvalue
*)
137 malloc (sizeof (struct thrd_with_exitvalue
));
140 /* Memory allocation failed. There is not much we can do. Have to
141 busy-loop, waiting for the availability of memory. */
146 thrd_sleep (&ts
, NULL
);
149 thread
->tid
= thrd_current ();
150 thread
->exitvalue
= NULL
; /* just to be deterministic */
151 if (tss_set (thrd_with_exitvalue_key
, thread
) != thrd_success
)
159 glthread_join (gl_thread_t thread
, void **return_value_ptr
)
161 /* On Solaris 11.4, thrd_join crashes when the second argument we pass is
165 if (thread
== gl_thread_self ())
167 if (thrd_join (thread
->tid
, &dummy
) != thrd_success
)
169 if (return_value_ptr
!= NULL
)
170 *return_value_ptr
= thread
->exitvalue
;
176 gl_thread_exit (void *return_value
)
178 gl_thread_t thread
= gl_thread_self ();
179 thread
->exitvalue
= return_value
;
185 /* ========================================================================= */
187 #if USE_POSIX_THREADS || USE_ISOC_AND_POSIX_THREADS
191 #if defined PTW32_VERSION || defined __MVS__
193 const gl_thread_t gl_null_thread
/* = { .p = NULL } */;
199 /* ========================================================================= */
201 #if USE_WINDOWS_THREADS
205 /* ========================================================================= */