]>
Commit | Line | Data |
---|---|---|
33574c17 | 1 | /* Thread creation. |
6d7e8eda | 2 | Copyright (C) 2000-2023 Free Software Foundation, Inc. |
33574c17 ST |
3 | This file is part of the GNU C Library. |
4 | ||
5 | The GNU C Library is free software; you can redistribute it and/or | |
ad2b41bf ST |
6 | modify it under the terms of the GNU Lesser General Public |
7 | License as published by the Free Software Foundation; either | |
8 | version 2.1 of the License, or (at your option) any later version. | |
33574c17 ST |
9 | |
10 | The GNU C Library is distributed in the hope that it will be useful, | |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
ad2b41bf | 13 | Lesser General Public License for more details. |
33574c17 | 14 | |
ad2b41bf ST |
15 | You should have received a copy of the GNU Lesser General Public |
16 | License along with the GNU C Library; if not, see | |
5a82c748 | 17 | <https://www.gnu.org/licenses/>. */ |
33574c17 ST |
18 | |
19 | #include <assert.h> | |
20 | #include <errno.h> | |
21 | #include <pthread.h> | |
22 | #include <signal.h> | |
23 | #include <resolv.h> | |
24 | ||
25 | #include <atomic.h> | |
26 | #include <hurd/resource.h> | |
706ad1e7 | 27 | #include <sys/single_threaded.h> |
33574c17 ST |
28 | |
29 | #include <pt-internal.h> | |
f6fb29d2 | 30 | #include <pthreadP.h> |
33574c17 ST |
31 | |
32 | #if IS_IN (libpthread) | |
33 | # include <ctype.h> | |
34 | #endif | |
35 | #ifdef HAVE_USELOCALE | |
36 | # include <locale.h> | |
37 | #endif | |
38 | ||
33574c17 ST |
39 | /* The entry-point for new threads. */ |
40 | static void | |
41 | entry_point (struct __pthread *self, void *(*start_routine) (void *), void *arg) | |
42 | { | |
d482ebfa ST |
43 | int err; |
44 | ||
33574c17 ST |
45 | ___pthread_self = self; |
46 | __resp = &self->res_state; | |
47 | ||
48 | #if IS_IN (libpthread) | |
49 | /* Initialize pointers to locale data. */ | |
50 | __ctype_init (); | |
51 | #endif | |
52 | #ifdef HAVE_USELOCALE | |
53 | /* A fresh thread needs to be bound to the global locale. */ | |
54 | uselocale (LC_GLOBAL_LOCALE); | |
55 | #endif | |
56 | ||
57 | __pthread_startup (); | |
58 | ||
d482ebfa ST |
59 | /* We can now unleash signals. */ |
60 | err = __pthread_sigstate (self, SIG_SETMASK, &self->init_sigset, 0, 0); | |
61 | assert_perror (err); | |
62 | ||
0c036123 ST |
63 | if (self->c11) |
64 | { | |
65 | /* The function pointer of the c11 thread start is cast to an incorrect | |
66 | type on __pthread_create call, however it is casted back to correct | |
67 | one so the call behavior is well-defined (it is assumed that pointers | |
68 | to void are able to represent all values of int). */ | |
69 | int (*start)(void*) = (int (*) (void*)) start_routine; | |
70 | __pthread_exit ((void*) (uintptr_t) start (arg)); | |
71 | } | |
72 | else | |
73 | __pthread_exit (start_routine (arg)); | |
33574c17 ST |
74 | } |
75 | ||
76 | /* Create a thread with attributes given by ATTR, executing | |
77 | START_ROUTINE with argument ARG. */ | |
78 | int | |
f6fb29d2 ST |
79 | __pthread_create (pthread_t * thread, const pthread_attr_t * attr, |
80 | void *(*start_routine) (void *), void *arg) | |
33574c17 ST |
81 | { |
82 | int err; | |
83 | struct __pthread *pthread; | |
84 | ||
85 | err = __pthread_create_internal (&pthread, attr, start_routine, arg); | |
86 | if (!err) | |
87 | *thread = pthread->thread; | |
88 | else if (err == ENOMEM) | |
89 | err = EAGAIN; | |
90 | ||
91 | return err; | |
92 | } | |
fba7fc5a | 93 | weak_alias (__pthread_create, pthread_create) |
7c331116 | 94 | hidden_def (__pthread_create) |
33574c17 ST |
95 | |
96 | /* Internal version of pthread_create. See comment in | |
97 | pt-internal.h. */ | |
98 | int | |
99 | __pthread_create_internal (struct __pthread **thread, | |
100 | const pthread_attr_t * attr, | |
101 | void *(*start_routine) (void *), void *arg) | |
102 | { | |
103 | int err; | |
104 | struct __pthread *pthread; | |
105 | const struct __pthread_attr *setup; | |
106 | sigset_t sigset; | |
107 | size_t stacksize; | |
108 | ||
706ad1e7 FW |
109 | /* Avoid a data race in the multi-threaded case. */ |
110 | if (__libc_single_threaded) | |
111 | __libc_single_threaded = 0; | |
112 | ||
33574c17 ST |
113 | /* Allocate a new thread structure. */ |
114 | err = __pthread_alloc (&pthread); | |
115 | if (err) | |
116 | goto failed; | |
117 | ||
0c036123 ST |
118 | if (attr == ATTR_C11_THREAD) |
119 | { | |
120 | attr = NULL; | |
121 | pthread->c11 = true; | |
122 | } | |
123 | else | |
124 | pthread->c11 = false; | |
125 | ||
33574c17 ST |
126 | /* Use the default attributes if ATTR is NULL. */ |
127 | setup = attr ? attr : &__pthread_default_attr; | |
128 | ||
129 | stacksize = setup->__stacksize; | |
130 | if (stacksize == 0) | |
131 | { | |
132 | struct rlimit rlim; | |
3a614f39 ST |
133 | err = __getrlimit (RLIMIT_STACK, &rlim); |
134 | if (err == 0 && rlim.rlim_cur != RLIM_INFINITY) | |
33574c17 ST |
135 | stacksize = rlim.rlim_cur; |
136 | if (stacksize == 0) | |
137 | stacksize = PTHREAD_STACK_DEFAULT; | |
138 | } | |
139 | ||
140 | /* Initialize the thread state. */ | |
141 | pthread->state = (setup->__detachstate == PTHREAD_CREATE_DETACHED | |
142 | ? PTHREAD_DETACHED : PTHREAD_JOINABLE); | |
143 | ||
144 | if (setup->__stackaddr) | |
145 | { | |
146 | pthread->stackaddr = setup->__stackaddr; | |
147 | ||
148 | /* If the user supplied a stack, it is not our responsibility to | |
149 | setup a stack guard. */ | |
150 | pthread->guardsize = 0; | |
151 | pthread->stack = 0; | |
152 | } | |
153 | else | |
154 | { | |
155 | /* Allocate a stack. */ | |
156 | err = __pthread_stack_alloc (&pthread->stackaddr, | |
157 | ((setup->__guardsize + __vm_page_size - 1) | |
158 | / __vm_page_size) * __vm_page_size | |
159 | + stacksize); | |
160 | if (err) | |
161 | goto failed_stack_alloc; | |
162 | ||
163 | pthread->guardsize = setup->__guardsize; | |
164 | pthread->stack = 1; | |
165 | } | |
166 | ||
167 | pthread->stacksize = stacksize; | |
168 | ||
169 | /* Allocate the kernel thread and other required resources. */ | |
170 | err = __pthread_thread_alloc (pthread); | |
171 | if (err) | |
172 | goto failed_thread_alloc; | |
173 | ||
174 | pthread->tcb = _dl_allocate_tls (NULL); | |
175 | if (pthread->tcb == NULL) | |
176 | { | |
177 | err = ENOMEM; | |
178 | goto failed_thread_tls_alloc; | |
179 | } | |
180 | pthread->tcb->tcb = pthread->tcb; | |
181 | ||
182 | /* And initialize the rest of the machine context. This may include | |
183 | additional machine- and system-specific initializations that | |
184 | prove convenient. */ | |
185 | err = __pthread_setup (pthread, entry_point, start_routine, arg); | |
186 | if (err) | |
187 | goto failed_setup; | |
188 | ||
189 | /* Initialize the system-specific signal state for the new | |
190 | thread. */ | |
191 | err = __pthread_sigstate_init (pthread); | |
192 | if (err) | |
193 | goto failed_sigstate; | |
194 | ||
195 | /* If the new thread is joinable, add a reference for the caller. */ | |
196 | if (pthread->state == PTHREAD_JOINABLE) | |
197 | pthread->nr_refs++; | |
198 | ||
199 | /* Set the new thread's signal mask and set the pending signals to | |
200 | empty. POSIX says: "The signal mask shall be inherited from the | |
201 | creating thread. The set of signals pending for the new thread | |
7f0d9e61 | 202 | shall be empty." If the current thread is not a pthread then we |
33574c17 | 203 | just inherit the process' sigmask. */ |
166bb3ea | 204 | if (GL (dl_pthread_num_threads) == 1) |
d482ebfa | 205 | err = __sigprocmask (0, 0, &pthread->init_sigset); |
33574c17 | 206 | else |
d482ebfa | 207 | err = __pthread_sigstate (_pthread_self (), 0, 0, &pthread->init_sigset, 0); |
33574c17 ST |
208 | assert_perror (err); |
209 | ||
51463869 ST |
210 | if (start_routine) |
211 | /* But block the signals for now, until the thread is fully initialized. */ | |
212 | __sigfillset (&sigset); | |
213 | else | |
214 | sigset = pthread->init_sigset; | |
33574c17 ST |
215 | err = __pthread_sigstate (pthread, SIG_SETMASK, &sigset, 0, 1); |
216 | assert_perror (err); | |
217 | ||
218 | /* Increase the total number of threads. We do this before actually | |
219 | starting the new thread, since the new thread might immediately | |
220 | call `pthread_exit' which decreases the number of threads and | |
221 | calls `exit' if the number of threads reaches zero. Increasing | |
222 | the number of threads from within the new thread isn't an option | |
223 | since this thread might return and call `pthread_exit' before the | |
224 | new thread runs. */ | |
d1babeb3 | 225 | atomic_fetch_add_relaxed (&__pthread_total, 1); |
33574c17 ST |
226 | |
227 | /* Store a pointer to this thread in the thread ID lookup table. We | |
228 | could use __thread_setid, however, we only lock for reading as no | |
229 | other thread should be using this entry (we also assume that the | |
230 | store is atomic). */ | |
166bb3ea SB |
231 | __libc_rwlock_rdlock (GL (dl_pthread_threads_lock)); |
232 | GL (dl_pthread_threads)[pthread->thread - 1] = pthread; | |
233 | __libc_rwlock_unlock (GL (dl_pthread_threads_lock)); | |
33574c17 ST |
234 | |
235 | /* At this point it is possible to guess our pthread ID. We have to | |
236 | make sure that all functions taking a pthread_t argument can | |
237 | handle the fact that this thread isn't really running yet. Since | |
238 | the new thread might be passed its ID through pthread_create (to | |
239 | avoid calling pthread_self), read it before starting the thread. */ | |
240 | *thread = pthread; | |
241 | ||
242 | /* Schedule the new thread. */ | |
243 | err = __pthread_thread_start (pthread); | |
244 | if (err) | |
245 | goto failed_starting; | |
246 | ||
247 | ||
248 | return 0; | |
249 | ||
250 | failed_starting: | |
251 | /* If joinable, a reference was added for the caller. */ | |
252 | if (pthread->state == PTHREAD_JOINABLE) | |
8c86ba44 ST |
253 | { |
254 | __pthread_dealloc (pthread); | |
255 | __pthread_dealloc_finish (pthread); | |
256 | } | |
33574c17 ST |
257 | |
258 | __pthread_setid (pthread->thread, NULL); | |
a364a3a7 | 259 | atomic_fetch_add_relaxed (&__pthread_total, -1); |
33574c17 ST |
260 | failed_sigstate: |
261 | __pthread_sigstate_destroy (pthread); | |
262 | failed_setup: | |
263 | _dl_deallocate_tls (pthread->tcb, 1); | |
264 | pthread->tcb = NULL; | |
265 | failed_thread_tls_alloc: | |
266 | __pthread_thread_terminate (pthread); | |
267 | ||
268 | /* __pthread_thread_terminate has taken care of deallocating the stack and | |
269 | the thread structure. */ | |
270 | goto failed; | |
271 | failed_thread_alloc: | |
272 | if (pthread->stack) | |
273 | __pthread_stack_dealloc (pthread->stackaddr, | |
274 | ((setup->__guardsize + __vm_page_size - 1) | |
275 | / __vm_page_size) * __vm_page_size + stacksize); | |
276 | failed_stack_alloc: | |
277 | __pthread_dealloc (pthread); | |
8c86ba44 | 278 | __pthread_dealloc_finish (pthread); |
33574c17 ST |
279 | failed: |
280 | return err; | |
281 | } |