Commit | Line | Data |
---|---|---|
71b3fa15 DX |
1 | /* |
2 | * Copyright (c) 2003 Daniel M. Eischen <deischen@freebsd.org> | |
3 | * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au> | |
4 | * All rights reserved. | |
5 | * | |
6 | * Redistribution and use in source and binary forms, with or without | |
7 | * modification, are permitted provided that the following conditions | |
8 | * are met: | |
9 | * 1. Redistributions of source code must retain the above copyright | |
10 | * notice, this list of conditions and the following disclaimer. | |
11 | * 2. Redistributions in binary form must reproduce the above copyright | |
12 | * notice, this list of conditions and the following disclaimer in the | |
13 | * documentation and/or other materials provided with the distribution. | |
14 | * 3. All advertising materials mentioning features or use of this software | |
15 | * must display the following acknowledgement: | |
16 | * This product includes software developed by John Birrell. | |
17 | * 4. Neither the name of the author nor the names of any co-contributors | |
18 | * may be used to endorse or promote products derived from this software | |
19 | * without specific prior written permission. | |
20 | * | |
21 | * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND | |
22 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
23 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
24 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | |
25 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
26 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
27 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
29 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
30 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
31 | * SUCH DAMAGE. | |
71b3fa15 DX |
32 | */ |
33 | ||
71b3fa15 DX |
34 | #include "namespace.h" |
35 | #include <sys/param.h> | |
71b3fa15 | 36 | #include <sys/signalvar.h> |
71b3fa15 | 37 | #include <sys/ioctl.h> |
71b3fa15 DX |
38 | #include <sys/sysctl.h> |
39 | #include <sys/time.h> | |
4b29dd4b MN |
40 | #include <sys/types.h> |
41 | #include <sys/resource.h> | |
71b3fa15 | 42 | #include <sys/ttycom.h> |
71b3fa15 | 43 | #include <sys/mman.h> |
e7bf3f77 | 44 | #include <stdio.h> |
71b3fa15 DX |
45 | #include <fcntl.h> |
46 | #include <paths.h> | |
47 | #include <pthread.h> | |
71b3fa15 | 48 | #include <signal.h> |
71b3fa15 DX |
49 | #include <stdlib.h> |
50 | #include <string.h> | |
51 | #include <unistd.h> | |
52 | #include "un-namespace.h" | |
53 | ||
54 | #include "libc_private.h" | |
55 | #include "thr_private.h" | |
56 | ||
602cfc0b | 57 | /* Default thread attributes: */ |
cf8046a9 | 58 | struct __pthread_attr_s _pthread_attr_default = { |
602cfc0b | 59 | .sched_policy = SCHED_OTHER, |
60 | .sched_inherit = 0, | |
61 | .prio = THR_DEFAULT_PRIORITY, | |
62 | .suspend = THR_CREATE_RUNNING, | |
467ee1bb | 63 | .flags = PTHREAD_SCOPE_SYSTEM, |
602cfc0b | 64 | .stackaddr_attr = NULL, |
65 | .stacksize_attr = THR_STACK_DEFAULT, | |
66 | .guardsize_attr = 0 | |
67 | }; | |
68 | ||
69 | /* Default mutex attributes: */ | |
cf8046a9 | 70 | struct __pthread_mutexattr_s _pthread_mutexattr_default = { |
602cfc0b | 71 | .m_type = PTHREAD_MUTEX_DEFAULT, |
72 | .m_protocol = PTHREAD_PRIO_NONE, | |
73 | .m_ceiling = 0, | |
74 | .m_flags = 0 | |
75 | }; | |
76 | ||
77 | /* Default condition variable attributes: */ | |
cf8046a9 | 78 | struct __pthread_condattr_s _pthread_condattr_default = { |
602cfc0b | 79 | .c_pshared = PTHREAD_PROCESS_PRIVATE, |
80 | .c_clockid = CLOCK_REALTIME | |
81 | }; | |
82 | ||
22d6e608 DX |
83 | /* thr_attr.c */ |
84 | STATIC_LIB_REQUIRE(_pthread_attr_init); | |
85 | /* thr_barrier.c */ | |
86 | STATIC_LIB_REQUIRE(_pthread_barrier_init); | |
87 | /* thr_barrierattr.c */ | |
88 | STATIC_LIB_REQUIRE(_pthread_barrierattr_init); | |
89 | /* thr_cancel.c */ | |
90 | STATIC_LIB_REQUIRE(_pthread_cancel); | |
91 | /* thr_clean.c */ | |
92 | STATIC_LIB_REQUIRE(_pthread_cleanup_push); | |
93 | /* thr_concurrency.c */ | |
34c13333 SW |
94 | STATIC_LIB_REQUIRE(_pthread_getconcurrency); |
95 | STATIC_LIB_REQUIRE(_pthread_setconcurrency); | |
22d6e608 DX |
96 | /* thr_cond.c */ |
97 | STATIC_LIB_REQUIRE(_pthread_cond_init); | |
98 | /* thr_condattr.c */ | |
99 | STATIC_LIB_REQUIRE(_pthread_condattr_init); | |
100 | /* thr_create.c */ | |
101 | STATIC_LIB_REQUIRE(_pthread_create); | |
102 | /* thr_detach.c */ | |
103 | STATIC_LIB_REQUIRE(_pthread_detach); | |
104 | /* thr_equal.c */ | |
105 | STATIC_LIB_REQUIRE(_pthread_equal); | |
106 | /* thr_exit.c */ | |
107 | STATIC_LIB_REQUIRE(_pthread_exit); | |
108 | /* thr_fork.c */ | |
109 | STATIC_LIB_REQUIRE(_pthread_atfork); | |
110 | STATIC_LIB_REQUIRE(_fork); | |
b2920380 SZ |
111 | /* thr_affinity.c */ |
112 | STATIC_LIB_REQUIRE(_pthread_getaffinity_np); | |
725edadf SW |
113 | /* thr_getcpuclockid.c */ |
114 | STATIC_LIB_REQUIRE(_pthread_getcpuclockid); | |
22d6e608 DX |
115 | /* thr_getprio.c */ |
116 | STATIC_LIB_REQUIRE(_pthread_getprio); | |
117 | /* thr_getschedparam.c */ | |
118 | STATIC_LIB_REQUIRE(_pthread_getschedparam); | |
c0f25c26 IV |
119 | /* thr_getthreadid_np.c */ |
120 | STATIC_LIB_REQUIRE(_pthread_getthreadid_np); | |
22d6e608 | 121 | /* thr_info.c */ |
eb396e51 MD |
122 | STATIC_LIB_REQUIRE(_pthread_get_name_np); |
123 | /* thr_info.c */ | |
ab5dc9ac SW |
124 | STATIC_LIB_REQUIRE(_pthread_getname_np); |
125 | /* thr_info.c */ | |
22d6e608 | 126 | STATIC_LIB_REQUIRE(_pthread_set_name_np); |
ab5dc9ac SW |
127 | /* thr_info.c */ |
128 | STATIC_LIB_REQUIRE(_pthread_setname_np); | |
a809fd39 MP |
129 | /* thr_init.c */ |
130 | STATIC_LIB_REQUIRE(_pthread_init_early); | |
22d6e608 DX |
131 | /* thr_join.c */ |
132 | STATIC_LIB_REQUIRE(_pthread_join); | |
133 | /* thr_kill.c */ | |
134 | STATIC_LIB_REQUIRE(_pthread_kill); | |
135 | /* thr_main_np.c */ | |
136 | STATIC_LIB_REQUIRE(_pthread_main_np); | |
137 | /* thr_multi_np.c */ | |
138 | STATIC_LIB_REQUIRE(_pthread_multi_np); | |
139 | /* thr_mutex.c */ | |
140 | STATIC_LIB_REQUIRE(_pthread_mutex_init); | |
141 | /* thr_mutex_prioceiling.c */ | |
142 | STATIC_LIB_REQUIRE(_pthread_mutexattr_getprioceiling); | |
143 | /* thr_mutex_protocol.c */ | |
144 | STATIC_LIB_REQUIRE(_pthread_mutexattr_getprotocol); | |
145 | /* thr_mutexattr.c */ | |
146 | STATIC_LIB_REQUIRE(_pthread_mutexattr_init); | |
147 | /* thr_once.c */ | |
148 | STATIC_LIB_REQUIRE(_pthread_once); | |
149 | /* thr_pspinlock.c */ | |
150 | STATIC_LIB_REQUIRE(_pthread_spin_init); | |
151 | /* thr_resume_np.c */ | |
152 | STATIC_LIB_REQUIRE(_pthread_resume_np); | |
153 | /* thr_rwlock.c */ | |
154 | STATIC_LIB_REQUIRE(_pthread_rwlock_init); | |
155 | /* thr_rwlockattr.c */ | |
156 | STATIC_LIB_REQUIRE(_pthread_rwlockattr_init); | |
157 | /* thr_self.c */ | |
158 | STATIC_LIB_REQUIRE(_pthread_self); | |
159 | /* thr_sem.c */ | |
160 | STATIC_LIB_REQUIRE(_sem_init); | |
b2920380 SZ |
161 | /* thr_affinity.c */ |
162 | STATIC_LIB_REQUIRE(_pthread_setaffinity_np); | |
22d6e608 DX |
163 | /* thr_setprio.c */ |
164 | STATIC_LIB_REQUIRE(_pthread_setprio); | |
165 | /* thr_setschedparam.c */ | |
166 | STATIC_LIB_REQUIRE(_pthread_setschedparam); | |
167 | /* thr_sig.c */ | |
168 | STATIC_LIB_REQUIRE(_sigwait); | |
169 | /* thr_single_np.c */ | |
170 | STATIC_LIB_REQUIRE(_pthread_single_np); | |
171 | /* thr_spec.c */ | |
172 | STATIC_LIB_REQUIRE(_pthread_key_create); | |
173 | /* thr_spinlock.c */ | |
174 | STATIC_LIB_REQUIRE(_spinlock); | |
175 | /* thr_suspend_np.c */ | |
176 | STATIC_LIB_REQUIRE(_pthread_suspend_np); | |
177 | /* thr_switch_np.c */ | |
178 | STATIC_LIB_REQUIRE(_pthread_switch_add_np); | |
179 | /* thr_symbols.c */ | |
180 | STATIC_LIB_REQUIRE(_thread_state_running); | |
181 | /* thr_syscalls.c */ | |
182 | STATIC_LIB_REQUIRE(__wait4); | |
183 | /* thr_yield.c */ | |
184 | STATIC_LIB_REQUIRE(_pthread_yield); | |
185 | ||
fc71f871 | 186 | char *_usrstack; |
940be950 | 187 | pthread_t _thr_initial; |
0dc5e56d | 188 | static void *_thr_main_redzone; |
e8382b15 DX |
189 | |
190 | pid_t _thr_pid; | |
fc71f871 DX |
191 | size_t _thr_guard_default; |
192 | size_t _thr_stack_default = THR_STACK_DEFAULT; | |
193 | size_t _thr_stack_initial = THR_STACK_INITIAL; | |
e8382b15 DX |
194 | int _thr_page_size; |
195 | ||
196 | static void init_private(void); | |
0dc5e56d | 197 | static void _libpthread_uninit(void); |
940be950 | 198 | static void init_main_thread(pthread_t thread); |
e8382b15 DX |
199 | |
200 | void _thread_init(void) __attribute__ ((constructor)); | |
201 | void | |
202 | _thread_init(void) | |
203 | { | |
204 | _libpthread_init(NULL); | |
721505de | 205 | _libc_thr_init(); |
e8382b15 DX |
206 | } |
207 | ||
0dc5e56d MD |
208 | void _thread_uninit(void) __attribute__ ((destructor)); |
209 | void | |
210 | _thread_uninit(void) | |
211 | { | |
212 | _libpthread_uninit(); | |
213 | } | |
214 | ||
a809fd39 MP |
215 | /* |
216 | * This function is used by libc to initialise libpthread | |
217 | * early during dynamic linking. | |
218 | */ | |
219 | void _pthread_init_early(void); | |
220 | void | |
221 | _pthread_init_early(void) | |
222 | { | |
223 | _libpthread_init(NULL); | |
224 | } | |
225 | ||
71b3fa15 DX |
226 | /* |
227 | * Threaded process initialization. | |
228 | * | |
229 | * This is only called under two conditions: | |
230 | * | |
231 | * 1) Some thread routines have detected that the library hasn't yet | |
232 | * been initialized (_thr_initial == NULL && curthread == NULL), or | |
233 | * | |
234 | * 2) An explicit call to reinitialize after a fork (indicated | |
235 | * by curthread != NULL) | |
236 | */ | |
237 | void | |
940be950 | 238 | _libpthread_init(pthread_t curthread) |
71b3fa15 DX |
239 | { |
240 | int fd, first = 0; | |
241 | sigset_t sigset, oldset; | |
242 | ||
243 | /* Check if this function has already been called: */ | |
244 | if ((_thr_initial != NULL) && (curthread == NULL)) | |
245 | /* Only initialize the threaded application once. */ | |
246 | return; | |
247 | ||
71b3fa15 DX |
248 | /* |
249 | * Check for the special case of this process running as | |
250 | * or in place of init as pid = 1: | |
251 | */ | |
252 | if ((_thr_pid = getpid()) == 1) { | |
253 | /* | |
254 | * Setup a new session for this process which is | |
255 | * assumed to be running as root. | |
256 | */ | |
257 | if (setsid() == -1) | |
258 | PANIC("Can't set session ID"); | |
259 | if (revoke(_PATH_CONSOLE) != 0) | |
260 | PANIC("Can't revoke console"); | |
261 | if ((fd = __sys_open(_PATH_CONSOLE, O_RDWR)) < 0) | |
262 | PANIC("Can't open console"); | |
263 | if (setlogin("root") == -1) | |
264 | PANIC("Can't set login to root"); | |
2038fb68 | 265 | if (__sys_ioctl(fd, TIOCSCTTY, NULL) == -1) |
71b3fa15 DX |
266 | PANIC("Can't set controlling terminal"); |
267 | } | |
268 | ||
269 | /* Initialize pthread private data. */ | |
270 | init_private(); | |
271 | ||
272 | /* Set the initial thread. */ | |
273 | if (curthread == NULL) { | |
274 | first = 1; | |
275 | /* Create and initialize the initial thread. */ | |
276 | curthread = _thr_alloc(NULL); | |
277 | if (curthread == NULL) | |
278 | PANIC("Can't allocate initial thread"); | |
279 | init_main_thread(curthread); | |
280 | } | |
281 | /* | |
282 | * Add the thread to the thread list queue. | |
283 | */ | |
284 | THR_LIST_ADD(curthread); | |
285 | _thread_active_threads = 1; | |
286 | ||
287 | /* Setup the thread specific data */ | |
9e2ee207 | 288 | tls_set_tcb(curthread->tcb); |
71b3fa15 DX |
289 | |
290 | if (first) { | |
291 | SIGFILLSET(sigset); | |
292 | __sys_sigprocmask(SIG_SETMASK, &sigset, &oldset); | |
293 | _thr_signal_init(); | |
294 | _thr_initial = curthread; | |
295 | SIGDELSET(oldset, SIGCANCEL); | |
296 | __sys_sigprocmask(SIG_SETMASK, &oldset, NULL); | |
3cd47da3 DX |
297 | if (td_eventismember(&_thread_event_mask, TD_CREATE)) |
298 | _thr_report_creation(curthread, curthread); | |
98247283 | 299 | _thr_rtld_init(); |
e2caf0e7 | 300 | _thr_malloc_init(); |
98247283 | 301 | _thr_sem_init(); |
71b3fa15 DX |
302 | } |
303 | } | |
304 | ||
0dc5e56d MD |
305 | static void |
306 | _libpthread_uninit(void) | |
307 | { | |
308 | if (_thr_initial == NULL) | |
309 | return; | |
310 | if (_thr_main_redzone && _thr_main_redzone != MAP_FAILED) { | |
311 | munmap(_thr_main_redzone, _thr_guard_default); | |
312 | _thr_main_redzone = NULL; | |
313 | } | |
314 | _thr_stack_cleanup(); | |
315 | } | |
316 | ||
71b3fa15 DX |
317 | /* |
318 | * This function and pthread_create() do a lot of the same things. | |
319 | * It'd be nice to consolidate the common stuff in one place. | |
320 | */ | |
321 | static void | |
940be950 | 322 | init_main_thread(pthread_t thread) |
71b3fa15 DX |
323 | { |
324 | /* Setup the thread attributes. */ | |
325 | thread->tid = _thr_get_tid(); | |
326 | thread->attr = _pthread_attr_default; | |
327 | /* | |
328 | * Set up the thread stack. | |
329 | * | |
330 | * Create a red zone below the main stack. All other stacks | |
331 | * are constrained to a maximum size by the parameters | |
332 | * passed to mmap(), but this stack is only limited by | |
333 | * resource limits, so this stack needs an explicitly mapped | |
334 | * red zone to protect the thread stack that is just beyond. | |
335 | */ | |
0dc5e56d MD |
336 | _thr_main_redzone = mmap(_usrstack - _thr_stack_initial - |
337 | _thr_guard_default, _thr_guard_default, | |
338 | 0, MAP_ANON | MAP_TRYFIXED, -1, 0); | |
339 | if (_thr_main_redzone == MAP_FAILED) { | |
71b3fa15 | 340 | PANIC("Cannot allocate red zone for initial thread"); |
2035b679 | 341 | } |
71b3fa15 DX |
342 | |
343 | /* | |
344 | * Mark the stack as an application supplied stack so that it | |
345 | * isn't deallocated. | |
346 | * | |
347 | * XXX - I'm not sure it would hurt anything to deallocate | |
348 | * the main thread stack because deallocation doesn't | |
349 | * actually free() it; it just puts it in the free | |
350 | * stack queue for later reuse. | |
351 | */ | |
fc71f871 | 352 | thread->attr.stackaddr_attr = _usrstack - _thr_stack_initial; |
eddabc99 | 353 | thread->attr.stacksize_attr = _thr_stack_initial; |
71b3fa15 DX |
354 | thread->attr.guardsize_attr = _thr_guard_default; |
355 | thread->attr.flags |= THR_STACK_USER; | |
356 | ||
357 | /* | |
358 | * Write a magic value to the thread structure | |
359 | * to help identify valid ones: | |
360 | */ | |
361 | thread->magic = THR_MAGIC; | |
362 | ||
363 | thread->cancelflags = PTHREAD_CANCEL_ENABLE | PTHREAD_CANCEL_DEFERRED; | |
e7bf3f77 MD |
364 | thread->name = __malloc(16); |
365 | snprintf(thread->name, 16, "initial thread"); | |
71b3fa15 DX |
366 | |
367 | /* Default the priority of the initial thread: */ | |
368 | thread->base_priority = THR_DEFAULT_PRIORITY; | |
369 | thread->active_priority = THR_DEFAULT_PRIORITY; | |
370 | thread->inherited_priority = 0; | |
371 | ||
372 | /* Initialize the mutex queue: */ | |
373 | TAILQ_INIT(&thread->mutexq); | |
71b3fa15 DX |
374 | |
375 | thread->state = PS_RUNNING; | |
376 | thread->uniqueid = 0; | |
377 | ||
378 | /* Others cleared to zero by thr_alloc() */ | |
379 | } | |
380 | ||
4b29dd4b MN |
381 | /* |
382 | * Determine the size of the main thread. | |
383 | * | |
384 | * Set the main thread's stack size equal to the value of RLIMIT_STACK for the | |
385 | * process. The size of stacks for threads created by the process at run-time | |
386 | * with pthread_create(3) is not affected by this and is still controlled by | |
387 | * thread attributes. | |
388 | * | |
389 | * Note: FreeBSD uses environment variables LIBPTHREAD_BIGSTACK_MAIN and | |
390 | * LIBPTHREAD_SPLITSTACK_MAIN to control use of RLIMIT_STACK vs the hard-coded | |
391 | * 4MB with RLIMIT_STACK being the default behaviour. DragonFly instead respects | |
392 | * RLIMIT_STACK unconditionally. | |
393 | */ | |
394 | static int64_t | |
395 | get_mainthread_size(void) | |
396 | { | |
397 | struct rlimit rlim; | |
398 | ||
399 | if (getrlimit(RLIMIT_STACK, &rlim) == -1) | |
400 | PANIC("Cannot get stack rlimit"); | |
401 | ||
402 | return rlim.rlim_cur; | |
403 | } | |
404 | ||
71b3fa15 DX |
405 | static void |
406 | init_private(void) | |
407 | { | |
fcaa7a3a | 408 | static int init_once = 0; |
71b3fa15 DX |
409 | size_t len; |
410 | int mib[2]; | |
411 | ||
71b3fa15 DX |
412 | /* |
413 | * Avoid reinitializing some things if they don't need to be, | |
414 | * e.g. after a fork(). | |
fcaa7a3a MD |
415 | * |
416 | * NOTE: _thr_atfork_*list must remain intact after a fork. | |
71b3fa15 DX |
417 | */ |
418 | if (init_once == 0) { | |
419 | /* Find the stack top */ | |
420 | mib[0] = CTL_KERN; | |
421 | mib[1] = KERN_USRSTACK; | |
422 | len = sizeof (_usrstack); | |
423 | if (sysctl(mib, 2, &_usrstack, &len, NULL, 0) == -1) | |
424 | PANIC("Cannot get kern.usrstack from sysctl"); | |
4b29dd4b | 425 | _thr_stack_initial = get_mainthread_size(); |
71b3fa15 DX |
426 | _thr_page_size = getpagesize(); |
427 | _thr_guard_default = _thr_page_size; | |
e8382b15 | 428 | _pthread_attr_default.guardsize_attr = _thr_guard_default; |
71b3fa15 | 429 | TAILQ_INIT(&_thr_atfork_list); |
fcaa7a3a MD |
430 | TAILQ_INIT(&_thr_atfork_kern_list); |
431 | init_once = 1; | |
71b3fa15 | 432 | } |
fcaa7a3a MD |
433 | |
434 | _thr_umtx_init(&_mutex_static_lock); | |
435 | _thr_umtx_init(&_cond_static_lock); | |
436 | _thr_umtx_init(&_rwlock_static_lock); | |
437 | _thr_umtx_init(&_keytable_lock); | |
438 | _thr_umtx_init(&_thr_atfork_lock); | |
439 | _thr_umtx_init(&_thr_event_lock); | |
440 | _thr_spinlock_init(); | |
441 | _thr_list_init(); | |
71b3fa15 | 442 | } |
a809fd39 MP |
443 | |
444 | __strong_reference(_pthread_init_early, pthread_init_early); |