]>
Commit | Line | Data |
---|---|---|
33574c17 | 1 | /* Thread creation. |
d614a753 | 2 | Copyright (C) 2000-2020 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> | |
27 | ||
28 | #include <pt-internal.h> | |
f6fb29d2 | 29 | #include <pthreadP.h> |
33574c17 ST |
30 | |
31 | #if IS_IN (libpthread) | |
32 | # include <ctype.h> | |
33 | #endif | |
34 | #ifdef HAVE_USELOCALE | |
35 | # include <locale.h> | |
36 | #endif | |
37 | ||
38 | /* The total number of pthreads currently active. This is defined | |
39 | here since it would be really stupid to have a threads-using | |
40 | program that doesn't call `pthread_create'. */ | |
41 | unsigned int __pthread_total; | |
42 | \f | |
43 | ||
44 | /* The entry-point for new threads. */ | |
45 | static void | |
46 | entry_point (struct __pthread *self, void *(*start_routine) (void *), void *arg) | |
47 | { | |
48 | ___pthread_self = self; | |
49 | __resp = &self->res_state; | |
50 | ||
51 | #if IS_IN (libpthread) | |
52 | /* Initialize pointers to locale data. */ | |
53 | __ctype_init (); | |
54 | #endif | |
55 | #ifdef HAVE_USELOCALE | |
56 | /* A fresh thread needs to be bound to the global locale. */ | |
57 | uselocale (LC_GLOBAL_LOCALE); | |
58 | #endif | |
59 | ||
60 | __pthread_startup (); | |
61 | ||
f6fb29d2 | 62 | __pthread_exit (start_routine (arg)); |
33574c17 ST |
63 | } |
64 | ||
65 | /* Create a thread with attributes given by ATTR, executing | |
66 | START_ROUTINE with argument ARG. */ | |
67 | int | |
f6fb29d2 ST |
68 | __pthread_create (pthread_t * thread, const pthread_attr_t * attr, |
69 | void *(*start_routine) (void *), void *arg) | |
33574c17 ST |
70 | { |
71 | int err; | |
72 | struct __pthread *pthread; | |
73 | ||
74 | err = __pthread_create_internal (&pthread, attr, start_routine, arg); | |
75 | if (!err) | |
76 | *thread = pthread->thread; | |
77 | else if (err == ENOMEM) | |
78 | err = EAGAIN; | |
79 | ||
80 | return err; | |
81 | } | |
f6fb29d2 | 82 | strong_alias (__pthread_create, pthread_create) |
33574c17 ST |
83 | |
84 | /* Internal version of pthread_create. See comment in | |
85 | pt-internal.h. */ | |
86 | int | |
87 | __pthread_create_internal (struct __pthread **thread, | |
88 | const pthread_attr_t * attr, | |
89 | void *(*start_routine) (void *), void *arg) | |
90 | { | |
91 | int err; | |
92 | struct __pthread *pthread; | |
93 | const struct __pthread_attr *setup; | |
94 | sigset_t sigset; | |
95 | size_t stacksize; | |
96 | ||
97 | /* Allocate a new thread structure. */ | |
98 | err = __pthread_alloc (&pthread); | |
99 | if (err) | |
100 | goto failed; | |
101 | ||
102 | /* Use the default attributes if ATTR is NULL. */ | |
103 | setup = attr ? attr : &__pthread_default_attr; | |
104 | ||
105 | stacksize = setup->__stacksize; | |
106 | if (stacksize == 0) | |
107 | { | |
108 | struct rlimit rlim; | |
109 | __getrlimit (RLIMIT_STACK, &rlim); | |
110 | if (rlim.rlim_cur != RLIM_INFINITY) | |
111 | stacksize = rlim.rlim_cur; | |
112 | if (stacksize == 0) | |
113 | stacksize = PTHREAD_STACK_DEFAULT; | |
114 | } | |
115 | ||
116 | /* Initialize the thread state. */ | |
117 | pthread->state = (setup->__detachstate == PTHREAD_CREATE_DETACHED | |
118 | ? PTHREAD_DETACHED : PTHREAD_JOINABLE); | |
119 | ||
120 | if (setup->__stackaddr) | |
121 | { | |
122 | pthread->stackaddr = setup->__stackaddr; | |
123 | ||
124 | /* If the user supplied a stack, it is not our responsibility to | |
125 | setup a stack guard. */ | |
126 | pthread->guardsize = 0; | |
127 | pthread->stack = 0; | |
128 | } | |
129 | else | |
130 | { | |
131 | /* Allocate a stack. */ | |
132 | err = __pthread_stack_alloc (&pthread->stackaddr, | |
133 | ((setup->__guardsize + __vm_page_size - 1) | |
134 | / __vm_page_size) * __vm_page_size | |
135 | + stacksize); | |
136 | if (err) | |
137 | goto failed_stack_alloc; | |
138 | ||
139 | pthread->guardsize = setup->__guardsize; | |
140 | pthread->stack = 1; | |
141 | } | |
142 | ||
143 | pthread->stacksize = stacksize; | |
144 | ||
145 | /* Allocate the kernel thread and other required resources. */ | |
146 | err = __pthread_thread_alloc (pthread); | |
147 | if (err) | |
148 | goto failed_thread_alloc; | |
149 | ||
150 | pthread->tcb = _dl_allocate_tls (NULL); | |
151 | if (pthread->tcb == NULL) | |
152 | { | |
153 | err = ENOMEM; | |
154 | goto failed_thread_tls_alloc; | |
155 | } | |
156 | pthread->tcb->tcb = pthread->tcb; | |
157 | ||
158 | /* And initialize the rest of the machine context. This may include | |
159 | additional machine- and system-specific initializations that | |
160 | prove convenient. */ | |
161 | err = __pthread_setup (pthread, entry_point, start_routine, arg); | |
162 | if (err) | |
163 | goto failed_setup; | |
164 | ||
165 | /* Initialize the system-specific signal state for the new | |
166 | thread. */ | |
167 | err = __pthread_sigstate_init (pthread); | |
168 | if (err) | |
169 | goto failed_sigstate; | |
170 | ||
171 | /* If the new thread is joinable, add a reference for the caller. */ | |
172 | if (pthread->state == PTHREAD_JOINABLE) | |
173 | pthread->nr_refs++; | |
174 | ||
175 | /* Set the new thread's signal mask and set the pending signals to | |
176 | empty. POSIX says: "The signal mask shall be inherited from the | |
177 | creating thread. The set of signals pending for the new thread | |
178 | shall be empty." If the currnet thread is not a pthread then we | |
179 | just inherit the process' sigmask. */ | |
180 | if (__pthread_num_threads == 1) | |
181 | err = sigprocmask (0, 0, &sigset); | |
182 | else | |
183 | err = __pthread_sigstate (_pthread_self (), 0, 0, &sigset, 0); | |
184 | assert_perror (err); | |
185 | ||
186 | err = __pthread_sigstate (pthread, SIG_SETMASK, &sigset, 0, 1); | |
187 | assert_perror (err); | |
188 | ||
189 | /* Increase the total number of threads. We do this before actually | |
190 | starting the new thread, since the new thread might immediately | |
191 | call `pthread_exit' which decreases the number of threads and | |
192 | calls `exit' if the number of threads reaches zero. Increasing | |
193 | the number of threads from within the new thread isn't an option | |
194 | since this thread might return and call `pthread_exit' before the | |
195 | new thread runs. */ | |
196 | atomic_increment (&__pthread_total); | |
197 | ||
198 | /* Store a pointer to this thread in the thread ID lookup table. We | |
199 | could use __thread_setid, however, we only lock for reading as no | |
200 | other thread should be using this entry (we also assume that the | |
201 | store is atomic). */ | |
202 | __pthread_rwlock_rdlock (&__pthread_threads_lock); | |
203 | __pthread_threads[pthread->thread - 1] = pthread; | |
204 | __pthread_rwlock_unlock (&__pthread_threads_lock); | |
205 | ||
206 | /* At this point it is possible to guess our pthread ID. We have to | |
207 | make sure that all functions taking a pthread_t argument can | |
208 | handle the fact that this thread isn't really running yet. Since | |
209 | the new thread might be passed its ID through pthread_create (to | |
210 | avoid calling pthread_self), read it before starting the thread. */ | |
211 | *thread = pthread; | |
212 | ||
213 | /* Schedule the new thread. */ | |
214 | err = __pthread_thread_start (pthread); | |
215 | if (err) | |
216 | goto failed_starting; | |
217 | ||
218 | ||
219 | return 0; | |
220 | ||
221 | failed_starting: | |
222 | /* If joinable, a reference was added for the caller. */ | |
223 | if (pthread->state == PTHREAD_JOINABLE) | |
224 | __pthread_dealloc (pthread); | |
225 | ||
226 | __pthread_setid (pthread->thread, NULL); | |
227 | atomic_decrement (&__pthread_total); | |
228 | failed_sigstate: | |
229 | __pthread_sigstate_destroy (pthread); | |
230 | failed_setup: | |
231 | _dl_deallocate_tls (pthread->tcb, 1); | |
232 | pthread->tcb = NULL; | |
233 | failed_thread_tls_alloc: | |
234 | __pthread_thread_terminate (pthread); | |
235 | ||
236 | /* __pthread_thread_terminate has taken care of deallocating the stack and | |
237 | the thread structure. */ | |
238 | goto failed; | |
239 | failed_thread_alloc: | |
240 | if (pthread->stack) | |
241 | __pthread_stack_dealloc (pthread->stackaddr, | |
242 | ((setup->__guardsize + __vm_page_size - 1) | |
243 | / __vm_page_size) * __vm_page_size + stacksize); | |
244 | failed_stack_alloc: | |
245 | __pthread_dealloc (pthread); | |
246 | failed: | |
247 | return err; | |
248 | } |