diff options
| author | John Birrell <jb@FreeBSD.org> | 1998-04-29 09:59:34 +0000 | 
|---|---|---|
| committer | John Birrell <jb@FreeBSD.org> | 1998-04-29 09:59:34 +0000 | 
| commit | 4a027d50c7f3f30178a89b3159ba9e4b44f06885 (patch) | |
| tree | b7a4ea836e97e11d436f9a6657ea6a9ec8036c33 /lib/libpthread | |
| parent | ccf47cfcedf9f3db1780bc3b52ca0adb4480d3f6 (diff) | |
Notes
Diffstat (limited to 'lib/libpthread')
38 files changed, 865 insertions, 1224 deletions
| diff --git a/lib/libpthread/thread/Makefile.inc b/lib/libpthread/thread/Makefile.inc index 4f1b308e9062..924453fec8ab 100644 --- a/lib/libpthread/thread/Makefile.inc +++ b/lib/libpthread/thread/Makefile.inc @@ -1,4 +1,4 @@ -#	$Id: Makefile.inc,v 1.9 1997/05/06 00:49:36 jdp Exp $ +#	$Id: Makefile.inc,v 1.10 1997/11/24 23:04:29 alex Exp $  # uthread sources  .PATH: ${.CURDIR}/uthread @@ -34,6 +34,7 @@ SRCS+= \  	uthread_fcntl.c \  	uthread_fd.c \  	uthread_file.c \ +	uthread_find_thread.c \  	uthread_flock.c \  	uthread_fork.c \  	uthread_fstat.c \ @@ -51,7 +52,6 @@ SRCS+= \  	uthread_kern.c \  	uthread_kill.c \  	uthread_listen.c \ -	uthread_longjmp.c \  	uthread_mattr_init.c \  	uthread_mattr_kind_np.c \  	uthread_multi_np.c \ @@ -70,23 +70,22 @@ SRCS+= \  	uthread_self.c \  	uthread_sendto.c \  	uthread_seterrno.c \ -	uthread_setjmp.c \  	uthread_setprio.c \  	uthread_setsockopt.c \  	uthread_shutdown.c \  	uthread_sig.c \  	uthread_sigaction.c \  	uthread_sigblock.c \ -	uthread_single_np.c \  	uthread_sigmask.c \ -	uthread_signal.c \  	uthread_sigprocmask.c \  	uthread_sigsetmask.c \  	uthread_sigsuspend.c \  	uthread_sigwait.c \ +	uthread_single_np.c \  	uthread_socket.c \  	uthread_socketpair.c \  	uthread_spec.c \ +	uthread_spinlock.c \  	uthread_suspend_np.c \  	uthread_wait4.c \  	uthread_write.c \ diff --git a/lib/libpthread/thread/thr_close.c b/lib/libpthread/thread/thr_close.c index 26a8fbfd5904..5678e2e76533 100644 --- a/lib/libpthread/thread/thr_close.c +++ b/lib/libpthread/thread/thr_close.c @@ -1,5 +1,5 @@  /* - * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>. + * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>   * All rights reserved.   *   * Redistribution and use in source and binary forms, with or without @@ -48,9 +48,6 @@ close(int fd)  	/* Lock the file descriptor while the file is closed: */  	if ((ret = _thread_fd_lock(fd, FD_RDWR, NULL, __FILE__, __LINE__)) == 0) { -		/* Block signals: */ -		_thread_kern_sig_block(&status); -  		/* Get file descriptor status. */  		fstat(fd, &sb); @@ -84,12 +81,8 @@ close(int fd)  		/* Close the file descriptor: */  		ret = _thread_sys_close(fd); -		/* Free the file descriptor table entry: */  		free(_thread_fd_table[fd]);  		_thread_fd_table[fd] = NULL; - -		/* Unblock signals again: */ -		_thread_kern_sig_unblock(status);  	}  	return (ret);  } diff --git a/lib/libpthread/thread/thr_cond.c b/lib/libpthread/thread/thr_cond.c index e7fcc62e155c..cb088534daa8 100644 --- a/lib/libpthread/thread/thr_cond.c +++ b/lib/libpthread/thread/thr_cond.c @@ -43,9 +43,9 @@ pthread_cond_init(pthread_cond_t * cond, const pthread_condattr_t * cond_attr)  	pthread_cond_t	pcond;  	int             rval = 0; -	if (cond == NULL) { +	if (cond == NULL)  		rval = EINVAL; -	} else { +	else {  		/*  		 * Check if a pointer to a condition variable attribute  		 * structure was passed by the caller:  @@ -85,6 +85,7 @@ pthread_cond_init(pthread_cond_t * cond, const pthread_condattr_t * cond_attr)  				_thread_queue_init(&pcond->c_queue);  				pcond->c_flags |= COND_FLAGS_INITED;  				pcond->c_type = type; +				pcond->access_lock = 0;  				*cond = pcond;  			}  		} @@ -98,31 +99,23 @@ pthread_cond_destroy(pthread_cond_t * cond)  {  	int             rval = 0; -	if (cond == NULL || *cond == NULL) { +	if (cond == NULL || *cond == NULL)  		rval = EINVAL; -	} else { -		/* Process according to condition variable type: */ -		switch ((*cond)->c_type) { -		/* Fast condition variable: */ -		case COND_TYPE_FAST: -			/* Nothing to do here. */ -			break; +	else { +		/* Lock the condition variable structure: */ +		_spinlock(&(*cond)->access_lock); -		/* Trap invalid condition variable types: */ -		default: -			/* Return an invalid argument error: */ -			rval = EINVAL; -			break; -		} +		/* +		 * Free the memory allocated for the condition +		 * variable structure: +		 */ +		free(*cond); -		/* Check for errors: */ -		if (rval == 0) { -			/* Destroy the contents of the condition structure: */ -			_thread_queue_init(&(*cond)->c_queue); -			(*cond)->c_flags = 0; -			free(*cond); -			*cond = NULL; -		} +		/* +		 * NULL the caller's pointer now that the condition +		 * variable has been destroyed: +		 */ +		*cond = NULL;  	}  	/* Return the completion status: */  	return (rval); @@ -143,8 +136,8 @@ pthread_cond_wait(pthread_cond_t * cond, pthread_mutex_t * mutex)  	 */  	else if (*cond != NULL ||  	    (rval = pthread_cond_init(cond,NULL)) == 0) { -		/* Block signals: */ -		_thread_kern_sig_block(&status); +		/* Lock the condition variable structure: */ +		_spinlock(&(*cond)->access_lock);  		/* Process according to condition variable type: */  		switch ((*cond)->c_type) { @@ -162,12 +155,15 @@ pthread_cond_wait(pthread_cond_t * cond, pthread_mutex_t * mutex)  			/* Wait forever: */  			_thread_run->wakeup_time.tv_sec = -1; +			/* Unlock the condition variable structure: */ +			_atomic_unlock(&(*cond)->access_lock); +  			/* Schedule the next thread: */  			_thread_kern_sched_state(PS_COND_WAIT,  			    __FILE__, __LINE__); -			/* Block signals: */ -			_thread_kern_sig_block(NULL); +			/* Lock the condition variable structure: */ +			_spinlock(&(*cond)->access_lock);  			/* Lock the mutex: */  			rval = pthread_mutex_lock(mutex); @@ -180,8 +176,8 @@ pthread_cond_wait(pthread_cond_t * cond, pthread_mutex_t * mutex)  			break;  		} -		/* Unblock signals: */ -		_thread_kern_sig_unblock(status); +	/* Unlock the condition variable structure: */ +	_atomic_unlock(&(*cond)->access_lock);  	}  	/* Return the completion status: */ @@ -204,8 +200,8 @@ pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex,  	 */  	else if (*cond != NULL ||  	    (rval = pthread_cond_init(cond,NULL)) == 0) { -		/* Block signals: */ -		_thread_kern_sig_block(&status); +		/* Lock the condition variable structure: */ +		_spinlock(&(*cond)->access_lock);  		/* Process according to condition variable type: */  		switch ((*cond)->c_type) { @@ -233,12 +229,15 @@ pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex,  				 */  				_thread_queue_deq(&(*cond)->c_queue);  			} else { +				/* Unlock the condition variable structure: */ +				_atomic_unlock(&(*cond)->access_lock); +  				/* Schedule the next thread: */  				_thread_kern_sched_state(PS_COND_WAIT,  				    __FILE__, __LINE__); -				/* Block signals: */ -				_thread_kern_sig_block(NULL); +				/* Lock the condition variable structure: */ +				_spinlock(&(*cond)->access_lock);  				/* Lock the mutex: */  				if ((rval = pthread_mutex_lock(mutex)) != 0) { @@ -258,8 +257,8 @@ pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex,  			break;  		} -		/* Unblock signals: */ -		_thread_kern_sig_unblock(status); +	/* Unlock the condition variable structure: */ +	_atomic_unlock(&(*cond)->access_lock);  	}  	/* Return the completion status: */ @@ -273,11 +272,11 @@ pthread_cond_signal(pthread_cond_t * cond)  	int             status;  	pthread_t       pthread; -	if (cond == NULL || *cond == NULL) { +	if (cond == NULL || *cond == NULL)  		rval = EINVAL; -	} else { -		/* Block signals: */ -		_thread_kern_sig_block(&status); +	else { +		/* Lock the condition variable structure: */ +		_spinlock(&(*cond)->access_lock);  		/* Process according to condition variable type: */  		switch ((*cond)->c_type) { @@ -297,8 +296,8 @@ pthread_cond_signal(pthread_cond_t * cond)  			break;  		} -		/* Unblock signals: */ -		_thread_kern_sig_unblock(status); +		/* Unlock the condition variable structure: */ +		_atomic_unlock(&(*cond)->access_lock);  	}  	/* Return the completion status: */ @@ -312,34 +311,38 @@ pthread_cond_broadcast(pthread_cond_t * cond)  	int             status;  	pthread_t       pthread; -	/* Block signals: */ -	_thread_kern_sig_block(&status); +	if (cond == NULL || *cond == NULL) +		rval = EINVAL; +	else { +		/* Lock the condition variable structure: */ +		_spinlock(&(*cond)->access_lock); -	/* Process according to condition variable type: */ -	switch ((*cond)->c_type) { -	/* Fast condition variable: */ -	case COND_TYPE_FAST: -		/* -		 * Enter a loop to bring all threads off the -		 * condition queue: -		 */ -		while ((pthread = -		    _thread_queue_deq(&(*cond)->c_queue)) != NULL) { -			/* Allow the thread to run: */ -			PTHREAD_NEW_STATE(pthread,PS_RUNNING); +		/* Process according to condition variable type: */ +		switch ((*cond)->c_type) { +		/* Fast condition variable: */ +		case COND_TYPE_FAST: +			/* +			 * Enter a loop to bring all threads off the +			 * condition queue: +			 */ +			while ((pthread = +			    _thread_queue_deq(&(*cond)->c_queue)) != NULL) { +				/* Allow the thread to run: */ +				PTHREAD_NEW_STATE(pthread,PS_RUNNING); +			} +			break; +	 +		/* Trap invalid condition variable types: */ +		default: +			/* Return an invalid argument error: */ +			rval = EINVAL; +			break;  		} -		break; -	/* Trap invalid condition variable types: */ -	default: -		/* Return an invalid argument error: */ -		rval = EINVAL; -		break; +		/* Unlock the condition variable structure: */ +		_atomic_unlock(&(*cond)->access_lock);  	} -	/* Unblock signals: */ -	_thread_kern_sig_unblock(status); -  	/* Return the completion status: */  	return (rval);  } diff --git a/lib/libpthread/thread/thr_create.c b/lib/libpthread/thread/thr_create.c index c9c6c9fb6d42..7603dd3a30c9 100644 --- a/lib/libpthread/thread/thr_create.c +++ b/lib/libpthread/thread/thr_create.c @@ -1,5 +1,5 @@  /* - * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>. + * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>   * All rights reserved.   *   * Redistribution and use in source and binary forms, with or without @@ -43,8 +43,8 @@  #include "libc_private.h"  int -_thread_create(pthread_t * thread, const pthread_attr_t * attr, -	       void *(*start_routine) (void *), void *arg, pthread_t parent) +pthread_create(pthread_t * thread, const pthread_attr_t * attr, +	       void *(*start_routine) (void *), void *arg)  {  	int             i;  	int             ret = 0; @@ -53,8 +53,11 @@ _thread_create(pthread_t * thread, const pthread_attr_t * attr,  	pthread_attr_t	pattr;  	void           *stack; -	/* Block signals: */ -	_thread_kern_sig_block(&status); +	/* +	 * Locking functions in libc are required when there are +	 * threads other than the initial thread. +	 */ +	__isthreaded = 1;  	/* Allocate memory for the thread structure: */  	if ((new_thread = (pthread_t) malloc(sizeof(struct pthread))) == NULL) { @@ -103,71 +106,33 @@ _thread_create(pthread_t * thread, const pthread_attr_t * attr,  			/* Initialise the thread for signals: */  			new_thread->sigmask = _thread_run->sigmask; -			/* -			 * Enter a loop to initialise the signal handler -			 * array:  -			 */ -			for (i = 1; i < NSIG; i++) { -				/* Default the signal handler: */ -				sigfillset(&new_thread->act[i - 1].sa_mask); -				new_thread->act[i - 1].sa_handler = _thread_run->act[i - 1].sa_handler; -				new_thread->act[i - 1].sa_flags = _thread_run->act[i - 1].sa_flags; -			} -  			/* Initialise the jump buffer: */ -			_thread_sys_setjmp(new_thread->saved_jmp_buf); +			setjmp(new_thread->saved_jmp_buf);  			/*  			 * Set up new stack frame so that it looks like it  			 * returned from a longjmp() to the beginning of -			 * _thread_start(). Check if this is a user thread:  +			 * _thread_start().  			 */ -			if (parent == NULL) { -				/* Use the user start function: */  #if	defined(__FreeBSD__)  #if	defined(__alpha__) -				new_thread->saved_jmp_buf[0]._jb[2] = (long) _thread_start; -				new_thread->saved_jmp_buf[0]._jb[4 + R_RA] = 0; -				new_thread->saved_jmp_buf[0]._jb[4 + R_T12] = (long) _thread_start; +			new_thread->saved_jmp_buf[0]._jb[2] = (long) _thread_start; +			new_thread->saved_jmp_buf[0]._jb[4 + R_RA] = 0; +			new_thread->saved_jmp_buf[0]._jb[4 + R_T12] = (long) _thread_start;  #else -				new_thread->saved_jmp_buf[0]._jb[0] = (long) _thread_start; +			new_thread->saved_jmp_buf[0]._jb[0] = (long) _thread_start;  #endif  #elif	defined(__NetBSD__)  #if	defined(__alpha__) -				new_thread->saved_jmp_buf[2] = (long) _thread_start; -				new_thread->saved_jmp_buf[4 + R_RA] = 0; -				new_thread->saved_jmp_buf[4 + R_T12] = (long) _thread_start; +			new_thread->saved_jmp_buf[2] = (long) _thread_start; +			new_thread->saved_jmp_buf[4 + R_RA] = 0; +			new_thread->saved_jmp_buf[4 + R_T12] = (long) _thread_start;  #else -				new_thread->saved_jmp_buf[0] = (long) _thread_start; +			new_thread->saved_jmp_buf[0] = (long) _thread_start;  #endif  #else  #error	"Don't recognize this operating system!"  #endif -			} else { -				/* -				 * Use the (funny) signal handler start -				 * function:  -				 */ -#if	defined(__FreeBSD__) -#if	defined(__alpha__) -				new_thread->saved_jmp_buf[0]._jb[2] = (long) _thread_start_sig_handler; -				new_thread->saved_jmp_buf[0]._jb[4 + R_RA] = 0; -				new_thread->saved_jmp_buf[0]._jb[4 + R_T12] = (long) _thread_start_sig_handler; -#else -				new_thread->saved_jmp_buf[0]._jb[0] = (int) _thread_start_sig_handler; -#endif -#elif	defined(__NetBSD__) -#if	defined(__alpha__) -				new_thread->saved_jmp_buf[2] = (long) _thread_start_sig_handler; -				new_thread->saved_jmp_buf[4 + R_RA] = 0; -				new_thread->saved_jmp_buf[4 + R_T12] = (long) _thread_start_sig_handler; -#else -				new_thread->saved_jmp_buf[0] = (long) _thread_start_sig_handler; -#endif -#else -#error	"Don't recognize this operating system!" -#endif -			}  			/* The stack starts high and builds down: */  #if	defined(__FreeBSD__) @@ -215,57 +180,26 @@ _thread_create(pthread_t * thread, const pthread_attr_t * attr,  			new_thread->cleanup = NULL;  			new_thread->queue = NULL;  			new_thread->qnxt = NULL; -			new_thread->parent_thread = parent;  			new_thread->flags = 0; +			/* Lock the thread list: */ +			_lock_thread_list(); +  			/* Add the thread to the linked list of all threads: */  			new_thread->nxt = _thread_link_list;  			_thread_link_list = new_thread; +			/* Unlock the thread list: */ +			_unlock_thread_list(); +  			/* Return a pointer to the thread structure: */ -			if(thread) -				(*thread) = new_thread; +			(*thread) = new_thread; -			/* Check if a parent thread was specified: */ -			if (parent != NULL) { -				/* -				 * A parent thread was specified, so this is -				 * a signal handler thread which must now -				 * wait for the signal handler to complete:  -				 */ -				PTHREAD_NEW_STATE(parent,PS_SIGTHREAD); -			} else { -				/* Schedule the new user thread: */ -				_thread_kern_sched(NULL); -			} +			/* Schedule the new user thread: */ +			_thread_kern_sched(NULL);  		}  	} -	/* Unblock signals: */ -	_thread_kern_sig_unblock(status); - -	/* Return the status: */ -	return (ret); -} - -int -pthread_create(pthread_t * thread, const pthread_attr_t * attr, -	       void *(*start_routine) (void *), void *arg) -{ -	int             ret = 0; - -	/* -	 * Locking functions in libc are required when there are -	 * threads other than the initial thread. -	 */ -	__isthreaded = 1; - -	/* -	 * Call the low level thread creation function which allows a parent -	 * thread to be specified:  -	 */ -	ret = _thread_create(thread, attr, start_routine, arg, NULL); -  	/* Return the status: */  	return (ret);  } @@ -279,33 +213,4 @@ _thread_start(void)  	/* This point should never be reached. */  	PANIC("Thread has resumed after exit");  } - -void -_thread_start_sig_handler(void) -{ -	int             sig; -	long            arg; -	void            (*sig_routine) (int); - -	/* -	 * Cast the argument from 'void *' to a variable that is NO SMALLER -	 * than a pointer (otherwise gcc under NetBSD/Alpha will complain):  -	 */ -	arg = (long) _thread_run->arg; - -	/* Cast the argument as a signal number: */ -	sig = (int) arg; - -	/* Cast a pointer to the signal handler function: */ -	sig_routine = (void (*) (int)) _thread_run->start_routine; - -	/* Call the signal handler function: */ -	(*sig_routine) (sig); - -	/* Exit the signal handler thread: */ -	pthread_exit(&arg); - -	/* This point should never be reached. */ -	PANIC("Signal handler thread has resumed after exit"); -}  #endif diff --git a/lib/libpthread/thread/thr_detach.c b/lib/libpthread/thread/thr_detach.c index 57c073ab3ab9..da456bfbab90 100644 --- a/lib/libpthread/thread/thr_detach.c +++ b/lib/libpthread/thread/thr_detach.c @@ -42,14 +42,11 @@ pthread_detach(pthread_t pthread)  	int             status;  	pthread_t       next_thread; -	/* Block signals: */ -	_thread_kern_sig_block(&status); -  	/* Check for invalid calling parameters: */ -	if (pthread == NULL || pthread->magic != PTHREAD_MAGIC) { +	if (pthread == NULL || pthread->magic != PTHREAD_MAGIC)  		/* Return an invalid argument error: */  		rval = EINVAL; -	} +  	/* Check if the thread has not been detached: */  	else if ((pthread->attr.flags & PTHREAD_DETACHED) == 0) {  		/* Flag the thread as detached: */ @@ -60,13 +57,9 @@ pthread_detach(pthread_t pthread)  			/* Make the thread run: */  			PTHREAD_NEW_STATE(next_thread,PS_RUNNING);  		} -	} else { +	} else  		/* Return an error: */  		rval = EINVAL; -	} - -	/* Unblock signals: */ -	_thread_kern_sig_unblock(status);  	/* Return the completion status: */  	return (rval); diff --git a/lib/libpthread/thread/thr_exit.c b/lib/libpthread/thread/thr_exit.c index 15bcfa36f4f4..4bc7da90bf1f 100644 --- a/lib/libpthread/thread/thr_exit.c +++ b/lib/libpthread/thread/thr_exit.c @@ -1,5 +1,5 @@  /* - * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>. + * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>   * All rights reserved.   *   * Redistribution and use in source and binary forms, with or without @@ -102,9 +102,6 @@ pthread_exit(void *status)  	long            l;  	pthread_t       pthread; -	/* Block signals: */ -	_thread_kern_sig_block(NULL); -  	/* Save the return value: */  	_thread_run->ret = status; @@ -126,6 +123,9 @@ pthread_exit(void *status)  		PTHREAD_NEW_STATE(pthread,PS_RUNNING);  	} +	/* Lock the thread list: */ +	_lock_thread_list(); +  	/* Check if the running thread is at the head of the linked list: */  	if (_thread_link_list == _thread_run) {  		/* There is no previous thread: */ @@ -153,39 +153,12 @@ pthread_exit(void *status)  		}  	} -	/* Check if this is a signal handler thread: */ -	if (_thread_run->parent_thread != NULL) { -		/* -		 * Enter a loop to search for other threads with the same -		 * parent:  -		 */ -		for (pthread = _thread_link_list; pthread != NULL; pthread = pthread->nxt) { -			/* Compare the parent thread pointers: */ -			if (pthread->parent_thread == _thread_run->parent_thread) { -				/* -				 * The parent thread is waiting on at least -				 * one other signal handler. Exit the loop -				 * now that this is known.  -				 */ -				break; -			} -		} +	/* Unlock the thread list: */ +	_unlock_thread_list(); -		/* -		 * Check if the parent is not waiting on any other signal -		 * handler threads and if it hasn't died in the meantime: -		 */ -		if (pthread == NULL && _thread_run->parent_thread->state != PS_DEAD) { -			/* Allow the parent thread to run again: */ -			PTHREAD_NEW_STATE(_thread_run->parent_thread,PS_RUNNING); -		} -		/* Get the signal number: */ -		l = (long) _thread_run->arg; -		sig = (int) l; +	/* Lock the dead thread list: */ +	_lock_dead_thread_list(); -		/* Unblock the signal from the parent thread: */ -		sigdelset(&_thread_run->parent_thread->sigmask, sig); -	}  	/*  	 * This thread will never run again. Add it to the list of dead  	 * threads:  @@ -193,6 +166,9 @@ pthread_exit(void *status)  	_thread_run->nxt = _thread_dead;  	_thread_dead = _thread_run; +	/* Unlock the dead thread list: */ +	_unlock_dead_thread_list(); +  	/*  	 * The running thread is no longer in the thread link list so it will  	 * now die:  diff --git a/lib/libpthread/thread/thr_fcntl.c b/lib/libpthread/thread/thr_fcntl.c index f83ee5098f37..9a50c1c159c8 100644 --- a/lib/libpthread/thread/thr_fcntl.c +++ b/lib/libpthread/thread/thr_fcntl.c @@ -1,5 +1,5 @@  /* - * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>. + * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>   * All rights reserved.   *   * Redistribution and use in source and binary forms, with or without @@ -46,9 +46,6 @@ fcntl(int fd, int cmd,...)  	int             status;  	va_list         ap; -	/* Block signals: */ -	_thread_kern_sig_block(&status); -  	/* Lock the file descriptor: */  	if ((ret = _thread_fd_lock(fd, FD_RDWR, NULL, __FILE__, __LINE__)) == 0) {  		/* Initialise the variable argument list: */ @@ -56,7 +53,7 @@ fcntl(int fd, int cmd,...)  		/* Process according to file control command type: */  		switch (cmd) { -			/* Duplicate a file descriptor: */ +		/* Duplicate a file descriptor: */  		case F_DUPFD:  			/*  			 * Get the file descriptor that the caller wants to @@ -107,8 +104,6 @@ fcntl(int fd, int cmd,...)  		/* Unlock the file descriptor: */  		_thread_fd_unlock(fd, FD_RDWR);  	} -	/* Unblock signals: */ -	_thread_kern_sig_unblock(status);  	/* Return the completion status: */  	return (ret); diff --git a/lib/libpthread/thread/thr_find_thread.c b/lib/libpthread/thread/thr_find_thread.c new file mode 100644 index 000000000000..99e302306d2a --- /dev/null +++ b/lib/libpthread/thread/thr_find_thread.c @@ -0,0 +1,97 @@ +/* + * Copyright (c) 1998 John Birrell <jb@cimlogic.com.au>. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + *    notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + *    notice, this list of conditions and the following disclaimer in the + *    documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + *    must display the following acknowledgement: + *	This product includes software developed by John Birrell. + * 4. Neither the name of the author nor the names of any co-contributors + *    may be used to endorse or promote products derived from this software + *    without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ +#include <errno.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +/* Find a thread in the linked list of active threads: */ +int +_find_thread(pthread_t pthread) +{ +	pthread_t pthread1; + +	/* Check if the caller has specified an invalid thread: */ +	if (pthread == NULL || pthread->magic != PTHREAD_MAGIC) +		/* Invalid thread: */ +		return(EINVAL); + +	/* Lock the thread list: */ +	_lock_thread_list(); + +	/* Point to the first thread in the list: */ +	pthread1 = _thread_link_list; + +	/* Search for the thread to join to: */ +	while (pthread1 != NULL && pthread1 != pthread) { +		/* Point to the next thread: */ +		pthread1 = pthread1->nxt; +	} + +	/* Unlock the thread list: */ +	_unlock_thread_list(); + +	/* Return zero if the thread exists: */ +	return ((pthread1 != NULL) ? 0:ESRCH); +} + +/* Find a thread in the linked list of dead threads: */ +int +_find_dead_thread(pthread_t pthread) +{ +	pthread_t pthread1; + +	/* Check if the caller has specified an invalid thread: */ +	if (pthread == NULL || pthread->magic != PTHREAD_MAGIC) +		/* Invalid thread: */ +		return(EINVAL); + +	/* Lock the dead thread list: */ +	_lock_dead_thread_list(); + +	/* Point to the first thread in the list: */ +	pthread1 = _thread_dead; + +	/* Search for the thread to join to: */ +	while (pthread1 != NULL && pthread1 != pthread) { +		/* Point to the next thread: */ +		pthread1 = pthread1->nxt; +	} + +	/* Unlock the dead thread list: */ +	_unlock_dead_thread_list(); + +	/* Return zero if the thread exists: */ +	return ((pthread1 != NULL) ? 0:ESRCH); +} +#endif diff --git a/lib/libpthread/thread/thr_fork.c b/lib/libpthread/thread/thr_fork.c index 29d60903a500..25d6703545fc 100644 --- a/lib/libpthread/thread/thr_fork.c +++ b/lib/libpthread/thread/thr_fork.c @@ -1,5 +1,5 @@  /* - * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>. + * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>   * All rights reserved.   *   * Redistribution and use in source and binary forms, with or without @@ -47,8 +47,8 @@ fork(void)  	pthread_t	pthread;  	pthread_t	pthread_next; -	/* Block signals to avoid being interrupted at a bad time: */ -	_thread_kern_sig_block(&status); +	/* Lock the thread list: */ +	_lock_thread_list();  	/* Fork a new process: */  	if ((ret = _thread_sys_fork()) <= 0) { @@ -59,12 +59,12 @@ fork(void)  		_thread_sys_close(_thread_kern_pipe[1]);  		/* Reset signals pending for the running thread: */ -		memset(_thread_run->sigpend, 0, sizeof(_thread_run->sigpend)); +		_thread_run->sigpend = 0;  		/*  		 * Create a pipe that is written to by the signal handler to  		 * prevent signals being missed in calls to -		 * _thread_sys_select:  +		 * _select:   		 */  		if (_thread_sys_pipe(_thread_kern_pipe) != 0) {  			/* Cannot create pipe, so abort: */ @@ -122,8 +122,8 @@ fork(void)  		}  	} -	/* Unblock signals: */ -	_thread_kern_sig_unblock(status); +	/* Unock the thread list: */ +	_unlock_thread_list();  	/* Return the process ID: */  	return (ret); diff --git a/lib/libpthread/thread/thr_fsync.c b/lib/libpthread/thread/thr_fsync.c index 51078e5515f8..5658c7354469 100644 --- a/lib/libpthread/thread/thr_fsync.c +++ b/lib/libpthread/thread/thr_fsync.c @@ -1,5 +1,5 @@  /* - * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>. + * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>   * All rights reserved.   *   * Redistribution and use in source and binary forms, with or without diff --git a/lib/libpthread/thread/thr_getprio.c b/lib/libpthread/thread/thr_getprio.c index 85bd2616b735..708b8f1adf75 100644 --- a/lib/libpthread/thread/thr_getprio.c +++ b/lib/libpthread/thread/thr_getprio.c @@ -38,36 +38,19 @@  int  pthread_getprio(pthread_t pthread)  { -	int             rval = 0; -	int             status; -	pthread_t       pthread_p; +	int ret; -	/* Block signals: */ -	_thread_kern_sig_block(&status); - -	/* Point to the first thread in the list: */ -	pthread_p = _thread_link_list; - -	/* Enter a loop to search for the thread: */ -	while (pthread_p != NULL && pthread_p != pthread) { -		/* Point to the next thread: */ -		pthread_p = pthread_p->nxt; -	} - -	/* Check if the thread pointer is NULL: */ -	if (pthread == NULL || pthread_p == NULL) { -		/* Return an invalid argument error: */ -		errno = EINVAL; -		rval = -1; -	} else { +	/* Find the thread in the list of active threads: */ +	if ((ret = _find_thread(pthread)) == 0)  		/* Get the thread priority: */ -		rval = pthread->pthread_priority; +		ret = pthread->pthread_priority; +	else { +		/* Invalid thread: */ +		errno = ret; +		ret = -1;  	} -	/* Unblock signals: */ -	_thread_kern_sig_unblock(status); -  	/* Return the thread priority or an error status: */ -	return (rval); +	return (ret);  }  #endif diff --git a/lib/libpthread/thread/thr_info.c b/lib/libpthread/thread/thr_info.c index 2909989beeaf..c2c34267e212 100644 --- a/lib/libpthread/thread/thr_info.c +++ b/lib/libpthread/thread/thr_info.c @@ -1,5 +1,5 @@  /* - * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>. + * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>   * All rights reserved.   *   * Redistribution and use in source and binary forms, with or without diff --git a/lib/libpthread/thread/thr_init.c b/lib/libpthread/thread/thr_init.c index 78967f4c0a9e..c267a2c8b313 100644 --- a/lib/libpthread/thread/thr_init.c +++ b/lib/libpthread/thread/thr_init.c @@ -1,5 +1,5 @@  /* - * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>. + * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>   * All rights reserved.   *   * Redistribution and use in source and binary forms, with or without @@ -44,7 +44,6 @@  #include <machine/reg.h>  #include <pthread.h>  #include "pthread_private.h" -extern int _thread_autoinit_dummy_decl;  #ifdef GCC_2_8_MADE_THREAD_AWARE  typedef void *** (*dynamic_handler_allocator)(); @@ -80,8 +79,6 @@ _thread_init(void)  	int             flags;  	int             i;  	struct sigaction act; -	/* Ensure that the auto-initialization routine is linked in: */ -	_thread_autoinit_dummy_decl = 1;  	/* Check if this function has already been called: */  	if (_thread_initial) @@ -96,7 +93,7 @@ _thread_init(void)  	/*  	 * Create a pipe that is written to by the signal handler to prevent -	 * signals being missed in calls to _thread_sys_select:  +	 * signals being missed in calls to _select:   	 */  	if (_thread_sys_pipe(_thread_kern_pipe) != 0) {  		/* Cannot create pipe, so abort: */ @@ -144,7 +141,6 @@ _thread_init(void)  		_thread_queue_init(&(_thread_initial->join_queue));  		/* Initialise the rest of the fields: */ -		_thread_initial->parent_thread = NULL;  		_thread_initial->specific_data = NULL;  		_thread_initial->cleanup = NULL;  		_thread_initial->queue = NULL; @@ -155,49 +151,42 @@ _thread_init(void)  		_thread_link_list = _thread_initial;  		_thread_run = _thread_initial; -		/* Enter a loop to get the existing signal status: */ -		for (i = 1; i < NSIG; i++) { -			/* Check for signals which cannot be trapped: */ -			if (i == SIGKILL || i == SIGSTOP) { -			} -			/* Get the signal handler details: */ -			else if (_thread_sys_sigaction(i, NULL, &act) != 0) { -				/* -				 * Abort this process if signal -				 * initialisation fails:  -				 */ -				PANIC("Cannot read signal handler info"); -			} -			/* Set the signal handler for the initial thread: */ -			else if (sigaction(i, &act, NULL) != 0) { -				/* -				 * Abort this process if signal -				 * initialisation fails:  -				 */ -				PANIC("Cannot initialise signal handler for initial thread"); -			} -		} -  		/* Initialise the global signal action structure: */  		sigfillset(&act.sa_mask);  		act.sa_handler = (void (*) ()) _thread_sig_handler;  		act.sa_flags = SA_RESTART; -		/* Enter a loop to initialise the rest of the signals: */ +		/* Enter a loop to get the existing signal status: */  		for (i = 1; i < NSIG; i++) {  			/* Check for signals which cannot be trapped: */  			if (i == SIGKILL || i == SIGSTOP) {  			} -			/* Initialise the signal for default handling: */ -			else if (_thread_sys_sigaction(i, &act, NULL) != 0) { + +			/* Get the signal handler details: */ +			else if (_thread_sys_sigaction(i, NULL, +			    &_thread_sigact[i - 1]) != 0) {  				/*  				 * Abort this process if signal  				 * initialisation fails:   				 */ -				PANIC("Cannot initialise signal handler"); +				PANIC("Cannot read signal handler info");  			}  		} +		/* +		 * Install the signal handler for the most important +		 * signals that the user-thread kernel needs. Actually +		 * SIGINFO isn't really needed, but it is nice to have. +		 */ +		if (_thread_sys_sigaction(SIGVTALRM, &act, NULL) != 0 || +		    _thread_sys_sigaction(SIGINFO  , &act, NULL) != 0 || +		    _thread_sys_sigaction(SIGCHLD  , &act, NULL) != 0) { +			/* +			 * Abort this process if signal initialisation fails:  +			 */ +			PANIC("Cannot initialise signal handler"); +		} +  		/* Get the table size: */  		if ((_thread_dtablesize = getdtablesize()) < 0) {  			/* diff --git a/lib/libpthread/thread/thr_join.c b/lib/libpthread/thread/thr_join.c index 9e86a0154b6b..83b0c2a8c0de 100644 --- a/lib/libpthread/thread/thr_join.c +++ b/lib/libpthread/thread/thr_join.c @@ -38,9 +38,8 @@  int  pthread_join(pthread_t pthread, void **thread_return)  { -	int             rval = 0; -	int             status; -	pthread_t	pthread1; +	int ret = 0; +	pthread_t pthread1 = NULL;  	/* Check if the caller has specified an invalid thread: */  	if (pthread == NULL || pthread->magic != PTHREAD_MAGIC) @@ -52,38 +51,23 @@ pthread_join(pthread_t pthread, void **thread_return)  		/* Avoid a deadlock condition: */  		return(EDEADLK); -	/* Block signals: */ -	_thread_kern_sig_block(&status); +	/* +	 * Find the thread in the list of active threads or in the +	 * list of dead threads: +	 */ +	if (_find_thread(pthread) == 0 || +	    _find_dead_thread(pthread) == 0) +		pthread1  = pthread; -	/* Point to the first thread in the list: */ -	pthread1 = _thread_link_list; - -	/* Search for the thread to join to: */ -	while (pthread1 != NULL && pthread1 != pthread) { -		/* Point to the next thread: */ -		pthread1 = pthread1->nxt; -	} - -	if (pthread1 == NULL) { -		/* Point to the first thread in the dead thread list: */ -		pthread1 = _thread_dead; - -		/* Search for the thread to join to: */ -		while (pthread1 != NULL && pthread1 != pthread) { -			/* Point to the next thread: */ -			pthread1 = pthread1->nxt; -		} -	} - -	if (pthread1 == NULL) { +	if (pthread1 == NULL)  		/* Return an error: */ -		rval = ESRCH; +		ret = ESRCH;  	/* Check if this thread has been detached: */ -	} else if ((pthread->attr.flags & PTHREAD_DETACHED) != 0) { +	else if ((pthread->attr.flags & PTHREAD_DETACHED) != 0)  		/* Return an error: */ -		rval = ESRCH; -	} +		ret = ESRCH; +  	/* Check if the thread is not dead: */  	else if (pthread->state != PS_DEAD) {  		/* Add the running thread to the join queue: */ @@ -92,32 +76,22 @@ pthread_join(pthread_t pthread, void **thread_return)  		/* Schedule the next thread: */  		_thread_kern_sched_state(PS_JOIN, __FILE__, __LINE__); -		/* Block signals again: */ -		_thread_kern_sig_block(NULL); -  		/* Check if the thread is not detached: */ -		if ((pthread->attr.flags & PTHREAD_DETACHED) == 0) { +		if ((pthread->attr.flags & PTHREAD_DETACHED) == 0)  			/* Check if the return value is required: */ -			if (thread_return) { +			if (thread_return)  				/* Return the thread's return value: */  				*thread_return = pthread->ret; -			} -		} else { +		else  			/* Return an error: */ -			rval = ESRCH; -		} -	} else { -		/* Check if the return value is required: */ -		if (thread_return != NULL) { -			/* Return the thread's return value: */ -			*thread_return = pthread->ret; -		} -	} +			ret = ESRCH; -	/* Unblock signals: */ -	_thread_kern_sig_unblock(status); +	/* Check if the return value is required: */ +	} else if (thread_return != NULL) +		/* Return the thread's return value: */ +		*thread_return = pthread->ret;  	/* Return the completion status: */ -	return (rval); +	return (ret);  }  #endif diff --git a/lib/libpthread/thread/thr_kern.c b/lib/libpthread/thread/thr_kern.c index 3b624223a7f6..36efc31321d6 100644 --- a/lib/libpthread/thread/thr_kern.c +++ b/lib/libpthread/thread/thr_kern.c @@ -1,5 +1,5 @@  /* - * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>. + * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>   * All rights reserved.   *   * Redistribution and use in source and binary forms, with or without @@ -29,7 +29,7 @@   * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF   * SUCH DAMAGE.   * - * $Id: uthread_kern.c,v 1.8 1998/04/11 07:47:22 jb Exp $ + * $Id: uthread_kern.c,v 1.9 1998/04/17 09:37:41 jb Exp $   *   */  #include <errno.h> @@ -49,15 +49,9 @@  #include <pthread.h>  #include "pthread_private.h" -/* Static variables: */ -static sigset_t sig_to_block = 0xffffffff; -static sigset_t sig_to_unblock = 0; -  /* Static function prototype definitions: */  static void   _thread_kern_select(int wait_reqd); -static void  -_thread_signal(pthread_t pthread, int sig);  void  _thread_kern_sched(struct sigcontext * scp) @@ -78,8 +72,12 @@ _thread_kern_sched(struct sigcontext * scp)  	struct timeval  tv;  	struct timeval  tv1; -	/* Block signals: */ -	_thread_kern_sig_block(NULL); +	/* +	 * Flag the pthread kernel as executing scheduler code +	 * to avoid a scheduler signal from interrupting this +	 * execution and calling the scheduler again. +	 */ +	_thread_kern_in_sched = 1;  	/* Check if this function was called from the signal handler: */  	if (scp != NULL) { @@ -101,14 +99,20 @@ __asm__("fnsave %0": :"m"(*fdata));  		_thread_run->sig_saved = 1;  	}  	/* Save the state of the current thread: */ -	else if (_thread_sys_setjmp(_thread_run->saved_jmp_buf) != 0) { -		/* Unblock signals (just in case): */ -		_thread_kern_sig_unblock(0); - +	else if (setjmp(_thread_run->saved_jmp_buf) != 0) {  		/*  		 * This point is reached when a longjmp() is called to  		 * restore the state of a thread.  +		 * +		 * This is the normal way out of the scheduler.  		 */ +		_thread_kern_in_sched = 0; + +		/* +		 * There might be pending signals for this thread, so +		 * dispatch any that aren't blocked: +		 */ +		_dispatch_signals();  		return;  	} else {  		/* Flag the jump buffer was the last state saved: */ @@ -135,10 +139,9 @@ __asm__("fnsave %0": :"m"(*fdata));  			pthread_prv = pthread;  		}  		/* -		 * Check if this thread has detached or if it is a signal -		 * handler thread:  +		 * Check if this thread has detached:  		 */ -		else if (((pthread->attr.flags & PTHREAD_DETACHED) != 0) || pthread->parent_thread != NULL) { +		else if ((pthread->attr.flags & PTHREAD_DETACHED) != 0) {  			/* Check if there is no previous dead thread: */  			if (pthread_prv == NULL) {  				/* @@ -210,41 +213,10 @@ __asm__("fnsave %0": :"m"(*fdata));  		_thread_kern_select(0);  		/* -		 * Enter a loop to look for sleeping threads that are ready -		 * or threads with pending signals that are no longer -		 * blocked:  +		 * Enter a loop to look for sleeping threads that are ready:  		 */ -		for (pthread = _thread_link_list; pthread != NULL; pthread = pthread->nxt) { -			/* Enter a loop to process the sending signals: */ -			for (i = 1; i < NSIG; i++) { -				/* -				 * Check if there are no pending signals of -				 * this type:  -				 */ -				if (pthread->sigpend[i] == 0) { -				} -				/* Check if this signal type is not masked: */ -				else if (sigismember(&pthread->sigmask, i) == 0) { -					/* -					 * Delete the signal from the set of -					 * pending signals for this thread:  -					 */ -					pthread->sigpend[i] -= 1; - -					/* -					 * Act on the signal for the current -					 * thread:  -					 */ -					_thread_signal(pthread, i); -				} else { -					/* -					 * This signal is masked, so make -					 * sure the count does not exceed 1:  -					 */ -					pthread->sigpend[i] = 1; -				} -			} - +		for (pthread = _thread_link_list; pthread != NULL; +		    pthread = pthread->nxt) {  			/* Check if this thread is to timeout: */  			if (pthread->state == PS_COND_WAIT ||  			    pthread->state == PS_SLEEP_WAIT || @@ -369,45 +341,6 @@ __asm__("fnsave %0": :"m"(*fdata));  		 * priority that is ready to run:   		 */  		for (pthread = _thread_link_list; pthread != NULL; pthread = pthread->nxt) { -			/* Check if in single-threaded mode: */ -			if (_thread_single != NULL) { -				/* -				 * Check if the current thread is -				 * the thread for which single-threaded -				 * mode is enabled: -				 */ -				if (pthread == _thread_single) { -					/* -					 * This thread is allowed -					 * to run. -					 */ -				} else { -					/* -					 * Walk up the signal handler -                                         * parent thread tree to see -					 * if the current thread is -					 * descended from the thread -					 * for which single-threaded -					 * mode is enabled. -					 */ -					pthread_nxt = pthread; -					while(pthread_nxt != NULL && -						pthread_nxt != _thread_single) { -						pthread_nxt = pthread->parent_thread; -					} -					/* -					 * Check if the current -					 * thread is not descended -					 * from the thread for which -					 * single-threaded mode is -					 * enabled. -					 */ -					if (pthread_nxt == NULL) -						/* Ignore this thread. */ -						continue; -				} -			} -  			/* Check if the current thread is unable to run: */  			if (pthread->state != PS_RUNNING) {  			} @@ -433,49 +366,11 @@ __asm__("fnsave %0": :"m"(*fdata));  		 * least recently.   		 */  		for (pthread = _thread_link_list; pthread != NULL; pthread = pthread->nxt) { -			/* Check if in single-threaded mode: */ -			if (_thread_single != NULL) { -				/* -				 * Check if the current thread is -				 * the thread for which single-threaded -				 * mode is enabled: -				 */ -				if (pthread == _thread_single) { -					/* -					 * This thread is allowed -					 * to run. -					 */ -				} else { -					/* -					 * Walk up the signal handler -                                         * parent thread tree to see -					 * if the current thread is -					 * descended from the thread -					 * for which single-threaded -					 * mode is enabled. -					 */ -					pthread_nxt = pthread; -					while(pthread_nxt != NULL && -						pthread_nxt != _thread_single) { -						pthread_nxt = pthread->parent_thread; -					} -					/* -					 * Check if the current -					 * thread is not descended -					 * from the thread for which -					 * single-threaded mode is -					 * enabled. -					 */ -					if (pthread_nxt == NULL) -						/* Ignore this thread. */ -						continue; -				} -			} -  			/* Check if the current thread is unable to run: */  			if (pthread->state != PS_RUNNING) {  				/* Ignore threads that are not ready to run. */  			} +  			/*  			 * Check if the current thread as an agregate  			 * priority not equal to the highest priority found @@ -487,6 +382,7 @@ __asm__("fnsave %0": :"m"(*fdata));  				 * priority.   				 */  			} +  			/*  			 * Check if the current thread reached its time slice  			 * allocation last time it ran (or if it has not run @@ -494,6 +390,7 @@ __asm__("fnsave %0": :"m"(*fdata));  			 */  			else if (pthread->slice_usec == -1) {  			} +  			/*  			 * Check if an eligible thread has not been found  			 * yet, or if the current thread has an inactive time @@ -526,45 +423,6 @@ __asm__("fnsave %0": :"m"(*fdata));  			 * priority. 3. Became inactive least recently.   			 */  			for (pthread = _thread_link_list; pthread != NULL; pthread = pthread->nxt) { -				/* Check if in single-threaded mode: */ -				if (_thread_single != NULL) { -					/* -					 * Check if the current thread is -					 * the thread for which single-threaded -					 * mode is enabled: -					 */ -					if (pthread == _thread_single) { -						/* -						 * This thread is allowed -						 * to run. -						 */ -					} else { -						/* -						 * Walk up the signal handler -						 * parent thread tree to see -						 * if the current thread is -						 * descended from the thread -						 * for which single-threaded -						 * mode is enabled. -						 */ -						pthread_nxt = pthread; -						while(pthread_nxt != NULL && -							pthread_nxt != _thread_single) { -							pthread_nxt = pthread->parent_thread; -						} -						/* -						 * Check if the current -						 * thread is not descended -						 * from the thread for which -						 * single-threaded mode is -						 * enabled. -						 */ -						if (pthread_nxt == NULL) -							/* Ignore this thread. */ -							continue; -					} -				} -  				/*  				 * Check if the current thread is unable to  				 * run:  @@ -804,14 +662,13 @@ __asm__("fnsave %0": :"m"(*fdata));  				 * was interrupted by a signal:   				 */  				_thread_sys_sigreturn(&_thread_run->saved_sigcontext); -			} else { +			} else  				/*  				 * Do a longjmp to restart the thread that  				 * was context switched out (by a longjmp to  				 * a different thread):   				 */ -				_thread_sys_longjmp(_thread_run->saved_jmp_buf, 1); -			} +				longjmp(_thread_run->saved_jmp_buf, 1);  			/* This point should not be reached. */  			PANIC("Thread has returned from sigreturn or longjmp"); @@ -822,243 +679,6 @@ __asm__("fnsave %0": :"m"(*fdata));  	exit(0);  } -static void -_thread_signal(pthread_t pthread, int sig) -{ -	int		done; -	long            l; -	pthread_t       new_pthread; -	struct sigaction act; -	void           *arg; - -	/* -	 * Assume that the signal will not be dealt with according -	 * to the thread state: -	 */ -	done = 0; - -	/* Process according to thread state: */ -	switch (pthread->state) { -	/* States which do not change when a signal is trapped: */ -	case PS_COND_WAIT: -	case PS_DEAD: -	case PS_FDLR_WAIT: -	case PS_FDLW_WAIT: -	case PS_FILE_WAIT: -	case PS_JOIN: -	case PS_MUTEX_WAIT: -	case PS_RUNNING: -	case PS_STATE_MAX: -	case PS_SIGTHREAD: -	case PS_SUSPENDED: -		/* Nothing to do here. */ -		break; - -	/* Wait for child: */ -	case PS_WAIT_WAIT: -		/* Check if the signal is from a child exiting: */ -		if (sig == SIGCHLD) { -			/* Reset the error: */ -			_thread_seterrno(pthread, 0); - -			/* Change the state of the thread to run: */ -			PTHREAD_NEW_STATE(pthread,PS_RUNNING); -		} else { -			/* Return the 'interrupted' error: */ -			_thread_seterrno(pthread, EINTR); - -			/* Change the state of the thread to run: */ -			PTHREAD_NEW_STATE(pthread,PS_RUNNING); -		} -		pthread->interrupted = 1; -		break; - -	/* Waiting on I/O for zero or more file descriptors: */ -	case PS_SELECT_WAIT: -		pthread->data.select_data->nfds = -1; - -		/* Return the 'interrupted' error: */ -		_thread_seterrno(pthread, EINTR); -		pthread->interrupted = 1; - -		/* Change the state of the thread to run: */ -		PTHREAD_NEW_STATE(pthread,PS_RUNNING); -		break; - -	/* -	 * States that are interrupted by the occurrence of a signal -	 * other than the scheduling alarm:  -	 */ -	case PS_FDR_WAIT: -	case PS_FDW_WAIT: -	case PS_SLEEP_WAIT: -	case PS_SIGWAIT: -		/* Return the 'interrupted' error: */ -		_thread_seterrno(pthread, EINTR); -		pthread->interrupted = 1; - -		/* Change the state of the thread to run: */ -		PTHREAD_NEW_STATE(pthread,PS_RUNNING); - -		/* Return the signal number: */ -		pthread->signo = sig; -		break; -	} - -	/* -	 * Check if this signal has been dealt with, or is being -	 * ignored: -	 */ -	if (done || pthread->act[sig - 1].sa_handler == SIG_IGN) { -		/* Ignore the signal for this thread. */ -	} -	/* Check if this signal is to use the default handler: */ -	else if (pthread->act[sig - 1].sa_handler == SIG_DFL) { -		/* Process according to signal type: */ -		switch (sig) { -		/* Signals which cause core dumps: */ -		case SIGQUIT: -		case SIGILL: -		case SIGTRAP: -		case SIGABRT: -		case SIGEMT: -		case SIGFPE: -		case SIGBUS: -		case SIGSEGV: -		case SIGSYS: -			/* Clear the signal action: */ -			sigfillset(&act.sa_mask); -			act.sa_handler = SIG_DFL; -			act.sa_flags = SA_RESTART; -			_thread_sys_sigaction(sig, &act, NULL); - -			/* -			 * Do a sigreturn back to where the signal was -			 * detected and a core dump should occur:  -			 */ -			_thread_sys_sigreturn(&pthread->saved_sigcontext); -			break; - -		/* -		 * The following signals should terminate the -		 * process. Do this by clearing the signal action -		 * and then re-throwing the signal. -		 */ -		case SIGHUP: -		case SIGINT: -		case SIGPIPE: -		case SIGALRM: -		case SIGTERM: -		case SIGXCPU: -		case SIGXFSZ: -		case SIGVTALRM: -		case SIGUSR1: -		case SIGUSR2: -		/* These signals stop the process. Also re-throw them. */ -		case SIGTSTP: -		case SIGTTIN: -		case SIGTTOU: -                        /* Clear the signal action: */ -                        sigfillset(&act.sa_mask); -                        act.sa_handler = SIG_DFL; -                        act.sa_flags = SA_RESTART; -                        _thread_sys_sigaction(sig, &act, NULL); -			/* Re-throw to ourselves. */ -                        kill(getpid(), sig); -			break; - -		case SIGCONT: -			/* -			 * If we get this it means that we were -			 * probably stopped and then continued. -			 * Reset the handler for the SIGTSTP, SIGTTIN -			 * and SIGTTOU signals. -			 */ - -                	sigfillset(&act.sa_mask); -	                act.sa_handler = (void (*) ()) _thread_sig_handler; -			act.sa_flags = SA_RESTART; - -                        /* Initialise the signals for default handling: */ -                        if (_thread_sys_sigaction(SIGTSTP, &act, NULL) != 0) { -                                PANIC("Cannot initialise SIGTSTP signal handler"); -                        } -                        if (_thread_sys_sigaction(SIGTTIN, &act, NULL) != 0) { -                                PANIC("Cannot initialise SIGTTIN signal handler"); -                        } -                        if (_thread_sys_sigaction(SIGTTOU, &act, NULL) != 0) { -                                PANIC("Cannot initialise SIGTTOU signal handler"); -                        } -			break; - -		/* Default processing for other signals: */ -		default: -			/* -			 * ### Default processing is a problem to resolve!      -			 * ###  -			 */ -			break; -		} -	} else { -		/* -		 * Cast the signal number as a long and then to a void -		 * pointer. Sigh. This is POSIX.  -		 */ -		l = (long) sig; -		arg = (void *) l; - -		/* Create a signal handler thread, but don't run it yet: */ -		if (_thread_create(&new_pthread, NULL, (void *) pthread->act[sig - 1].sa_handler, arg, pthread) != 0) { -			/* -			 * Error creating signal handler thread, so abort -			 * this process:  -			 */ -			PANIC("Cannot create signal handler thread"); -		} -	} - -	/* Nothing to return. */ -	return; -} - -void -_thread_kern_sig_block(int *status) -{ -	sigset_t        oset; - -	/* -	 * Block all signals so that the process will not be interrupted by -	 * signals:  -	 */ -	_thread_sys_sigprocmask(SIG_SETMASK, &sig_to_block, &oset); - -	/* Check if the caller wants the current block status returned: */ -	if (status != NULL) { -		/* Return the previous signal block status: */ -		*status = (oset != 0); -	} -	return; -} - -void -_thread_kern_sig_unblock(int status) -{ -	sigset_t        oset; - -	/* -	 * Check if the caller thinks that signals weren't blocked when it -	 * called _thread_kern_sig_block:  -	 */ -	if (status == 0) { -		/* -		 * Unblock all signals so that the process will be -		 * interrupted when a signal occurs:  -		 */ -		_thread_sys_sigprocmask(SIG_SETMASK, &sig_to_unblock, &oset); -	} -	return; -} -  void  _thread_kern_sched_state(enum pthread_state state, char *fname, int lineno)  { @@ -1382,18 +1002,12 @@ _thread_kern_select(int wait_reqd)  		 */  		_thread_kern_in_select = 1; -		/* Unblock all signals: */ -		_thread_kern_sig_unblock(0); -  		/*  		 * Wait for a file descriptor to be ready for read, write, or  		 * an exception, or a timeout to occur:   		 */  		count = _thread_sys_select(nfds + 1, &fd_set_read, &fd_set_write, &fd_set_except, p_tv); -		/* Block all signals again: */ -		_thread_kern_sig_block(NULL); -  		/* Reset the kernel in select flag: */  		_thread_kern_in_select = 0; @@ -1426,10 +1040,10 @@ _thread_kern_select(int wait_reqd)  				 * signal and each byte is the signal number.  				 * This data is not used, but the fact that  				 * the signal handler wrote to the pipe *is* -				 * used to cause the _thread_sys_select call +				 * used to cause the _select call  				 * to complete if the signal occurred between  				 * the time when signals were unblocked and -				 * the _thread_sys_select select call being +				 * the _select select call being  				 * made.   				 */  			} @@ -1439,36 +1053,22 @@ _thread_kern_select(int wait_reqd)  	else if (count > 0) {  		/*  		 * Point to the time value structure which has been zeroed so -		 * that the call to _thread_sys_select will not wait:  +		 * that the call to _select will not wait:   		 */  		p_tv = &tv;  		/* Poll file descrptors without wait: */  		count = _thread_sys_select(nfds + 1, &fd_set_read, &fd_set_write, &fd_set_except, p_tv);  	} +  	/* -	 * Check if the select call was interrupted, or some other error -	 * occurred:  +	 * Check if any file descriptors are ready:  	 */ -	if (count < 0) { -		/* Check if the select call was interrupted: */ -		if (errno == EINTR) { -			/* -			 * Interrupted calls are expected. The interrupting -			 * signal will be in the sigpend array.  -			 */ -		} else { -			/* This should not occur: */ -		} -	} -	/* Check if no file descriptors are ready: */ -	else if (count == 0) { -		/* Nothing to do here.                                              */ -	} else { +	if (count > 0) {  		/*  		 * Enter a loop to look for threads waiting on file  		 * descriptors that are flagged as available by the -		 * _thread_sys_select syscall:  +		 * _select syscall:   		 */  		for (pthread = _thread_link_list; pthread != NULL; pthread = pthread->nxt) {  			/* Process according to thread state: */ diff --git a/lib/libpthread/thread/thr_kill.c b/lib/libpthread/thread/thr_kill.c index eb2c6b75d740..f6e684b0d4b5 100644 --- a/lib/libpthread/thread/thr_kill.c +++ b/lib/libpthread/thread/thr_kill.c @@ -39,40 +39,19 @@  int  pthread_kill(pthread_t pthread, int sig)  { -	int             rval = 0; -	int             status; -	pthread_t	p_pthread; +	int ret;  	/* Check for invalid signal numbers: */  	if (sig < 0 || sig >= NSIG)  		/* Invalid signal: */ -		rval = EINVAL; -	else { -		/* Assume that the search will succeed: */ -		rval = 0; +		ret = EINVAL; -		/* Block signals: */ -		_thread_kern_sig_block(&status); - -		/* Search for the thread: */ -		p_pthread = _thread_link_list; -		while (p_pthread != NULL && p_pthread != pthread) { -			p_pthread = p_pthread->nxt; -		} - -		/* Check if the thread was not found: */ -		if (p_pthread == NULL) -			/* Can't find the thread: */ -			rval = ESRCH; -		else -			/* Increment the pending signal count: */ -			p_pthread->sigpend[sig] += 1; - -		/* Unblock signals: */ -		_thread_kern_sig_unblock(status); -	} +	/* Find the thread in the list of active threads: */ +	else if ((ret = _find_thread(pthread)) == 0) +		/* Increment the pending signal count: */ +		sigaddset(&pthread->sigpend,sig);  	/* Return the completion status: */ -	return (rval); +	return (ret);  }  #endif diff --git a/lib/libpthread/thread/thr_mutex.c b/lib/libpthread/thread/thr_mutex.c index 9f92de9eb3e8..fb737cf0d4e2 100644 --- a/lib/libpthread/thread/thr_mutex.c +++ b/lib/libpthread/thread/thr_mutex.c @@ -49,28 +49,26 @@ pthread_mutex_init(pthread_mutex_t * mutex,  		ret = EINVAL;  	} else {  		/* Check if default mutex attributes: */ -		if (mutex_attr == NULL || *mutex_attr == NULL) { +		if (mutex_attr == NULL || *mutex_attr == NULL)  			/* Default to a fast mutex: */  			type = MUTEX_TYPE_FAST; -		} else if ((*mutex_attr)->m_type >= MUTEX_TYPE_MAX) { + +		else if ((*mutex_attr)->m_type >= MUTEX_TYPE_MAX)  			/* Return an invalid argument error: */  			ret = EINVAL; -		} else { +		else  			/* Use the requested mutex type: */  			type = (*mutex_attr)->m_type; -		}  		/* Check no errors so far: */  		if (ret == 0) { -			if ((pmutex = (pthread_mutex_t) malloc(sizeof(struct pthread_mutex))) == NULL) { +			if ((pmutex = (pthread_mutex_t) +			    malloc(sizeof(struct pthread_mutex))) == NULL)  				ret = ENOMEM; -			} else { +			else {  				/* Reset the mutex flags: */  				pmutex->m_flags = 0; -				/* Block signals: */ -				_thread_kern_sig_block(&status); -  				/* Process according to mutex type: */  				switch (type) {  				/* Fast mutex: */ @@ -96,14 +94,12 @@ pthread_mutex_init(pthread_mutex_t * mutex,  					pmutex->m_flags |= MUTEX_FLAGS_INITED;  					pmutex->m_owner = NULL;  					pmutex->m_type = type; +					pmutex->access_lock = 0;  					*mutex = pmutex;  				} else {  					free(pmutex);  					*mutex = NULL;  				} - -				/* Unblock signals: */ -				_thread_kern_sig_unblock(status);  			}  		}  	} @@ -114,42 +110,25 @@ pthread_mutex_init(pthread_mutex_t * mutex,  int  pthread_mutex_destroy(pthread_mutex_t * mutex)  { -	int             ret = 0; -	int             status; +	int ret = 0; -	if (mutex == NULL || *mutex == NULL) { +	if (mutex == NULL || *mutex == NULL)  		ret = EINVAL; -	} else { -		/* Block signals: */ -		_thread_kern_sig_block(&status); - -		/* Process according to mutex type: */ -		switch ((*mutex)->m_type) { -		/* Fast mutex: */ -		case MUTEX_TYPE_FAST: -			/* Nothing to do here. */ -			break; - -		/* Counting mutex: */ -		case MUTEX_TYPE_COUNTING_FAST: -			/* Reset the mutex count: */ -			(*mutex)->m_data.m_count = 0; -			break; - -		/* Trap undefined mutex types: */ -		default: -			/* Return an invalid argument error: */ -			ret = EINVAL; -			break; -		} - -		/* Clean up the mutex in case that others want to use it: */ -		_thread_queue_init(&(*mutex)->m_queue); -		(*mutex)->m_owner = NULL; -		(*mutex)->m_flags = 0; - -		/* Unblock signals: */ -		_thread_kern_sig_unblock(status); +	else { +		/* Lock the mutex structure: */ +		_spinlock(&(*mutex)->access_lock); + +		/* +		 * Free the memory allocated for the mutex +		 * structure: +		 */ +		free(*mutex); + +		/* +		 * Leave the caller's pointer NULL now that +		 * the mutex has been destroyed: +		 */ +		*mutex = NULL;  	}  	/* Return the completion status: */ @@ -160,7 +139,6 @@ int  pthread_mutex_trylock(pthread_mutex_t * mutex)  {  	int             ret = 0; -	int             status;  	if (mutex == NULL)  		ret = EINVAL; @@ -171,8 +149,8 @@ pthread_mutex_trylock(pthread_mutex_t * mutex)  	 */  	else if (*mutex != NULL ||  	    (ret = pthread_mutex_init(mutex,NULL)) == 0) { -		/* Block signals: */ -		_thread_kern_sig_block(&status); +		/* Lock the mutex structure: */ +		_spinlock(&(*mutex)->access_lock);  		/* Process according to mutex type: */  		switch ((*mutex)->m_type) { @@ -216,8 +194,8 @@ pthread_mutex_trylock(pthread_mutex_t * mutex)  			break;  		} -		/* Unblock signals: */ -		_thread_kern_sig_unblock(status); +		/* Unlock the mutex structure: */ +		_atomic_unlock(&(*mutex)->access_lock);  	}  	/* Return the completion status: */ @@ -228,7 +206,6 @@ int  pthread_mutex_lock(pthread_mutex_t * mutex)  {  	int             ret = 0; -	int             status;  	if (mutex == NULL)  		ret = EINVAL; @@ -239,8 +216,8 @@ pthread_mutex_lock(pthread_mutex_t * mutex)  	 */  	else if (*mutex != NULL ||  	    (ret = pthread_mutex_init(mutex,NULL)) == 0) { -		/* Block signals: */ -		_thread_kern_sig_block(&status); +		/* Lock the mutex structure: */ +		_spinlock(&(*mutex)->access_lock);  		/* Process according to mutex type: */  		switch ((*mutex)->m_type) { @@ -262,11 +239,14 @@ pthread_mutex_lock(pthread_mutex_t * mutex)  					 */  					_thread_queue_enq(&(*mutex)->m_queue, _thread_run); +					/* Unlock the mutex structure: */ +					_atomic_unlock(&(*mutex)->access_lock); +  					/* Block signals: */  					_thread_kern_sched_state(PS_MUTEX_WAIT, __FILE__, __LINE__); -					/* Block signals: */ -					_thread_kern_sig_block(NULL); +					/* Lock the mutex again: */ +					_spinlock(&(*mutex)->access_lock);  				}  			}  			break; @@ -292,11 +272,14 @@ pthread_mutex_lock(pthread_mutex_t * mutex)  					 */  					_thread_queue_enq(&(*mutex)->m_queue, _thread_run); +					/* Unlock the mutex structure: */ +					_atomic_unlock(&(*mutex)->access_lock); +  					/* Block signals: */  					_thread_kern_sched_state(PS_MUTEX_WAIT, __FILE__, __LINE__); -					/* Block signals: */ -					_thread_kern_sig_block(NULL); +					/* Lock the mutex again: */ +					_spinlock(&(*mutex)->access_lock);  				}  			} @@ -311,8 +294,8 @@ pthread_mutex_lock(pthread_mutex_t * mutex)  			break;  		} -		/* Unblock signals: */ -		_thread_kern_sig_unblock(status); +		/* Unlock the mutex structure: */ +		_atomic_unlock(&(*mutex)->access_lock);  	}  	/* Return the completion status: */ @@ -323,13 +306,12 @@ int  pthread_mutex_unlock(pthread_mutex_t * mutex)  {  	int             ret = 0; -	int             status;  	if (mutex == NULL || *mutex == NULL) {  		ret = EINVAL;  	} else { -		/* Block signals: */ -		_thread_kern_sig_block(&status); +		/* Lock the mutex structure: */ +		_spinlock(&(*mutex)->access_lock);  		/* Process according to mutex type: */  		switch ((*mutex)->m_type) { @@ -379,8 +361,8 @@ pthread_mutex_unlock(pthread_mutex_t * mutex)  			break;  		} -		/* Unblock signals: */ -		_thread_kern_sig_unblock(status); +		/* Unlock the mutex structure: */ +		_atomic_unlock(&(*mutex)->access_lock);  	}  	/* Return the completion status: */ diff --git a/lib/libpthread/thread/thr_nanosleep.c b/lib/libpthread/thread/thr_nanosleep.c index 39c7dadd2232..4ec7d3f31720 100644 --- a/lib/libpthread/thread/thr_nanosleep.c +++ b/lib/libpthread/thread/thr_nanosleep.c @@ -66,6 +66,7 @@ nanosleep(const struct timespec * time_to_sleep,  			_thread_run->wakeup_time.tv_sec += 1;  			_thread_run->wakeup_time.tv_nsec -= 1000000000;  		} +		_thread_run->interrupted = 0;  		/* Reschedule the current thread to sleep: */  		_thread_kern_sched_state(PS_SLEEP_WAIT, __FILE__, __LINE__); @@ -106,8 +107,8 @@ nanosleep(const struct timespec * time_to_sleep,  			time_remaining->tv_nsec = remaining_time.tv_nsec;  		} -		/* Check if the entire sleep was not completed: */ -		if (remaining_time.tv_nsec != 0 || remaining_time.tv_sec != 0) { +		/* Check if the sleep was interrupted: */ +		if (_thread_run->interrupted) {  			/* Return an EINTR error : */  			errno = EINTR;  			ret = -1; diff --git a/lib/libpthread/thread/thr_open.c b/lib/libpthread/thread/thr_open.c index ef7a5048fffb..a538a758f461 100644 --- a/lib/libpthread/thread/thr_open.c +++ b/lib/libpthread/thread/thr_open.c @@ -1,5 +1,5 @@  /* - * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>. + * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>   * All rights reserved.   *   * Redistribution and use in source and binary forms, with or without @@ -29,7 +29,7 @@   * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF   * SUCH DAMAGE.   * - * $Id$ + * $Id: uthread_open.c,v 1.3 1997/05/03 03:57:21 jb Exp $   *   */  #include <stdarg.h> @@ -49,9 +49,6 @@ open(const char *path, int flags,...)  	int             status;  	va_list         ap; -	/* Block signals: */ -	_thread_kern_sig_block(&status); -  	/* Check if the file is being created: */  	if (flags & O_CREAT) {  		/* Get the creation mode: */ @@ -71,9 +68,6 @@ open(const char *path, int flags,...)  		fd = -1;  	} -	/* Unblock signals: */ -	_thread_kern_sig_unblock(status); -  	/* Return the file descriptor or -1 on error: */  	return (fd);  } diff --git a/lib/libpthread/thread/thr_private.h b/lib/libpthread/thread/thr_private.h index 5ceeabaf0cc2..5f0f3a8fd3be 100644 --- a/lib/libpthread/thread/thr_private.h +++ b/lib/libpthread/thread/thr_private.h @@ -60,6 +60,10 @@   */  #define PANIC(string)   _thread_exit(__FILE__,__LINE__,string) +/* Output debug messages like this: */ +#define	stdout_debug(_x)	_write(1,_x,strlen(_x)); +#define	stderr_debug(_x)	_write(2,_x,strlen(_x)); +  /*   * State change macro:   */ @@ -97,6 +101,11 @@ struct pthread_mutex {  	struct pthread			*m_owner;  	union pthread_mutex_data	m_data;  	long				m_flags; + +	/* +	 * Lock for accesses to this structure. +	 */ +	long			access_lock;  };  /* @@ -131,6 +140,11 @@ struct pthread_cond {  	struct pthread_queue	c_queue;  	void			*c_data;  	long			c_flags; + +	/* +	 * Lock for accesses to this structure. +	 */ +	long			access_lock;  };  struct pthread_cond_attr { @@ -204,6 +218,7 @@ struct pthread_attr {  struct pthread_key {  	pthread_mutex_t mutex; +	long            access_lock;  	long            count;  	void            (*destructor) ();  }; @@ -243,6 +258,13 @@ enum pthread_state {   * File descriptor table structure.   */  struct fd_table_entry { +	/* +	 * Lock for accesses to this file descriptor table +	 * entry. This is passed to _spinlock() to provide atomic +	 * access to this structure. It does *not* represent the +	 * state of the lock on the file descriptor. +	 */ +	long			access_lock;  	struct pthread_queue	r_queue;	/* Read queue.                        */  	struct pthread_queue	w_queue;	/* Write queue.                       */  	struct pthread		*r_owner;	/* Ptr to thread owning read lock.    */ @@ -288,6 +310,11 @@ struct pthread {  	char			*name;  	/* +	 * Lock for accesses to this thread structure. +	 */ +	long			access_lock; + +	/*  	 * Pointer to the next thread in the thread linked list.  	 */  	struct pthread	*nxt; @@ -301,13 +328,6 @@ struct pthread {  	void			*stack;  	struct pthread_attr	attr; -	/* -	 * Thread-specific signal handler interface: -	 * -	 * Array of signal actions for this thread. -	 */ -	struct  sigaction act[NSIG]; -  #if (defined(__FreeBSD__) || defined(__NetBSD__)) && defined(__i386__)  	/*  	 * Saved floating point registers on systems where they are not @@ -335,17 +355,10 @@ struct pthread {  	int	sig_saved;  	/* -	 * Current signal mask and array of pending signals. +	 * Current signal mask and pending signals.  	 */  	sigset_t	sigmask; -	int		sigpend[NSIG]; - -	/* -	 * Pointer to the parent thread for which the current thread is -	 * a signal handler thread, otherwise NULL if the current thread -	 * is not a signal handler thread. -	 */ -	struct  pthread	*parent_thread; +	sigset_t	sigpend;  	/* Thread state: */  	enum pthread_state	state; @@ -463,7 +476,7 @@ SCLASS struct pthread   * volatile _thread_link_list  /*   * Array of kernel pipe file descriptors that are used to ensure that - * no signals are missed in calls to _thread_sys_select. + * no signals are missed in calls to _select.   */  SCLASS int              _thread_kern_pipe[2]  #ifdef GLOBAL_PTHREAD_PRIVATE @@ -480,6 +493,12 @@ SCLASS int              _thread_kern_in_select  #else  ;  #endif +SCLASS int              _thread_kern_in_sched +#ifdef GLOBAL_PTHREAD_PRIVATE += 0; +#else +; +#endif  /* Last time that an incremental priority update was performed: */  SCLASS struct timeval   kern_inc_prio_time @@ -558,6 +577,11 @@ SCLASS int    _thread_dtablesize        /* Descriptor table size.           */  ;  #endif +/* + * Array of signal actions for this process. + */ +struct  sigaction _thread_sigact[NSIG]; +  /* Undefine the storage class specifier: */  #undef  SCLASS @@ -568,8 +592,18 @@ __BEGIN_DECLS  char    *__ttyname_basic(int);  char    *__ttyname_r_basic(int, char *, size_t);  char    *ttyname_r(int, char *, size_t); +int     _find_dead_thread(pthread_t); +int     _find_thread(pthread_t);  int     _thread_create(pthread_t *,const pthread_attr_t *,void *(*start_routine)(void *),void *,pthread_t);  int     _thread_fd_lock(int, int, struct timespec *,char *fname,int lineno); +void    _dispatch_signals(void); +void    _thread_signal(pthread_t, int); +void    _lock_dead_thread_list(void); +void    _lock_thread(void); +void    _lock_thread_list(void); +void    _unlock_dead_thread_list(void); +void    _unlock_thread(void); +void    _unlock_thread_list(void);  void    _thread_exit(char *, int, char *);  void    _thread_fd_unlock(int, int);  void    *_thread_cleanup(pthread_t); @@ -579,8 +613,6 @@ void    _thread_init(void);  void    _thread_kern_sched(struct sigcontext *);  void    _thread_kern_sched_state(enum pthread_state,char *fname,int lineno);  void    _thread_kern_set_timeout(struct timespec *); -void    _thread_kern_sig_block(int *); -void    _thread_kern_sig_unblock(int);  void    _thread_sig_handler(int, int, struct sigcontext *);  void    _thread_start(void);  void    _thread_start_sig_handler(void); @@ -597,11 +629,9 @@ int     _thread_sys_sigaction(int, const struct sigaction *, struct sigaction *)  int     _thread_sys_sigpending(sigset_t *);  int     _thread_sys_sigprocmask(int, const sigset_t *, sigset_t *);  int     _thread_sys_sigsuspend(const sigset_t *); -int     _thread_sys_sigblock(int);  int     _thread_sys_siginterrupt(int, int);  int     _thread_sys_sigpause(int);  int     _thread_sys_sigreturn(struct sigcontext *); -int     _thread_sys_sigsetmask(int);  int     _thread_sys_sigstack(const struct sigstack *, struct sigstack *);  int     _thread_sys_sigvec(int, struct sigvec *, struct sigvec *);  void    _thread_sys_psignal(unsigned int, const char *); @@ -734,17 +764,6 @@ int     _thread_sys_flock(int, int);  int     _thread_sys_open(const char *, int, ...);  #endif -/* #include <setjmp.h> */ -#ifdef  _SETJMP_H_ -int     __thread_sys_setjmp(jmp_buf); -int     _thread_sys_setjmp(jmp_buf); -int     _thread_sys_sigsetjmp(sigjmp_buf, int); -void    __thread_sys_longjmp(jmp_buf, int); -void    _thread_sys_longjmp(jmp_buf, int); -void    _thread_sys_longjmperror(void); -void    _thread_sys_siglongjmp(sigjmp_buf, int); -#endif -  /* #include <sys/ioctl.h> */  #ifdef  _SYS_IOCTL_H_  int     _thread_sys_ioctl(int, unsigned long, ...); diff --git a/lib/libpthread/thread/thr_read.c b/lib/libpthread/thread/thr_read.c index 242014eaea69..76df2cff7ad6 100644 --- a/lib/libpthread/thread/thr_read.c +++ b/lib/libpthread/thread/thr_read.c @@ -1,5 +1,5 @@  /* - * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>. + * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>   * All rights reserved.   *   * Redistribution and use in source and binary forms, with or without @@ -29,7 +29,7 @@   * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF   * SUCH DAMAGE.   * - * $Id$ + * $Id: uthread_read.c,v 1.3 1997/04/01 22:44:15 jb Exp $   *   */  #include <sys/types.h> @@ -45,7 +45,6 @@ ssize_t  read(int fd, void *buf, size_t nbytes)  {  	int	ret; -	int	status;  	/* Lock the file descriptor for read: */  	if ((ret = _thread_fd_lock(fd, FD_READ, NULL, @@ -54,7 +53,6 @@ read(int fd, void *buf, size_t nbytes)  		while ((ret = _thread_sys_read(fd, buf, nbytes)) < 0) {  			if ((_thread_fd_table[fd]->flags & O_NONBLOCK) == 0 &&  			    (errno == EWOULDBLOCK || errno == EAGAIN)) { -				_thread_kern_sig_block(&status);  				_thread_run->data.fd.fd = fd;  				_thread_kern_set_timeout(NULL); @@ -69,6 +67,7 @@ read(int fd, void *buf, size_t nbytes)  				 * interrupted by a signal  				 */  				if (_thread_run->interrupted) { +					errno = EINTR;  					ret = -1;  					break;  				} diff --git a/lib/libpthread/thread/thr_readv.c b/lib/libpthread/thread/thr_readv.c index 3ea065ee6bd2..10d1a43a379a 100644 --- a/lib/libpthread/thread/thr_readv.c +++ b/lib/libpthread/thread/thr_readv.c @@ -1,5 +1,5 @@  /* - * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>. + * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>   * All rights reserved.   *   * Redistribution and use in source and binary forms, with or without @@ -29,7 +29,7 @@   * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF   * SUCH DAMAGE.   * - * $Id$ + * $Id: uthread_readv.c,v 1.3 1997/04/01 22:44:16 jb Exp $   *   */  #include <sys/types.h> @@ -45,7 +45,6 @@ ssize_t  readv(int fd, const struct iovec * iov, int iovcnt)  {  	int	ret; -	int	status;  	/* Lock the file descriptor for read: */  	if ((ret = _thread_fd_lock(fd, FD_READ, NULL, @@ -54,7 +53,6 @@ readv(int fd, const struct iovec * iov, int iovcnt)  		while ((ret = _thread_sys_readv(fd, iov, iovcnt)) < 0) {  			if ((_thread_fd_table[fd]->flags & O_NONBLOCK) == 0 &&  			    (errno == EWOULDBLOCK || errno == EAGAIN)) { -				_thread_kern_sig_block(&status);  				_thread_run->data.fd.fd = fd;  				_thread_kern_set_timeout(NULL); @@ -69,6 +67,7 @@ readv(int fd, const struct iovec * iov, int iovcnt)  				 * interrupted by a signal  				 */  				if (_thread_run->interrupted) { +					errno = EINTR;  					ret = -1;  					break;  				} diff --git a/lib/libpthread/thread/thr_resume_np.c b/lib/libpthread/thread/thr_resume_np.c index 934df58c75a4..7c5f46adfcef 100644 --- a/lib/libpthread/thread/thr_resume_np.c +++ b/lib/libpthread/thread/thr_resume_np.c @@ -35,36 +35,20 @@  #include <pthread.h>  #include "pthread_private.h" +/* Resume a thread: */  int  pthread_resume_np(pthread_t thread)  { -	int		ret	= -1; -	pthread_t	pthread; -	/* -	 * Search for the thread in the linked list. -	 */ -	for (pthread = _thread_link_list; pthread != NULL && ret == -1; pthread = pthread->nxt) { -		/* Is this the thread? */ -		if (pthread == thread) { -			/* Found the thread. Is it suspended? */ -			if (pthread->state == PS_SUSPENDED) { -				/* Allow the thread to run. */ -				PTHREAD_NEW_STATE(pthread,PS_RUNNING); -				ret = 0; -			} else if (pthread->state == PS_RUNNING) { -				/* Thread is already running. */ -				ret = 0; -			} else { -				/* Thread is in some other state. */ -				errno = EINVAL; -			} +	int ret; + +	/* Find the thread in the list of active threads: */ +	if ((ret = _find_thread(thread)) == 0) { +		/* The thread exists. Is it suspended? */ +		if (thread->state != PS_SUSPENDED) { +			/* Allow the thread to run. */ +			PTHREAD_NEW_STATE(thread,PS_RUNNING);  		}  	} -	/* Check if thread was not found. */ -	if (ret == -1) { -		/* No such thread */ -		errno = ESRCH; -	}  	return(ret);  }  #endif diff --git a/lib/libpthread/thread/thr_select.c b/lib/libpthread/thread/thr_select.c index 7db3ed2f2444..96df9c19bf54 100644 --- a/lib/libpthread/thread/thr_select.c +++ b/lib/libpthread/thread/thr_select.c @@ -1,5 +1,5 @@  /* - * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>. + * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>   * All rights reserved.   *   * Redistribution and use in source and binary forms, with or without @@ -125,8 +125,13 @@ select(int numfds, fd_set * readfds, fd_set * writefds,  				memcpy(&data.exceptfds, exceptfds, sizeof(data.exceptfds));  			}  			_thread_run->data.select_data = &data; +			_thread_run->interrupted = 0;  			_thread_kern_sched_state(PS_SELECT_WAIT, __FILE__, __LINE__); -			ret = data.nfds; +			if (_thread_run->interrupted) { +				errno = EINTR; +				ret = -1; +			} else +				ret = data.nfds;  		}  	}  	/* clean up the locks */ diff --git a/lib/libpthread/thread/thr_seterrno.c b/lib/libpthread/thread/thr_seterrno.c index c4fe08b6cc36..570807f1fc7e 100644 --- a/lib/libpthread/thread/thr_seterrno.c +++ b/lib/libpthread/thread/thr_seterrno.c @@ -47,15 +47,14 @@ void  _thread_seterrno(pthread_t thread, int error)  {  	/* Check for the initial thread: */ -	if (thread == _thread_initial) { +	if (thread == _thread_initial)  		/* The initial thread always uses the global error variable: */  		errno = error; -	} else { +	else  		/*  		 * Threads other than the initial thread always use the error  		 * field in the thread structureL   		 */  		thread->error = error; -	}  }  #endif diff --git a/lib/libpthread/thread/thr_setprio.c b/lib/libpthread/thread/thr_setprio.c index 4b49ed096afb..dd89f156a50f 100644 --- a/lib/libpthread/thread/thr_setprio.c +++ b/lib/libpthread/thread/thr_setprio.c @@ -38,43 +38,19 @@  int  pthread_setprio(pthread_t pthread, int prio)  { -	int             rval = 0; -	int             status; -	pthread_t       pthread_p; +	int ret;  	/* Check if the priority is invalid: */ -	if (prio < PTHREAD_MIN_PRIORITY || prio > PTHREAD_MAX_PRIORITY) { +	if (prio < PTHREAD_MIN_PRIORITY || prio > PTHREAD_MAX_PRIORITY)  		/* Return an invalid argument error: */ -		errno = EINVAL; -		rval = -1; -	} else { -		/* Block signals: */ -		_thread_kern_sig_block(&status); +		ret = EINVAL; -		/* Point to the first thread in the list: */ -		pthread_p = _thread_link_list; - -		/* Enter a loop to search for the thread: */ -		while (pthread_p != NULL && pthread_p != pthread) { -			/* Point to the next thread: */ -			pthread_p = pthread_p->nxt; -		} - -		/* Check if the thread pointer is NULL: */ -		if (pthread == NULL || pthread_p == NULL) { -			/* Return a 'search' error: */ -			errno  = ESRCH; -			rval = -1; -		} else { -			/* Set the thread priority: */ -			pthread->pthread_priority = prio; -		} - -		/* Unblock signals: */ -		_thread_kern_sig_unblock(status); -	} +	/* Find the thread in the list of active threads: */ +	else if ((ret = _find_thread(pthread)) == 0) +		/* Set the thread priority: */ +		pthread->pthread_priority = prio;  	/* Return the error status: */ -	return (rval); +	return (ret);  }  #endif diff --git a/lib/libpthread/thread/thr_sig.c b/lib/libpthread/thread/thr_sig.c index e73d5a21e3af..1e5ee630ce4b 100644 --- a/lib/libpthread/thread/thr_sig.c +++ b/lib/libpthread/thread/thr_sig.c @@ -1,5 +1,5 @@  /* - * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>. + * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>   * All rights reserved.   *   * Redistribution and use in source and binary forms, with or without @@ -38,16 +38,79 @@  #include <pthread.h>  #include "pthread_private.h" +/* Static variables: */ +static int	volatile yield_on_unlock_dead		= 0; +static int	volatile yield_on_unlock_thread	= 0; +static long	volatile thread_dead_lock		= 0; +static long	volatile thread_link_list_lock		= 0; + +/* Lock the thread list: */ +void +_lock_thread_list() +{ +	/* Lock the thread list: */ +	_spinlock(&thread_link_list_lock); +} + +/* Lock the dead thread list: */ +void +_lock_dead_thread_list() +{ +	/* Lock the dead thread list: */ +	_spinlock(&thread_dead_lock); +} + +/* Lock the thread list: */ +void +_unlock_thread_list() +{ +	/* Unlock the thread list: */ +	_atomic_unlock(&thread_link_list_lock); + +	/* +	 * Check if a scheduler interrupt occurred while the thread +	 * list was locked: +	 */ +	if (yield_on_unlock_thread) { +		/* Reset the interrupt flag: */ +		yield_on_unlock_thread = 0; + +		/* This thread has overstayed it's welcome: */ +		sched_yield(); +	} +} + +/* Lock the dead thread list: */ +void +_unlock_dead_thread_list() +{ +	/* Unlock the dead thread list: */ +	_atomic_unlock(&thread_dead_lock); + +	/* +	 * Check if a scheduler interrupt occurred while the dead +	 * thread list was locked: +	 */ +	if (yield_on_unlock_dead) { +		/* Reset the interrupt flag: */ +		yield_on_unlock_dead = 0; + +		/* This thread has overstayed it's welcome: */ +		sched_yield(); +	} +} +  void  _thread_sig_handler(int sig, int code, struct sigcontext * scp)  {  	char            c;  	int             i; +	int		dispatch = 0;  	pthread_t       pthread;  	/*  	 * Check if the pthread kernel has unblocked signals (or is about to) -	 * and was on its way into a _thread_sys_select when the current +	 * and was on its way into a _select when the current  	 * signal interrupted it:   	 */  	if (_thread_kern_in_select) { @@ -57,51 +120,65 @@ _thread_sig_handler(int sig, int code, struct sigcontext * scp)  		/*  		 * Write the signal number to the kernel pipe so that it will  		 * be ready to read when this signal handler returns. This -		 * means that the _thread_sys_select call will complete +		 * means that the _select call will complete  		 * immediately.   		 */ -		if (_thread_sys_write(_thread_kern_pipe[1], &c, 1) != 1) { -		} +		_thread_sys_write(_thread_kern_pipe[1], &c, 1);  	} +  	/* Check if the signal requires a dump of thread information: */ -	if (sig == SIGINFO) { +	if (sig == SIGINFO)  		/* Dump thread information to file: */  		_thread_dump_info(); -	} else { -		/* Handle depending on signal type: */ -		switch (sig) { -		/* Interval timer used for timeslicing: */ -		case SIGVTALRM: + +	/* Check if an interval timer signal: */ +	else if (sig == SIGVTALRM) { +		/* Check if the scheduler interrupt has come at an +		 * unfortunate time which one of the threads is +		 * modifying the thread list: +		 */ +		if (thread_link_list_lock)  			/* -			 * Don't add the signal to any thread.  Just want to -			 * call the scheduler: +			 * Set a flag so that the thread that has +			 * the lock yields when it unlocks the +			 * thread list:  			 */ -			break; +			yield_on_unlock_thread = 1; -		/* Child termination: */ -		case SIGCHLD: +		/* Check if the scheduler interrupt has come at an +		 * unfortunate time which one of the threads is +		 * modifying the dead thread list: +		 */ +		if (thread_dead_lock)  			/* -			 * Enter a loop to process each thread in the linked -			 * list: +			 * Set a flag so that the thread that has +			 * the lock yields when it unlocks the +			 * dead thread list:  			 */ -			for (pthread = _thread_link_list; pthread != NULL; -			     pthread = pthread->nxt) { -				/* -				 * Add the signal to the set of pending -				 * signals: -				 */ -				pthread->sigpend[sig] += 1; -				if (pthread->state == PS_WAIT_WAIT) { -					/* Reset the error: */ -					/* There should be another flag so that this is not required! ### */ -					_thread_seterrno(pthread, 0); - -					/* Change the state of the thread to run: */ -					PTHREAD_NEW_STATE(pthread,PS_RUNNING); -				} -			} +			yield_on_unlock_dead = 1; + +		/* +		 * Check if the kernel has not been interrupted while +		 * executing scheduler code: +		 */ +		else if (!_thread_kern_in_sched) { +			/* +			 * Schedule the next thread. This function is not +			 * expected to return because it will do a longjmp +			 * instead.  +			 */ +			_thread_kern_sched(scp);  			/* +			 * This point should not be reached, so abort the +			 * process:  +			 */ +			PANIC("Returned to signal function from scheduler"); +		} +	} else { +		/* Check if a child has terminated: */ +		if (sig == SIGCHLD) { +			/*  			 * Go through the file list and set all files  			 * to non-blocking again in case the child  			 * set some of them to block. Sigh. @@ -109,59 +186,137 @@ _thread_sig_handler(int sig, int code, struct sigcontext * scp)  			for (i = 0; i < _thread_dtablesize; i++) {  				/* Check if this file is used: */  				if (_thread_fd_table[i] != NULL) { -					/* Set the file descriptor to non-blocking: */ -					_thread_sys_fcntl(i, F_SETFL, _thread_fd_table[i]->flags | O_NONBLOCK); +					/* +					 * Set the file descriptor to +					 * non-blocking: +					 */ +					_thread_sys_fcntl(i, F_SETFL, +					    _thread_fd_table[i]->flags | +					    O_NONBLOCK);  				}  			} -			break; +		} -		/* Signals specific to the running thread: */ -		case SIGBUS: -		case SIGEMT: -		case SIGFPE: -		case SIGILL: -		case SIGPIPE: -		case SIGSEGV: -		case SIGSYS: -			/* Add the signal to the set of pending signals: */ -			_thread_run->sigpend[sig] += 1; -			break; +		/* +		 * POSIX says that pending SIGCONT signals are +		 * discarded when one of there signals occurs. +		 */ +		if (sig == SIGTSTP || sig == SIGTTIN || sig == SIGTTOU) { +			/* +			 * Enter a loop to discard pending SIGCONT +			 * signals: +			 */ +			for (pthread = _thread_link_list; +			    pthread != NULL; +			    pthread = pthread->nxt) +				sigdelset(&pthread->sigpend,SIGCONT); +		} -		/* Signals to send to all threads: */ -		default: +		/* Check if the signal is not being ignored: */ +		if (_thread_sigact[sig - 1].sa_handler != SIG_IGN)  			/*  			 * Enter a loop to process each thread in the linked  			 * list:   			 */  			for (pthread = _thread_link_list; pthread != NULL; -			     pthread = pthread->nxt) { -				/* -				 * Add the signal to the set of pending -				 * signals:  -				 */ -				pthread->sigpend[sig] += 1; -			} +			     pthread = pthread->nxt) +				_thread_signal(pthread,sig); + +		/* Dispatch pending signals to the running thread: */ +		_dispatch_signals(); +	} + +	/* Returns nothing. */ +	return; +} + +/* Perform thread specific actions in response to a signal: */ +void +_thread_signal(pthread_t pthread, int sig) +{ +	pthread_t saved; +	struct sigaction act; + +	/* +	 * Flag the signal as pending. It will be dispatched later. +	 */ +	sigaddset(&pthread->sigpend,sig); + +	/* Check if system calls are not restarted: */ +	if ((_thread_sigact[sig - 1].sa_flags & SA_RESTART) == 0) { +		/* +		 * Process according to thread state: +		 */ +		switch (pthread->state) { +		/* +		 * States which do not change when a signal is trapped: +		 */ +		case PS_COND_WAIT: +		case PS_DEAD: +		case PS_FDLR_WAIT: +		case PS_FDLW_WAIT: +		case PS_FILE_WAIT: +		case PS_JOIN: +		case PS_MUTEX_WAIT: +		case PS_RUNNING: +		case PS_STATE_MAX: +		case PS_SIGTHREAD: +		case PS_SUSPENDED: +			/* Nothing to do here. */ +			break; + +		/* +		 * States that are interrupted by the occurrence of a signal +		 * other than the scheduling alarm:  +		 */ +		case PS_FDR_WAIT: +		case PS_FDW_WAIT: +		case PS_SLEEP_WAIT: +		case PS_SIGWAIT: +		case PS_WAIT_WAIT: +		case PS_SELECT_WAIT: +			/* Flag the operation as interrupted: */ +			pthread->interrupted = 1; + +			/* Change the state of the thread to run: */ +			PTHREAD_NEW_STATE(pthread,PS_RUNNING); + +			/* Return the signal number: */ +			pthread->signo = sig;  			break;  		} +	} +} -		/* Check if the kernel is not locked: */ -		if (_thread_run != &_thread_kern_thread) { -			/* -			 * Schedule the next thread. This function is not -			 * expected to return because it will do a longjmp -			 * instead.  -			 */ -			_thread_kern_sched(scp); +/* Dispatch pending signals to the running thread: */ +void +_dispatch_signals() +{ +	int i; +	/* +	 * Check if there are pending signals for the running +	 * thread that aren't blocked: +	 */ +	if ((_thread_run->sigpend & ~_thread_run->sigmask) != 0) +		/* Look for all possible pending signals: */ +		for (i = 1; i < NSIG; i++)  			/* -			 * This point should not be reached, so abort the -			 * process:  +			 * Check that a custom handler is installed +			 * and if the signal is not blocked:  			 */ -			PANIC("Returned to signal function from scheduler"); -		} -	} +			if (_thread_sigact[i - 1].sa_handler != SIG_DFL && +			    _thread_sigact[i - 1].sa_handler != SIG_IGN && +			    sigismember(&_thread_run->sigpend,i) && +			    !sigismember(&_thread_run->sigmask,i)) { +				/* Clear the pending signal: */ +				sigdelset(&_thread_run->sigpend,i); -	/* Returns nothing. */ -	return; +				/* +				 * Dispatch the signal via the custom signal +				 * handler: +				 */ +				(*(_thread_sigact[i - 1].sa_handler))(i); +			}  }  #endif diff --git a/lib/libpthread/thread/thr_sigaction.c b/lib/libpthread/thread/thr_sigaction.c index dd084056366c..3538f276ebae 100644 --- a/lib/libpthread/thread/thr_sigaction.c +++ b/lib/libpthread/thread/thr_sigaction.c @@ -1,5 +1,5 @@  /* - * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>. + * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>   * All rights reserved.   *   * Redistribution and use in source and binary forms, with or without @@ -39,8 +39,8 @@  int  sigaction(int sig, const struct sigaction * act, struct sigaction * oact)  { -	int             ret = 0; -	int             status; +	int ret = 0; +	struct sigaction gact;  	/* Check if the signal number is out of range: */  	if (sig < 1 || sig > NSIG) { @@ -54,25 +54,47 @@ sigaction(int sig, const struct sigaction * act, struct sigaction * oact)  		 */  		if (oact != NULL) {  			/* Return the existing signal action contents: */ -			oact->sa_handler = _thread_run->act[sig - 1].sa_handler; -			oact->sa_mask = _thread_run->act[sig - 1].sa_mask; -			oact->sa_flags = _thread_run->act[sig - 1].sa_flags; +			oact->sa_handler = _thread_sigact[sig - 1].sa_handler; +			oact->sa_mask = _thread_sigact[sig - 1].sa_mask; +			oact->sa_flags = _thread_sigact[sig - 1].sa_flags;  		} +  		/* Check if a signal action was supplied: */  		if (act != NULL) { -			/* Block signals while the signal handler is changed: */ -			_thread_kern_sig_block(&status); -  			/* Set the new signal handler: */ -			_thread_run->act[sig - 1].sa_handler = act->sa_handler; -			_thread_run->act[sig - 1].sa_mask = act->sa_mask; -			_thread_run->act[sig - 1].sa_flags = act->sa_flags; +			_thread_sigact[sig - 1].sa_mask = act->sa_mask; +			_thread_sigact[sig - 1].sa_flags = act->sa_flags; +			_thread_sigact[sig - 1].sa_handler = act->sa_handler; +		} + +		/* +		 * Check if the kernel needs to be advised of a change +		 * in signal action: +		 */ +		if (act != NULL && sig != SIGVTALRM && sig != SIGCHLD && +		    sig != SIGINFO) { +			/* Initialise the global signal action structure: */ +			gact.sa_mask = act->sa_mask; +			gact.sa_flags = act->sa_flags | SA_RESTART;  			/* -			 * Unblock signals to allow the new signal handler to -			 * take effect:  +			 * Check if the signal handler is being set to +			 * the default or ignore handlers:  			 */ -			_thread_kern_sig_unblock(status); +			if (act->sa_handler == SIG_DFL || +			    act->sa_handler == SIG_IGN) +				/* Specify the built in handler: */ +				gact.sa_handler = act->sa_handler; +			else +				/* +				 * Specify the thread kernel signal +				 * handler: +				 */ +				gact.sa_handler = (void (*) ()) _thread_sig_handler; + +			/* Change the signal action in the kernel: */ +		    	if (_thread_sys_sigaction(sig,&gact,NULL) != 0) +				ret = -1;  		}  	} diff --git a/lib/libpthread/thread/thr_sigmask.c b/lib/libpthread/thread/thr_sigmask.c index 94f64cb7991f..23d6b7ff2a3e 100644 --- a/lib/libpthread/thread/thr_sigmask.c +++ b/lib/libpthread/thread/thr_sigmask.c @@ -39,8 +39,7 @@  int  pthread_sigmask(int how, const sigset_t *set, sigset_t *oset)  { -	int	ret = 0; -	int	status; +	int ret = 0;  	/* Check if the existing signal process mask is to be returned: */  	if (oset != NULL) { @@ -49,9 +48,6 @@ pthread_sigmask(int how, const sigset_t *set, sigset_t *oset)  	}  	/* Check if a new signal set was provided by the caller: */  	if (set != NULL) { -		/* Block signals while the signal mask is changed: */ -		_thread_kern_sig_block(&status); -  		/* Process according to what to do: */  		switch (how) {  		/* Block signals: */ @@ -81,11 +77,12 @@ pthread_sigmask(int how, const sigset_t *set, sigset_t *oset)  		}  		/* -		 * Schedule the next thread in case there are signals that -		 * now need to be acted on:  +		 * Dispatch signals to the running thread that are pending +		 * and now unblocked:  		 */ -		_thread_kern_sched(NULL); +		_dispatch_signals();  	} +  	/* Return the completion status: */  	return (ret);  } diff --git a/lib/libpthread/thread/thr_sigprocmask.c b/lib/libpthread/thread/thr_sigprocmask.c index b4a8d84940eb..81b602f581c8 100644 --- a/lib/libpthread/thread/thr_sigprocmask.c +++ b/lib/libpthread/thread/thr_sigprocmask.c @@ -39,8 +39,7 @@  int  sigprocmask(int how, const sigset_t * set, sigset_t * oset)  { -	int             ret = 0; -	int             status; +	int ret = 0;  	/* Check if the existing signal process mask is to be returned: */  	if (oset != NULL) { @@ -49,9 +48,6 @@ sigprocmask(int how, const sigset_t * set, sigset_t * oset)  	}  	/* Check if a new signal set was provided by the caller: */  	if (set != NULL) { -		/* Block signals while the signal mask is changed: */ -		_thread_kern_sig_block(&status); -  		/* Process according to what to do: */  		switch (how) {  		/* Block signals: */ @@ -81,10 +77,10 @@ sigprocmask(int how, const sigset_t * set, sigset_t * oset)  		}  		/* -		 * Schedule the next thread in case there are signals that -		 * now need to be acted on:  +		 * Dispatch signals to the running thread that are pending +		 * and now unblocked:  		 */ -		_thread_kern_sched(NULL); +		_dispatch_signals();  	}  	/* Return the completion status: */  	return (ret); diff --git a/lib/libpthread/thread/thr_sigsuspend.c b/lib/libpthread/thread/thr_sigsuspend.c index 14cf74b31ece..f7a7b123e347 100644 --- a/lib/libpthread/thread/thr_sigsuspend.c +++ b/lib/libpthread/thread/thr_sigsuspend.c @@ -53,6 +53,9 @@ sigsuspend(const sigset_t * set)  		/* Wait for a signal: */  		_thread_kern_sched_state(PS_SIGWAIT, __FILE__, __LINE__); +		/* Always return an interrupted error: */ +		errno = EINTR; +  		/* Restore the signal mask: */  		_thread_run->sigmask = oset;  	} else { diff --git a/lib/libpthread/thread/thr_sigwait.c b/lib/libpthread/thread/thr_sigwait.c index 4f95190e4216..63c7093f7c34 100644 --- a/lib/libpthread/thread/thr_sigwait.c +++ b/lib/libpthread/thread/thr_sigwait.c @@ -43,9 +43,6 @@ sigwait(const sigset_t * set, int *sig)  	int status;  	sigset_t oset; -	/* Block signals: */ -	_thread_kern_sig_block(&status); -  	/* Save the current sigmal mask: */  	oset = _thread_run->sigmask; @@ -55,18 +52,12 @@ sigwait(const sigset_t * set, int *sig)  	/* Wait for a signal: */  	_thread_kern_sched_state(PS_SIGWAIT, __FILE__, __LINE__); -	/* Block signals again: */ -	_thread_kern_sig_block(NULL); -  	/* Return the signal number to the caller: */  	*sig = _thread_run->signo;  	/* Restore the signal mask: */  	_thread_run->sigmask = oset; -	/* Unblock signals: */ -	_thread_kern_sig_unblock(status); -  	/* Return the completion status: */  	return (ret);  } diff --git a/lib/libpthread/thread/thr_spec.c b/lib/libpthread/thread/thr_spec.c index 7ff905404388..dc493dd74e69 100644 --- a/lib/libpthread/thread/thr_spec.c +++ b/lib/libpthread/thread/thr_spec.c @@ -39,29 +39,38 @@  #include "pthread_private.h"  /* Static variables: */ -static struct pthread_key key_table[PTHREAD_KEYS_MAX]; +static	struct pthread_key key_table[PTHREAD_KEYS_MAX]; +static	long	key_table_lock	= 0;  int  pthread_key_create(pthread_key_t * key, void (*destructor) (void *))  { +	/* Lock the key table: */ +	_spinlock(&key_table_lock); +  	for ((*key) = 0; (*key) < PTHREAD_KEYS_MAX; (*key)++) {  		if (key_table[(*key)].count == 0) {  			key_table[(*key)].count++;  			key_table[(*key)].destructor = destructor; + +			/* Unlock the key table: */ +			_atomic_unlock(&key_table_lock);  			return (0);  		}  	} + +	/* Unlock the key table: */ +	_atomic_unlock(&key_table_lock);  	return (EAGAIN);  }  int  pthread_key_delete(pthread_key_t key)  { -	int             ret; -	int             status; +	int ret; -	/* Block signals: */ -	_thread_kern_sig_block(&status); +	/* Lock the key table: */ +	_spinlock(&key_table_lock);  	if (key < PTHREAD_KEYS_MAX) {  		switch (key_table[key].count) { @@ -74,12 +83,11 @@ pthread_key_delete(pthread_key_t key)  		default:  			ret = EBUSY;  		} -	} else { +	} else  		ret = EINVAL; -	} -	/* Unblock signals: */ -	_thread_kern_sig_unblock(status); +	/* Unlock the key table: */ +	_atomic_unlock(&key_table_lock);  	return (ret);  } @@ -89,14 +97,13 @@ _thread_cleanupspecific(void)  	void           *data;  	int             key;  	int             itr; -	int             status; - -	/* Block signals: */ -	_thread_kern_sig_block(&status);  	for (itr = 0; itr < PTHREAD_DESTRUCTOR_ITERATIONS; itr++) {  		for (key = 0; key < PTHREAD_KEYS_MAX; key++) {  			if (_thread_run->specific_data_count) { +				/* Lock the key table entry: */ +				_spinlock(&key_table[key].access_lock); +  				if (_thread_run->specific_data[key]) {  					data = (void *) _thread_run->specific_data[key];  					_thread_run->specific_data[key] = NULL; @@ -106,19 +113,16 @@ _thread_cleanupspecific(void)  					}  					key_table[key].count--;  				} + +				/* Unlock the key table entry: */ +				_atomic_unlock(&key_table[key].access_lock);  			} else {  				free(_thread_run->specific_data); - -				/* Unblock signals: */ -				_thread_kern_sig_unblock(status);  				return;  			}  		}  	}  	free(_thread_run->specific_data); - -	/* Unblock signals: */ -	_thread_kern_sig_unblock(status);  }  static inline const void ** @@ -136,25 +140,16 @@ pthread_setspecific(pthread_key_t key, const void *value)  {  	pthread_t       pthread;  	int             ret = 0; -	int             status; - -	/* Block signals: */ -	_thread_kern_sig_block(&status);  	/* Point to the running thread: */  	pthread = _thread_run; -	/* -	 * Enter a loop for signal handler threads to find the parent thread -	 * which has the specific data associated with it:  -	 */ -	while (pthread->parent_thread != NULL) { -		/* Point to the parent thread: */ -		pthread = pthread->parent_thread; -	} - -	if ((pthread->specific_data) || (pthread->specific_data = pthread_key_allocate_data())) { +	if ((pthread->specific_data) || +	    (pthread->specific_data = pthread_key_allocate_data())) {  		if ((key < PTHREAD_KEYS_MAX) && (key_table)) { +			/* Lock the key table entry: */ +			_spinlock(&key_table[key].access_lock); +  			if (key_table[key].count) {  				if (pthread->specific_data[key] == NULL) {  					if (value != NULL) { @@ -169,18 +164,16 @@ pthread_setspecific(pthread_key_t key, const void *value)  				}  				pthread->specific_data[key] = value;  				ret = 0; -			} else { +			} else  				ret = EINVAL; -			} -		} else { + +			/* Unlock the key table entry: */ +			_atomic_unlock(&key_table[key].access_lock); + +		} else  			ret = EINVAL; -		} -	} else { +	} else  		ret = ENOMEM; -	} - -	/* Unblock signals: */ -	_thread_kern_sig_unblock(status);  	return (ret);  } @@ -188,31 +181,17 @@ void *  pthread_getspecific(pthread_key_t key)  {  	pthread_t       pthread; -	int             status;  	void		*data; -	/* Block signals: */ -	_thread_kern_sig_block(&status); -  	/* Point to the running thread: */  	pthread = _thread_run; -	/* -	 * Enter a loop for signal handler threads to find the parent thread -	 * which has the specific data associated with it:  -	 */ -	while (pthread->parent_thread != NULL) { -		/* Point to the parent thread: */ -		pthread = pthread->parent_thread; -	} - -	/* Check for errors: */ -	if (pthread == NULL) { -		/* Return an invalid argument error: */ -		data = NULL; -	}  	/* Check if there is specific data: */ -	else if (pthread->specific_data != NULL && (key < PTHREAD_KEYS_MAX) && (key_table)) { +	if (pthread->specific_data != NULL && +	    (key < PTHREAD_KEYS_MAX) && (key_table)) { +		/* Lock the key table entry: */ +		_spinlock(&key_table[key].access_lock); +  		/* Check if this key has been used before: */  		if (key_table[key].count) {  			/* Return the value: */ @@ -224,13 +203,12 @@ pthread_getspecific(pthread_key_t key)  			 */  			data = NULL;  		} -	} else { + +		/* Unlock the key table entry: */ +		_atomic_unlock(&key_table[key].access_lock); +	} else  		/* No specific data has been created, so just return NULL: */  		data = NULL; -	} - -	/* Unblock signals: */ -	_thread_kern_sig_unblock(status);  	return (data);  }  #endif diff --git a/lib/libpthread/thread/thr_spinlock.c b/lib/libpthread/thread/thr_spinlock.c new file mode 100644 index 000000000000..b2fe269ccf8f --- /dev/null +++ b/lib/libpthread/thread/thr_spinlock.c @@ -0,0 +1,65 @@ +/* + * Copyright (c) 1997 John Birrell <jb@cimlogic.com.au>. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + *    notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + *    notice, this list of conditions and the following disclaimer in the + *    documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + *    must display the following acknowledgement: + *	This product includes software developed by John Birrell. + * 4. Neither the name of the author nor the names of any co-contributors + *    may be used to endorse or promote products derived from this software + *    without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id$ + * + */ + +#include <stdio.h> +#include <sched.h> +#include <unistd.h> +#include <pthread.h> +#include "spinlock.h" +#include "pthread_private.h" + +/* + * Lock a location for the running thread. Yield to allow other + * threads to run if this thread is blocked because the lock is + * not available. Note that this function does not sleep. It + * assumes that the lock will be available very soon. + */ +void +_spinlock(long *lck) +{ +	do { +		/* +		 * Allow other threads to run if the lock is not +		 * available: +		 */ +		while (*lck != 0) +			sched_yield(); + +	/* +	 * Try to grab the lock and loop if another thread grabs +	 * it before we do. +	 */ +	} while(_atomic_lock(lck,(long) _thread_run)); +} diff --git a/lib/libpthread/thread/thr_suspend_np.c b/lib/libpthread/thread/thr_suspend_np.c index d065b73964e2..871683ad92ab 100644 --- a/lib/libpthread/thread/thr_suspend_np.c +++ b/lib/libpthread/thread/thr_suspend_np.c @@ -1,5 +1,5 @@  /* - * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>. + * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>.   * All rights reserved.   *   * Redistribution and use in source and binary forms, with or without @@ -35,32 +35,24 @@  #include <pthread.h>  #include "pthread_private.h" +/* Suspend a thread: */  int  pthread_suspend_np(pthread_t thread)  { -	int		ret	= -1; -	pthread_t	pthread; -	/* -	 * Search for the thread in the linked list. -	 */ -	for (pthread = _thread_link_list; pthread != NULL && ret == -1; pthread = pthread->nxt) { -		/* Is this the thread? */ -		if (pthread == thread) { -			/* Found the thread. Is it running? */ -			if (pthread->state != PS_RUNNING && -				pthread->state != PS_SUSPENDED) { -			    /* The thread operation has been interrupted */ -			    _thread_seterrno(pthread,EINTR); -			} -			/* Suspend the thread. */ -			PTHREAD_NEW_STATE(pthread,PS_SUSPENDED); -			ret = 0; +	int ret; + +	/* Find the thread in the list of active threads: */ +	if ((ret = _find_thread(thread)) == 0) { +		/* The thread exists. Is it running? */ +		if (thread->state != PS_RUNNING && +		    thread->state != PS_SUSPENDED) { +			/* The thread operation has been interrupted */ +			_thread_seterrno(thread,EINTR); +			thread->interrupted = 1;  		} -	} -	/* Check if thread was not found. */ -	if (ret == -1) { -		/* No such thread */ -		errno = ESRCH; + +		/* Suspend the thread. */ +		PTHREAD_NEW_STATE(thread,PS_SUSPENDED);  	}  	return(ret);  } diff --git a/lib/libpthread/thread/thr_wait4.c b/lib/libpthread/thread/thr_wait4.c index 0a721af4fda9..dda8aeea61cb 100644 --- a/lib/libpthread/thread/thr_wait4.c +++ b/lib/libpthread/thread/thr_wait4.c @@ -1,5 +1,5 @@  /* - * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>. + * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>   * All rights reserved.   *   * Redistribution and use in source and binary forms, with or without @@ -39,23 +39,23 @@  pid_t  wait4(pid_t pid, int *istat, int options, struct rusage * rusage)  { -	int             status;  	pid_t           ret; -	_thread_kern_sig_block(&status);  	/* Perform a non-blocking wait4 syscall: */  	while ((ret = _thread_sys_wait4(pid, istat, options | WNOHANG, rusage)) == 0 && (options & WNOHANG) == 0) { +		/* Reset the interrupted operation flag: */ +		_thread_run->interrupted = 0; +  		/* Schedule the next thread while this one waits: */  		_thread_kern_sched_state(PS_WAIT_WAIT, __FILE__, __LINE__);  		/* Check if this call was interrupted by a signal: */ -		if (errno == EINTR) { +		if (_thread_run->interrupted) { +			errno = EINTR;  			ret = -1;  			break;  		} -		_thread_kern_sig_block(NULL);  	} -	_thread_kern_sig_unblock(status);  	return (ret);  }  #endif diff --git a/lib/libpthread/thread/thr_write.c b/lib/libpthread/thread/thr_write.c index e86e71b87996..f8be7da47450 100644 --- a/lib/libpthread/thread/thr_write.c +++ b/lib/libpthread/thread/thr_write.c @@ -1,5 +1,5 @@  /* - * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>. + * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>   * All rights reserved.   *   * Redistribution and use in source and binary forms, with or without @@ -29,7 +29,7 @@   * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF   * SUCH DAMAGE.   * - * $Id: uthread_write.c,v 1.3 1997/04/01 22:44:17 jb Exp $ + * $Id: uthread_write.c,v 1.4 1998/02/13 01:27:33 julian Exp $   *   */  #include <sys/types.h> @@ -45,7 +45,6 @@ ssize_t  write(int fd, const void *buf, size_t nbytes)  {  	int	ret; -	int	status;  	/* Lock the file descriptor for write: */  	if ((ret = _thread_fd_lock(fd, FD_WRITE, NULL, @@ -54,7 +53,6 @@ write(int fd, const void *buf, size_t nbytes)  		while ((ret = _thread_sys_write(fd, buf, nbytes)) < 0) {  			if ((_thread_fd_table[fd]->flags & O_NONBLOCK) == 0 &&  			    (errno == EWOULDBLOCK || errno == EAGAIN)) { -				_thread_kern_sig_block(&status);  				_thread_run->data.fd.fd = fd;  				_thread_kern_set_timeout(NULL); @@ -69,6 +67,7 @@ write(int fd, const void *buf, size_t nbytes)  				 * interrupted by a signal  				 */  				if (_thread_run->interrupted) { +					errno = EINTR;  					ret = -1;  					break;  				} diff --git a/lib/libpthread/thread/thr_writev.c b/lib/libpthread/thread/thr_writev.c index 56e1872c6d82..f3badecb7aa5 100644 --- a/lib/libpthread/thread/thr_writev.c +++ b/lib/libpthread/thread/thr_writev.c @@ -1,5 +1,5 @@  /* - * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>. + * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>   * All rights reserved.   *   * Redistribution and use in source and binary forms, with or without @@ -29,7 +29,7 @@   * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF   * SUCH DAMAGE.   * - * $Id: uthread_writev.c,v 1.3 1997/04/01 22:44:18 jb Exp $ + * $Id: uthread_writev.c,v 1.4 1998/02/13 01:27:34 julian Exp $   *   */  #include <sys/types.h> @@ -45,7 +45,6 @@ ssize_t  writev(int fd, const struct iovec * iov, int iovcnt)  {  	int	ret; -	int	status;  	/* Lock the file descriptor for write: */  	if ((ret = _thread_fd_lock(fd, FD_WRITE, NULL, @@ -54,7 +53,6 @@ writev(int fd, const struct iovec * iov, int iovcnt)  		while ((ret = _thread_sys_writev(fd, iov, iovcnt)) < 0) {  			if ((_thread_fd_table[fd]->flags & O_NONBLOCK) == 0 &&  			    (errno == EWOULDBLOCK || errno == EAGAIN)) { -				_thread_kern_sig_block(&status);  				_thread_run->data.fd.fd = fd;  				_thread_kern_set_timeout(NULL); @@ -69,6 +67,7 @@ writev(int fd, const struct iovec * iov, int iovcnt)  				 * interrupted by a signal  				 */  				if (_thread_run->interrupted) { +					errno = EINTR;  					ret = -1;  					break;  				} | 
