1 /* Creating and controlling threads.
2 Copyright (C) 2005-2025 Free Software Foundation, Inc.
4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as
6 published by the Free Software Foundation; either version 2.1 of the
7 License, or (at your option) any later version.
9 This file 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 Lesser General Public License for more details.
14 You should have received a copy of the GNU Lesser 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 #include "glthread/thread.h"
27 /* ========================================================================= */
31 struct thrd_with_exitvalue
34 void * volatile exitvalue
;
37 /* The Thread-Specific Storage (TSS) key that allows to access each thread's
38 'struct thrd_with_exitvalue *' pointer. */
39 static tss_t thrd_with_exitvalue_key
;
41 /* Initializes thrd_with_exitvalue_key.
42 This function must only be called once. */
44 do_init_thrd_with_exitvalue_key (void)
46 if (tss_create (&thrd_with_exitvalue_key
, NULL
) != thrd_success
)
50 /* Initializes thrd_with_exitvalue_key. */
52 init_thrd_with_exitvalue_key (void)
54 static once_flag once
= ONCE_FLAG_INIT
;
55 call_once (&once
, do_init_thrd_with_exitvalue_key
);
60 struct thrd_with_exitvalue t
;
63 thrd_t tid
; /* reserve memory for t.tid */
64 void *(*mainfunc
) (void *);
71 thrd_main_func (void *pmarg
)
73 /* Unpack the object that combines mainfunc and arg. */
74 main_arg_t
*main_arg
= (main_arg_t
*) pmarg
;
75 void *(*mainfunc
) (void *) = main_arg
->a
.mainfunc
;
76 void *arg
= main_arg
->a
.arg
;
78 if (tss_set (thrd_with_exitvalue_key
, &main_arg
->t
) != thrd_success
)
81 /* Execute mainfunc, with arg as argument. */
83 void *exitvalue
= mainfunc (arg
);
84 /* Store the exitvalue, for use by glthread_join(). */
85 main_arg
->t
.exitvalue
= exitvalue
;
91 glthread_create (gl_thread_t
*threadp
, void *(*mainfunc
) (void *), void *arg
)
93 init_thrd_with_exitvalue_key ();
95 /* Combine mainfunc and arg in a single object.
96 A stack-allocated object does not work, because it would be out of
97 existence when thrd_create returns before thrd_main_func is
98 entered. So, allocate it in the heap. */
99 main_arg_t
*main_arg
= (main_arg_t
*) malloc (sizeof (main_arg_t
));
100 if (main_arg
== NULL
)
102 main_arg
->a
.mainfunc
= mainfunc
;
103 main_arg
->a
.arg
= arg
;
104 switch (thrd_create ((thrd_t
*) &main_arg
->t
.tid
, thrd_main_func
, main_arg
))
115 *threadp
= &main_arg
->t
;
121 gl_thread_self (void)
123 init_thrd_with_exitvalue_key ();
126 (struct thrd_with_exitvalue
*) tss_get (thrd_with_exitvalue_key
);
129 /* This happens only in threads that have not been created through
130 glthread_create(), such as the main thread. */
134 (struct thrd_with_exitvalue
*)
135 malloc (sizeof (struct thrd_with_exitvalue
));
138 /* Memory allocation failed. There is not much we can do. Have to
139 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 /* ========================================================================= */
208 gl_thread_create (void *(*func
) (void *arg
), void *arg
)
213 ret
= glthread_create (&thread
, func
, arg
);