diff options
Diffstat (limited to 'lib/libthr/thread/thr_init.c')
| -rw-r--r-- | lib/libthr/thread/thr_init.c | 375 | 
1 files changed, 214 insertions, 161 deletions
diff --git a/lib/libthr/thread/thr_init.c b/lib/libthr/thread/thr_init.c index 45d238c88e96..f9545c262326 100644 --- a/lib/libthr/thread/thr_init.c +++ b/lib/libthr/thread/thr_init.c @@ -1,4 +1,5 @@  /* + * Copyright (c) 2003 Daniel M. Eischen <deischen@freebsd.org>   * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>   * All rights reserved.   * @@ -38,6 +39,7 @@  #include "namespace.h"  #include <sys/param.h>  #include <sys/types.h> +#include <sys/signalvar.h>  #include <machine/reg.h>  #include <sys/ioctl.h> @@ -56,6 +58,7 @@  #include <fcntl.h>  #include <paths.h>  #include <pthread.h> +#include <pthread_np.h>  #include <signal.h>  #include <stdio.h>  #include <stdlib.h> @@ -63,19 +66,22 @@  #include <unistd.h>  #include "un-namespace.h" +#include "libc_private.h"  #include "thr_private.h" -extern void _thread_init_hack(void); +int	__pthread_cond_wait(pthread_cond_t *, pthread_mutex_t *); +int	__pthread_mutex_lock(pthread_mutex_t *); +int	__pthread_mutex_trylock(pthread_mutex_t *); +void	_thread_init_hack(void) __attribute__ ((constructor)); + +static void init_private(void); +static void init_main_thread(struct pthread *thread);  /*   * All weak references used within libc should be in this table. - * This will is so that static libraries will work. - * - * XXXTHR - Check this list. + * This is so that static libraries will work.   */  static void *references[] = { -	&_thread_init_hack, -	&_thread_init,  	&_accept,  	&_bind,  	&_close, @@ -126,6 +132,7 @@ static void *references[] = {  	&_sigsuspend,  	&_socket,  	&_socketpair, +	&_thread_init_hack,  	&_wait4,  	&_write,  	&_writev @@ -138,8 +145,6 @@ static void *references[] = {   * libraries, then the actual functions will not be loaded.   */  static void *libgcc_references[] = { -	&_thread_init_hack, -	&_thread_init,  	&_pthread_once,  	&_pthread_key_create,  	&_pthread_key_delete, @@ -149,123 +154,93 @@ static void *libgcc_references[] = {  	&_pthread_mutex_destroy,  	&_pthread_mutex_lock,  	&_pthread_mutex_trylock, -	&_pthread_mutex_unlock +	&_pthread_mutex_unlock, +	&_pthread_create  }; -int _pthread_guard_default; -int _pthread_page_size; -int _pthread_stack_default; -int _pthread_stack_initial; +#define	DUAL_ENTRY(entry)	\ +	(pthread_func_t)entry, (pthread_func_t)entry -/* - * Initialize the current thread. - */ -void -init_td_common(struct pthread *td, struct pthread_attr *attrp, int reinit) -{ -	/* -	 * Some parts of a pthread are initialized only once. -	 */ -	if (!reinit) { -		memset(td, 0, sizeof(struct pthread)); -		td->cancelmode = M_DEFERRED; -		td->cancelstate = M_DEFERRED; -		td->cancellation = CS_NULL; -		memcpy(&td->attr, attrp, sizeof(struct pthread_attr)); -		td->magic = PTHREAD_MAGIC; -		TAILQ_INIT(&td->mutexq); -		td->base_priority = PTHREAD_DEFAULT_PRIORITY; -		td->active_priority = PTHREAD_DEFAULT_PRIORITY; -		td->inherited_priority = PTHREAD_MIN_PRIORITY; -	} else { -		memset(&td->join_status, 0, sizeof(struct join_status)); -	} -	td->joiner = NULL; -	td->error = 0; -	td->flags = 0; -} +static pthread_func_t jmp_table[][2] = { +	{DUAL_ENTRY(_pthread_cond_broadcast)},	/* PJT_COND_BROADCAST */ +	{DUAL_ENTRY(_pthread_cond_destroy)},	/* PJT_COND_DESTROY */ +	{DUAL_ENTRY(_pthread_cond_init)},	/* PJT_COND_INIT */ +	{DUAL_ENTRY(_pthread_cond_signal)},	/* PJT_COND_SIGNAL */ +	{(pthread_func_t)__pthread_cond_wait, +	 (pthread_func_t)_pthread_cond_wait},	/* PJT_COND_WAIT */ +	{DUAL_ENTRY(_pthread_getspecific)},	/* PJT_GETSPECIFIC */ +	{DUAL_ENTRY(_pthread_key_create)},	/* PJT_KEY_CREATE */ +	{DUAL_ENTRY(_pthread_key_delete)},	/* PJT_KEY_DELETE*/ +	{DUAL_ENTRY(_pthread_main_np)},		/* PJT_MAIN_NP */ +	{DUAL_ENTRY(_pthread_mutex_destroy)},	/* PJT_MUTEX_DESTROY */ +	{DUAL_ENTRY(_pthread_mutex_init)},	/* PJT_MUTEX_INIT */ +	{(pthread_func_t)__pthread_mutex_lock, +	 (pthread_func_t)_pthread_mutex_lock},	/* PJT_MUTEX_LOCK */ +	{(pthread_func_t)__pthread_mutex_trylock, +	 (pthread_func_t)_pthread_mutex_trylock},/* PJT_MUTEX_TRYLOCK */ +	{DUAL_ENTRY(_pthread_mutex_unlock)},	/* PJT_MUTEX_UNLOCK */ +	{DUAL_ENTRY(_pthread_mutexattr_destroy)}, /* PJT_MUTEXATTR_DESTROY */ +	{DUAL_ENTRY(_pthread_mutexattr_init)},	/* PJT_MUTEXATTR_INIT */ +	{DUAL_ENTRY(_pthread_mutexattr_settype)}, /* PJT_MUTEXATTR_SETTYPE */ +	{DUAL_ENTRY(_pthread_once)},		/* PJT_ONCE */ +	{DUAL_ENTRY(_pthread_rwlock_destroy)},	/* PJT_RWLOCK_DESTROY */ +	{DUAL_ENTRY(_pthread_rwlock_init)},	/* PJT_RWLOCK_INIT */ +	{DUAL_ENTRY(_pthread_rwlock_rdlock)},	/* PJT_RWLOCK_RDLOCK */ +	{DUAL_ENTRY(_pthread_rwlock_tryrdlock)},/* PJT_RWLOCK_TRYRDLOCK */ +	{DUAL_ENTRY(_pthread_rwlock_trywrlock)},/* PJT_RWLOCK_TRYWRLOCK */ +	{DUAL_ENTRY(_pthread_rwlock_unlock)},	/* PJT_RWLOCK_UNLOCK */ +	{DUAL_ENTRY(_pthread_rwlock_wrlock)},	/* PJT_RWLOCK_WRLOCK */ +	{DUAL_ENTRY(_pthread_self)},		/* PJT_SELF */ +	{DUAL_ENTRY(_pthread_setspecific)},	/* PJT_SETSPECIFIC */ +	{DUAL_ENTRY(_pthread_sigmask)}		/* PJT_SIGMASK */ +}; + +extern int _thread_state_running; +static int init_once = 0;  /* - * Initialize the active and dead threads list. Any threads in the active - * list will be removed and the thread td * will be marked as the - * initial thread and inserted in the list as the only thread. Any threads - * in the dead threads list will also be removed. + * For the shared version of the threads library, the above is sufficient. + * But for the archive version of the library, we need a little bit more. + * Namely, we must arrange for this particular module to be pulled in from + * the archive library at link time.  To accomplish that, we define and + * initialize a variable, "_thread_autoinit_dummy_decl".  This variable is + * referenced (as an extern) from libc/stdlib/exit.c. This will always + * create a need for this module, ensuring that it is present in the + * executable.   */ +extern int _thread_autoinit_dummy_decl; +int _thread_autoinit_dummy_decl = 0; +  void -init_tdlist(struct pthread *td, int reinit) +_thread_init_hack(void)  { -	struct pthread *tdTemp, *tdTemp2; - -	_thread_initial = td; -	td->name = strdup("_thread_initial"); - -	/* -	 * If this is not the first initialization, remove any entries -	 * that may be in the list and deallocate their memory. Also -	 * destroy any global pthread primitives (they will be recreated). -	 */ -	if (reinit) { -		TAILQ_FOREACH_SAFE(tdTemp, &_thread_list, tle, tdTemp2) { -			if (tdTemp != NULL && tdTemp != td) { -				TAILQ_REMOVE(&_thread_list, tdTemp, tle); -				free(tdTemp); -			} -		} -		TAILQ_FOREACH_SAFE(tdTemp, &_dead_list, dle, tdTemp2) { -			if (tdTemp != NULL) { -				TAILQ_REMOVE(&_dead_list, tdTemp, dle); -				free(tdTemp); -			} -		} -		_pthread_mutex_destroy(&dead_list_lock); -	} else { -		TAILQ_INIT(&_thread_list); -		TAILQ_INIT(&_dead_list); - -		/* Insert this thread as the first thread in the active list */ -		TAILQ_INSERT_HEAD(&_thread_list, td, tle); -	} -	/* -	 * Initialize the active thread list lock and the -	 * dead threads list lock. -	 */ -	memset(&thread_list_lock, 0, sizeof(spinlock_t)); -	if (_pthread_mutex_init(&dead_list_lock,NULL) != 0) -		PANIC("Failed to initialize garbage collector primitives"); +	_libpthread_init(NULL);  } +  /* - * Threaded process initialization + * Threaded process initialization. + * + * This is only called under two conditions: + * + *   1) Some thread routines have detected that the library hasn't yet + *      been initialized (_thr_initial == NULL && curthread == NULL), or + * + *   2) An explicit call to reinitialize after a fork (indicated + *      by curthread != NULL)   */  void -_thread_init(void) +_libpthread_init(struct pthread *curthread)  { -	struct pthread	*pthread; -	int		fd; -	size_t		len; -	int		mib[2]; -	int		error; +	int fd, first = 0; +	sigset_t sigset, oldset;  	/* Check if this function has already been called: */ -	if (_thread_initial) -		/* Only initialise the threaded application once. */ +	if ((_thr_initial != NULL) && (curthread == NULL)) +		/* Only initialize the threaded application once. */  		return; -	_pthread_page_size = getpagesize(); -	_pthread_guard_default = getpagesize(); -	if (sizeof(void *) == 8) { -		_pthread_stack_default = PTHREAD_STACK64_DEFAULT; -		_pthread_stack_initial = PTHREAD_STACK64_INITIAL; -	} -	else { -		_pthread_stack_default = PTHREAD_STACK32_DEFAULT; -		_pthread_stack_initial = PTHREAD_STACK32_INITIAL; -	} - -	pthread_attr_default.guardsize_attr = _pthread_guard_default; -	pthread_attr_default.stacksize_attr = _pthread_stack_default; -  	/*  	 * Make gcc quiescent about {,libgcc_}references not being  	 * referenced: @@ -273,11 +248,22 @@ _thread_init(void)  	if ((references[0] == NULL) || (libgcc_references[0] == NULL))  		PANIC("Failed loading mandatory references in _thread_init"); +	/* Pull debug symbols in for static binary */ +	_thread_state_running = PS_RUNNING; + +	/* +	 * Check the size of the jump table to make sure it is preset +	 * with the correct number of entries. +	 */ +	if (sizeof(jmp_table) != (sizeof(pthread_func_t) * PJT_MAX * 2)) +		PANIC("Thread jump table not properly initialized"); +	memcpy(__thr_jtable, jmp_table, sizeof(jmp_table)); +  	/*  	 * Check for the special case of this process running as  	 * or in place of init as pid = 1:  	 */ -	if (getpid() == 1) { +	if ((_thr_pid = getpid()) == 1) {  		/*  		 * Setup a new session for this process which is  		 * assumed to be running as root. @@ -292,74 +278,141 @@ _thread_init(void)  			PANIC("Can't set login to root");  		if (__sys_ioctl(fd, TIOCSCTTY, (char *) NULL) == -1)  			PANIC("Can't set controlling terminal"); -		if (__sys_dup2(fd, 0) == -1 || -		    __sys_dup2(fd, 1) == -1 || -		    __sys_dup2(fd, 2) == -1) -			PANIC("Can't dup2");  	} -	/* Allocate memory for the thread structure of the initial thread: */ -	if ((pthread = (pthread_t) malloc(sizeof(struct pthread))) == NULL) { -		/* -		 * Insufficient memory to initialise this application, so -		 * abort: -		 */ -		PANIC("Cannot allocate memory for initial thread"); +	/* Initialize pthread private data. */ +	init_private(); + +	/* Set the initial thread. */ +	if (curthread == NULL) { +		first = 1; +		/* Create and initialize the initial thread. */ +		curthread = _thr_alloc(NULL); +		if (curthread == NULL) +			PANIC("Can't allocate initial thread"); +		init_main_thread(curthread);  	} +	/* +	 * Add the thread to the thread list queue. +	 */ +	THR_LIST_ADD(curthread); +	_thread_active_threads = 1; -	init_tdlist(pthread, 0); -	init_td_common(pthread, &pthread_attr_default, 0); -	pthread->arch_id = _set_curthread(NULL, pthread, &error); +	/* Setup the thread specific data */ +	_tcb_set(curthread->tcb); -	/* Get our thread id. */ -	thr_self(&pthread->thr_id); +	if (first) { +		SIGFILLSET(sigset); +		SIGDELSET(sigset, SIGTRAP); +		__sys_sigprocmask(SIG_SETMASK, &sigset, &oldset); +		_thr_signal_init(); +		_thr_initial = curthread; +		SIGDELSET(oldset, SIGCANCEL); +		__sys_sigprocmask(SIG_SETMASK, &oldset, NULL); +	} +} -	/* Find the stack top */ -	mib[0] = CTL_KERN; -	mib[1] = KERN_USRSTACK; -	len = sizeof (_usrstack); -	if (sysctl(mib, 2, &_usrstack, &len, NULL, 0) == -1) -		_usrstack = (void *)USRSTACK; +/* + * This function and pthread_create() do a lot of the same things. + * It'd be nice to consolidate the common stuff in one place. + */ +static void +init_main_thread(struct pthread *thread) +{ +	/* Setup the thread attributes. */ +	thr_self(&thread->tid); +	thread->attr = _pthread_attr_default;  	/* -	 * Create a red zone below the main stack.  All other stacks are -	 * constrained to a maximum size by the paramters passed to -	 * mmap(), but this stack is only limited by resource limits, so -	 * this stack needs an explicitly mapped red zone to protect the -	 * thread stack that is just beyond. +	 * Set up the thread stack. +	 * +	 * Create a red zone below the main stack.  All other stacks +	 * are constrained to a maximum size by the parameters +	 * passed to mmap(), but this stack is only limited by +	 * resource limits, so this stack needs an explicitly mapped +	 * red zone to protect the thread stack that is just beyond.  	 */ -	if (mmap(_usrstack - _pthread_stack_initial - -	    _pthread_guard_default, _pthread_guard_default, 0, -	    MAP_ANON, -1, 0) == MAP_FAILED) +	if (mmap((void *)_usrstack - _thr_stack_initial - +	    _thr_guard_default, _thr_guard_default, 0, MAP_ANON, +	    -1, 0) == MAP_FAILED)  		PANIC("Cannot allocate red zone for initial thread"); -	/* Set the main thread stack pointer. */ -	pthread->stack = _usrstack - _pthread_stack_initial; +	/* +	 * Mark the stack as an application supplied stack so that it +	 * isn't deallocated. +	 * +	 * XXX - I'm not sure it would hurt anything to deallocate +	 *       the main thread stack because deallocation doesn't +	 *       actually free() it; it just puts it in the free +	 *       stack queue for later reuse. +	 */ +	thread->attr.stackaddr_attr = (void *)_usrstack - _thr_stack_initial; +	thread->attr.stacksize_attr = _thr_stack_initial; +	thread->attr.guardsize_attr = _thr_guard_default; +	thread->attr.flags |= THR_STACK_USER; + +	/* +	 * Write a magic value to the thread structure +	 * to help identify valid ones: +	 */ +	thread->magic = THR_MAGIC; -	/* Set the stack attributes. */ -	pthread->attr.stackaddr_attr = pthread->stack; -	pthread->attr.stacksize_attr = _pthread_stack_initial; +	thread->cancelflags = PTHREAD_CANCEL_ENABLE | PTHREAD_CANCEL_DEFERRED; +	thread->name = strdup("initial thread"); -	/* Setup the context for initial thread. */ -	getcontext(&pthread->ctx); -	pthread->ctx.uc_stack.ss_sp = pthread->stack; -	pthread->ctx.uc_stack.ss_size = _pthread_stack_initial; +	/* Default the priority of the initial thread: */ +	thread->base_priority = THR_DEFAULT_PRIORITY; +	thread->active_priority = THR_DEFAULT_PRIORITY; +	thread->inherited_priority = 0; -	/* Initialize the atfork list and mutex */ -	TAILQ_INIT(&_atfork_list); -	_pthread_mutex_init(&_atfork_mutex, NULL); -} +	/* Initialize the mutex queue: */ +	TAILQ_INIT(&thread->mutexq); +	TAILQ_INIT(&thread->pri_mutexq); -/* - * Special start up code for NetBSD/Alpha - */ -#if	defined(__NetBSD__) && defined(__alpha__) -int -main(int argc, char *argv[], char *env); +	thread->state = PS_RUNNING; +	thread->uniqueid = 0; -int -_thread_main(int argc, char *argv[], char *env) -{ -	_thread_init(); -	return (main(argc, argv, env)); +	/* Others cleared to zero by thr_alloc() */  } + +static void +init_private(void) +{ +	size_t len; +	int mib[2]; + +	_thr_umtx_init(&_mutex_static_lock); +	_thr_umtx_init(&_cond_static_lock); +	_thr_umtx_init(&_rwlock_static_lock); +	_thr_umtx_init(&_keytable_lock); +	_thr_umtx_init(&_thr_atfork_lock); +	_thr_spinlock_init(); +	_thr_list_init(); + +	/* +	 * Avoid reinitializing some things if they don't need to be, +	 * e.g. after a fork(). +	 */ +	if (init_once == 0) { +		/* Find the stack top */ +		mib[0] = CTL_KERN; +		mib[1] = KERN_USRSTACK; +		len = sizeof (_usrstack); +		if (sysctl(mib, 2, &_usrstack, &len, NULL, 0) == -1) +			PANIC("Cannot get kern.usrstack from sysctl"); +		_thr_page_size = getpagesize(); +		_thr_guard_default = _thr_page_size; +		_pthread_attr_default.guardsize_attr = _thr_guard_default; +		_pthread_attr_default.stacksize_attr = _thr_stack_default; + +		TAILQ_INIT(&_thr_atfork_list); +#ifdef SYSTEM_SCOPE_ONLY +		_thr_scope_system = 1; +#else +		if (getenv("LIBPTHREAD_SYSTEM_SCOPE") != NULL) +			_thr_scope_system = 1; +		else if (getenv("LIBPTHREAD_PROCESS_SCOPE") != NULL) +			_thr_scope_system = -1;  #endif +	} +	init_once = 1; +}  | 
