| 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. |
| 32 | * |
| 33 | * $FreeBSD: src/lib/libpthread/thread/thr_init.c,v 1.66 2004/08/21 11:49:19 davidxu Exp $ |
| 34 | * $DragonFly: src/lib/libthread_xu/thread/thr_init.c,v 1.3 2005/03/29 19:26:20 joerg Exp $ |
| 35 | */ |
| 36 | |
| 37 | /* Allocate space for global thread variables here: */ |
| 38 | #define GLOBAL_PTHREAD_PRIVATE |
| 39 | |
| 40 | #include "namespace.h" |
| 41 | #include <sys/param.h> |
| 42 | #include <sys/types.h> |
| 43 | #include <sys/signalvar.h> |
| 44 | #include <machine/reg.h> |
| 45 | #include <machine/tls.h> |
| 46 | |
| 47 | #include <sys/ioctl.h> |
| 48 | #include <sys/mount.h> |
| 49 | #include <sys/uio.h> |
| 50 | #include <sys/socket.h> |
| 51 | #include <sys/event.h> |
| 52 | #include <sys/stat.h> |
| 53 | #include <sys/sysctl.h> |
| 54 | #include <sys/time.h> |
| 55 | #include <sys/ttycom.h> |
| 56 | #include <sys/wait.h> |
| 57 | #include <sys/mman.h> |
| 58 | |
| 59 | #include <dirent.h> |
| 60 | #include <errno.h> |
| 61 | #include <fcntl.h> |
| 62 | #include <paths.h> |
| 63 | #include <pthread.h> |
| 64 | #include <pthread_np.h> |
| 65 | #include <signal.h> |
| 66 | #include <stdio.h> |
| 67 | #include <stdlib.h> |
| 68 | #include <string.h> |
| 69 | #include <unistd.h> |
| 70 | #include "un-namespace.h" |
| 71 | |
| 72 | #include "libc_private.h" |
| 73 | #include "thr_private.h" |
| 74 | |
| 75 | extern int _thread_state_running; |
| 76 | |
| 77 | int __pthread_cond_wait(pthread_cond_t *, pthread_mutex_t *); |
| 78 | int __pthread_mutex_lock(pthread_mutex_t *); |
| 79 | int __pthread_mutex_trylock(pthread_mutex_t *); |
| 80 | |
| 81 | void _thread_init(void) __attribute__ ((constructor)); |
| 82 | |
| 83 | static void init_private(void); |
| 84 | static void init_main_thread(struct pthread *thread); |
| 85 | |
| 86 | /* |
| 87 | * All weak references used within libc should be in this table. |
| 88 | * This is so that static libraries will work. |
| 89 | */ |
| 90 | static void *references[] = { |
| 91 | &_accept, |
| 92 | &_bind, |
| 93 | &_close, |
| 94 | &_connect, |
| 95 | &_dup, |
| 96 | &_dup2, |
| 97 | &_execve, |
| 98 | &_fcntl, |
| 99 | &_flock, |
| 100 | &_flockfile, |
| 101 | &_fstat, |
| 102 | &_fstatfs, |
| 103 | &_fsync, |
| 104 | &_funlockfile, |
| 105 | &_getdirentries, |
| 106 | &_getlogin, |
| 107 | &_getpeername, |
| 108 | &_getsockname, |
| 109 | &_getsockopt, |
| 110 | &_ioctl, |
| 111 | &_kevent, |
| 112 | &_listen, |
| 113 | &_nanosleep, |
| 114 | &_open, |
| 115 | &_pthread_getspecific, |
| 116 | &_pthread_key_create, |
| 117 | &_pthread_key_delete, |
| 118 | &_pthread_mutex_destroy, |
| 119 | &_pthread_mutex_init, |
| 120 | &_pthread_mutex_lock, |
| 121 | &_pthread_mutex_trylock, |
| 122 | &_pthread_mutex_unlock, |
| 123 | &_pthread_mutexattr_init, |
| 124 | &_pthread_mutexattr_destroy, |
| 125 | &_pthread_mutexattr_settype, |
| 126 | &_pthread_once, |
| 127 | &_pthread_setspecific, |
| 128 | &_read, |
| 129 | &_readv, |
| 130 | &_recvfrom, |
| 131 | &_recvmsg, |
| 132 | &_select, |
| 133 | &_sendmsg, |
| 134 | &_sendto, |
| 135 | &_setsockopt, |
| 136 | &_sigaction, |
| 137 | &_sigprocmask, |
| 138 | &_sigsuspend, |
| 139 | &_socket, |
| 140 | &_socketpair, |
| 141 | &_thread_init, |
| 142 | &_wait4, |
| 143 | &_write, |
| 144 | &_writev |
| 145 | }; |
| 146 | |
| 147 | /* |
| 148 | * These are needed when linking statically. All references within |
| 149 | * libgcc (and in the future libc) to these routines are weak, but |
| 150 | * if they are not (strongly) referenced by the application or other |
| 151 | * libraries, then the actual functions will not be loaded. |
| 152 | */ |
| 153 | static void *libgcc_references[] = { |
| 154 | &_pthread_once, |
| 155 | &_pthread_key_create, |
| 156 | &_pthread_key_delete, |
| 157 | &_pthread_getspecific, |
| 158 | &_pthread_setspecific, |
| 159 | &_pthread_mutex_init, |
| 160 | &_pthread_mutex_destroy, |
| 161 | &_pthread_mutex_lock, |
| 162 | &_pthread_mutex_trylock, |
| 163 | &_pthread_mutex_unlock, |
| 164 | &_pthread_cond_init, |
| 165 | &_pthread_cond_destroy, |
| 166 | &_pthread_cond_wait, |
| 167 | &_pthread_cond_timedwait, |
| 168 | &_pthread_cond_signal, |
| 169 | &_pthread_cond_broadcast |
| 170 | }; |
| 171 | |
| 172 | #if 0 |
| 173 | #define DUAL_ENTRY(entry) \ |
| 174 | (pthread_func_t)entry, (pthread_func_t)entry |
| 175 | |
| 176 | static pthread_func_t jmp_table[][2] = { |
| 177 | {DUAL_ENTRY(_pthread_cond_broadcast)}, /* PJT_COND_BROADCAST */ |
| 178 | {DUAL_ENTRY(_pthread_cond_destroy)}, /* PJT_COND_DESTROY */ |
| 179 | {DUAL_ENTRY(_pthread_cond_init)}, /* PJT_COND_INIT */ |
| 180 | {DUAL_ENTRY(_pthread_cond_signal)}, /* PJT_COND_SIGNAL */ |
| 181 | {(pthread_func_t)__pthread_cond_wait, |
| 182 | (pthread_func_t)_pthread_cond_wait}, /* PJT_COND_WAIT */ |
| 183 | {DUAL_ENTRY(_pthread_getspecific)}, /* PJT_GETSPECIFIC */ |
| 184 | {DUAL_ENTRY(_pthread_key_create)}, /* PJT_KEY_CREATE */ |
| 185 | {DUAL_ENTRY(_pthread_key_delete)}, /* PJT_KEY_DELETE*/ |
| 186 | {DUAL_ENTRY(_pthread_main_np)}, /* PJT_MAIN_NP */ |
| 187 | {DUAL_ENTRY(_pthread_mutex_destroy)}, /* PJT_MUTEX_DESTROY */ |
| 188 | {DUAL_ENTRY(_pthread_mutex_init)}, /* PJT_MUTEX_INIT */ |
| 189 | {(pthread_func_t)__pthread_mutex_lock, |
| 190 | (pthread_func_t)_pthread_mutex_lock}, /* PJT_MUTEX_LOCK */ |
| 191 | {(pthread_func_t)__pthread_mutex_trylock, |
| 192 | (pthread_func_t)_pthread_mutex_trylock},/* PJT_MUTEX_TRYLOCK */ |
| 193 | {DUAL_ENTRY(_pthread_mutex_unlock)}, /* PJT_MUTEX_UNLOCK */ |
| 194 | {DUAL_ENTRY(_pthread_mutexattr_destroy)}, /* PJT_MUTEXATTR_DESTROY */ |
| 195 | {DUAL_ENTRY(_pthread_mutexattr_init)}, /* PJT_MUTEXATTR_INIT */ |
| 196 | {DUAL_ENTRY(_pthread_mutexattr_settype)}, /* PJT_MUTEXATTR_SETTYPE */ |
| 197 | {DUAL_ENTRY(_pthread_once)}, /* PJT_ONCE */ |
| 198 | {DUAL_ENTRY(_pthread_rwlock_destroy)}, /* PJT_RWLOCK_DESTROY */ |
| 199 | {DUAL_ENTRY(_pthread_rwlock_init)}, /* PJT_RWLOCK_INIT */ |
| 200 | {DUAL_ENTRY(_pthread_rwlock_rdlock)}, /* PJT_RWLOCK_RDLOCK */ |
| 201 | {DUAL_ENTRY(_pthread_rwlock_tryrdlock)},/* PJT_RWLOCK_TRYRDLOCK */ |
| 202 | {DUAL_ENTRY(_pthread_rwlock_trywrlock)},/* PJT_RWLOCK_TRYWRLOCK */ |
| 203 | {DUAL_ENTRY(_pthread_rwlock_unlock)}, /* PJT_RWLOCK_UNLOCK */ |
| 204 | {DUAL_ENTRY(_pthread_rwlock_wrlock)}, /* PJT_RWLOCK_WRLOCK */ |
| 205 | {DUAL_ENTRY(_pthread_self)}, /* PJT_SELF */ |
| 206 | {DUAL_ENTRY(_pthread_setspecific)}, /* PJT_SETSPECIFIC */ |
| 207 | {DUAL_ENTRY(_pthread_sigmask)} /* PJT_SIGMASK */ |
| 208 | }; |
| 209 | #endif |
| 210 | |
| 211 | static int init_once = 0; |
| 212 | |
| 213 | /* |
| 214 | * Threaded process initialization. |
| 215 | * |
| 216 | * This is only called under two conditions: |
| 217 | * |
| 218 | * 1) Some thread routines have detected that the library hasn't yet |
| 219 | * been initialized (_thr_initial == NULL && curthread == NULL), or |
| 220 | * |
| 221 | * 2) An explicit call to reinitialize after a fork (indicated |
| 222 | * by curthread != NULL) |
| 223 | */ |
| 224 | void |
| 225 | _libpthread_init(struct pthread *curthread) |
| 226 | { |
| 227 | int fd, first = 0; |
| 228 | sigset_t sigset, oldset; |
| 229 | |
| 230 | /* Check if this function has already been called: */ |
| 231 | if ((_thr_initial != NULL) && (curthread == NULL)) |
| 232 | /* Only initialize the threaded application once. */ |
| 233 | return; |
| 234 | |
| 235 | /* |
| 236 | * Make gcc quiescent about {,libgcc_}references not being |
| 237 | * referenced: |
| 238 | */ |
| 239 | if ((references[0] == NULL) || (libgcc_references[0] == NULL)) |
| 240 | PANIC("Failed loading mandatory references in _thread_init"); |
| 241 | |
| 242 | /* Pull debug symbols in for static binary */ |
| 243 | _thread_state_running = PS_RUNNING; |
| 244 | |
| 245 | #if 0 |
| 246 | /* |
| 247 | * Check the size of the jump table to make sure it is preset |
| 248 | * with the correct number of entries. |
| 249 | */ |
| 250 | if (sizeof(jmp_table) != (sizeof(pthread_func_t) * PJT_MAX * 2)) |
| 251 | PANIC("Thread jump table not properly initialized"); |
| 252 | memcpy(__thr_jtable, jmp_table, sizeof(jmp_table)); |
| 253 | #endif |
| 254 | /* |
| 255 | * Check for the special case of this process running as |
| 256 | * or in place of init as pid = 1: |
| 257 | */ |
| 258 | if ((_thr_pid = getpid()) == 1) { |
| 259 | /* |
| 260 | * Setup a new session for this process which is |
| 261 | * assumed to be running as root. |
| 262 | */ |
| 263 | if (setsid() == -1) |
| 264 | PANIC("Can't set session ID"); |
| 265 | if (revoke(_PATH_CONSOLE) != 0) |
| 266 | PANIC("Can't revoke console"); |
| 267 | if ((fd = __sys_open(_PATH_CONSOLE, O_RDWR)) < 0) |
| 268 | PANIC("Can't open console"); |
| 269 | if (setlogin("root") == -1) |
| 270 | PANIC("Can't set login to root"); |
| 271 | if (__sys_ioctl(fd, TIOCSCTTY, (char *) NULL) == -1) |
| 272 | PANIC("Can't set controlling terminal"); |
| 273 | } |
| 274 | |
| 275 | /* Initialize pthread private data. */ |
| 276 | init_private(); |
| 277 | |
| 278 | /* Set the initial thread. */ |
| 279 | if (curthread == NULL) { |
| 280 | first = 1; |
| 281 | /* Create and initialize the initial thread. */ |
| 282 | curthread = _thr_alloc(NULL); |
| 283 | if (curthread == NULL) |
| 284 | PANIC("Can't allocate initial thread"); |
| 285 | init_main_thread(curthread); |
| 286 | } |
| 287 | /* |
| 288 | * Add the thread to the thread list queue. |
| 289 | */ |
| 290 | THR_LIST_ADD(curthread); |
| 291 | _thread_active_threads = 1; |
| 292 | |
| 293 | /* Setup the thread specific data */ |
| 294 | tls_set_tcb(curthread->tcb); |
| 295 | |
| 296 | if (first) { |
| 297 | SIGFILLSET(sigset); |
| 298 | __sys_sigprocmask(SIG_SETMASK, &sigset, &oldset); |
| 299 | _thr_signal_init(); |
| 300 | _thr_initial = curthread; |
| 301 | SIGDELSET(oldset, SIGCANCEL); |
| 302 | __sys_sigprocmask(SIG_SETMASK, &oldset, NULL); |
| 303 | } |
| 304 | } |
| 305 | |
| 306 | /* |
| 307 | * This function and pthread_create() do a lot of the same things. |
| 308 | * It'd be nice to consolidate the common stuff in one place. |
| 309 | */ |
| 310 | static void |
| 311 | init_main_thread(struct pthread *thread) |
| 312 | { |
| 313 | /* Setup the thread attributes. */ |
| 314 | thread->tid = _thr_get_tid(); |
| 315 | thread->attr = _pthread_attr_default; |
| 316 | /* |
| 317 | * Set up the thread stack. |
| 318 | * |
| 319 | * Create a red zone below the main stack. All other stacks |
| 320 | * are constrained to a maximum size by the parameters |
| 321 | * passed to mmap(), but this stack is only limited by |
| 322 | * resource limits, so this stack needs an explicitly mapped |
| 323 | * red zone to protect the thread stack that is just beyond. |
| 324 | */ |
| 325 | if (mmap((void *)_usrstack - _thr_stack_initial - |
| 326 | _thr_guard_default, _thr_guard_default, 0, MAP_ANON, |
| 327 | -1, 0) == MAP_FAILED) |
| 328 | PANIC("Cannot allocate red zone for initial thread"); |
| 329 | |
| 330 | /* |
| 331 | * Mark the stack as an application supplied stack so that it |
| 332 | * isn't deallocated. |
| 333 | * |
| 334 | * XXX - I'm not sure it would hurt anything to deallocate |
| 335 | * the main thread stack because deallocation doesn't |
| 336 | * actually free() it; it just puts it in the free |
| 337 | * stack queue for later reuse. |
| 338 | */ |
| 339 | thread->attr.stackaddr_attr = (void *)_usrstack - _thr_stack_initial; |
| 340 | thread->attr.stacksize_attr = _thr_stack_initial; |
| 341 | thread->attr.guardsize_attr = _thr_guard_default; |
| 342 | thread->attr.flags |= THR_STACK_USER; |
| 343 | |
| 344 | /* |
| 345 | * Write a magic value to the thread structure |
| 346 | * to help identify valid ones: |
| 347 | */ |
| 348 | thread->magic = THR_MAGIC; |
| 349 | |
| 350 | thread->cancelflags = PTHREAD_CANCEL_ENABLE | PTHREAD_CANCEL_DEFERRED; |
| 351 | thread->name = strdup("initial thread"); |
| 352 | |
| 353 | /* Default the priority of the initial thread: */ |
| 354 | thread->base_priority = THR_DEFAULT_PRIORITY; |
| 355 | thread->active_priority = THR_DEFAULT_PRIORITY; |
| 356 | thread->inherited_priority = 0; |
| 357 | |
| 358 | /* Initialize the mutex queue: */ |
| 359 | TAILQ_INIT(&thread->mutexq); |
| 360 | TAILQ_INIT(&thread->pri_mutexq); |
| 361 | |
| 362 | thread->state = PS_RUNNING; |
| 363 | thread->uniqueid = 0; |
| 364 | |
| 365 | /* Others cleared to zero by thr_alloc() */ |
| 366 | } |
| 367 | |
| 368 | static void |
| 369 | init_private(void) |
| 370 | { |
| 371 | size_t len; |
| 372 | int mib[2]; |
| 373 | |
| 374 | _thr_umtx_init(&_mutex_static_lock); |
| 375 | _thr_umtx_init(&_cond_static_lock); |
| 376 | _thr_umtx_init(&_rwlock_static_lock); |
| 377 | _thr_umtx_init(&_keytable_lock); |
| 378 | _thr_umtx_init(&_thr_atfork_lock); |
| 379 | _thr_spinlock_init(); |
| 380 | _thr_list_init(); |
| 381 | |
| 382 | /* |
| 383 | * Avoid reinitializing some things if they don't need to be, |
| 384 | * e.g. after a fork(). |
| 385 | */ |
| 386 | if (init_once == 0) { |
| 387 | /* Find the stack top */ |
| 388 | mib[0] = CTL_KERN; |
| 389 | mib[1] = KERN_USRSTACK; |
| 390 | len = sizeof (_usrstack); |
| 391 | if (sysctl(mib, 2, &_usrstack, &len, NULL, 0) == -1) |
| 392 | PANIC("Cannot get kern.usrstack from sysctl"); |
| 393 | _thr_page_size = getpagesize(); |
| 394 | _thr_guard_default = _thr_page_size; |
| 395 | _pthread_attr_default.guardsize_attr = _thr_guard_default; |
| 396 | |
| 397 | TAILQ_INIT(&_thr_atfork_list); |
| 398 | #ifdef SYSTEM_SCOPE_ONLY |
| 399 | _thread_scope_system = 1; |
| 400 | #else |
| 401 | if (getenv("LIBPTHREAD_SYSTEM_SCOPE") != NULL) |
| 402 | _thread_scope_system = 1; |
| 403 | else if (getenv("LIBPTHREAD_PROCESS_SCOPE") != NULL) |
| 404 | _thread_scope_system = -1; |
| 405 | #endif |
| 406 | } |
| 407 | init_once = 1; |
| 408 | } |
| 409 | |
| 410 | void |
| 411 | _thread_init(void) |
| 412 | { |
| 413 | _libpthread_init(NULL); |
| 414 | } |
| 415 | |
| 416 | extern int _thread_autoinit_dummy_decl; |
| 417 | int _thread_autoinit_dummy_decl = 0; |