diff options
| author | Julian Elischer <julian@FreeBSD.org> | 1996-08-20 08:22:01 +0000 | 
|---|---|---|
| committer | Julian Elischer <julian@FreeBSD.org> | 1996-08-20 08:22:01 +0000 | 
| commit | 0f7d684755aefbcfd70b45d24efc2d39bc505c4c (patch) | |
| tree | b14348030d1048f8628b798374a8a061a990aae3 /lib/libpthread/thread | |
| parent | 1bbb22c82e47dbc805e523be5e2fe3d4436761e0 (diff) | |
Notes
Diffstat (limited to 'lib/libpthread/thread')
25 files changed, 1531 insertions, 464 deletions
| diff --git a/lib/libpthread/thread/Makefile.inc b/lib/libpthread/thread/Makefile.inc index f37a21fbc58a..72a6e57a56c5 100644 --- a/lib/libpthread/thread/Makefile.inc +++ b/lib/libpthread/thread/Makefile.inc @@ -1,4 +1,4 @@ -#	$Id: Makefile.inc,v 1.1 1996/01/22 00:23:03 julian Exp $ +#	$Id: Makefile.inc,v 1.2 1996/02/17 02:19:35 jdp Exp $  CPLUSPLUSLIB=	cpluspluslib @@ -7,7 +7,7 @@ CPLUSPLUSLIB=	cpluspluslib  SRCS+= \  	uthread_accept.c \ -	uthread_attr_setcreatesuspend.c \ +	uthread_attr_setcreatesuspend_np.c \  	uthread_autoinit.cc \  	uthread_bind.c \  	uthread_clean.c \ @@ -52,7 +52,7 @@ SRCS+= \  	uthread_read.c \  	uthread_readv.c \  	uthread_recvfrom.c \ -	uthread_resume.c \ +	uthread_resume_np.c \  	uthread_select.c \  	uthread_self.c \  	uthread_sendto.c \ @@ -71,7 +71,7 @@ SRCS+= \  	uthread_socket.c \  	uthread_socketpair.c \  	uthread_spec.c \ -	uthread_suspend.c \ +	uthread_suspend_np.c \  	uthread_wait4.c \  	uthread_write.c \  	uthread_writev.c \ diff --git a/lib/libpthread/thread/thr_attr_destroy.c b/lib/libpthread/thread/thr_attr_destroy.c new file mode 100644 index 000000000000..be6b2a2d7dcb --- /dev/null +++ b/lib/libpthread/thread/thr_attr_destroy.c @@ -0,0 +1,52 @@ +/* + * Copyright (c) 1996 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 <stdlib.h> +#include <errno.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +int pthread_attr_destroy(pthread_attr_t *attr) +{ +	int	ret; +	if (attr == NULL || *attr == NULL) { +		errno = EINVAL; +		ret = -1; +	} else { +		free(*attr); +		*attr = NULL; +		ret = 0; +	} +	return(ret); +} +#endif diff --git a/lib/libpthread/thread/thr_attr_init.c b/lib/libpthread/thread/thr_attr_init.c new file mode 100644 index 000000000000..7dade978a48f --- /dev/null +++ b/lib/libpthread/thread/thr_attr_init.c @@ -0,0 +1,54 @@ +/* + * Copyright (c) 1996 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 <string.h> +#include <stdlib.h> +#include <errno.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +int pthread_attr_init(pthread_attr_t *attr) +{ +	int	ret; +	pthread_attr_t	pattr; +	if ((pattr = (pthread_attr_t) malloc(sizeof(struct pthread_attr))) == NULL) { +		errno = ENOMEM; +		ret = -1; +	} else { +		memcpy(pattr, &pthread_attr_default, sizeof(struct pthread_attr)); +		*attr = pattr; +		ret = 0; +	} +	return(ret); +} +#endif diff --git a/lib/libpthread/thread/thr_attr_setcreatesuspend_np.c b/lib/libpthread/thread/thr_attr_setcreatesuspend_np.c new file mode 100644 index 000000000000..afe6b23c3cb2 --- /dev/null +++ b/lib/libpthread/thread/thr_attr_setcreatesuspend_np.c @@ -0,0 +1,51 @@ +/* + * Copyright (c) 1995 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" + +int +pthread_attr_setcreatesuspend_np(pthread_attr_t *attr) +{ +	int	ret; +	if (attr == NULL || *attr == NULL) { +		errno = EINVAL; +		ret = -1; +	} else { +		(*attr)->suspend = PTHREAD_CREATE_SUSPENDED; +		ret = 0; +	} +	return(ret); +} +#endif diff --git a/lib/libpthread/thread/thr_attr_setstacksize.c b/lib/libpthread/thread/thr_attr_setstacksize.c new file mode 100644 index 000000000000..5e59798f579b --- /dev/null +++ b/lib/libpthread/thread/thr_attr_setstacksize.c @@ -0,0 +1,50 @@ +/* + * Copyright (c) 1996 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" + +int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize) +{ +	int	ret; +	if (attr == NULL || *attr == NULL || stacksize < PTHREAD_STACK_MIN) { +		errno = EINVAL; +		ret = -1; +	} else { +		(*attr)->stacksize_attr = stacksize; +		ret = 0; +	} +	return(ret); +} +#endif diff --git a/lib/libpthread/thread/thr_close.c b/lib/libpthread/thread/thr_close.c index f98e056aaab3..26a8fbfd5904 100644 --- a/lib/libpthread/thread/thr_close.c +++ b/lib/libpthread/thread/thr_close.c @@ -30,7 +30,10 @@   * SUCH DAMAGE.   *   */ +#include <stdlib.h>  #include <unistd.h> +#include <fcntl.h> +#include <sys/stat.h>  #ifdef _THREAD_SAFE  #include <pthread.h>  #include "pthread_private.h" @@ -38,10 +41,55 @@  int  close(int fd)  { -	int ret; +	int		flags; +	int		ret; +	int		status; +	struct stat	sb; + +	/* 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); + +		/* +		 * Check if the file should be left as blocking. +		 * +		 * This is so that the file descriptors shared with a parent +		 * process aren't left set to non-blocking if the child +		 * closes them prior to exit.  An example where this causes +		 * problems with /bin/sh is when a child closes stdin. +		 * +		 * Setting a file as blocking causes problems if a threaded +		 * parent accesses the file descriptor before the child exits. +		 * Once the threaded parent receives a SIGCHLD then it resets +		 * all of its files to non-blocking, and so it is then safe +		 * to access them. +		 * +		 * Pipes are not set to blocking when they are closed, as +		 * the parent and child will normally close the file +		 * descriptor of the end of the pipe that they are not +		 * using, which would then cause any reads to block +		 * indefinitely. +		 */ +		if ((S_ISREG(sb.st_mode) || S_ISCHR(sb.st_mode)) && (_thread_fd_table[fd]->flags & O_NONBLOCK) == 0) { +			/* Get the current flags: */ +			flags = _thread_sys_fcntl(fd, F_GETFL, NULL); +			/* Clear the nonblocking file descriptor flag: */ +			_thread_sys_fcntl(fd, F_SETFL, flags & ~O_NONBLOCK); +		} + +		/* Close the file descriptor: */  		ret = _thread_sys_close(fd); -		_thread_fd_unlock(fd, FD_RDWR); + +		/* 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 930f31aea623..0f9f30230ba0 100644 --- a/lib/libpthread/thread/thr_cond.c +++ b/lib/libpthread/thread/thr_cond.c @@ -40,41 +40,56 @@ int  pthread_cond_init(pthread_cond_t * cond, const pthread_condattr_t * cond_attr)  {  	enum pthread_cond_type type; +	pthread_cond_t	pcond;  	int             rval = 0; -	/* -	 * Check if a pointer to a condition variable attribute structure was -	 * passed by the caller:  -	 */ -	if (cond_attr != NULL) { -		/* Default to a fast condition variable: */ -		type = cond_attr->c_type; +	if (cond == NULL) { +		errno = EINVAL; +		rval = -1;  	} else { -		/* Default to a fast condition variable: */ -		type = COND_TYPE_FAST; -	} - -	/* Process according to condition variable type: */ -	switch (type) { -		/* Fast condition variable: */ -	case COND_TYPE_FAST: -		/* Nothing to do here. */ -		break; +		/* +		 * Check if a pointer to a condition variable attribute structure was +		 * passed by the caller:  +		 */ +		if (cond_attr != NULL && *cond_attr != NULL) { +			/* Default to a fast condition variable: */ +			type = (*cond_attr)->c_type; +		} else { +			/* Default to a fast condition variable: */ +			type = COND_TYPE_FAST; +		} -		/* Trap invalid condition variable types: */ -	default: -		/* Return an invalid argument error: */ -		_thread_seterrno(_thread_run, EINVAL); -		rval = -1; -		break; -	} +		/* Process according to condition variable type: */ +		switch (type) { +			/* Fast condition variable: */ +		case COND_TYPE_FAST: +			/* Nothing to do here. */ +			break; + +			/* Trap invalid condition variable types: */ +		default: +			/* Return an invalid argument error: */ +			errno = EINVAL; +			rval = -1; +			break; +		} -	/* Check for no errors: */ -	if (rval == 0) { -		/* Initialise the condition variable structure: */ -		_thread_queue_init(&cond->c_queue); -		cond->c_flags |= COND_FLAGS_INITED; -		cond->c_type = type; +		/* Check for no errors: */ +		if (rval == 0) { +			if ((pcond = (pthread_cond_t) malloc(sizeof(struct pthread_cond))) == NULL) { +				errno = ENOMEM; +				rval = -1; +			} else { +				/* +				 * Initialise the condition variable +				 * structure: +				 */ +				_thread_queue_init(&pcond->c_queue); +				pcond->c_flags |= COND_FLAGS_INITED; +				pcond->c_type = type; +				*cond = pcond; +			} +		}  	}  	/* Return the completion status: */  	return (rval); @@ -85,26 +100,33 @@ pthread_cond_destroy(pthread_cond_t * cond)  {  	int             rval = 0; -	/* Process according to condition variable type: */ -	switch (cond->c_type) { -		/* Fast condition variable: */ -	case COND_TYPE_FAST: -		/* Nothing to do here. */ -		break; - -		/* Trap invalid condition variable types: */ -	default: -		/* Return an invalid argument error: */ -		_thread_seterrno(_thread_run, EINVAL); +	if (cond == NULL || *cond == NULL) { +		errno = EINVAL;  		rval = -1; -		break; -	} +	} else { +		/* Process according to condition variable type: */ +		switch ((*cond)->c_type) { +			/* Fast condition variable: */ +		case COND_TYPE_FAST: +			/* Nothing to do here. */ +			break; + +			/* Trap invalid condition variable types: */ +		default: +			/* Return an invalid argument error: */ +			errno = EINVAL; +			rval = -1; +			break; +		} -	/* Check for errors: */ -	if (rval == 0) { -		/* Destroy the contents of the condition structure: */ -		_thread_queue_init(&cond->c_queue); -		cond->c_flags = 0; +		/* 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; +		}  	}  	/* Return the completion status: */  	return (rval); @@ -116,40 +138,45 @@ pthread_cond_wait(pthread_cond_t * cond, pthread_mutex_t * mutex)  	int             rval = 0;  	int             status; -	/* Block signals: */ -	_thread_kern_sig_block(&status); +	if (cond == NULL || *cond == NULL) { +		errno = EINVAL; +		rval = -1; +	} else { +		/* Block signals: */ +		_thread_kern_sig_block(&status); -	/* Process according to condition variable type: */ -	switch (cond->c_type) { -		/* Fast condition variable: */ -	case COND_TYPE_FAST: -		/* Queue the running thread for the condition variable: */ -			_thread_queue_enq(&cond->c_queue, _thread_run); +		/* Process according to condition variable type: */ +		switch ((*cond)->c_type) { +			/* Fast condition variable: */ +		case COND_TYPE_FAST: +			/* Queue the running thread for the condition variable: */ +				_thread_queue_enq(&(*cond)->c_queue, _thread_run); -		/* Unlock the mutex: */ -		pthread_mutex_unlock(mutex); +			/* Unlock the mutex: */ +			pthread_mutex_unlock(mutex); -		/* Schedule the next thread: */ -		_thread_kern_sched_state(PS_COND_WAIT, __FILE__, __LINE__); +			/* Schedule the next thread: */ +			_thread_kern_sched_state(PS_COND_WAIT, __FILE__, __LINE__); -		/* Block signals: */ -		_thread_kern_sig_block(NULL); +			/* Block signals: */ +			_thread_kern_sig_block(NULL); -		/* Lock the mutex: */ -		rval = pthread_mutex_lock(mutex); -		break; +			/* Lock the mutex: */ +			rval = pthread_mutex_lock(mutex); +			break; + +			/* Trap invalid condition variable types: */ +		default: +			/* Return an invalid argument error: */ +			errno = EINVAL; +			rval = -1; +			break; +		} -		/* Trap invalid condition variable types: */ -	default: -		/* Return an invalid argument error: */ -		_thread_seterrno(_thread_run, EINVAL); -		rval = -1; -		break; +		/* Unblock signals: */ +		_thread_kern_sig_unblock(status);  	} -	/* Unblock signals: */ -	_thread_kern_sig_unblock(status); -  	/* Return the completion status: */  	return (rval);  } @@ -161,60 +188,70 @@ pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex,  	int             rval = 0;  	int             status; -	/* Block signals: */ -	_thread_kern_sig_block(&status); - -	/* Process according to condition variable type: */ -	switch (cond->c_type) { -		/* Fast condition variable: */ -	case COND_TYPE_FAST: -		/* Set the wakeup time: */ -		_thread_run->wakeup_time.ts_sec = abstime->ts_sec; -		_thread_run->wakeup_time.ts_nsec = abstime->ts_nsec; - -		/* Reset the timeout flag: */ -		_thread_run->timeout = 0; - -		/* Queue the running thread for the condition variable: */ -		_thread_queue_enq(&cond->c_queue, _thread_run); - -		/* Unlock the mutex: */ -		if ((rval = pthread_mutex_unlock(mutex)) != 0) { -			/* -			 * Cannot unlock the mutex, so remove the running -			 * thread from the condition variable queue:  -			 */ -			_thread_queue_deq(&cond->c_queue); -		} else { -			/* Schedule the next thread: */ -			_thread_kern_sched_state(PS_COND_WAIT, __FILE__, __LINE__); - -			/* Block signals: */ -			_thread_kern_sig_block(NULL); +	if (cond == NULL || *cond == NULL) { +		errno = EINVAL; +		rval = -1; +	} else { +		/* Block signals: */ +		_thread_kern_sig_block(&status); + +		/* Process according to condition variable type: */ +		switch ((*cond)->c_type) { +			/* Fast condition variable: */ +		case COND_TYPE_FAST: +			/* Set the wakeup time: */ +#if	defined(__FreeBSD__) +			_thread_run->wakeup_time.ts_sec = abstime->ts_sec; +			_thread_run->wakeup_time.ts_nsec = abstime->ts_nsec; +#else +			_thread_run->wakeup_time.tv_sec = abstime->tv_sec; +			_thread_run->wakeup_time.tv_nsec = abstime->tv_nsec; +#endif -			/* Lock the mutex: */ -			if ((rval = pthread_mutex_lock(mutex)) != 0) { -			} -			/* Check if the wait timed out: */ -			else if (_thread_run->timeout) { -				/* Return a timeout error: */ -				_thread_seterrno(_thread_run, EAGAIN); -				rval = -1; +			/* Reset the timeout flag: */ +			_thread_run->timeout = 0; + +			/* Queue the running thread for the condition variable: */ +			_thread_queue_enq(&(*cond)->c_queue, _thread_run); + +			/* Unlock the mutex: */ +			if ((rval = pthread_mutex_unlock(mutex)) != 0) { +				/* +				 * Cannot unlock the mutex, so remove the running +				 * thread from the condition variable queue:  +				 */ +				_thread_queue_deq(&(*cond)->c_queue); +			} else { +				/* Schedule the next thread: */ +				_thread_kern_sched_state(PS_COND_WAIT, __FILE__, __LINE__); + +				/* Block signals: */ +				_thread_kern_sig_block(NULL); + +				/* Lock the mutex: */ +				if ((rval = pthread_mutex_lock(mutex)) != 0) { +				} +				/* Check if the wait timed out: */ +				else if (_thread_run->timeout) { +					/* Return a timeout error: */ +					errno = EAGAIN; +					rval = -1; +				}  			} +			break; + +			/* Trap invalid condition variable types: */ +		default: +			/* Return an invalid argument error: */ +			errno = EINVAL; +			rval = -1; +			break;  		} -		break; -		/* Trap invalid condition variable types: */ -	default: -		/* Return an invalid argument error: */ -		_thread_seterrno(_thread_run, EINVAL); -		rval = -1; -		break; +		/* Unblock signals: */ +		_thread_kern_sig_unblock(status);  	} -	/* Unblock signals: */ -	_thread_kern_sig_unblock(status); -  	/* Return the completion status: */  	return (rval);  } @@ -226,31 +263,36 @@ pthread_cond_signal(pthread_cond_t * cond)  	int             status;  	pthread_t       pthread; -	/* Block signals: */ -	_thread_kern_sig_block(&status); - -	/* Process according to condition variable type: */ -	switch (cond->c_type) { -		/* Fast condition variable: */ -	case COND_TYPE_FAST: -		/* Bring the next thread off the condition queue: */ -		if ((pthread = _thread_queue_deq(&cond->c_queue)) != NULL) { -			/* Allow the thread to run: */ -			pthread->state = PS_RUNNING; +	if (cond == NULL || *cond == NULL) { +		errno = EINVAL; +		rval = -1; +	} else { +		/* Block signals: */ +		_thread_kern_sig_block(&status); + +		/* Process according to condition variable type: */ +		switch ((*cond)->c_type) { +			/* Fast condition variable: */ +		case COND_TYPE_FAST: +			/* Bring the next thread off the condition queue: */ +			if ((pthread = _thread_queue_deq(&(*cond)->c_queue)) != NULL) { +				/* Allow the thread to run: */ +				pthread->state = PS_RUNNING; +			} +			break; + +			/* Trap invalid condition variable types: */ +		default: +			/* Return an invalid argument error: */ +			errno = EINVAL; +			rval = -1; +			break;  		} -		break; -		/* Trap invalid condition variable types: */ -	default: -		/* Return an invalid argument error: */ -		_thread_seterrno(_thread_run, EINVAL); -		rval = -1; -		break; +		/* Unblock signals: */ +		_thread_kern_sig_unblock(status);  	} -	/* Unblock signals: */ -	_thread_kern_sig_unblock(status); -  	/* Return the completion status: */  	return (rval);  } @@ -266,11 +308,11 @@ pthread_cond_broadcast(pthread_cond_t * cond)  	_thread_kern_sig_block(&status);  	/* Process according to condition variable type: */ -	switch (cond->c_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) { +		while ((pthread = _thread_queue_deq(&(*cond)->c_queue)) != NULL) {  			/* Allow the thread to run: */  			pthread->state = PS_RUNNING;  		} @@ -279,7 +321,7 @@ pthread_cond_broadcast(pthread_cond_t * cond)  		/* Trap invalid condition variable types: */  	default:  		/* Return an invalid argument error: */ -		_thread_seterrno(_thread_run, EINVAL); +		errno = EINVAL;  		rval = -1;  		break;  	} diff --git a/lib/libpthread/thread/thr_create.c b/lib/libpthread/thread/thr_create.c index e6db38144f64..1d57f8a1626d 100644 --- a/lib/libpthread/thread/thr_create.c +++ b/lib/libpthread/thread/thr_create.c @@ -49,6 +49,7 @@ _thread_create(pthread_t * thread, const pthread_attr_t * attr,  	int             ret = 0;  	int             status;  	pthread_t       new_thread; +	pthread_attr_t	pattr;  	void           *stack;  	/* Block signals: */ @@ -60,15 +61,17 @@ _thread_create(pthread_t * thread, const pthread_attr_t * attr,  		ret = EAGAIN;  	} else {  		/* Check if default thread attributes are required: */ -		if (attr == NULL) { +		if (attr == NULL || *attr == NULL) {  			/* Use the default thread attributes: */ -			attr = &pthread_attr_default; +			pattr = &pthread_attr_default; +		} else { +			pattr = *attr;  		}  		/* Check if a stack was specified in the thread attributes: */ -		if ((stack = attr->stackaddr_attr) != NULL) { +		if ((stack = pattr->stackaddr_attr) != NULL) {  		}  		/* Allocate memory for the stack: */ -		else if ((stack = (void *) malloc(attr->stacksize_attr)) == NULL) { +		else if ((stack = (void *) malloc(pattr->stacksize_attr)) == NULL) {  			/* Insufficient memory to create a thread: */  			ret = EAGAIN;  			free(new_thread); @@ -83,7 +86,7 @@ _thread_create(pthread_t * thread, const pthread_attr_t * attr,  			new_thread->stack = stack;  			new_thread->start_routine = start_routine;  			new_thread->arg = arg; -			if (attr->suspend == PTHREAD_CREATE_SUSPENDED) { +			if (pattr->suspend == PTHREAD_CREATE_SUSPENDED) {  				new_thread->state = PS_SUSPENDED;  			} else {  				new_thread->state = PS_RUNNING; @@ -148,19 +151,19 @@ _thread_create(pthread_t * thread, const pthread_attr_t * attr,  			/* The stack starts high and builds down: */  #if	defined(__FreeBSD__) -			new_thread->saved_jmp_buf[0]._jb[2] = (int) (new_thread->stack + attr->stacksize_attr - sizeof(double)); +			new_thread->saved_jmp_buf[0]._jb[2] = (int) (new_thread->stack + pattr->stacksize_attr - sizeof(double));  #elif	defined(__NetBSD__)  #if	defined(__alpha) -			new_thread->saved_jmp_buf[4 + R_SP] = (long) new_thread->stack + attr->stacksize_attr - sizeof(double); +			new_thread->saved_jmp_buf[4 + R_SP] = (long) new_thread->stack + pattr->stacksize_attr - sizeof(double);  #else -			new_thread->saved_jmp_buf[2] = (long) new_thread->stack + attr->stacksize_attr - sizeof(double); +			new_thread->saved_jmp_buf[2] = (long) new_thread->stack + pattr->stacksize_attr - sizeof(double);  #endif  #else  #error	"Don't recognize this operating system!"  #endif  			/* Copy the thread attributes: */ -			memcpy(&new_thread->attr, attr, sizeof(pthread_attr_t)); +			memcpy(&new_thread->attr, pattr, sizeof(struct pthread_attr));  			/*  			 * Check if this thread is to inherit the scheduling diff --git a/lib/libpthread/thread/thr_exit.c b/lib/libpthread/thread/thr_exit.c index 292fce9c0fb8..60662060e01e 100644 --- a/lib/libpthread/thread/thr_exit.c +++ b/lib/libpthread/thread/thr_exit.c @@ -31,11 +31,49 @@   *   */  #include <errno.h> +#include <unistd.h> +#include <fcntl.h>  #include <string.h>  #ifdef _THREAD_SAFE  #include <pthread.h>  #include "pthread_private.h" +void _exit(int status) +{ +	int		flags; +	int             i; +	struct itimerval itimer; + +	/* Disable the interval timer: */ +	itimer.it_interval.tv_sec  = 0; +	itimer.it_interval.tv_usec = 0; +	itimer.it_value.tv_sec     = 0; +	itimer.it_value.tv_usec    = 0; +	setitimer(ITIMER_VIRTUAL, &itimer, NULL); + +	/* Close the pthread kernel pipe: */ +	_thread_sys_close(_thread_kern_pipe[0]); +	_thread_sys_close(_thread_kern_pipe[1]); + +	/* +	 * Enter a loop to set all file descriptors to blocking +	 * if they were not created as non-blocking: +	 */ +	for (i = 0; i < _thread_dtablesize; i++) { +		/* Check if this file descriptor is in use: */ +		if (_thread_fd_table[i] != NULL && +			!(_thread_fd_table[i]->flags & O_NONBLOCK)) { +			/* Get the current flags: */ +			flags = _thread_sys_fcntl(i, F_GETFL, NULL); +			/* Clear the nonblocking file descriptor flag: */ +			_thread_sys_fcntl(i, F_SETFL, flags & ~O_NONBLOCK); +		} +	} + +	/* Call the _exit syscall: */ +	_thread_sys__exit(status); +} +  void  _thread_exit(char *fname, int lineno, char *string)  { diff --git a/lib/libpthread/thread/thr_fcntl.c b/lib/libpthread/thread/thr_fcntl.c index ae069b8e36a9..f83ee5098f37 100644 --- a/lib/libpthread/thread/thr_fcntl.c +++ b/lib/libpthread/thread/thr_fcntl.c @@ -31,6 +31,7 @@   *   */  #include <stdarg.h> +#include <unistd.h>  #include <fcntl.h>  #ifdef _THREAD_SAFE  #include <pthread.h> diff --git a/lib/libpthread/thread/thr_fork.c b/lib/libpthread/thread/thr_fork.c index 6e7ca0d43b44..19f674d39552 100644 --- a/lib/libpthread/thread/thr_fork.c +++ b/lib/libpthread/thread/thr_fork.c @@ -31,6 +31,8 @@   *   */  #include <errno.h> +#include <string.h> +#include <unistd.h>  #include <fcntl.h>  #ifdef _THREAD_SAFE  #include <pthread.h> diff --git a/lib/libpthread/thread/thr_init.c b/lib/libpthread/thread/thr_init.c index 6139935176e1..d044063ce9d4 100644 --- a/lib/libpthread/thread/thr_init.c +++ b/lib/libpthread/thread/thr_init.c @@ -202,18 +202,6 @@ _thread_main(int argc, char *argv[], char *env)  	_thread_init();  	return (main(argc, argv, env));  } -#else -/* - * Force our auto-initialization module to be pulled in from the library, - * by referencing a symbol that is defined in it. - * - * The auto-initialization module is a small C++ module.  It has a static - * constructor that calls _thread_init() automatically, at the beginning - * of program execution.  That eliminates the need for any special hooks - * in crt0.o. - */ -extern int _thread_autoinit_dummy_decl; -static int *_thread_autoinit_dummy_ref = &_thread_autoinit_dummy_decl;  #endif  #else  /* diff --git a/lib/libpthread/thread/thr_kern.c b/lib/libpthread/thread/thr_kern.c index 35e8e29b9711..c6759cfe3b3d 100644 --- a/lib/libpthread/thread/thr_kern.c +++ b/lib/libpthread/thread/thr_kern.c @@ -250,18 +250,30 @@ __asm__("fnsave %0": :"m"(*fdata));  			    pthread->state == PS_FDW_WAIT ||  			    pthread->state == PS_SELECT_WAIT) {  				/* Check if this thread is to wait forever: */ +#if	defined(__FreeBSD__)  				if (pthread->wakeup_time.ts_sec == -1) { +#else +				if (pthread->wakeup_time.tv_sec == -1) { +#endif  				}  				/*  				 * Check if this thread is to wakeup  				 * immediately or if it is past its wakeup  				 * time:   				 */ +#if	defined(__FreeBSD__)  				else if ((pthread->wakeup_time.ts_sec == 0 &&  					pthread->wakeup_time.ts_nsec == 0) ||  					 (ts.ts_sec > pthread->wakeup_time.ts_sec) ||  					 ((ts.ts_sec == pthread->wakeup_time.ts_sec) &&  					  (ts.ts_nsec >= pthread->wakeup_time.ts_nsec))) { +#else +				else if ((pthread->wakeup_time.tv_sec == 0 && +					pthread->wakeup_time.tv_nsec == 0) || +					 (ts.tv_sec > pthread->wakeup_time.tv_sec) || +					 ((ts.tv_sec == pthread->wakeup_time.tv_sec) && +					  (ts.tv_nsec >= pthread->wakeup_time.tv_nsec))) { +#endif  					/*  					 * Check if this thread is waiting on  					 * select:  @@ -364,9 +376,48 @@ __asm__("fnsave %0": :"m"(*fdata));  		}  		/*  		 * Enter a loop to look for the first thread of the highest -		 * priority:  +		 * 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) {  			} @@ -392,6 +443,45 @@ __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. */ @@ -446,6 +536,45 @@ __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:  @@ -565,22 +694,37 @@ __asm__("fnsave %0": :"m"(*fdata));  						 * Check if this thread is to  						 * wait forever:   						 */ +#if	defined(__FreeBSD__)  						if (pthread->wakeup_time.ts_sec == -1) { +#else +						if (pthread->wakeup_time.tv_sec == -1) { +#endif  						}  						/*  						 * Check if this thread is to  						 * wakeup immediately:   						 */ +#if	defined(__FreeBSD__)  						else if (pthread->wakeup_time.ts_sec == 0 &&  							 pthread->wakeup_time.ts_nsec == 0) { +#else +						else if (pthread->wakeup_time.tv_sec == 0 && +							 pthread->wakeup_time.tv_nsec == 0) { +#endif  						}  						/*  						 * Check if the current time  						 * is after the wakeup time:   						 */ +#if	defined(__FreeBSD__)  						else if ((ts.ts_sec > pthread->wakeup_time.ts_sec) ||  							 ((ts.ts_sec == pthread->wakeup_time.ts_sec) &&  							  (ts.ts_nsec > pthread->wakeup_time.ts_nsec))) { +#else +						else if ((ts.tv_sec > pthread->wakeup_time.tv_sec) || +							 ((ts.tv_sec == pthread->wakeup_time.tv_sec) && +							  (ts.tv_nsec > pthread->wakeup_time.tv_nsec))) { +#endif  						} else {  							/*  							 * Calculate the time @@ -589,16 +733,26 @@ __asm__("fnsave %0": :"m"(*fdata));  							 * for the clock  							 * resolution:   							 */ +#if	defined(__FreeBSD__)  							ts1.ts_sec = pthread->wakeup_time.ts_sec - ts.ts_sec;  							ts1.ts_nsec = pthread->wakeup_time.ts_nsec - ts.ts_nsec +  								CLOCK_RES_NSEC; +#else +							ts1.tv_sec = pthread->wakeup_time.tv_sec - ts.tv_sec; +							ts1.tv_nsec = pthread->wakeup_time.tv_nsec - ts.tv_nsec + +								CLOCK_RES_NSEC; +#endif  							/*  							 * Check for  							 * underflow of the  							 * nanosecond field:   							 */ +#if	defined(__FreeBSD__)  							if (ts1.ts_nsec < 0) { +#else +							if (ts1.tv_nsec < 0) { +#endif  								/*  								 * Allow for  								 * the @@ -607,15 +761,24 @@ __asm__("fnsave %0": :"m"(*fdata));  								 * nanosecond  								 * field:   								 */ +#if	defined(__FreeBSD__)  								ts1.ts_sec--;  								ts1.ts_nsec += 1000000000; +#else +								ts1.tv_sec--; +								ts1.tv_nsec += 1000000000; +#endif  							}  							/*  							 * Check for overflow  							 * of the nanosecond  							 * field:   							 */ +#if	defined(__FreeBSD__)  							if (ts1.ts_nsec >= 1000000000) { +#else +							if (ts1.tv_nsec >= 1000000000) { +#endif  								/*  								 * Allow for  								 * the @@ -624,8 +787,13 @@ __asm__("fnsave %0": :"m"(*fdata));  								 * nanosecond  								 * field:   								 */ +#if	defined(__FreeBSD__)  								ts1.ts_sec++;  								ts1.ts_nsec -= 1000000000; +#else +								ts1.tv_sec++; +								ts1.tv_nsec -= 1000000000; +#endif  							}  							/*  							 * Convert the @@ -1100,11 +1268,20 @@ _thread_kern_select(int wait_reqd)  		 */  		if (wait_reqd && settimeout) {  			/* Check if this thread wants to wait forever: */ +#if	defined(__FreeBSD__)  			if (pthread->wakeup_time.ts_sec == -1) { +#else +			if (pthread->wakeup_time.tv_sec == -1) { +#endif  			}  			/* Check if this thread doesn't want to wait at all: */ +#if	defined(__FreeBSD__)  			else if (pthread->wakeup_time.ts_sec == 0 &&  				 pthread->wakeup_time.ts_nsec == 0) { +#else +			else if (pthread->wakeup_time.tv_sec == 0 && +				 pthread->wakeup_time.tv_nsec == 0) { +#endif  				/* Override the caller's request to wait: */  				wait_reqd = 0;  			} else { @@ -1112,33 +1289,57 @@ _thread_kern_select(int wait_reqd)  				 * Calculate the time until this thread is  				 * ready, allowing for the clock resolution:   				 */ +#if	defined(__FreeBSD__)  				ts1.ts_sec = pthread->wakeup_time.ts_sec - ts.ts_sec;  				ts1.ts_nsec = pthread->wakeup_time.ts_nsec - ts.ts_nsec +  					CLOCK_RES_NSEC; +#else +				ts1.tv_sec = pthread->wakeup_time.tv_sec - ts.tv_sec; +				ts1.tv_nsec = pthread->wakeup_time.tv_nsec - ts.tv_nsec + +					CLOCK_RES_NSEC; +#endif  				/*  				 * Check for underflow of the nanosecond  				 * field:   				 */ +#if	defined(__FreeBSD__)  				if (ts1.ts_nsec < 0) { +#else +				if (ts1.tv_nsec < 0) { +#endif  					/*  					 * Allow for the underflow of the  					 * nanosecond field:   					 */ +#if	defined(__FreeBSD__)  					ts1.ts_sec--;  					ts1.ts_nsec += 1000000000; +#else +					ts1.tv_sec--; +					ts1.tv_nsec += 1000000000; +#endif  				}  				/*  				 * Check for overflow of the nanosecond  				 * field:   				 */ +#if	defined(__FreeBSD__)  				if (ts1.ts_nsec >= 1000000000) { +#else +				if (ts1.tv_nsec >= 1000000000) { +#endif  					/*  					 * Allow for the overflow of the  					 * nanosecond field:   					 */ +#if	defined(__FreeBSD__)  					ts1.ts_sec++;  					ts1.ts_nsec -= 1000000000; +#else +					ts1.tv_sec++; +					ts1.tv_nsec -= 1000000000; +#endif  				}  				/*  				 * Convert the timespec structure to a @@ -1552,28 +1753,56 @@ _thread_kern_set_timeout(struct timespec * timeout)  		 * Set the wakeup time to something that can be recognised as  		 * different to an actual time of day:   		 */ +#if	defined(__FreeBSD__)  		_thread_run->wakeup_time.ts_sec = -1;  		_thread_run->wakeup_time.ts_nsec = -1; +#else +		_thread_run->wakeup_time.tv_sec = -1; +		_thread_run->wakeup_time.tv_nsec = -1; +#endif  	}  	/* Check if no waiting is required: */ +#if	defined(__FreeBSD__)  	else if (timeout->ts_sec == 0 && timeout->ts_nsec == 0) { +#else +	else if (timeout->tv_sec == 0 && timeout->tv_nsec == 0) { +#endif  		/* Set the wake up time to 'immediately': */ +#if	defined(__FreeBSD__)  		_thread_run->wakeup_time.ts_sec = 0;  		_thread_run->wakeup_time.ts_nsec = 0; +#else +		_thread_run->wakeup_time.tv_sec = 0; +		_thread_run->wakeup_time.tv_nsec = 0; +#endif  	} else {  		/* Get the current time: */  		gettimeofday(&tv, NULL);  		TIMEVAL_TO_TIMESPEC(&tv, ¤t_time);  		/* Calculate the time for the current thread to wake up: */ +#if	defined(__FreeBSD__)  		_thread_run->wakeup_time.ts_sec = current_time.ts_sec + timeout->ts_sec;  		_thread_run->wakeup_time.ts_nsec = current_time.ts_nsec + timeout->ts_nsec; +#else +		_thread_run->wakeup_time.tv_sec = current_time.tv_sec + timeout->tv_sec; +		_thread_run->wakeup_time.tv_nsec = current_time.tv_nsec + timeout->tv_nsec; +#endif  		/* Check if the nanosecond field needs to wrap: */ +#if	defined(__FreeBSD__)  		if (_thread_run->wakeup_time.ts_nsec >= 1000000000) { +#else +		if (_thread_run->wakeup_time.tv_nsec >= 1000000000) { +#endif  			/* Wrap the nanosecond field: */ +#if	defined(__FreeBSD__)  			_thread_run->wakeup_time.ts_sec += 1;  			_thread_run->wakeup_time.ts_nsec -= 1000000000; +#else +			_thread_run->wakeup_time.tv_sec += 1; +			_thread_run->wakeup_time.tv_nsec -= 1000000000; +#endif  		}  	}  	return; diff --git a/lib/libpthread/thread/thr_multi_np.c b/lib/libpthread/thread/thr_multi_np.c new file mode 100644 index 000000000000..64f360fdacfe --- /dev/null +++ b/lib/libpthread/thread/thr_multi_np.c @@ -0,0 +1,44 @@ +/* + * Copyright (c) 1996 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 <string.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +int pthread_multi_np() +{ +	/* Return to multi-threaded scheduling mode: */ +	_thread_single = NULL; +	return(0); +} +#endif diff --git a/lib/libpthread/thread/thr_mutex.c b/lib/libpthread/thread/thr_mutex.c index 0fc9fbba3e50..dc9be3c5ff78 100644 --- a/lib/libpthread/thread/thr_mutex.c +++ b/lib/libpthread/thread/thr_mutex.c @@ -41,35 +41,95 @@ pthread_mutex_init(pthread_mutex_t * mutex,  		   const pthread_mutexattr_t * mutex_attr)  {  	enum pthread_mutextype type; +	pthread_mutex_t	pmutex;  	int             ret = 0;  	int             status; -	/* Check if the mutex attributes specify some mutex other than fast: */ -	if (mutex_attr != NULL && mutex_attr->m_type != MUTEX_TYPE_FAST) { -		/* Check if the mutex type is out of range: */ -		if (mutex_attr->m_type >= MUTEX_TYPE_MAX) { +	if (mutex == NULL) { +		errno = EINVAL; +		ret = -1; +	} else { +		/* Check if default mutex attributes: */ +		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) {  			/* Return an invalid argument error: */ -			_thread_seterrno(_thread_run, EINVAL); +			errno = EINVAL;  			ret = -1;  		} else {  			/* Use the requested mutex type: */ -			type = mutex_attr->m_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) { +				errno = ENOMEM; +				ret = -1; +			} 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: */ +				case MUTEX_TYPE_FAST: +					/* Nothing to do here. */ +					break; + +					/* Counting mutex: */ +				case MUTEX_TYPE_COUNTING_FAST: +					/* Reset the mutex count: */ +					pmutex->m_data.m_count = 0; +					break; + +					/* Trap invalid mutex types: */ +				default: +					/* Return an invalid argument error: */ +					errno = EINVAL; +					ret = -1; +					break; +				} +				if (ret == 0) { +					/* Initialise the rest of the mutex: */ +					_thread_queue_init(&pmutex->m_queue); +					pmutex->m_flags |= MUTEX_FLAGS_INITED; +					pmutex->m_owner = NULL; +					pmutex->m_type = type; +					*mutex = pmutex; +				} else { +					free(pmutex); +					*mutex = NULL; +				} + +				/* Unblock signals: */ +				_thread_kern_sig_unblock(status); +			}  		} -	} else { -		/* Default to a fast mutex: */ -		type = MUTEX_TYPE_FAST;  	} +	/* Return the completion status: */ +	return (ret); +} -	/* Check no errors so far: */ -	if (ret == 0) { -		/* Reset the mutex flags: */ -		mutex->m_flags = 0; +int +pthread_mutex_destroy(pthread_mutex_t * mutex) +{ +	int             ret = 0; +	int             status; +	if (mutex == NULL || *mutex == NULL) { +		errno = EINVAL; +		ret = -1; +	} else {  		/* Block signals: */  		_thread_kern_sig_block(&status);  		/* Process according to mutex type: */ -		switch (type) { +		switch ((*mutex)->m_type) {  			/* Fast mutex: */  		case MUTEX_TYPE_FAST:  			/* Nothing to do here. */ @@ -78,67 +138,25 @@ pthread_mutex_init(pthread_mutex_t * mutex,  			/* Counting mutex: */  		case MUTEX_TYPE_COUNTING_FAST:  			/* Reset the mutex count: */ -			mutex->m_data.m_count = 0; +			(*mutex)->m_data.m_count = 0;  			break; -			/* Trap invalid mutex types: */ +			/* Trap undefined mutex types: */  		default:  			/* Return an invalid argument error: */ -			_thread_seterrno(_thread_run, EINVAL); +			errno = EINVAL;  			ret = -1;  			break;  		} -		/* Initialise the rest of the mutex: */ -		_thread_queue_init(&mutex->m_queue); -		mutex->m_flags |= MUTEX_FLAGS_INITED; -		mutex->m_owner = NULL; -		mutex->m_type = type; +		/* 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);  	} -	/* Return the completion status: */ -	return (ret); -} - -int -pthread_mutex_destroy(pthread_mutex_t * mutex) -{ -	int             ret = 0; -	int             status; - -	/* 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: */ -		_thread_seterrno(_thread_run, EINVAL); -		ret = -1; -		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);  	/* Return the completion status: */  	return (ret); @@ -150,56 +168,61 @@ pthread_mutex_trylock(pthread_mutex_t * mutex)  	int             ret = 0;  	int             status; -	/* Block signals: */ -	_thread_kern_sig_block(&status); +	if (mutex == NULL || *mutex == NULL) { +		errno = EINVAL; +		ret = -1; +	} else { +		/* Block signals: */ +		_thread_kern_sig_block(&status); -	/* Process according to mutex type: */ -	switch (mutex->m_type) { +		/* Process according to mutex type: */ +		switch ((*mutex)->m_type) {  		/* Fast mutex: */ -	case MUTEX_TYPE_FAST: -		/* Check if this mutex is not locked: */ -		if (mutex->m_owner == NULL) { -			/* Lock the mutex for the running thread: */ -			mutex->m_owner = _thread_run; -		} else { -			/* Return a busy error: */ -			_thread_seterrno(_thread_run, EBUSY); -			ret = -1; -		} -		break; - -		/* Counting mutex: */ -	case MUTEX_TYPE_COUNTING_FAST: -		/* Check if this mutex is locked: */ -		if (mutex->m_owner != NULL) { -			/* -			 * Check if the mutex is locked by the running -			 * thread:  -			 */ -			if (mutex->m_owner == _thread_run) { -				/* Increment the lock count: */ -				mutex->m_data.m_count++; +		case MUTEX_TYPE_FAST: +			/* Check if this mutex is not locked: */ +			if ((*mutex)->m_owner == NULL) { +				/* Lock the mutex for the running thread: */ +				(*mutex)->m_owner = _thread_run;  			} else {  				/* Return a busy error: */ -				_thread_seterrno(_thread_run, EBUSY); +				errno = EBUSY;  				ret = -1;  			} -		} else { -			/* Lock the mutex for the running thread: */ -			mutex->m_owner = _thread_run; -		} -		break; +			break; + +		/* Counting mutex: */ +		case MUTEX_TYPE_COUNTING_FAST: +			/* Check if this mutex is locked: */ +			if ((*mutex)->m_owner != NULL) { +				/* +				 * Check if the mutex is locked by the running +				 * thread:  +				 */ +				if ((*mutex)->m_owner == _thread_run) { +					/* Increment the lock count: */ +					(*mutex)->m_data.m_count++; +				} else { +					/* Return a busy error: */ +					errno = EBUSY; +					ret = -1; +				} +			} else { +				/* Lock the mutex for the running thread: */ +				(*mutex)->m_owner = _thread_run; +			} +			break;  		/* Trap invalid mutex types: */ -	default: -		/* Return an invalid argument error: */ -		_thread_seterrno(_thread_run, EINVAL); -		ret = -1; -		break; -	} +		default: +			/* Return an invalid argument error: */ +			errno = EINVAL; +			ret = -1; +			break; +		} -	/* Unblock signals: */ -	_thread_kern_sig_unblock(status); +		/* Unblock signals: */ +		_thread_kern_sig_unblock(status); +	}  	/* Return the completion status: */  	return (ret); @@ -211,81 +234,86 @@ pthread_mutex_lock(pthread_mutex_t * mutex)  	int             ret = 0;  	int             status; -	/* Block signals: */ -	_thread_kern_sig_block(&status); +	if (mutex == NULL || *mutex == NULL) { +		errno = EINVAL; +		ret = -1; +	} else { +		/* Block signals: */ +		_thread_kern_sig_block(&status); -	/* Process according to mutex type: */ -	switch (mutex->m_type) { +		/* Process according to mutex type: */ +		switch ((*mutex)->m_type) {  		/* Fast mutexes do not check for any error conditions: */ -	case MUTEX_TYPE_FAST: -		/* -		 * Enter a loop to wait for the mutex to be locked by the -		 * current thread:  -		 */ -		while (mutex->m_owner != _thread_run) { -			/* Check if the mutex is not locked: */ -			if (mutex->m_owner == NULL) { -				/* Lock the mutex for this thread: */ -				mutex->m_owner = _thread_run; -			} else { -				/* -				 * Join the queue of threads waiting to lock -				 * the mutex:  -				 */ -				_thread_queue_enq(&mutex->m_queue, _thread_run); - -				/* Block signals: */ -				_thread_kern_sched_state(PS_MUTEX_WAIT, __FILE__, __LINE__); - -				/* Block signals: */ -				_thread_kern_sig_block(NULL); +		case MUTEX_TYPE_FAST: +			/* +			 * Enter a loop to wait for the mutex to be locked by the +			 * current thread:  +			 */ +			while ((*mutex)->m_owner != _thread_run) { +				/* Check if the mutex is not locked: */ +				if ((*mutex)->m_owner == NULL) { +					/* Lock the mutex for this thread: */ +					(*mutex)->m_owner = _thread_run; +				} else { +					/* +					 * Join the queue of threads waiting to lock +					 * the mutex:  +					 */ +					_thread_queue_enq(&(*mutex)->m_queue, _thread_run); + +					/* Block signals: */ +					_thread_kern_sched_state(PS_MUTEX_WAIT, __FILE__, __LINE__); + +					/* Block signals: */ +					_thread_kern_sig_block(NULL); +				}  			} -		} -		break; +			break;  		/* Counting mutex: */ -	case MUTEX_TYPE_COUNTING_FAST: -		/* -		 * Enter a loop to wait for the mutex to be locked by the -		 * current thread:  -		 */ -		while (mutex->m_owner != _thread_run) { -			/* Check if the mutex is not locked: */ -			if (mutex->m_owner == NULL) { -				/* Lock the mutex for this thread: */ -				mutex->m_owner = _thread_run; - -				/* Reset the lock count for this mutex: */ -				mutex->m_data.m_count = 0; -			} else { -				/* -				 * Join the queue of threads waiting to lock -				 * the mutex:  -				 */ -				_thread_queue_enq(&mutex->m_queue, _thread_run); - -				/* Block signals: */ -				_thread_kern_sched_state(PS_MUTEX_WAIT, __FILE__, __LINE__); - -				/* Block signals: */ -				_thread_kern_sig_block(NULL); +		case MUTEX_TYPE_COUNTING_FAST: +			/* +			 * Enter a loop to wait for the mutex to be locked by the +			 * current thread:  +			 */ +			while ((*mutex)->m_owner != _thread_run) { +				/* Check if the mutex is not locked: */ +				if ((*mutex)->m_owner == NULL) { +					/* Lock the mutex for this thread: */ +					(*mutex)->m_owner = _thread_run; + +					/* Reset the lock count for this mutex: */ +					(*mutex)->m_data.m_count = 0; +				} else { +					/* +					 * Join the queue of threads waiting to lock +					 * the mutex:  +					 */ +					_thread_queue_enq(&(*mutex)->m_queue, _thread_run); + +					/* Block signals: */ +					_thread_kern_sched_state(PS_MUTEX_WAIT, __FILE__, __LINE__); + +					/* Block signals: */ +					_thread_kern_sig_block(NULL); +				}  			} -		} -		/* Increment the lock count for this mutex: */ -		mutex->m_data.m_count++; -		break; +			/* Increment the lock count for this mutex: */ +			(*mutex)->m_data.m_count++; +			break;  		/* Trap invalid mutex types: */ -	default: -		/* Return an invalid argument error: */ -		_thread_seterrno(_thread_run, EINVAL); -		ret = -1; -		break; -	} +		default: +			/* Return an invalid argument error: */ +			errno = EINVAL; +			ret = -1; +			break; +		} -	/* Unblock signals: */ -	_thread_kern_sig_unblock(status); +		/* Unblock signals: */ +		_thread_kern_sig_unblock(status); +	}  	/* Return the completion status: */  	return (ret); @@ -297,63 +325,68 @@ pthread_mutex_unlock(pthread_mutex_t * mutex)  	int             ret = 0;  	int             status; -	/* Block signals: */ -	_thread_kern_sig_block(&status); +	if (mutex == NULL || *mutex == NULL) { +		errno = EINVAL; +		ret = -1; +	} else { +		/* Block signals: */ +		_thread_kern_sig_block(&status); -	/* Process according to mutex type: */ -	switch (mutex->m_type) { +		/* Process according to mutex type: */ +		switch ((*mutex)->m_type) {  		/* Fast mutexes do not check for any error conditions: */ -	case MUTEX_TYPE_FAST: -		/* Check if the running thread is not the owner of the mutex: */ -		if (mutex->m_owner != _thread_run) { -			/* Return an invalid argument error: */ -			_thread_seterrno(_thread_run, EINVAL); -			ret = -1; -		} -		/* -		 * Get the next thread from the queue of threads waiting on -		 * the mutex:  -		 */ -		else if ((mutex->m_owner = _thread_queue_deq(&mutex->m_queue)) != NULL) { -			/* Allow the new owner of the mutex to run: */ -			mutex->m_owner->state = PS_RUNNING; -		} -		break; +		case MUTEX_TYPE_FAST: +			/* Check if the running thread is not the owner of the mutex: */ +			if ((*mutex)->m_owner != _thread_run) { +				/* Return an invalid argument error: */ +				errno = EINVAL; +				ret = -1; +			} +			/* +			 * Get the next thread from the queue of threads waiting on +			 * the mutex:  +			 */ +			else if (((*mutex)->m_owner = _thread_queue_deq(&(*mutex)->m_queue)) != NULL) { +				/* Allow the new owner of the mutex to run: */ +				(*mutex)->m_owner->state = PS_RUNNING; +			} +			break;  		/* Counting mutex: */ -	case MUTEX_TYPE_COUNTING_FAST: -		/* Check if the running thread is not the owner of the mutex: */ -		if (mutex->m_owner != _thread_run) { +		case MUTEX_TYPE_COUNTING_FAST: +			/* Check if the running thread is not the owner of the mutex: */ +			if ((*mutex)->m_owner != _thread_run) { +				/* Return an invalid argument error: */ +				errno = EINVAL; +				ret = -1; +			} +			/* Check if there are still counts: */ +			else if ((*mutex)->m_data.m_count) { +				/* Decrement the count: */ +				(*mutex)->m_data.m_count--; +			} +			/* +			 * Get the next thread from the queue of threads waiting on +			 * the mutex:  +			 */ +			else if (((*mutex)->m_owner = _thread_queue_deq(&(*mutex)->m_queue)) != NULL) { +				/* Allow the new owner of the mutex to run: */ +				(*mutex)->m_owner->state = PS_RUNNING; +			} +			break; + +		/* Trap invalid mutex types: */ +		default:  			/* Return an invalid argument error: */ -			_thread_seterrno(_thread_run, EINVAL); +			errno = EINVAL;  			ret = -1; +			break;  		} -		/* Check if there are still counts: */ -		else if (mutex->m_data.m_count) { -			/* Decrement the count: */ -			mutex->m_data.m_count--; -		} -		/* -		 * Get the next thread from the queue of threads waiting on -		 * the mutex:  -		 */ -		else if ((mutex->m_owner = _thread_queue_deq(&mutex->m_queue)) != NULL) { -			/* Allow the new owner of the mutex to run: */ -			mutex->m_owner->state = PS_RUNNING; -		} -		break; -		/* Trap invalid mutex types: */ -	default: -		/* Return an invalid argument error: */ -		_thread_seterrno(_thread_run, EINVAL); -		ret = -1; -		break; +		/* Unblock signals: */ +		_thread_kern_sig_unblock(status);  	} -	/* Unblock signals: */ -	_thread_kern_sig_unblock(status); -  	/* Return the completion status: */  	return (ret);  } diff --git a/lib/libpthread/thread/thr_nanosleep.c b/lib/libpthread/thread/thr_nanosleep.c index e91ca5765113..58ade9888c35 100644 --- a/lib/libpthread/thread/thr_nanosleep.c +++ b/lib/libpthread/thread/thr_nanosleep.c @@ -31,6 +31,7 @@   *   */  #include <stdio.h> +#include <errno.h>  #ifdef _THREAD_SAFE  #include <pthread.h>  #include "pthread_private.h" @@ -38,50 +39,138 @@  int  nanosleep(struct timespec * time_to_sleep, struct timespec * time_remaining)  { +	int             ret = 0;  	struct timespec current_time;  	struct timespec current_time1; +	struct timespec remaining_time;  	struct timeval  tv; -	/* Get the current time: */ -	gettimeofday(&tv, NULL); -	TIMEVAL_TO_TIMESPEC(&tv, ¤t_time); +	/* Check if the time to sleep is legal: */ +#if	defined(__FreeBSD__) +	if (time_to_sleep == NULL || time_to_sleep->ts_nsec < 0 || time_to_sleep->ts_nsec > 1000000000) { +#else +	if (time_to_sleep == NULL || time_to_sleep->tv_nsec < 0 || time_to_sleep->tv_nsec > 1000000000) { +#endif +		/* Return an EINVAL error : */ +		errno = EINVAL; +		ret = -1; +	} else { +		/* Get the current time: */ +		gettimeofday(&tv, NULL); +		TIMEVAL_TO_TIMESPEC(&tv, ¤t_time); -	/* Calculate the time for the current thread to wake up: */ -	_thread_run->wakeup_time.ts_sec = current_time.ts_sec + time_to_sleep->ts_sec; -	_thread_run->wakeup_time.ts_nsec = current_time.ts_nsec + time_to_sleep->ts_nsec; +		/* Calculate the time for the current thread to wake up: */ +#if	defined(__FreeBSD__) +		_thread_run->wakeup_time.ts_sec = current_time.ts_sec + time_to_sleep->ts_sec; +		_thread_run->wakeup_time.ts_nsec = current_time.ts_nsec + time_to_sleep->ts_nsec; +#else +		_thread_run->wakeup_time.tv_sec = current_time.tv_sec + time_to_sleep->tv_sec; +		_thread_run->wakeup_time.tv_nsec = current_time.tv_nsec + time_to_sleep->tv_nsec; +#endif -	/* Check if the nanosecond field has overflowed: */ -	if (_thread_run->wakeup_time.ts_nsec >= 1000000000) { -		/* Wrap the nanosecond field: */ -		_thread_run->wakeup_time.ts_sec += 1; -		_thread_run->wakeup_time.ts_nsec -= 1000000000; -	} -	/* Reschedule the current thread to sleep: */ -	_thread_kern_sched_state(PS_SLEEP_WAIT, __FILE__, __LINE__); +		/* Check if the nanosecond field has overflowed: */ +#if	defined(__FreeBSD__) +		if (_thread_run->wakeup_time.ts_nsec >= 1000000000) { +#else +		if (_thread_run->wakeup_time.tv_nsec >= 1000000000) { +#endif +			/* Wrap the nanosecond field: */ +#if	defined(__FreeBSD__) +			_thread_run->wakeup_time.ts_sec += 1; +			_thread_run->wakeup_time.ts_nsec -= 1000000000; +#else +			_thread_run->wakeup_time.tv_sec += 1; +			_thread_run->wakeup_time.tv_nsec -= 1000000000; +#endif +		} + +		/* Reschedule the current thread to sleep: */ +		_thread_kern_sched_state(PS_SLEEP_WAIT, __FILE__, __LINE__); -	/* Check if the time remaining is to be returned: */ -	if (time_remaining != NULL) {  		/* Get the current time: */  		gettimeofday(&tv, NULL);  		TIMEVAL_TO_TIMESPEC(&tv, ¤t_time1); -		/* Return the actual time slept: */ -		time_remaining->ts_sec = time_to_sleep->ts_sec + current_time1.ts_sec - current_time.ts_sec; -		time_remaining->ts_nsec = time_to_sleep->ts_nsec + current_time1.ts_nsec - current_time.ts_nsec; +		/* Calculate the remaining time to sleep: */ +#if	defined(__FreeBSD__) +		remaining_time.ts_sec = time_to_sleep->ts_sec + current_time.ts_sec - current_time1.ts_sec; +		remaining_time.ts_nsec = time_to_sleep->ts_nsec + current_time.ts_nsec - current_time1.ts_nsec; +#else +		remaining_time.tv_sec = time_to_sleep->tv_sec + current_time.tv_sec - current_time1.tv_sec; +		remaining_time.tv_nsec = time_to_sleep->tv_nsec + current_time.tv_nsec - current_time1.tv_nsec; +#endif  		/* Check if the nanosecond field has underflowed: */ -		if (time_remaining->ts_nsec < 0) { +#if	defined(__FreeBSD__) +		if (remaining_time.ts_nsec < 0) { +#else +		if (remaining_time.tv_nsec < 0) { +#endif  			/* Handle the underflow: */ -			time_remaining->ts_sec -= 1; -			time_remaining->ts_nsec += 1000000000; +#if	defined(__FreeBSD__) +			remaining_time.ts_sec -= 1; +			remaining_time.ts_nsec += 1000000000; +#else +			remaining_time.tv_sec -= 1; +			remaining_time.tv_nsec += 1000000000; +#endif  		} + +		/* Check if the nanosecond field has overflowed: */ +#if	defined(__FreeBSD__) +		if (remaining_time.ts_nsec >= 1000000000) { +#else +		if (remaining_time.tv_nsec >= 1000000000) { +#endif +			/* Handle the overflow: */ +#if	defined(__FreeBSD__) +			remaining_time.ts_sec += 1; +			remaining_time.ts_nsec -= 1000000000; +#else +			remaining_time.tv_sec += 1; +			remaining_time.tv_nsec -= 1000000000; +#endif +		} +  		/* Check if the sleep was longer than the required time: */ -		if (time_remaining->ts_sec < 0) { -			/* Reset the time teft: */ -			time_remaining->ts_sec = 0; -			time_remaining->ts_nsec = 0; +#if	defined(__FreeBSD__) +		if (remaining_time.ts_sec < 0) { +#else +		if (remaining_time.tv_sec < 0) { +#endif +			/* Reset the time left: */ +#if	defined(__FreeBSD__) +			remaining_time.ts_sec = 0; +			remaining_time.ts_nsec = 0; +#else +			remaining_time.tv_sec = 0; +			remaining_time.tv_nsec = 0; +#endif +		} + +		/* Check if the time remaining is to be returned: */ +		if (time_remaining != NULL) { +			/* Return the actual time slept: */ +#if	defined(__FreeBSD__) +			time_remaining->ts_sec = remaining_time.ts_sec; +			time_remaining->ts_nsec = remaining_time.ts_nsec; +#else +			time_remaining->tv_sec = remaining_time.tv_sec; +			time_remaining->tv_nsec = remaining_time.tv_nsec; +#endif +		} + +		/* Check if the entire sleep was not completed: */ +#if	defined(__FreeBSD__) +		if (remaining_time.ts_nsec != 0 || remaining_time.ts_sec != 0) { +#else +		if (remaining_time.tv_nsec != 0 || remaining_time.tv_sec != 0) { +#endif +			/* Return an EINTR error : */ +			errno = EINTR; +			ret = -1;  		}  	} -	return (0); +	return (ret);  }  #endif diff --git a/lib/libpthread/thread/thr_open.c b/lib/libpthread/thread/thr_open.c index ead651ea3d9e..00bb91335755 100644 --- a/lib/libpthread/thread/thr_open.c +++ b/lib/libpthread/thread/thr_open.c @@ -31,6 +31,7 @@   *   */  #include <stdarg.h> +#include <unistd.h>  #include <fcntl.h>  #include <dirent.h>  #ifdef _THREAD_SAFE @@ -55,8 +56,8 @@ open(const char *path, int flags,...)  		mode = va_arg(ap, int);  		va_end(ap);  	} -	/* Open the file, forcing it to use non-blocking I/O operations: */ -	if ((fd = _thread_sys_open(path, flags | O_NONBLOCK, mode)) < 0) { +	/* Open the file: */ +	if ((fd = _thread_sys_open(path, flags, mode)) < 0) {  	}  	/* Initialise the file descriptor table entry: */  	else if (_thread_fd_table_init(fd) != 0) { @@ -65,12 +66,6 @@ open(const char *path, int flags,...)  		/* Reset the file descriptor: */  		fd = -1; -	} else { -		/* -		 * Save the file open flags so that they can be checked -		 * later:  -		 */ -		_thread_fd_table[fd]->flags = flags;  	}  	/* Unblock signals: */ diff --git a/lib/libpthread/thread/thr_private.h b/lib/libpthread/thread/thr_private.h index fc8ba276a42c..48e70ce00d1e 100644 --- a/lib/libpthread/thread/thr_private.h +++ b/lib/libpthread/thread/thr_private.h @@ -59,6 +59,129 @@  #define PANIC(string)   _thread_exit(__FILE__,__LINE__,string)  /* + * Queue definitions. + */ +struct pthread_queue { +	struct pthread	*q_next; +	struct pthread	*q_last; +	void		*q_data; +}; + +/* + * Static queue initialization values.  + */ +#define PTHREAD_QUEUE_INITIALIZER { NULL, NULL, NULL } + +/*  + * Mutex definitions. + */ +enum pthread_mutextype { +	MUTEX_TYPE_FAST		= 1, +	MUTEX_TYPE_COUNTING_FAST	= 2,	/* Recursive */ +	MUTEX_TYPE_MAX +}; + +union pthread_mutex_data { +	void	*m_ptr; +	int	m_count; +}; + +struct pthread_mutex { +	enum pthread_mutextype		m_type; +	struct pthread_queue		m_queue; +	struct pthread			*m_owner; +	union pthread_mutex_data	m_data; +	long				m_flags; +}; + +/* + * Flags for mutexes.  + */ +#define MUTEX_FLAGS_PRIVATE	0x01 +#define MUTEX_FLAGS_INITED	0x02 +#define MUTEX_FLAGS_BUSY	0x04 + +/* + * Static mutex initialization values.  + */ +#define PTHREAD_MUTEX_INITIALIZER   \ +	{ MUTEX_TYPE_FAST, PTHREAD_QUEUE_INITIALIZER, \ +	NULL, { NULL }, MUTEX_FLAGS_INITED } + +struct pthread_mutex_attr { +	enum pthread_mutextype	m_type; +	long			m_flags; +}; + +/*  + * Condition variable definitions. + */ +enum pthread_cond_type { +	COND_TYPE_FAST, +	COND_TYPE_MAX +}; + +struct pthread_cond { +	enum pthread_cond_type	c_type; +	struct pthread_queue	c_queue; +	void			*c_data; +	long			c_flags; +}; + +struct pthread_cond_attr { +	enum pthread_cond_type	c_type; +	long			c_flags; +}; + +/* + * Flags for condition variables. + */ +#define COND_FLAGS_PRIVATE	0x01 +#define COND_FLAGS_INITED	0x02 +#define COND_FLAGS_BUSY		0x04 + +/* + * Static cond initialization values.  + */ +#define PTHREAD_COND_INITIALIZER    \ +	{ COND_TYPE_FAST, PTHREAD_QUEUE_INITIALIZER, NULL, COND_FLAGS_INITED } + +/* + * Cleanup definitions. + */ +struct pthread_cleanup { +	struct pthread_cleanup	*next; +	void			(*routine) (); +	void			*routine_arg; +}; + +/* + * Scheduling definitions. + */ +enum schedparam_policy { +	SCHED_RR, +	SCHED_IO, +	SCHED_FIFO, +	SCHED_OTHER +}; + +struct pthread_attr { +	enum schedparam_policy	schedparam_policy; +	int			prio; +	int			suspend; +	int			flags; +	void			*arg_attr; +	void			(*cleanup_attr) (); +	void			*stackaddr_attr; +	size_t			stacksize_attr; +}; + +struct sched_param { +	int	prio; +	void	*no_data; +}; + +/*   * Thread creation state attributes.   */  #define PTHREAD_CREATE_RUNNING			0 @@ -67,14 +190,11 @@  /*   * Miscellaneous definitions.   */ -#define PTHREAD_STACK_MIN			1024  #define PTHREAD_STACK_DEFAULT			65536 -#define PTHREAD_DATAKEYS_MAX			256  #define PTHREAD_DEFAULT_PRIORITY		64  #define PTHREAD_MAX_PRIORITY			126  #define PTHREAD_MIN_PRIORITY			0  #define _POSIX_THREAD_ATTR_STACKSIZE -#define _POSIX_THREAD_DESTRUTOR_ITERATIONS	4  /*   * Clock resolution in nanoseconds. @@ -190,10 +310,10 @@ struct pthread {  	 * Thread start routine, argument, stack pointer and thread  	 * attributes.  	 */ -	void		*(*start_routine)(void *); -	void		*arg; -	void		*stack; -	pthread_attr_t	attr; +	void			*(*start_routine)(void *); +	void			*arg; +	void			*stack; +	struct pthread_attr	attr;  	/*  	 * Thread-specific signal handler interface: @@ -319,6 +439,17 @@ SCLASS struct pthread   *_thread_run  ;  #endif +/* + * Ptr to the thread running in single-threaded mode or NULL if + * running multi-threaded (default POSIX behaviour). + */ +SCLASS struct pthread   *_thread_single +#ifdef GLOBAL_PTHREAD_PRIVATE += NULL; +#else +; +#endif +  /* Ptr to the first thread in the thread linked list: */  SCLASS struct pthread   *_thread_link_list  #ifdef GLOBAL_PTHREAD_PRIVATE @@ -372,7 +503,7 @@ SCLASS struct pthread *_thread_initial  #endif  /* Default thread attributes: */ -SCLASS pthread_attr_t pthread_attr_default +SCLASS struct pthread_attr pthread_attr_default  #ifdef GLOBAL_PTHREAD_PRIVATE  = { SCHED_RR, PTHREAD_DEFAULT_PRIORITY, PTHREAD_CREATE_RUNNING,  	PTHREAD_CREATE_JOINABLE, NULL, NULL, NULL, PTHREAD_STACK_DEFAULT }; @@ -570,6 +701,7 @@ pid_t   _thread_sys_fork(void);  pid_t   _thread_sys_tcgetpgrp(int);  ssize_t _thread_sys_read(int, void *, size_t);  ssize_t _thread_sys_write(int, const void *, size_t); +void	_thread_sys__exit(int);  #endif  /* #include <fcntl.h> */ diff --git a/lib/libpthread/thread/thr_resume_np.c b/lib/libpthread/thread/thr_resume_np.c new file mode 100644 index 000000000000..a254814163af --- /dev/null +++ b/lib/libpthread/thread/thr_resume_np.c @@ -0,0 +1,70 @@ +/* + * Copyright (c) 1995 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" + +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->state = PS_RUNNING; +				ret = 0; +			} else if (pthread->state == PS_RUNNING) { +				/* Thread is already running. */ +				ret = 0; +			} else { +				/* Thread is in some other state. */ +				_thread_seterrno(_thread_run,EINVAL); +			} +		} +	} +	/* Check if thread was not found. */ +	if (ret == -1) { +		/* No such thread */ +		_thread_seterrno(_thread_run,ESRCH); +	} +	return(ret); +} +#endif diff --git a/lib/libpthread/thread/thr_select.c b/lib/libpthread/thread/thr_select.c index b3f548373e99..7db3ed2f2444 100644 --- a/lib/libpthread/thread/thr_select.c +++ b/lib/libpthread/thread/thr_select.c @@ -142,36 +142,29 @@ select(int numfds, fd_set * readfds, fd_set * writefds,  	if (ret > 0) {  		if (readfds != NULL) { -			FD_ZERO(readfds);  			for (i = 0; i < numfds; i++) { -				if (FD_ISSET(i, &data.readfds)) { -					FD_SET(i, readfds); +				if (FD_ISSET(i, readfds) && +					!FD_ISSET(i, &data.readfds)) { +					FD_CLR(i, readfds);  				}  			}  		}  		if (writefds != NULL) { -			FD_ZERO(writefds);  			for (i = 0; i < numfds; i++) { -				if (FD_ISSET(i, &data.writefds)) { -					FD_SET(i, writefds); +				if (FD_ISSET(i, writefds) && +					!FD_ISSET(i, &data.writefds)) { +					FD_CLR(i, writefds);  				}  			}  		}  		if (exceptfds != NULL) { -			FD_ZERO(exceptfds);  			for (i = 0; i < numfds; i++) { -				if (FD_ISSET(i, &data.exceptfds)) { -					FD_SET(i, exceptfds); +				if (FD_ISSET(i, exceptfds) && +					!FD_ISSET(i, &data.exceptfds)) { +					FD_CLR(i, exceptfds);  				}  			}  		} -	} else { -		if (exceptfds != NULL) -			FD_ZERO(exceptfds); -		if (writefds != NULL) -			FD_ZERO(writefds); -		if (readfds != NULL) -			FD_ZERO(readfds);  	}  	return (ret); diff --git a/lib/libpthread/thread/thr_sig.c b/lib/libpthread/thread/thr_sig.c index 77ec713b63d9..c3ec1919077e 100644 --- a/lib/libpthread/thread/thr_sig.c +++ b/lib/libpthread/thread/thr_sig.c @@ -31,6 +31,8 @@   *   */  #include <signal.h> +#include <fcntl.h> +#include <unistd.h>  #include <errno.h>  #ifdef _THREAD_SAFE  #include <pthread.h> @@ -40,6 +42,7 @@ void  _thread_sig_handler(int sig, int code, struct sigcontext * scp)  {  	char            c; +	int             i;  	pthread_t       pthread;  	/* @@ -67,16 +70,52 @@ _thread_sig_handler(int sig, int code, struct sigcontext * scp)  	} else {  		/* Handle depending on signal type: */  		switch (sig) { -			/* Interval timer used for timeslicing: */ +		/* Interval timer used for timeslicing: */  		case SIGVTALRM:  			/*  			 * Don't add the signal to any thread.  Just want to -			 * call    +			 * call the scheduler:  			 */ -			/* the scheduler: */  			break; -			/* Signals specific to the running thread: */ +		/* Child termination: */ +		case SIGCHLD: +			/* +			 * 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; +				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->state = PS_RUNNING; +				} +			} + +			/* +			 * Go through the file list and set all files +			 * to non-blocking again in case the child +			 * set some of them to block. Sigh. +			 */ +			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); +				} +			} +			break; + +		/* Signals specific to the running thread: */  		case SIGBUS:  		case SIGEMT:  		case SIGFPE: @@ -88,7 +127,7 @@ _thread_sig_handler(int sig, int code, struct sigcontext * scp)  			_thread_run->sigpend[sig] += 1;  			break; -			/* Signals to send to all threads: */ +		/* Signals to send to all threads: */  		default:  			/*  			 * Enter a loop to process each thread in the linked diff --git a/lib/libpthread/thread/thr_sigsuspend.c b/lib/libpthread/thread/thr_sigsuspend.c index ee2d0b5671df..a26b6b99bf4b 100644 --- a/lib/libpthread/thread/thr_sigsuspend.c +++ b/lib/libpthread/thread/thr_sigsuspend.c @@ -47,6 +47,9 @@ sigsuspend(const sigset_t * set)  		/* Save the current sigmal mask: */  		oset = _thread_run->sigmask; +		/* Combine the caller's mask with the current one: */ +		_thread_run->sigmask |= *set; +  		/* Wait for a signal: */  		_thread_kern_sched_state(PS_SIGWAIT, __FILE__, __LINE__); diff --git a/lib/libpthread/thread/thr_single_np.c b/lib/libpthread/thread/thr_single_np.c new file mode 100644 index 000000000000..e36c856c6376 --- /dev/null +++ b/lib/libpthread/thread/thr_single_np.c @@ -0,0 +1,44 @@ +/* + * Copyright (c) 1996 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 <string.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +int pthread_single_np() +{ +	/* Enter single-threaded (non-POSIX) scheduling mode: */ +	_thread_single = _thread_run; +	return(0); +} +#endif diff --git a/lib/libpthread/thread/thr_spec.c b/lib/libpthread/thread/thr_spec.c index e7c45d2953c7..cc83c6066ee0 100644 --- a/lib/libpthread/thread/thr_spec.c +++ b/lib/libpthread/thread/thr_spec.c @@ -39,12 +39,12 @@  #include "pthread_private.h"  /* Static variables: */ -static struct pthread_key key_table[PTHREAD_DATAKEYS_MAX]; +static struct pthread_key key_table[PTHREAD_KEYS_MAX];  int -pthread_keycreate(pthread_key_t * key, void (*destructor) (void *)) +pthread_key_create(pthread_key_t * key, void (*destructor) (void *))  { -	for ((*key) = 0; (*key) < PTHREAD_DATAKEYS_MAX; (*key)++) { +	for ((*key) = 0; (*key) < PTHREAD_KEYS_MAX; (*key)++) {  		if (key_table[(*key)].count == 0) {  			key_table[(*key)].count++;  			key_table[(*key)].destructor = destructor; @@ -63,7 +63,7 @@ pthread_key_delete(pthread_key_t key)  	/* Block signals: */  	_thread_kern_sig_block(&status); -	if (key < PTHREAD_DATAKEYS_MAX) { +	if (key < PTHREAD_KEYS_MAX) {  		switch (key_table[key].count) {  		case 1:  			key_table[key].destructor = NULL; @@ -94,8 +94,8 @@ _thread_cleanupspecific(void)  	/* Block signals: */  	_thread_kern_sig_block(&status); -	for (itr = 0; itr < _POSIX_THREAD_DESTRUTOR_ITERATIONS; itr++) { -		for (key = 0; key < PTHREAD_DATAKEYS_MAX; key++) { +	for (itr = 0; itr < PTHREAD_DESTRUCTOR_ITERATIONS; itr++) { +		for (key = 0; key < PTHREAD_KEYS_MAX; key++) {  			if (_thread_run->specific_data_count) {  				if (_thread_run->specific_data[key]) {  					data = (void *) _thread_run->specific_data[key]; @@ -125,8 +125,8 @@ static inline const void **  pthread_key_allocate_data(void)  {  	const void    **new_data; -	if ((new_data = (const void **) malloc(sizeof(void *) * PTHREAD_DATAKEYS_MAX)) != NULL) { -		memset((void *) new_data, 0, sizeof(void *) * PTHREAD_DATAKEYS_MAX); +	if ((new_data = (const void **) malloc(sizeof(void *) * PTHREAD_KEYS_MAX)) != NULL) { +		memset((void *) new_data, 0, sizeof(void *) * PTHREAD_KEYS_MAX);  	}  	return (new_data);  } @@ -154,7 +154,7 @@ pthread_setspecific(pthread_key_t key, const void *value)  	}  	if ((pthread->specific_data) || (pthread->specific_data = pthread_key_allocate_data())) { -		if ((key < PTHREAD_DATAKEYS_MAX) && (key_table)) { +		if ((key < PTHREAD_KEYS_MAX) && (key_table)) {  			if (key_table[key].count) {  				if (pthread->specific_data[key] == NULL) {  					if (value != NULL) { @@ -213,7 +213,7 @@ pthread_getspecific(pthread_key_t key, void **p_data)  		rval = -1;  	}  	/* Check if there is specific data: */ -	else if (pthread->specific_data != NULL && (key < PTHREAD_DATAKEYS_MAX) && (key_table)) { +	else if (pthread->specific_data != NULL && (key < PTHREAD_KEYS_MAX) && (key_table)) {  		/* Check if this key has been used before: */  		if (key_table[key].count) {  			/* Return the value: */ diff --git a/lib/libpthread/thread/thr_suspend_np.c b/lib/libpthread/thread/thr_suspend_np.c new file mode 100644 index 000000000000..fb90c1d494d2 --- /dev/null +++ b/lib/libpthread/thread/thr_suspend_np.c @@ -0,0 +1,67 @@ +/* + * Copyright (c) 1995 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" + +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->state = PS_SUSPENDED; +			ret = 0; +		} +	} +	/* Check if thread was not found. */ +	if (ret == -1) { +		/* No such thread */ +		_thread_seterrno(_thread_run,ESRCH); +	} +	return(ret); +} +#endif | 
