diff options
| author | Julian Elischer <julian@FreeBSD.org> | 1996-01-22 00:23:58 +0000 | 
|---|---|---|
| committer | Julian Elischer <julian@FreeBSD.org> | 1996-01-22 00:23:58 +0000 | 
| commit | 012dfd00b378d9a003a6841a980187c7f15d3716 (patch) | |
| tree | d93df8a19a0cab699bfc2c0b9e4bc691251efa16 /lib/libpthread | |
| parent | f70177e76e605ec6e6cd5b938fa77ade5d380e87 (diff) | |
Notes
Diffstat (limited to 'lib/libpthread')
38 files changed, 6198 insertions, 0 deletions
| diff --git a/lib/libpthread/Makefile b/lib/libpthread/Makefile new file mode 100644 index 000000000000..c0fd385a66b3 --- /dev/null +++ b/lib/libpthread/Makefile @@ -0,0 +1,66 @@ +#	@(#)Makefile	8.2 (Berkeley) 2/3/94 +# +# All library objects contain rcsid strings by default; they may be +# excluded as a space-saving measure.  To produce a library that does +# not contain these strings, delete -DLIBC_RCS and -DSYSLIBC_RCS +# from CFLAGS below.  To remove these strings from just the system call +# stubs, remove just -DSYSLIBC_RCS from CFLAGS. +LIB=c_r +SHLIB_MAJOR= 2 +SHLIB_MINOR= 2 +CFLAGS+=-DLIBC_RCS -DSYSLIBC_RCS +CFLAGS+=-DPTHREAD_KERNEL -D_THREAD_SAFE -I${.CURDIR}/uthread +AINC=	-I${.CURDIR}/../libc/${MACHINE} -I${.CURDIR}/uthread +CLEANFILES+=tags +INSTALL_PIC_ARCHIVE=	yes +PRECIOUSLIB=	yes + +.include "${.CURDIR}/db/Makefile.inc" +.include "${.CURDIR}/compat-43/Makefile.inc" +.include "${.CURDIR}/gen/Makefile.inc" +.include "${.CURDIR}/gmon/Makefile.inc" +.include "${.CURDIR}/locale/Makefile.inc" +.include "${.CURDIR}/net/Makefile.inc" +.include "${.CURDIR}/nls/Makefile.inc" +.include "${.CURDIR}/quad/Makefile.inc" +.include "${.CURDIR}/regex/Makefile.inc" +.include "${.CURDIR}/stdio/Makefile.inc" +.include "${.CURDIR}/stdlib/Makefile.inc" +.include "${.CURDIR}/stdtime/Makefile.inc" +.include "${.CURDIR}/string/Makefile.inc" +.include "${.CURDIR}/sys/Makefile.inc" +.include "${.CURDIR}/rpc/Makefile.inc" +.include "${.CURDIR}/uthread/Makefile.inc" +.include "${.CURDIR}/xdr/Makefile.inc" +.if !defined(NO_YP_LIBC) +CFLAGS+= -DYP +.include "${.CURDIR}/yp/Makefile.inc" +.endif +.include "${.CURDIR}/${MACHINE}/sys/Makefile.inc" + +KQSRCS=	adddi3.c anddi3.c ashldi3.c ashrdi3.c cmpdi2.c divdi3.c iordi3.c \ +	lshldi3.c lshrdi3.c moddi3.c muldi3.c negdi2.c notdi2.c qdivrem.c \ +	subdi3.c ucmpdi2.c udivdi3.c umoddi3.c xordi3.c +KSRCS=	bcmp.c ffs.c index.c mcount.c rindex.c strcat.c strcmp.c strcpy.c \ +	strlen.c strncpy.c + +libkern: libkern.gen libkern.${MACHINE} + +libkern.gen: ${KQSRCS} ${KSRCS} +	cp -p ${.CURDIR}/quad/quad.h ${.ALLSRC} /sys/libkern + +libkern.${MACHINE}:: ${KMSRCS} +.if defined(KMSRCS) && !empty(KMSRCS) +	cp -p ${.ALLSRC} /sys/libkern/${MACHINE} +.endif + +#beforeinstall: tags +#	${INSTALL} ${COPY} -o bin -g bin -m 444 tags /var/db/libc.tags + +tags: ${SRCS} +	ctags ${.ALLSRC:M*.c} +	egrep -o "^ENTRY(.*)|^FUNC(.*)|^SYSCALL(.*)" ${.ALLSRC:M*.s} | \ +	    sed "s;\([^:]*\):\([^(]*\)(\([^, )]*\)\(.*\);\3 \1 /^\2(\3\4$$/;" \ +	    >> tags; sort -o tags tags + +.include <bsd.lib.mk> diff --git a/lib/libpthread/sys/Makefile.inc b/lib/libpthread/sys/Makefile.inc new file mode 100644 index 000000000000..2b22537d3c19 --- /dev/null +++ b/lib/libpthread/sys/Makefile.inc @@ -0,0 +1,107 @@ +#	@(#)Makefile.inc	8.1 (Berkeley) 6/17/93 + +# sys sources +.PATH: ${.CURDIR}/../libc/${MACHINE}/sys ${.CURDIR}/../libc/sys \ +	${.CURDIR}/sys + +# modules with non-default implementations on at least one architecture: +SRCS+=	Ovfork.S brk.S cerror.S exect.S fork.S pipe.S ptrace.S reboot.S \ +	sbrk.S setlogin.S sigpending.S sigprocmask.S sigreturn.S \ +	sigsuspend.S syscall.S __error.c + +# glue to provide compatibility between GCC 1.X and 2.X +SRCS+=	ftruncate.c lseek.c mmap.c truncate.c + +# modules with default implementations on all architectures: +ASM=	access.o acct.o adjtime.o chdir.o chflags.o chmod.o \ +	chown.o chroot.o getdtablesize.o getegid.o geteuid.o \ +	getfh.o getfsstat.o getgid.o getgroups.o getitimer.o \ +	getpgrp.o getpid.o getppid.o getpriority.o \ +	getrlimit.o getrusage.o gettimeofday.o getuid.o kill.o \ +	ktrace.o lfs_bmapv.o lfs_markv.o lfs_segclean.o \ +	lfs_segwait.o link.o lstat.o madvise.o mincore.o \ +	mkdir.o mlock.o mount.o mprotect.o msgsys.o msync.o \ +	munlock.o munmap.o ntp_adjtime.o pathconf.o profil.o \ +	quotactl.o readlink.o rename.o revoke.o rmdir.o rtprio.o \ +	semsys.o setegid.o seteuid.o setgid.o setgroups.o setitimer.o \ +	setpgid.o setpriority.o setregid.o setreuid.o setrlimit.o \ +	setsid.o settimeofday.o setuid.o shmsys.o stat.o statfs.o \ +	swapon.o symlink.o sync.o sysarch.o umask.o unlink.o \ +	unmount.o utimes.o vadvise.o __syscall.o __sysctl.o + +# Syscalls renamed as _thread_sys_{syscall}. +THREADASM=	accept.o bind.o close.o connect.o dup.o dup2.o \ +	execve.o fchdir.o fchflags.o fchmod.o fchown.o fcntl.o \ +	flock.o fpathconf.o fstat.o fstatfs.o fsync.o getdirentries.o \ +	getpeername.o getsockname.o getsockopt.o ioctl.o listen.o \ +	mkfifo.o mknod.o nfssvc.o open.o read.o readv.o recvfrom.o \ +	recvmsg.o select.o sendmsg.o sendto.o setsockopt.o \ +	shutdown.o sigaction.o sigaltstack.o socket.o socketpair.o \ +	wait4.o write.o writev.o + +PSEUDO=	_exit.o _getlogin.o + +OBJS+=	${ASM} ${THREADASM} ${PSEUDO} + +${ASM}: ${.CURDIR}/../libc/${MACHINE}/SYS.h /usr/include/sys/syscall.h +	@${ECHO} creating ${.PREFIX}.o +	@printf '#include "SYS.h"\nRSYSCALL(${.PREFIX})\n' | \ +	    ${CPP} ${CFLAGS:M-[ID]*} ${AINC} | ${AS} -o ${.PREFIX}.o +	@${LD} -x -r ${.PREFIX}.o +	@mv a.out ${.PREFIX}.o + +PASM=	${ASM:.o=.po} +${PASM}: ${.CURDIR}/../libc/${MACHINE}/SYS.h /usr/include/sys/syscall.h +	@${ECHO} creating ${.PREFIX}.po +	@printf '#include "SYS.h"\nRSYSCALL(${.PREFIX})\n' | \ +	    ${CPP} -DPROF ${CFLAGS:M-[ID]*} ${AINC} | ${AS} -o ${.PREFIX}.po +	@${LD} -x -r ${.PREFIX}.po +	@mv a.out ${.PREFIX}.po + +SASM=	${ASM:.o=.so} +${SASM}: ${.CURDIR}/../libc/${MACHINE}/SYS.h /usr/include/sys/syscall.h +	@${ECHO} creating ${.PREFIX}.so +	@printf '#include "SYS.h"\nRSYSCALL(${.PREFIX})\n' | \ +	    ${CPP} -DPIC ${CFLAGS:M-[ID]*} ${AINC} | ${AS} -k -o ${.PREFIX}.so + +${THREADASM}: ${.CURDIR}/../libc/${MACHINE}/SYS.h /usr/include/sys/syscall.h +	@${ECHO} creating ${.PREFIX}.o +	@printf '#include "SYS.h"\nPRSYSCALL(${.PREFIX})\n' | \ +	    ${CPP} ${CFLAGS:M-[ID]*} ${AINC} | ${AS} -o ${.PREFIX}.o +	@${LD} -x -r ${.PREFIX}.o +	@mv a.out ${.PREFIX}.o + +PTHREADASM=	${THREADASM:.o=.po} +${PTHREADASM}: ${.CURDIR}/../libc/${MACHINE}/SYS.h /usr/include/sys/syscall.h +	@${ECHO} creating ${.PREFIX}.po +	@printf '#include "SYS.h"\nPRSYSCALL(${.PREFIX})\n' | \ +	    ${CPP} -DPROF ${CFLAGS:M-[ID]*} ${AINC} | ${AS} -o ${.PREFIX}.po +	@${LD} -x -r ${.PREFIX}.po +	@mv a.out ${.PREFIX}.po + +STHREADASM=	${THREADASM:.o=.so} +${STHREADASM}: ${.CURDIR}/../libc/${MACHINE}/SYS.h /usr/include/sys/syscall.h +	@${ECHO} creating ${.PREFIX}.so +	@printf '#include "SYS.h"\nPRSYSCALL(${.PREFIX})\n' | \ +	    ${CPP} -DPIC ${CFLAGS:M-[ID]*} ${AINC} | ${AS} -k -o ${.PREFIX}.so + +${PSEUDO}: ${.CURDIR}/../libc/${MACHINE}/SYS.h /usr/include/sys/syscall.h +	@${ECHO} creating ${.PREFIX}.o +	@printf '#include "SYS.h"\nPSEUDO(${.PREFIX},${.PREFIX:S/_//})\n' | \ +	    ${CPP} ${CFLAGS:M-[ID]*} ${AINC} | ${AS} -o ${.PREFIX}.o +	@${LD} -x -r ${.PREFIX}.o +	@mv a.out ${.PREFIX}.o + +PPSEUDO=${PSEUDO:.o=.po} +${PPSEUDO}: ${.CURDIR}/../libc/${MACHINE}/SYS.h /usr/include/sys/syscall.h +	@${ECHO} creating ${.PREFIX}.po +	@printf '#include "SYS.h"\nPSEUDO(${.PREFIX},${.PREFIX:S/_//})\n' | \ +	    ${CPP} -DPROF ${CFLAGS:M-[ID]*} ${AINC} | ${AS} -o ${.PREFIX}.po +	@${LD} -x -r ${.PREFIX}.po +	@mv a.out ${.PREFIX}.po + +SPSEUDO=${PSEUDO:.o=.so} +${SPSEUDO}: ${.CURDIR}/../libc/${MACHINE}/SYS.h /usr/include/sys/syscall.h +	@${ECHO} creating ${.PREFIX}.so +	@printf '#include "SYS.h"\nPSEUDO(${.PREFIX},${.PREFIX:S/_//})\n' | \ +	    ${CPP} -DPIC ${CFLAGS:M-[ID]*} ${AINC} | ${AS} -k -o ${.PREFIX}.so diff --git a/lib/libpthread/thread/Makefile.inc b/lib/libpthread/thread/Makefile.inc new file mode 100644 index 000000000000..a3f6ff99ea55 --- /dev/null +++ b/lib/libpthread/thread/Makefile.inc @@ -0,0 +1,75 @@ +#	$Id$ + +# uthread sources +.PATH: ${.CURDIR}/uthread + +SRCS+= \ +	uthread_accept.c \ +	uthread_attr_setcreatesuspend.c \ +	uthread_bind.c \ +	uthread_clean.c \ +	uthread_close.c \ +	uthread_cond.c \ +	uthread_connect.c \ +	uthread_create.c \ +	uthread_detach.c \ +	uthread_dup.c \ +	uthread_dup2.c \ +	uthread_equal.c \ +	uthread_execve.c \ +	uthread_exit.c \ +	uthread_fchmod.c \ +	uthread_fchown.c \ +	uthread_fcntl.c \ +	uthread_fd.c \ +	uthread_file.c \ +	uthread_flock.c \ +	uthread_fork.c \ +	uthread_fstat.c \ +	uthread_fstatfs.c \ +	uthread_fsync.c \ +	uthread_getdirentries.c \ +	uthread_getpeername.c \ +	uthread_getprio.c \ +	uthread_getsockname.c \ +	uthread_getsockopt.c \ +	uthread_info.c \ +	uthread_init.c \ +	uthread_ioctl.c \ +	uthread_join.c \ +	uthread_kern.c \ +	uthread_listen.c \ +	uthread_longjmp.c \ +	uthread_mutex.c \ +	uthread_nanosleep.c \ +	uthread_once.c \ +	uthread_open.c \ +	uthread_pipe.c \ +	uthread_queue.c \ +	uthread_read.c \ +	uthread_readv.c \ +	uthread_recvfrom.c \ +	uthread_resume.c \ +	uthread_select.c \ +	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_signal.c \ +	uthread_sigprocmask.c \ +	uthread_sigsetmask.c \ +	uthread_sigsuspend.c \ +	uthread_socket.c \ +	uthread_socketpair.c \ +	uthread_spec.c \ +	uthread_suspend.c \ +	uthread_wait4.c \ +	uthread_write.c \ +	uthread_writev.c \ +	uthread_yield.c diff --git a/lib/libpthread/thread/thr_clean.c b/lib/libpthread/thread/thr_clean.c new file mode 100644 index 000000000000..99893f671b1d --- /dev/null +++ b/lib/libpthread/thread/thr_clean.c @@ -0,0 +1,73 @@ +/* + * 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 <signal.h> +#include <errno.h> +#include <stdlib.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +int +_thread_cleanup_push(void (*routine) (void *), void *routine_arg) +{ +	struct pthread_cleanup *new; +	int             ret; + +	if ((new = (struct pthread_cleanup *) malloc(sizeof(struct pthread_cleanup))) != NULL) { +		new->routine = routine; +		new->routine_arg = routine_arg; +		new->next = _thread_run->cleanup; + +		_thread_run->cleanup = new; +		ret = 0; +	} else { +		ret = ENOMEM; +	} +	return (ret); +} + +void +_thread_cleanup_pop(int execute) +{ +	struct pthread_cleanup *old; + +	if ((old = _thread_run->cleanup) != NULL) { +		_thread_run->cleanup = old->next; +		if (execute) { +			old->routine(old->routine_arg); +		} +		free(old); +	} +} + +#endif diff --git a/lib/libpthread/thread/thr_close.c b/lib/libpthread/thread/thr_close.c new file mode 100644 index 000000000000..f98e056aaab3 --- /dev/null +++ b/lib/libpthread/thread/thr_close.c @@ -0,0 +1,48 @@ +/* + * 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 <unistd.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +int +close(int fd) +{ +	int ret; +	if ((ret = _thread_fd_lock(fd, FD_RDWR, NULL, __FILE__, __LINE__)) == 0) { +		ret = _thread_sys_close(fd); +		_thread_fd_unlock(fd, FD_RDWR); +	} +	return (ret); +} +#endif diff --git a/lib/libpthread/thread/thr_cond.c b/lib/libpthread/thread/thr_cond.c new file mode 100644 index 000000000000..930f31aea623 --- /dev/null +++ b/lib/libpthread/thread/thr_cond.c @@ -0,0 +1,293 @@ +/* + * 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 <stdlib.h> +#include <errno.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +int +pthread_cond_init(pthread_cond_t * cond, const pthread_condattr_t * cond_attr) +{ +	enum pthread_cond_type type; +	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; +	} 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; + +		/* Trap invalid condition variable types: */ +	default: +		/* Return an invalid argument error: */ +		_thread_seterrno(_thread_run, 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; +	} +	/* Return the completion status: */ +	return (rval); +} + +int +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); +		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; +	} +	/* Return the completion status: */ +	return (rval); +} + +int +pthread_cond_wait(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: +		/* Queue the running thread for the condition variable: */ +			_thread_queue_enq(&cond->c_queue, _thread_run); + +		/* Unlock the mutex: */ +		pthread_mutex_unlock(mutex); + +		/* Schedule the next thread: */ +		_thread_kern_sched_state(PS_COND_WAIT, __FILE__, __LINE__); + +		/* Block signals: */ +		_thread_kern_sig_block(NULL); + +		/* Lock the mutex: */ +		rval = pthread_mutex_lock(mutex); +		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); + +	/* Return the completion status: */ +	return (rval); +} + +int +pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex, +		       const struct timespec * abstime) +{ +	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); + +			/* 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; +			} +		} +		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); + +	/* Return the completion status: */ +	return (rval); +} + +int +pthread_cond_signal(pthread_cond_t * cond) +{ +	int             rval = 0; +	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; +		} +		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); + +	/* Return the completion status: */ +	return (rval); +} + +int +pthread_cond_broadcast(pthread_cond_t * cond) +{ +	int             rval = 0; +	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: +		/* 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->state = PS_RUNNING; +		} +		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); + +	/* Return the completion status: */ +	return (rval); +} +#endif diff --git a/lib/libpthread/thread/thr_create.c b/lib/libpthread/thread/thr_create.c new file mode 100644 index 000000000000..e6db38144f64 --- /dev/null +++ b/lib/libpthread/thread/thr_create.c @@ -0,0 +1,277 @@ +/* + * 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> +#include <stdlib.h> +#include <string.h> +#include <fcntl.h> +#include <unistd.h> +#include <sys/time.h> +#ifdef _THREAD_SAFE +#include <machine/reg.h> +#include <pthread.h> +#include "pthread_private.h" + +int +_thread_create(pthread_t * thread, const pthread_attr_t * attr, +	       void *(*start_routine) (void *), void *arg, pthread_t parent) +{ +	int             i; +	int             ret = 0; +	int             status; +	pthread_t       new_thread; +	void           *stack; + +	/* Block signals: */ +	_thread_kern_sig_block(&status); + +	/* Allocate memory for the thread structure: */ +	if ((new_thread = (pthread_t) malloc(sizeof(struct pthread))) == NULL) { +		/* Insufficient memory to create a thread: */ +		ret = EAGAIN; +	} else { +		/* Check if default thread attributes are required: */ +		if (attr == NULL) { +			/* Use the default thread attributes: */ +			attr = &pthread_attr_default; +		} +		/* Check if a stack was specified in the thread attributes: */ +		if ((stack = attr->stackaddr_attr) != NULL) { +		} +		/* Allocate memory for the stack: */ +		else if ((stack = (void *) malloc(attr->stacksize_attr)) == NULL) { +			/* Insufficient memory to create a thread: */ +			ret = EAGAIN; +			free(new_thread); +		} +		/* Check for errors: */ +		if (ret != 0) { +		} else { +			/* Initialise the thread structure: */ +			memset(new_thread, 0, sizeof(struct pthread)); +			new_thread->slice_usec = -1; +			new_thread->sig_saved = 0; +			new_thread->stack = stack; +			new_thread->start_routine = start_routine; +			new_thread->arg = arg; +			if (attr->suspend == PTHREAD_CREATE_SUSPENDED) { +				new_thread->state = PS_SUSPENDED; +			} else { +				new_thread->state = PS_RUNNING; +			} + +			/* 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); + +			/* +			 * 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:  +			 */ +			if (parent == NULL) { +				/* Use the user start function: */ +#if	defined(__FreeBSD__) +				new_thread->saved_jmp_buf[0]._jb[0] = (long) _thread_start; +#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; +#else +				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__) +				new_thread->saved_jmp_buf[0]._jb[0] = (int) _thread_start_sig_handler; +#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__) +			new_thread->saved_jmp_buf[0]._jb[2] = (int) (new_thread->stack + attr->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); +#else +			new_thread->saved_jmp_buf[2] = (long) new_thread->stack + attr->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)); + +			/* +			 * Check if this thread is to inherit the scheduling +			 * attributes from its parent:  +			 */ +			if (new_thread->attr.flags & PTHREAD_INHERIT_SCHED) { +				/* Copy the scheduling attributes: */ +				new_thread->pthread_priority = _thread_run->pthread_priority; +				new_thread->attr.prio = _thread_run->pthread_priority; +				new_thread->attr.schedparam_policy = _thread_run->attr.schedparam_policy; +			} else { +				/* +				 * Use just the thread priority, leaving the +				 * other scheduling attributes as their +				 * default values:  +				 */ +				new_thread->pthread_priority = new_thread->attr.prio; +			} + +			/* Initialise the join queue for the new thread: */ +			_thread_queue_init(&(new_thread->join_queue)); + +			/* Initialise hooks in the thread structure: */ +			new_thread->specific_data = NULL; +			new_thread->cleanup = NULL; +			new_thread->queue = NULL; +			new_thread->qnxt = NULL; +			new_thread->parent_thread = parent; +			new_thread->flags = 0; + +			/* Add the thread to the linked list of all threads: */ +			new_thread->nxt = _thread_link_list; +			_thread_link_list = new_thread; + +			/* Return a pointer to the thread structure: */ +			(*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:  +				 */ +				parent->state = PS_SIGTHREAD; +			} else { +				/* 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; + +	/* +	 * 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); +} + +void +_thread_start(void) +{ +	/* Run the current thread's start routine with argument: */ +	pthread_exit(_thread_run->start_routine(_thread_run->arg)); + +	/* 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 new file mode 100644 index 000000000000..f24d16f2dbce --- /dev/null +++ b/lib/libpthread/thread/thr_detach.c @@ -0,0 +1,83 @@ +/* + * 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_detach(pthread_t * p_pthread) +{ +	int             rval = 0; +	int             status; +	pthread_t       next_thread; +	pthread_t       pthread; + +	/* Block signals: */ +	_thread_kern_sig_block(&status); + +	/* Check for invalid calling parameters: */ +	if (p_pthread == NULL || (pthread = *p_pthread) == NULL) { +		/* Return an invalid argument error: */ +		_thread_seterrno(_thread_run, EINVAL); +		rval = -1; +	} +	/* Check if the thread has not been detached: */ +	else if ((pthread->attr.flags & PTHREAD_DETACHED) == 0) { +		/* Flag the thread as detached: */ +		pthread->attr.flags |= PTHREAD_DETACHED; + +		/* Enter a loop to bring all threads off the join queue: */ +		while ((next_thread = _thread_queue_deq(&pthread->join_queue)) != NULL) { +			/* Make the thread run: */ +			next_thread->state = PS_RUNNING; +		} + +		/* +		 * NULL the thread pointer now that the thread has been +		 * detached:  +		 */ +		*p_pthread = NULL; +	} else { +		/* Return an error: */ +		_thread_seterrno(_thread_run, ESRCH); +		rval = -1; +	} + +	/* Unblock signals: */ +	_thread_kern_sig_unblock(status); + +	/* Return the completion status: */ +	return (rval); +} +#endif diff --git a/lib/libpthread/thread/thr_equal.c b/lib/libpthread/thread/thr_equal.c new file mode 100644 index 000000000000..99ffb5d8b7d7 --- /dev/null +++ b/lib/libpthread/thread/thr_equal.c @@ -0,0 +1,43 @@ +/* + * 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. + * + */ +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +int +pthread_equal(pthread_t t1, pthread_t t2) +{ +	/* Compare the two thread pointers: */ +	return (t1 == t2); +} +#endif diff --git a/lib/libpthread/thread/thr_exit.c b/lib/libpthread/thread/thr_exit.c new file mode 100644 index 000000000000..292fce9c0fb8 --- /dev/null +++ b/lib/libpthread/thread/thr_exit.c @@ -0,0 +1,167 @@ +/* + * 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> +#include <string.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +void +_thread_exit(char *fname, int lineno, char *string) +{ +	char            s[256]; + +	/* Prepare an error message string: */ +	strcpy(s, "Fatal error '"); +	strcat(s, string); +	strcat(s, "' at line ? "); +	strcat(s, "in file "); +	strcat(s, fname); +	strcat(s, " (errno = ?"); +	strcat(s, ")\n"); + +	/* Write the string to the standard error file descriptor: */ +	_thread_sys_write(2, s, strlen(s)); + +	/* Force this process to exit: */ +	_exit(1); +} + +void +pthread_exit(void *status) +{ +	int             sig; +	long            l; +	pthread_t       pthread; + +	/* Block signals: */ +	_thread_kern_sig_block(NULL); + +	/* Save the return value: */ +	_thread_run->ret = status; + +	while (_thread_run->cleanup != NULL) { +		_thread_cleanup_pop(1); +	} + +	if (_thread_run->attr.cleanup_attr != NULL) { +		_thread_run->attr.cleanup_attr(_thread_run->attr.arg_attr); +	} +	/* Check if there is thread specific data: */ +	if (_thread_run->specific_data != NULL) { +		/* Run the thread-specific data destructors: */ +		_thread_cleanupspecific(); +	} +	/* Check if there are any threads joined to this one: */ +	while ((pthread = _thread_queue_deq(&(_thread_run->join_queue))) != NULL) { +		/* Wake the joined thread and let it detach this thread: */ +		pthread->state = PS_RUNNING; +	} + +	/* Check if the running thread is at the head of the linked list: */ +	if (_thread_link_list == _thread_run) { +		/* There is no previous thread: */ +		_thread_link_list = _thread_run->nxt; +	} else { +		/* Point to the first thread in the list: */ +		pthread = _thread_link_list; + +		/* +		 * Enter a loop to find the thread in the linked list before +		 * the running thread:  +		 */ +		while (pthread != NULL && pthread->nxt != _thread_run) { +			/* Point to the next thread: */ +			pthread = pthread->nxt; +		} + +		/* Check that a previous thread was found: */ +		if (pthread != NULL) { +			/* +			 * Point the previous thread to the one after the +			 * running thread:  +			 */ +			pthread->nxt = _thread_run->nxt; +		} +	} + +	/* 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; +			} +		} + +		/* +		 * Check if the parent is not waiting on any other signal +		 * handler threads:  +		 */ +		if (pthread == NULL) { +			/* Allow the parent thread to run again: */ +			_thread_run->parent_thread->state = PS_RUNNING; +		} +		/* Get the signal number: */ +		l = (long) _thread_run->arg; +		sig = (int) l; + +		/* 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:  +	 */ +	_thread_run->nxt = _thread_dead; +	_thread_dead = _thread_run; + +	/* +	 * The running thread is no longer in the thread link list so it will +	 * now die:  +	 */ +	_thread_kern_sched_state(PS_DEAD, __FILE__, __LINE__); + +	/* This point should not be reached. */ +	PANIC("Dead thread has resumed"); +} +#endif diff --git a/lib/libpthread/thread/thr_fcntl.c b/lib/libpthread/thread/thr_fcntl.c new file mode 100644 index 000000000000..ae069b8e36a9 --- /dev/null +++ b/lib/libpthread/thread/thr_fcntl.c @@ -0,0 +1,115 @@ +/* + * 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 <stdarg.h> +#include <fcntl.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +int +fcntl(int fd, int cmd,...) +{ +	int             flags = 0; +	int             oldfd; +	int             ret; +	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: */ +		va_start(ap, cmd); + +		/* Process according to file control command type: */ +		switch (cmd) { +			/* Duplicate a file descriptor: */ +		case F_DUPFD: +			/* +			 * Get the file descriptor that the caller wants to +			 * use:  +			 */ +			oldfd = va_arg(ap, int); + +			/* Initialise the file descriptor table entry: */ +			if ((ret = _thread_sys_fcntl(fd, cmd, oldfd)) < 0) { +			} +			/* Initialise the file descriptor table entry: */ +			else if (_thread_fd_table_init(ret) != 0) { +				/* Quietly close the file: */ +				_thread_sys_close(ret); + +				/* Reset the file descriptor: */ +				ret = -1; +			} else { +				/* +				 * Save the file open flags so that they can +				 * be         checked later:  +				 */ +				_thread_fd_table[ret]->flags = _thread_fd_table[fd]->flags; +			} +			break; +		case F_SETFD: +			break; +		case F_GETFD: +			break; +		case F_GETFL: +			ret = _thread_fd_table[fd]->flags; +			break; +		case F_SETFL: +			flags = va_arg(ap, int); +			if ((ret = _thread_sys_fcntl(fd, cmd, flags | O_NONBLOCK)) == 0) { +				_thread_fd_table[fd]->flags = flags; +			} +			break; +		default: +			/* Might want to make va_arg use a union */ +			ret = _thread_sys_fcntl(fd, cmd, va_arg(ap, void *)); +			break; +		} + +		/* Free variable arguments: */ +		va_end(ap); + +		/* Unlock the file descriptor: */ +		_thread_fd_unlock(fd, FD_RDWR); +	} +	/* Unblock signals: */ +	_thread_kern_sig_unblock(status); + +	/* Return the completion status: */ +	return (ret); +} +#endif diff --git a/lib/libpthread/thread/thr_fork.c b/lib/libpthread/thread/thr_fork.c new file mode 100644 index 000000000000..6e7ca0d43b44 --- /dev/null +++ b/lib/libpthread/thread/thr_fork.c @@ -0,0 +1,90 @@ +/* + * 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> +#include <fcntl.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +pid_t +fork(void) +{ +	int             flags; +	pid_t           ret; + +	/* Fork a new process: */ +	if ((ret = _thread_sys_fork()) <= 0) { +		/* Parent process or error. Nothing to do here. */ +	} else { +		/* Close the pthread kernel pipe: */ +		_thread_sys_close(_thread_kern_pipe[0]); +		_thread_sys_close(_thread_kern_pipe[1]); + +		/* Reset signals pending for the running thread: */ +		memset(_thread_run->sigpend, 0, sizeof(_thread_run->sigpend)); + +		/* +		 * Create a pipe that is written to by the signal handler to +		 * prevent signals being missed in calls to +		 * _thread_sys_select:  +		 */ +		if (_thread_sys_pipe(_thread_kern_pipe) != 0) { +			/* Cannot create pipe, so abort: */ +			PANIC("Cannot create pthread kernel pipe for forked process"); +		} +		/* Get the flags for the read pipe: */ +		else if ((flags = _thread_sys_fcntl(_thread_kern_pipe[0], F_GETFL, NULL)) == -1) { +			/* Abort this application: */ +			abort(); +		} +		/* Make the read pipe non-blocking: */ +		else if (_thread_sys_fcntl(_thread_kern_pipe[0], F_SETFL, flags | O_NONBLOCK) == -1) { +			/* Abort this application: */ +			abort(); +		} +		/* Get the flags for the write pipe: */ +		else if ((flags = _thread_sys_fcntl(_thread_kern_pipe[1], F_GETFL, NULL)) == -1) { +			/* Abort this application: */ +			abort(); +		} +		/* Make the write pipe non-blocking: */ +		else if (_thread_sys_fcntl(_thread_kern_pipe[1], F_SETFL, flags | O_NONBLOCK) == -1) { +			/* Abort this application: */ +			abort(); +		} +	} + +	/* Return the process ID: */ +	return (ret); +} +#endif diff --git a/lib/libpthread/thread/thr_fsync.c b/lib/libpthread/thread/thr_fsync.c new file mode 100644 index 000000000000..51078e5515f8 --- /dev/null +++ b/lib/libpthread/thread/thr_fsync.c @@ -0,0 +1,49 @@ +/* + * 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 <unistd.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +int +fsync(int fd) +{ +	int             ret; + +	if ((ret = _thread_fd_lock(fd, FD_RDWR, NULL, __FILE__, __LINE__)) == 0) { +		ret = _thread_sys_fsync(fd); +		_thread_fd_unlock(fd, FD_RDWR); +	} +	return (ret); +} +#endif diff --git a/lib/libpthread/thread/thr_getprio.c b/lib/libpthread/thread/thr_getprio.c new file mode 100644 index 000000000000..345f6ce2c888 --- /dev/null +++ b/lib/libpthread/thread/thr_getprio.c @@ -0,0 +1,73 @@ +/* + * 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_getprio(pthread_t pthread) +{ +	int             rval = 0; +	int             status; +	pthread_t       pthread_p; + +	/* 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: */ +		_thread_seterrno(_thread_run, EINVAL); +		rval = -1; +	} else { +		/* Get the thread priority: */ +		rval = pthread->pthread_priority; +	} + +	/* Unblock signals: */ +	_thread_kern_sig_unblock(status); + +	/* Return the thread priority or an error status: */ +	return (rval); +} +#endif diff --git a/lib/libpthread/thread/thr_info.c b/lib/libpthread/thread/thr_info.c new file mode 100644 index 000000000000..e69145f8fd4b --- /dev/null +++ b/lib/libpthread/thread/thr_info.c @@ -0,0 +1,175 @@ +/* + * 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 <stdio.h> +#include <fcntl.h> +#include <string.h> +#include <unistd.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +struct s_thread_info { +	enum pthread_state state; +	char           *name; +}; + +/* Static variables: */ +static const struct s_thread_info thread_info[] = { +	{PS_RUNNING	, "Running"}, +	{PS_SIGTHREAD	, "Waiting on signal thread"}, +	{PS_MUTEX_WAIT	, "Waiting on a mutex"}, +	{PS_COND_WAIT	, "Waiting on a condition variable"}, +	{PS_FDLR_WAIT	, "Waiting for a file read lock"}, +	{PS_FDLW_WAIT	, "Waiting for a file write lock"}, +	{PS_FDR_WAIT	, "Waiting for read"}, +	{PS_FDW_WAIT	, "Waitingfor write"}, +	{PS_SELECT_WAIT	, "Waiting on select"}, +	{PS_SLEEP_WAIT	, "Sleeping"}, +	{PS_WAIT_WAIT	, "Waiting process"}, +	{PS_SIGWAIT	, "Waiting for a signal"}, +	{PS_JOIN	, "Waiting to join"}, +	{PS_SUSPENDED	, "Suspended"}, +	{PS_DEAD	, "Dead"}, +	{PS_STATE_MAX	, "Not a real state!"} +}; + +void +_thread_dump_info(void) +{ +	char            s[128]; +	int             fd; +	int             i; +	int             j; +	pthread_t       pthread; + +	/* Open the dump file for append and create it if necessary: */ +	if ((fd = _thread_sys_open("/tmp/uthread.dump", O_RDWR | O_CREAT | O_APPEND, 0666)) < 0) { +		/* Can't open the dump file. */ +	} else { +		/* Output a header for active threads: */ +		strcpy(s, "\n\n=============\nACTIVE THREADS\n\n"); +		_thread_sys_write(fd, s, strlen(s)); + +		/* Enter a loop to report each thread in the global list: */ +		for (pthread = _thread_link_list; pthread != NULL; pthread = pthread->nxt) { +			/* Find the state: */ +			for (j = 0; j < (sizeof(thread_info) / sizeof(struct s_thread_info)) - 1; j++) +				if (thread_info[j].state == pthread->state) +					break; +			/* Output a record for the current thread: */ +			sprintf(s, "--------------------\nThread %p prio %3d state %s\n", +				pthread, pthread->pthread_priority, thread_info[j].name); +			_thread_sys_write(fd, s, strlen(s)); + +			/* Check if this is the running thread: */ +			if (pthread == _thread_run) { +				/* Output a record for the running thread: */ +				strcpy(s, "This is the running thread\n"); +				_thread_sys_write(fd, s, strlen(s)); +			} +			/* Check if this is the initial thread: */ +			if (pthread == _thread_initial) { +				/* Output a record for the initial thread: */ +				strcpy(s, "This is the initial thread\n"); +				_thread_sys_write(fd, s, strlen(s)); +			} +			/* Process according to thread state: */ +			switch (pthread->state) { +				/* File descriptor read lock wait: */ +			case PS_FDLR_WAIT: +				/* Write the lock details: */ +				sprintf(s, "fd %d[%s:%d]", pthread->data.fd.fd, pthread->data.fd.fname, pthread->data.fd.branch); +				_thread_sys_write(fd, s, strlen(s)); +				sprintf(s, "owner %pr/%pw\n", _thread_fd_table[pthread->data.fd.fd]->r_owner, _thread_fd_table[pthread->data.fd.fd]->w_owner); +				_thread_sys_write(fd, s, strlen(s)); +				break; + +				/* +				 * Trap other states that are not explicitly +				 * coded to dump information:  +				 */ +			default: +				/* Nothing to do here. */ +				break; +			} +		} + +		/* Check if there are no dead threads: */ +		if (_thread_dead == NULL) { +			/* Output a record: */ +			strcpy(s, "\n\nTHERE ARE NO DEAD THREADS\n"); +			_thread_sys_write(fd, s, strlen(s)); +		} else { +			/* Output a header for dead threads: */ +			strcpy(s, "\n\nDEAD THREADS\n\n"); +			_thread_sys_write(fd, s, strlen(s)); + +			/* +			 * Enter a loop to report each thread in the global +			 * dead thread list:  +			 */ +			for (pthread = _thread_dead; pthread != NULL; pthread = pthread->nxt) { +				/* Output a record for the current thread: */ +				sprintf(s, "Thread %p prio %3d\n", pthread, pthread->pthread_priority); +				_thread_sys_write(fd, s, strlen(s)); +			} +		} + +		/* Enter a loop to report file descriptor lock usage: */ +		for (i = 0; i < _thread_dtablesize; i++) { +			/* +			 * Check if memory is allocated for this file +			 * descriptor:  +			 */ +			if (_thread_fd_table[i] != NULL) { +				/* Report the file descriptor lock status: */ +				sprintf(s, "fd[%3d] read owner %p count %d [%s:%d]\n        write owner %p count %d [%s:%d]\n", +					i, +					_thread_fd_table[i]->r_owner, +					_thread_fd_table[i]->r_lockcount, +					_thread_fd_table[i]->r_fname, +					_thread_fd_table[i]->r_lineno, +					_thread_fd_table[i]->w_owner, +					_thread_fd_table[i]->w_lockcount, +					_thread_fd_table[i]->w_fname, +					_thread_fd_table[i]->w_lineno); +				_thread_sys_write(fd, s, strlen(s)); +			} +		} + +		/* Close the dump file: */ +		_thread_sys_close(fd); +	} +	return; +} +#endif diff --git a/lib/libpthread/thread/thr_init.c b/lib/libpthread/thread/thr_init.c new file mode 100644 index 000000000000..d044063ce9d4 --- /dev/null +++ b/lib/libpthread/thread/thr_init.c @@ -0,0 +1,214 @@ +/* + * 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. + * + */ + +/* Allocate space for global thread variables here: */ +#define GLOBAL_PTHREAD_PRIVATE + +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include <fcntl.h> +#include <unistd.h> +#include <sys/time.h> +#ifdef _THREAD_SAFE +#include <machine/reg.h> +#include <pthread.h> +#include "pthread_private.h" + +void +_thread_init(void) +{ +	int             flags; +	int             i; +	struct sigaction act; + +	/* Check if this function has already been called: */ +	if (_thread_initial) { +		/* Only initialise the threaded application once. */ +	} +	/* +	 * Create a pipe that is written to by the signal handler to prevent +	 * signals being missed in calls to _thread_sys_select:  +	 */ +	else if (_thread_sys_pipe(_thread_kern_pipe) != 0) { +		/* Cannot create pipe, so abort: */ +		PANIC("Cannot create kernel pipe"); +	} +	/* Get the flags for the read pipe: */ +	else if ((flags = _thread_sys_fcntl(_thread_kern_pipe[0], F_GETFL, NULL)) == -1) { +		/* Abort this application: */ +		PANIC("Cannot get kernel read pipe flags"); +	} +	/* Make the read pipe non-blocking: */ +	else if (_thread_sys_fcntl(_thread_kern_pipe[0], F_SETFL, flags | O_NONBLOCK) == -1) { +		/* Abort this application: */ +		PANIC("Cannot make kernel read pipe non-blocking"); +	} +	/* Get the flags for the write pipe: */ +	else if ((flags = _thread_sys_fcntl(_thread_kern_pipe[1], F_GETFL, NULL)) == -1) { +		/* Abort this application: */ +		PANIC("Cannot get kernel write pipe flags"); +	} +	/* Make the write pipe non-blocking: */ +	else if (_thread_sys_fcntl(_thread_kern_pipe[1], F_SETFL, flags | O_NONBLOCK) == -1) { +		/* Abort this application: */ +		PANIC("Cannot get kernel write pipe flags"); +	} +	/* Allocate memory for the thread structure of the initial thread: */ +	else if ((_thread_initial = (pthread_t) malloc(sizeof(struct pthread))) == NULL) { +		/* +		 * Insufficient memory to initialise this application, so +		 * abort:  +		 */ +		PANIC("Cannot allocate memory for initial thread"); +	} else { +		/* Zero the global kernel thread structure: */ +		memset(&_thread_kern_thread, 0, sizeof(struct pthread)); +		memset(_thread_initial, 0, sizeof(struct pthread)); + +		/* Default the priority of the initial thread: */ +		_thread_initial->pthread_priority = PTHREAD_DEFAULT_PRIORITY; + +		/* Initialise the state of the initial thread: */ +		_thread_initial->state = PS_RUNNING; + +		/* Initialise the queue: */ +		_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; +		_thread_initial->qnxt = NULL; +		_thread_initial->nxt = NULL; +		_thread_initial->flags = 0; +		_thread_initial->error = 0; +		_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: */ +		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) { +				/* +				 * Abort this process if signal +				 * initialisation fails:  +				 */ +				PANIC("Cannot initialise signal handler"); +			} +		} + +		/* Get the table size: */ +		if ((_thread_dtablesize = getdtablesize()) < 0) { +			/* +			 * Cannot get the system defined table size, so abort +			 * this process.  +			 */ +			PANIC("Cannot get dtablesize"); +		} +		/* Allocate memory for the file descriptor table: */ +		if ((_thread_fd_table = (struct fd_table_entry **) malloc(sizeof(struct fd_table_entry) * _thread_dtablesize)) == NULL) { +			/* +			 * Cannot allocate memory for the file descriptor +			 * table, so abort this process.  +			 */ +			PANIC("Cannot allocate memory for file descriptor table"); +		} else { +			/* +			 * Enter a loop to initialise the file descriptor +			 * table:  +			 */ +			for (i = 0; i < _thread_dtablesize; i++) { +				/* Initialise the file descriptor table: */ +				_thread_fd_table[i] = NULL; +			} +		} +	} +	return; +} + +/* + * Special start up code for NetBSD/Alpha  + */ +#if	defined(__NetBSD__) && defined(__alpha__) +int  +main(int argc, char *argv[], char *env); + +int +_thread_main(int argc, char *argv[], char *env) +{ +	_thread_init(); +	return (main(argc, argv, env)); +} +#endif +#else +/* + * A stub for non-threaded programs. + */ +void +_thread_init(void) +{ +} +#endif diff --git a/lib/libpthread/thread/thr_join.c b/lib/libpthread/thread/thr_join.c new file mode 100644 index 000000000000..d0093ae72f05 --- /dev/null +++ b/lib/libpthread/thread/thr_join.c @@ -0,0 +1,90 @@ +/* + * 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_join(pthread_t pthread, void **thread_return) +{ +	int             rval = 0; +	int             status; + +	/* Block signals: */ +	_thread_kern_sig_block(&status); + +	/* Check if this thread has been detached: */ +	if ((pthread->attr.flags & PTHREAD_DETACHED) != 0) { +		/* Return an error: */ +		_thread_seterrno(_thread_run, ESRCH); +		rval = -1; +	} +	/* Check if the thread is not dead: */ +	else if (pthread->state != PS_DEAD) { +		/* Add the running thread to the join queue: */ +		_thread_queue_enq(&(pthread->join_queue), _thread_run); + +		/* 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) { +			/* Check if the return value is required: */ +			if (thread_return) { +				/* Return the thread's return value: */ +				*thread_return = pthread->ret; +			} +		} else { +			/* Return an error: */ +			_thread_seterrno(_thread_run, ESRCH); +			rval = -1; +		} +	} else { +		/* Check if the return value is required: */ +		if (thread_return != NULL) { +			/* Return the thread's return value: */ +			*thread_return = pthread->ret; +		} +	} + +	/* Unblock signals: */ +	_thread_kern_sig_unblock(status); + +	/* Return the completion status: */ +	return (rval); +} +#endif diff --git a/lib/libpthread/thread/thr_kern.c b/lib/libpthread/thread/thr_kern.c new file mode 100644 index 000000000000..35e8e29b9711 --- /dev/null +++ b/lib/libpthread/thread/thr_kern.c @@ -0,0 +1,1581 @@ +/* + * 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> +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <unistd.h> +#include <setjmp.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <sys/socket.h> +#include <sys/uio.h> +#include <sys/syscall.h> +#include <fcntl.h> +#ifdef _THREAD_SAFE +#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) +{ +#ifndef	__alpha +	char           *fdata; +#endif +	int             i; +	int             prio = -1; +	pthread_t       pthread; +	pthread_t       pthread_h = NULL; +	pthread_t       pthread_nxt = NULL; +	pthread_t       pthread_prv = NULL; +	pthread_t       pthread_s = NULL; +	struct itimerval itimer; +	struct timespec ts; +	struct timespec ts1; +	struct timeval  tv; +	struct timeval  tv1; + +	/* Block signals: */ +	_thread_kern_sig_block(NULL); + +	/* Check if this function was called from the signal handler: */ +	if (scp != NULL) { +		/* +		 * Copy the signal context to the current thread's jump +		 * buffer:  +		 */ +		memcpy(&_thread_run->saved_sigcontext, scp, sizeof(_thread_run->saved_sigcontext)); + +#ifndef	__alpha +		/* Point to the floating point data in the running thread: */ +		fdata = _thread_run->saved_fp; + +		/* Save the floating point data: */ +__asm__("fnsave %0": :"m"(*fdata)); +#endif + +		/* Flag the signal context as the last state saved: */ +		_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); + +		/* +		 * This point is reached when a longjmp() is called to +		 * restore the state of a thread.  +		 */ +		return; +	} else { +		/* Flag the jump buffer was the last state saved: */ +		_thread_run->sig_saved = 0; +	} + +	/* Point to the first dead thread (if there are any): */ +	pthread = _thread_dead; + +	/* There is no previous dead thread: */ +	pthread_prv = NULL; + +	/* Enter a loop to cleanup after dead threads: */ +	while (pthread != NULL) { +		/* Save a pointer to the next thread: */ +		pthread_nxt = pthread->nxt; + +		/* Check if this thread is one which is running: */ +		if (pthread == _thread_run || pthread == _thread_initial) { +			/* +			 * Don't destroy the running thread or the initial +			 * thread.  +			 */ +			pthread_prv = pthread; +		} +		/* +		 * Check if this thread has detached or if it is a signal +		 * handler thread:  +		 */ +		else if (((pthread->attr.flags & PTHREAD_DETACHED) != 0) || pthread->parent_thread != NULL) { +			/* Check if there is no previous dead thread: */ +			if (pthread_prv == NULL) { +				/* +				 * The dead thread is at the head of the +				 * list:  +				 */ +				_thread_dead = pthread_nxt; +			} else { +				/* +				 * The dead thread is not at the head of the +				 * list:  +				 */ +				pthread_prv->nxt = pthread->nxt; +			} + +			/* +			 * Check if the stack was not specified by the caller +			 * to pthread_create and has not been destroyed yet:  +			 */ +			if (pthread->attr.stackaddr_attr == NULL && pthread->stack != NULL) { +				/* Free the stack of the dead thread: */ +				free(pthread->stack); +			} +			/* Free the memory allocated to the thread structure: */ +			free(pthread); +		} else { +			/* +			 * This thread has not detached, so do not destroy +			 * it:  +			 */ +			pthread_prv = pthread; + +			/* +			 * Check if the stack was not specified by the caller +			 * to pthread_create and has not been destroyed yet:  +			 */ +			if (pthread->attr.stackaddr_attr == NULL && pthread->stack != NULL) { +				/* Free the stack of the dead thread: */ +				free(pthread->stack); + +				/* +				 * NULL the stack pointer now that the memory +				 * has been freed:  +				 */ +				pthread->stack = NULL; +			} +		} + +		/* Point to the next thread: */ +		pthread = pthread_nxt; +	} + +	/* +	 * Enter a the scheduling loop that finds the next thread that is +	 * ready to run. This loop completes when there are no more threads +	 * in the global list or when a thread has its state restored by +	 * either a sigreturn (if the state was saved as a sigcontext) or a +	 * longjmp (if the state was saved by a setjmp).  +	 */ +	while (_thread_link_list != NULL) { +		/* Get the current time of day: */ +		gettimeofday(&tv, NULL); +		TIMEVAL_TO_TIMESPEC(&tv, &ts); + +		/* +		 * Poll file descriptors to update the state of threads +		 * waiting on file I/O where data may be available:  +		 */ +		_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:  +		 */ +		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; +				} +			} + +			/* Check if this thread is to timeout: */ +			if (pthread->state == PS_COND_WAIT || +			    pthread->state == PS_SLEEP_WAIT || +			    pthread->state == PS_FDR_WAIT || +			    pthread->state == PS_FDW_WAIT || +			    pthread->state == PS_SELECT_WAIT) { +				/* Check if this thread is to wait forever: */ +				if (pthread->wakeup_time.ts_sec == -1) { +				} +				/* +				 * Check if this thread is to wakeup +				 * immediately or if it is past its wakeup +				 * time:  +				 */ +				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))) { +					/* +					 * Check if this thread is waiting on +					 * select:  +					 */ +					if (pthread->state == PS_SELECT_WAIT) { +						/* +						 * The select has timed out, +						 * so zero the file +						 * descriptor sets:  +						 */ +						FD_ZERO(&pthread->data.select_data->readfds); +						FD_ZERO(&pthread->data.select_data->writefds); +						FD_ZERO(&pthread->data.select_data->exceptfds); +						pthread->data.select_data->nfds = 0; +					} +					/* +					 * Return an error as an interrupted +					 * wait:  +					 */ +					_thread_seterrno(pthread, EINTR); + +					/* +					 * Flag the timeout in the thread +					 * structure:  +					 */ +					pthread->timeout = 1; + +					/* +					 * Change the threads state to allow +					 * it to be restarted:  +					 */ +					pthread->state = PS_RUNNING; +				} +			} +		} + +		/* Check if there is a current thread: */ +		if (_thread_run != &_thread_kern_thread) { +			/* +			 * Save the current time as the time that the thread +			 * became inactive:  +			 */ +			_thread_run->last_inactive.tv_sec = tv.tv_sec; +			_thread_run->last_inactive.tv_usec = tv.tv_usec; + +			/* +			 * Accumulate the number of microseconds that this +			 * thread has run for:  +			 */ +			_thread_run->slice_usec += (_thread_run->last_inactive.tv_sec - +				_thread_run->last_active.tv_sec) * 1000000 + +				_thread_run->last_inactive.tv_usec - +				_thread_run->last_active.tv_usec; + +			/* +			 * Check if this thread has reached its allocated +			 * time slice period:  +			 */ +			if (_thread_run->slice_usec > TIMESLICE_USEC) { +				/* +				 * Flag the allocated time slice period as +				 * up:  +				 */ +				_thread_run->slice_usec = -1; +			} +		} +		/* Check if an incremental priority update is required: */ +		if (((tv.tv_sec - kern_inc_prio_time.tv_sec) * 1000000 + +		 tv.tv_usec - kern_inc_prio_time.tv_usec) > INC_PRIO_USEC) { +			/* +			 * Enter a loop to look for run-enabled threads that +			 * have not run since the last time that an +			 * incremental priority update was performed:  +			 */ +			for (pthread = _thread_link_list; pthread != NULL; pthread = pthread->nxt) { +				/* Check if this thread is unable to run: */ +				if (pthread->state != PS_RUNNING) { +				} +				/* +				 * Check if the last time that this thread +				 * was run (as indicated by the last time it +				 * became inactive) is before the time that +				 * the last incremental priority check was +				 * made:  +				 */ +				else if (timercmp(&_thread_run->last_inactive, &kern_inc_prio_time, >)) { +					/* +					 * Increment the incremental priority +					 * for this thread in the hope that +					 * it will eventually get a chance to +					 * run:  +					 */ +					(pthread->inc_prio)++; +				} +			} + +			/* Save the new incremental priority update time: */ +			kern_inc_prio_time.tv_sec = tv.tv_sec; +			kern_inc_prio_time.tv_usec = tv.tv_usec; +		} +		/* +		 * Enter a loop to look for the first thread of the highest +		 * priority:  +		 */ +		for (pthread = _thread_link_list; pthread != NULL; pthread = pthread->nxt) { +			/* Check if the current thread is unable to run: */ +			if (pthread->state != PS_RUNNING) { +			} +			/* +			 * Check if no run-enabled thread has been seen or if +			 * the current thread has a priority higher than the +			 * highest seen so far:  +			 */ +			else if (pthread_h == NULL || (pthread->pthread_priority + pthread->inc_prio) > prio) { +				/* +				 * Save this thread as the highest priority +				 * thread seen so far:  +				 */ +				pthread_h = pthread; +				prio = pthread->pthread_priority + pthread->inc_prio; +			} +		} + +		/* +		 * Enter a loop to look for a thread that: 1. Is run-enabled. +		 * 2. Has the required agregate priority. 3. Has not been +		 * allocated its allocated time slice. 4. Became inactive +		 * least recently.  +		 */ +		for (pthread = _thread_link_list; pthread != NULL; pthread = pthread->nxt) { +			/* 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 +			 * above:  +			 */ +			else if ((pthread->pthread_priority + pthread->inc_prio) != prio) { +				/* +				 * Ignore threads which have lower agregate +				 * priority.  +				 */ +			} +			/* +			 * Check if the current thread reached its time slice +			 * allocation last time it ran (or if it has not run +			 * yet):  +			 */ +			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 +			 * earlier than the last one seen:  +			 */ +			else if (pthread_s == NULL || timercmp(&pthread->last_inactive, &tv1, <)) { +				/* +				 * Save the pointer to the current thread as +				 * the most eligible thread seen so far:  +				 */ +				pthread_s = pthread; + +				/* +				 * Save the time that the selected thread +				 * became inactive:  +				 */ +				tv1.tv_sec = pthread->last_inactive.tv_sec; +				tv1.tv_usec = pthread->last_inactive.tv_usec; +			} +		} + +		/* +		 * Check if no thread was selected according to incomplete +		 * time slice allocation:  +		 */ +		if (pthread_s == NULL) { +			/* +			 * Enter a loop to look for any other thread that: 1. +			 * Is run-enabled. 2. Has the required agregate +			 * priority. 3. Became inactive least recently.  +			 */ +			for (pthread = _thread_link_list; pthread != NULL; pthread = pthread->nxt) { +				/* +				 * 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 above:  +				 */ +				else if ((pthread->pthread_priority + pthread->inc_prio) != prio) { +					/* +					 * Ignore threads which have lower +					 * agregate priority.    +					 */ +				} +				/* +				 * Check if an eligible thread has not been +				 * found yet, or if the current thread has an +				 * inactive time earlier than the last one +				 * seen:  +				 */ +				else if (pthread_s == NULL || timercmp(&pthread->last_inactive, &tv1, <)) { +					/* +					 * Save the pointer to the current +					 * thread as the most eligible thread +					 * seen so far:  +					 */ +					pthread_s = pthread; + +					/* +					 * Save the time that the selected +					 * thread became inactive:  +					 */ +					tv1.tv_sec = pthread->last_inactive.tv_sec; +					tv1.tv_usec = pthread->last_inactive.tv_usec; +				} +			} +		} +		/* Check if there are no threads ready to run: */ +		if (pthread_s == NULL) { +			/* +			 * Lock the pthread kernel by changing the pointer to +			 * the running thread to point to the global kernel +			 * thread structure:  +			 */ +			_thread_run = &_thread_kern_thread; + +			/* +			 * There are no threads ready to run, so wait until +			 * something happens that changes this condition:  +			 */ +			_thread_kern_select(1); +		} else { +			/* Make the selected thread the current thread: */ +			_thread_run = pthread_s; + +			/* +			 * Save the current time as the time that the thread +			 * became active:  +			 */ +			_thread_run->last_active.tv_sec = tv.tv_sec; +			_thread_run->last_active.tv_usec = tv.tv_usec; + +			/* +			 * Check if this thread is running for the first time +			 * or running again after using its full time slice +			 * allocation:  +			 */ +			if (_thread_run->slice_usec == -1) { +				/* Reset the accumulated time slice period: */ +				_thread_run->slice_usec = 0; +			} +			/* +			 * Reset the incremental priority now that this +			 * thread has been given the chance to run:  +			 */ +			_thread_run->inc_prio = 0; + +			/* Check if there is more than one thread: */ +			if (_thread_run != _thread_link_list || _thread_run->nxt != NULL) { +				/* +				 * Define the maximum time before a SIGVTALRM +				 * is required:  +				 */ +				itimer.it_value.tv_sec = 0; +				itimer.it_value.tv_usec = TIMESLICE_USEC; + +				/* +				 * The interval timer is not reloaded when it +				 * times out. The interval time needs to be +				 * calculated every time.  +				 */ +				itimer.it_interval.tv_sec = 0; +				itimer.it_interval.tv_usec = 0; + +				/* +				 * Enter a loop to look for threads waiting +				 * for a time:  +				 */ +				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 || +					    pthread->state == PS_FDR_WAIT || +					    pthread->state == PS_FDW_WAIT || +					 pthread->state == PS_SELECT_WAIT) { +						/* +						 * Check if this thread is to +						 * wait forever:  +						 */ +						if (pthread->wakeup_time.ts_sec == -1) { +						} +						/* +						 * Check if this thread is to +						 * wakeup immediately:  +						 */ +						else if (pthread->wakeup_time.ts_sec == 0 && +							 pthread->wakeup_time.ts_nsec == 0) { +						} +						/* +						 * Check if the current time +						 * is after the wakeup time:  +						 */ +						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 { +							/* +							 * Calculate the time +							 * until this thread +							 * is ready, allowing +							 * for the clock +							 * resolution:  +							 */ +							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; + +							/* +							 * Check for +							 * underflow of the +							 * nanosecond field:  +							 */ +							if (ts1.ts_nsec < 0) { +								/* +								 * Allow for +								 * the +								 * underflow +								 * of the +								 * nanosecond +								 * field:  +								 */ +								ts1.ts_sec--; +								ts1.ts_nsec += 1000000000; +							} +							/* +							 * Check for overflow +							 * of the nanosecond +							 * field:  +							 */ +							if (ts1.ts_nsec >= 1000000000) { +								/* +								 * Allow for +								 * the +								 * overflow +								 * of the +								 * nanosecond +								 * field:  +								 */ +								ts1.ts_sec++; +								ts1.ts_nsec -= 1000000000; +							} +							/* +							 * Convert the +							 * timespec structure +							 * to a timeval +							 * structure:  +							 */ +							TIMESPEC_TO_TIMEVAL(&tv, &ts1); + +							/* +							 * Check if the +							 * thread will be +							 * ready sooner than +							 * the earliest one +							 * found so far:  +							 */ +							if (timercmp(&tv, &itimer.it_value, <)) { +								/* +								 * Update the +								 * time +								 * value:  +								 */ +								itimer.it_value.tv_sec = tv.tv_sec; +								itimer.it_value.tv_usec = tv.tv_usec; +							} +						} +					} +				} + +				/* +				 * Start the interval timer for the +				 * calculated time interval:  +				 */ +				if (setitimer(ITIMER_VIRTUAL, &itimer, NULL) != 0) { +					/* +					 * Cannot initialise the timer, so +					 * abort this process:  +					 */ +					PANIC("Cannot set virtual timer"); +				} +			} +			/* Check if a signal context was saved: */ +			if (_thread_run->sig_saved == 1) { +#ifndef	__alpha +				/* +				 * Point to the floating point data in the +				 * running thread:  +				 */ +				fdata = _thread_run->saved_fp; + +				/* Restore the floating point state: */ +		__asm__("frstor %0": :"m"(*fdata)); +#endif + +				/* +				 * Do a sigreturn to restart the thread that +				 * was interrupted by a signal:  +				 */ +				_thread_sys_sigreturn(&_thread_run->saved_sigcontext); +			} 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); +			} + +			/* This point should not be reached. */ +			PANIC("Thread has returned from sigreturn or longjmp"); +		} +	} + +	/* There are no more threads, so exit this process: */ +	exit(0); +} + +static void +_thread_signal(pthread_t pthread, int sig) +{ +	long            l; +	pthread_t       new_pthread; +	struct sigaction act; +	void           *arg; + +	/* 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_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->state = PS_RUNNING; +		} else { +			/* Return the 'interrupted' error: */ +			_thread_seterrno(pthread, EINTR); + +			/* Change the state of the thread to run: */ +			pthread->state = 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_SELECT_WAIT: +	case PS_SLEEP_WAIT: +	case PS_SIGWAIT: +		/* Return the 'interrupted' error: */ +		_thread_seterrno(pthread, EINTR); + +		/* Change the state of the thread to run: */ +		pthread->state = PS_RUNNING; +		break; +	} + +	/* Check if this signal is being ignored: */ +	if (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; + +			/* 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) +{ +	/* Change the state of the current thread: */ +	_thread_run->state = state; + +	/* Schedule the next thread that is ready: */ +	_thread_kern_sched(NULL); +	return; +} + +static void +_thread_kern_select(int wait_reqd) +{ +	char            bufr[128]; +	fd_set          fd_set_except; +	fd_set          fd_set_read; +	fd_set          fd_set_write; +	int             count = 0; +	int             count_dec; +	int             found_one; +	int             i; +	int             nfds = -1; +	int             settimeout; +	pthread_t       pthread; +	ssize_t         num; +	struct timespec ts; +	struct timespec ts1; +	struct timeval *p_tv; +	struct timeval  tv; +	struct timeval  tv1; + +	/* Zero the file descriptor sets: */ +	FD_ZERO(&fd_set_read); +	FD_ZERO(&fd_set_write); +	FD_ZERO(&fd_set_except); + +	/* Check if the caller wants to wait: */ +	if (wait_reqd) { +		/* +		 * Add the pthread kernel pipe file descriptor to the read +		 * set:  +		 */ +		FD_SET(_thread_kern_pipe[0], &fd_set_read); +		nfds = _thread_kern_pipe[0]; + +		/* Get the current time of day: */ +		gettimeofday(&tv, NULL); +		TIMEVAL_TO_TIMESPEC(&tv, &ts); +	} +	/* Initialise the time value structure: */ +	tv.tv_sec = 0; +	tv.tv_usec = 0; + +	/* +	 * Enter a loop to process threads waiting on either file descriptors +	 * or times:  +	 */ +	for (pthread = _thread_link_list; pthread != NULL; pthread = pthread->nxt) { +		/* Assume that this state does not time out: */ +		settimeout = 0; + +		/* Process according to thread state: */ +		switch (pthread->state) { +			/* +			 * States which do not depend on file descriptor I/O +			 * operations or timeouts:  +			 */ +		case PS_DEAD: +		case PS_FDLR_WAIT: +		case PS_FDLW_WAIT: +		case PS_JOIN: +		case PS_MUTEX_WAIT: +		case PS_RUNNING: +		case PS_SIGTHREAD: +		case PS_SIGWAIT: +		case PS_STATE_MAX: +		case PS_WAIT_WAIT: +		case PS_SUSPENDED: +			/* Nothing to do here. */ +			break; + +			/* File descriptor read wait: */ +		case PS_FDR_WAIT: +			/* Add the file descriptor to the read set: */ +			FD_SET(pthread->data.fd.fd, &fd_set_read); + +			/* +			 * Check if this file descriptor is greater than any +			 * of those seen so far:  +			 */ +			if (pthread->data.fd.fd > nfds) { +				/* Remember this file descriptor: */ +				nfds = pthread->data.fd.fd; +			} +			/* Increment the file descriptor count: */ +			count++; + +			/* This state can time out: */ +			settimeout = 1; +			break; + +			/* File descriptor write wait: */ +		case PS_FDW_WAIT: +			/* Add the file descriptor to the write set: */ +			FD_SET(pthread->data.fd.fd, &fd_set_write); + +			/* +			 * Check if this file descriptor is greater than any +			 * of those seen so far:  +			 */ +			if (pthread->data.fd.fd > nfds) { +				/* Remember this file descriptor: */ +				nfds = pthread->data.fd.fd; +			} +			/* Increment the file descriptor count: */ +			count++; + +			/* This state can time out: */ +			settimeout = 1; +			break; + +			/* States that time out: */ +		case PS_SLEEP_WAIT: +		case PS_COND_WAIT: +			/* Flag a timeout as required: */ +			settimeout = 1; +			break; + +			/* Select wait: */ +		case PS_SELECT_WAIT: +			/* +			 * Enter a loop to process each file descriptor in +			 * the thread-specific file descriptor sets:  +			 */ +			for (i = 0; i < pthread->data.select_data->nfds; i++) { +				/* +				 * Check if this file descriptor is set for +				 * exceptions:  +				 */ +				if (FD_ISSET(i, &pthread->data.select_data->exceptfds)) { +					/* +					 * Add the file descriptor to the +					 * exception set:  +					 */ +					FD_SET(i, &fd_set_except); + +					/* +					 * Increment the file descriptor +					 * count:  +					 */ +					count++; + +					/* +					 * Check if this file descriptor is +					 * greater than any of those seen so +					 * far:  +					 */ +					if (i > nfds) { +						/* +						 * Remember this file +						 * descriptor:  +						 */ +						nfds = i; +					} +				} +				/* +				 * Check if this file descriptor is set for +				 * write:  +				 */ +				if (FD_ISSET(i, &pthread->data.select_data->writefds)) { +					/* +					 * Add the file descriptor to the +					 * write set:  +					 */ +					FD_SET(i, &fd_set_write); + +					/* +					 * Increment the file descriptor +					 * count:  +					 */ +					count++; + +					/* +					 * Check if this file descriptor is +					 * greater than any of those seen so +					 * far:  +					 */ +					if (i > nfds) { +						/* +						 * Remember this file +						 * descriptor:  +						 */ +						nfds = i; +					} +				} +				/* +				 * Check if this file descriptor is set for +				 * read:  +				 */ +				if (FD_ISSET(i, &pthread->data.select_data->readfds)) { +					/* +					 * Add the file descriptor to the +					 * read set:  +					 */ +					FD_SET(i, &fd_set_read); + +					/* +					 * Increment the file descriptor +					 * count:  +					 */ +					count++; + +					/* +					 * Check if this file descriptor is +					 * greater than any of those seen so +					 * far:  +					 */ +					if (i > nfds) { +						/* +						 * Remember this file +						 * descriptor:  +						 */ +						nfds = i; +					} +				} +			} + +			/* This state can time out: */ +			settimeout = 1; +			break; +		} + +		/* +		 * Check if the caller wants to wait and if the thread state +		 * is one that times out:  +		 */ +		if (wait_reqd && settimeout) { +			/* Check if this thread wants to wait forever: */ +			if (pthread->wakeup_time.ts_sec == -1) { +			} +			/* Check if this thread doesn't want to wait at all: */ +			else if (pthread->wakeup_time.ts_sec == 0 && +				 pthread->wakeup_time.ts_nsec == 0) { +				/* Override the caller's request to wait: */ +				wait_reqd = 0; +			} else { +				/* +				 * Calculate the time until this thread is +				 * ready, allowing for the clock resolution:  +				 */ +				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; + +				/* +				 * Check for underflow of the nanosecond +				 * field:  +				 */ +				if (ts1.ts_nsec < 0) { +					/* +					 * Allow for the underflow of the +					 * nanosecond field:  +					 */ +					ts1.ts_sec--; +					ts1.ts_nsec += 1000000000; +				} +				/* +				 * Check for overflow of the nanosecond +				 * field:  +				 */ +				if (ts1.ts_nsec >= 1000000000) { +					/* +					 * Allow for the overflow of the +					 * nanosecond field:  +					 */ +					ts1.ts_sec++; +					ts1.ts_nsec -= 1000000000; +				} +				/* +				 * Convert the timespec structure to a +				 * timeval structure:  +				 */ +				TIMESPEC_TO_TIMEVAL(&tv1, &ts1); + +				/* +				 * Check if no time value has been found yet, +				 * or if the thread will be ready sooner that +				 * the earliest one found so far:  +				 */ +				if ((tv.tv_sec == 0 && tv.tv_usec == 0) || timercmp(&tv1, &tv, <)) { +					/* Update the time value: */ +					tv.tv_sec = tv1.tv_sec; +					tv.tv_usec = tv1.tv_usec; +				} +			} +		} +	} + +	/* Check if the caller wants to wait: */ +	if (wait_reqd) { +		/* Check if no threads were found with timeouts: */ +		if (tv.tv_sec == 0 && tv.tv_usec == 0) { +			/* Wait forever: */ +			p_tv = NULL; +		} else { +			/* +			 * Point to the time value structure which contains +			 * the earliest time that a thread will be ready:  +			 */ +			p_tv = &tv; +		} + +		/* +		 * Flag the pthread kernel as in a select. This is to avoid +		 * the window between the next statement that unblocks +		 * signals and the select statement which follows.  +		 */ +		_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; + +		/* +		 * Check if it is possible that there are bytes in the kernel +		 * read pipe waiting to be read:  +		 */ +		if (count < 0 || FD_ISSET(_thread_kern_pipe[0], &fd_set_read)) { +			/* +			 * Check if the kernel read pipe was included in the +			 * count:  +			 */ +			if (count > 0) { +				/* +				 * Remove the kernel read pipe from the +				 * count:  +				 */ +				FD_CLR(_thread_kern_pipe[0], &fd_set_read); + +				/* Decrement the count of file descriptors: */ +				count--; +			} +			/* +			 * Enter a loop to read (and trash) bytes from the +			 * pthread kernel pipe:  +			 */ +			while ((num = _thread_sys_read(_thread_kern_pipe[0], bufr, sizeof(bufr))) > 0) { +				/* +				 * The buffer read contains one byte per +				 * 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 +				 * to complete if the signal occurred between +				 * the time when signals were unblocked and +				 * the _thread_sys_select select call being +				 * made.  +				 */ +			} +		} +	} +	/* Check if there are file descriptors to poll: */ +	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:  +		 */ +		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:  +	 */ +	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 { +		/* +		 * Enter a loop to look for threads waiting on file +		 * descriptors that are flagged as available by the +		 * _thread_sys_select syscall:  +		 */ +		for (pthread = _thread_link_list; pthread != NULL; pthread = pthread->nxt) { +			/* Process according to thread state: */ +			switch (pthread->state) { +				/* +				 * States which do not depend on file +				 * descriptor I/O operations:  +				 */ +			case PS_RUNNING: +			case PS_COND_WAIT: +			case PS_DEAD: +			case PS_FDLR_WAIT: +			case PS_FDLW_WAIT: +			case PS_JOIN: +			case PS_MUTEX_WAIT: +			case PS_SIGWAIT: +			case PS_SLEEP_WAIT: +			case PS_WAIT_WAIT: +			case PS_SIGTHREAD: +			case PS_STATE_MAX: +			case PS_SUSPENDED: +				/* Nothing to do here. */ +				break; + +				/* File descriptor read wait: */ +			case PS_FDR_WAIT: +				/* +				 * Check if the file descriptor is available +				 * for read:  +				 */ +				if (FD_ISSET(pthread->data.fd.fd, &fd_set_read)) { +					/* +					 * Change the thread state to allow +					 * it to read from the file when it +					 * is scheduled next:  +					 */ +					pthread->state = PS_RUNNING; +				} +				break; + +				/* File descriptor write wait: */ +			case PS_FDW_WAIT: +				/* +				 * Check if the file descriptor is available +				 * for write:  +				 */ +				if (FD_ISSET(pthread->data.fd.fd, &fd_set_write)) { +					/* +					 * Change the thread state to allow +					 * it to write to the file when it is +					 * scheduled next:  +					 */ +					pthread->state = PS_RUNNING; +				} +				break; + +				/* Select wait: */ +			case PS_SELECT_WAIT: +				/* +				 * Reset the flag that indicates if a file +				 * descriptor is ready for some type of +				 * operation:  +				 */ +				count_dec = 0; + +				/* +				 * Enter a loop to search though the +				 * thread-specific select file descriptors +				 * for the first descriptor that is ready:  +				 */ +				for (i = 0; i < pthread->data.select_data->nfds && count_dec == 0; i++) { +					/* +					 * Check if this file descriptor does +					 * not have an exception:  +					 */ +					if (FD_ISSET(i, &pthread->data.select_data->exceptfds) && FD_ISSET(i, &fd_set_except)) { +						/* +						 * Flag this file descriptor +						 * as ready:  +						 */ +						count_dec = 1; +					} +					/* +					 * Check if this file descriptor is +					 * not ready for write:  +					 */ +					if (FD_ISSET(i, &pthread->data.select_data->writefds) && FD_ISSET(i, &fd_set_write)) { +						/* +						 * Flag this file descriptor +						 * as ready:  +						 */ +						count_dec = 1; +					} +					/* +					 * Check if this file descriptor is +					 * not ready for read:  +					 */ +					if (FD_ISSET(i, &pthread->data.select_data->readfds) && FD_ISSET(i, &fd_set_read)) { +						/* +						 * Flag this file descriptor +						 * as ready:  +						 */ +						count_dec = 1; +					} +				} + +				/* +				 * Check if any file descriptors are ready +				 * for the current thread:  +				 */ +				if (count_dec) { +					/* +					 * Reset the count of file +					 * descriptors that are ready for +					 * this thread:  +					 */ +					found_one = 0; + +					/* +					 * Enter a loop to search though the +					 * thread-specific select file +					 * descriptors:  +					 */ +					for (i = 0; i < pthread->data.select_data->nfds; i++) { +						/* +						 * Reset the count of +						 * operations for which the +						 * current file descriptor is +						 * ready:  +						 */ +						count_dec = 0; + +						/* +						 * Check if this file +						 * descriptor is selected for +						 * exceptions:  +						 */ +						if (FD_ISSET(i, &pthread->data.select_data->exceptfds)) { +							/* +							 * Check if this file +							 * descriptor has an +							 * exception:  +							 */ +							if (FD_ISSET(i, &fd_set_except)) { +								/* +								 * Increment +								 * the count +								 * for this +								 * file:  +								 */ +								count_dec++; +							} else { +								/* +								 * Clear the +								 * file +								 * descriptor +								 * in the +								 * thread-spec +								 * ific file +								 * descriptor +								 * set:  +								 */ +								FD_CLR(i, &pthread->data.select_data->exceptfds); +							} +						} +						/* +						 * Check if this file +						 * descriptor is selected for +						 * write:  +						 */ +						if (FD_ISSET(i, &pthread->data.select_data->writefds)) { +							/* +							 * Check if this file +							 * descriptor is +							 * ready for write:  +							 */ +							if (FD_ISSET(i, &fd_set_write)) { +								/* +								 * Increment +								 * the count +								 * for this +								 * file:  +								 */ +								count_dec++; +							} else { +								/* +								 * Clear the +								 * file +								 * descriptor +								 * in the +								 * thread-spec +								 * ific file +								 * descriptor +								 * set:  +								 */ +								FD_CLR(i, &pthread->data.select_data->writefds); +							} +						} +						/* +						 * Check if this file +						 * descriptor is selected for +						 * read:  +						 */ +						if (FD_ISSET(i, &pthread->data.select_data->readfds)) { +							/* +							 * Check if this file +							 * descriptor is +							 * ready for read:  +							 */ +							if (FD_ISSET(i, &fd_set_read)) { +								/* +								 * Increment +								 * the count +								 * for this +								 * file:  +								 */ +								count_dec++; +							} else { +								/* +								 * Clear the +								 * file +								 * descriptor +								 * in the +								 * thread-spec +								 * ific file +								 * descriptor +								 * set:  +								 */ +								FD_CLR(i, &pthread->data.select_data->readfds); +							} +						} +						/* +						 * Check if the current file +						 * descriptor is ready for +						 * any one of the operations:  +						 */ +						if (count_dec > 0) { +							/* +							 * Increment the +							 * count of file +							 * descriptors that +							 * are ready for the +							 * current thread:  +							 */ +							found_one++; +						} +					} + +					/* +					 * Return the number of file +					 * descriptors that are ready:  +					 */ +					pthread->data.select_data->nfds = found_one; + +					/* +					 * Change the state of the current +					 * thread to run:  +					 */ +					pthread->state = PS_RUNNING; +				} +				break; +			} +		} +	} + +	/* Nothing to return. */ +	return; +} + +void +_thread_kern_set_timeout(struct timespec * timeout) +{ +	struct timespec current_time; +	struct timeval  tv; + +	/* Reset the timeout flag for the running thread: */ +	_thread_run->timeout = 0; + +	/* Check if the thread is to wait forever: */ +	if (timeout == NULL) { +		/* +		 * Set the wakeup time to something that can be recognised as +		 * different to an actual time of day:  +		 */ +		_thread_run->wakeup_time.ts_sec = -1; +		_thread_run->wakeup_time.ts_nsec = -1; +	} +	/* Check if no waiting is required: */ +	else if (timeout->ts_sec == 0 && timeout->ts_nsec == 0) { +		/* Set the wake up time to 'immediately': */ +		_thread_run->wakeup_time.ts_sec = 0; +		_thread_run->wakeup_time.ts_nsec = 0; +	} 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 + timeout->ts_sec; +		_thread_run->wakeup_time.ts_nsec = current_time.ts_nsec + timeout->ts_nsec; + +		/* Check if the nanosecond field needs to wrap: */ +		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; +		} +	} +	return; +} +#endif diff --git a/lib/libpthread/thread/thr_mutex.c b/lib/libpthread/thread/thr_mutex.c new file mode 100644 index 000000000000..0fc9fbba3e50 --- /dev/null +++ b/lib/libpthread/thread/thr_mutex.c @@ -0,0 +1,360 @@ +/* + * 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 <stdlib.h> +#include <errno.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +int +pthread_mutex_init(pthread_mutex_t * mutex, +		   const pthread_mutexattr_t * mutex_attr) +{ +	enum pthread_mutextype type; +	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) { +			/* Return an invalid argument error: */ +			_thread_seterrno(_thread_run, EINVAL); +			ret = -1; +		} else { +			/* Use the requested mutex type: */ +			type = mutex_attr->m_type; +		} +	} else { +		/* Default to a fast mutex: */ +		type = MUTEX_TYPE_FAST; +	} + +	/* Check no errors so far: */ +	if (ret == 0) { +		/* Reset the mutex flags: */ +		mutex->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: */ +			mutex->m_data.m_count = 0; +			break; + +			/* Trap invalid mutex types: */ +		default: +			/* Return an invalid argument error: */ +			_thread_seterrno(_thread_run, 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; + +		/* 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); +} + +int +pthread_mutex_trylock(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: +		/* 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++; +			} else { +				/* Return a busy error: */ +				_thread_seterrno(_thread_run, 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; +	} + +	/* Unblock signals: */ +	_thread_kern_sig_unblock(status); + +	/* Return the completion status: */ +	return (ret); +} + +int +pthread_mutex_lock(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 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); +			} +		} +		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); +			} +		} + +		/* 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; +	} + +	/* Unblock signals: */ +	_thread_kern_sig_unblock(status); + +	/* Return the completion status: */ +	return (ret); +} + +int +pthread_mutex_unlock(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 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; + +		/* 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) { +			/* Return an invalid argument error: */ +			_thread_seterrno(_thread_run, 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); +		ret = -1; +		break; +	} + +	/* Unblock signals: */ +	_thread_kern_sig_unblock(status); + +	/* Return the completion status: */ +	return (ret); +} +#endif diff --git a/lib/libpthread/thread/thr_nanosleep.c b/lib/libpthread/thread/thr_nanosleep.c new file mode 100644 index 000000000000..e91ca5765113 --- /dev/null +++ b/lib/libpthread/thread/thr_nanosleep.c @@ -0,0 +1,87 @@ +/* + * 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 <stdio.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +int +nanosleep(struct timespec * time_to_sleep, struct timespec * time_remaining) +{ +	struct timespec current_time; +	struct timespec current_time1; +	struct timeval  tv; + +	/* 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; + +	/* 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 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; + +		/* Check if the nanosecond field has underflowed: */ +		if (time_remaining->ts_nsec < 0) { +			/* Handle the underflow: */ +			time_remaining->ts_sec -= 1; +			time_remaining->ts_nsec += 1000000000; +		} +		/* 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; +		} +	} +	return (0); +} +#endif diff --git a/lib/libpthread/thread/thr_once.c b/lib/libpthread/thread/thr_once.c new file mode 100644 index 000000000000..c55ba9eaf74b --- /dev/null +++ b/lib/libpthread/thread/thr_once.c @@ -0,0 +1,50 @@ +/* + * 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. + * + */ +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +int +pthread_once(pthread_once_t * once_control, void (*init_routine) (void)) +{ +	if (once_control->state == PTHREAD_NEEDS_INIT) { +		pthread_mutex_lock(&(once_control->mutex)); +		if (once_control->state == PTHREAD_NEEDS_INIT) { +			init_routine(); +			once_control->state = PTHREAD_DONE_INIT; +		} +		pthread_mutex_unlock(&(once_control->mutex)); +	} +	return (0); +} +#endif diff --git a/lib/libpthread/thread/thr_open.c b/lib/libpthread/thread/thr_open.c new file mode 100644 index 000000000000..ead651ea3d9e --- /dev/null +++ b/lib/libpthread/thread/thr_open.c @@ -0,0 +1,82 @@ +/* + * 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 <stdarg.h> +#include <fcntl.h> +#include <dirent.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +int +open(const char *path, int flags,...) +{ +	int             fd; +	int             mode = 0; +	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: */ +		va_start(ap, 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) { +	} +	/* Initialise the file descriptor table entry: */ +	else if (_thread_fd_table_init(fd) != 0) { +		/* Quietly close the file: */ +		_thread_sys_close(fd); + +		/* 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: */ +	_thread_kern_sig_unblock(status); + +	/* Return the file descriptor or -1 on error: */ +	return (fd); +} +#endif diff --git a/lib/libpthread/thread/thr_private.h b/lib/libpthread/thread/thr_private.h new file mode 100644 index 000000000000..fc8ba276a42c --- /dev/null +++ b/lib/libpthread/thread/thr_private.h @@ -0,0 +1,629 @@ +/* + * 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. + * + * Private thread definitions for the uthread kernel. + * + */ + +#ifndef _PTHREAD_PRIVATE_H +#define _PTHREAD_PRIVATE_H + +/* + * Evaluate the storage class specifier. + */ +#ifdef GLOBAL_PTHREAD_PRIVATE +#define SCLASS +#else +#define SCLASS extern +#endif + +/* + * Include files. + */ +#include <setjmp.h> +#include <signal.h> +#include <sys/types.h> +#include <sys/time.h> + +/* + * Kernel fatal error handler macro. + */ +#define PANIC(string)   _thread_exit(__FILE__,__LINE__,string) + +/* + * Thread creation state attributes. + */ +#define PTHREAD_CREATE_RUNNING			0 +#define PTHREAD_CREATE_SUSPENDED		1 + +/* + * 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. + */ +#define CLOCK_RES_NSEC				10000000 + +/* + * Number of microseconds between incremental priority updates for + * threads that are ready to run, but denied being run. + */ +#define INC_PRIO_USEC				500000 + +/* + * Time slice period in microseconds. + */ +#define TIMESLICE_USEC				100000 + +/* + * Flags. + */ +#define PTHREAD_DETACHED            0x1 +#define PTHREAD_SCOPE_SYSTEM        0x2 +#define PTHREAD_INHERIT_SCHED       0x4 +#define PTHREAD_NOFLOAT             0x8 + +#define PTHREAD_CREATE_DETACHED     PTHREAD_DETACHED +#define PTHREAD_CREATE_JOINABLE     0 +#define PTHREAD_SCOPE_PROCESS       0 +#define PTHREAD_EXPLICIT_SCHED      0 + +struct pthread_key { +	pthread_mutex_t mutex; +	long            count; +	void            (*destructor) (); +}; + +/* + * Thread states. + */ +enum pthread_state { +	PS_RUNNING, +	PS_SIGTHREAD, +	PS_MUTEX_WAIT, +	PS_COND_WAIT, +	PS_FDLR_WAIT, +	PS_FDLW_WAIT, +	PS_FDR_WAIT, +	PS_FDW_WAIT, +	PS_SELECT_WAIT, +	PS_SLEEP_WAIT, +	PS_WAIT_WAIT, +	PS_SIGWAIT, +	PS_JOIN, +	PS_SUSPENDED, +	PS_DEAD, +	PS_STATE_MAX +}; + + +/* + * File descriptor locking definitions. + */ +#define FD_READ             0x1 +#define FD_WRITE            0x2 +#define FD_RDWR             (FD_READ | FD_WRITE) + +/* + * File descriptor table structure. + */ +struct fd_table_entry { +	struct pthread_queue	r_queue;	/* Read queue.                        */ +	struct pthread_queue	w_queue;	/* Write queue.                       */ +	struct pthread		*r_owner;	/* Ptr to thread owning read lock.    */ +	struct pthread		*w_owner;	/* Ptr to thread owning write lock.   */ +	char			*r_fname;	/* Ptr to read lock source file name  */ +	int			r_lineno;	/* Read lock source line number.      */ +	char			*w_fname;	/* Ptr to write lock source file name */ +	int			w_lineno;	/* Write lock source line number.     */ +	int			r_lockcount;	/* Count for FILE read locks.         */ +	int			w_lockcount;	/* Count for FILE write locks.        */ +	int			flags;		/* Flags used in open.                */ +}; + +struct pthread_select_data { +	int	nfds; +	fd_set	readfds; +	fd_set	writefds; +	fd_set	exceptfds; +}; + +union pthread_wait_data { +	pthread_mutex_t	*mutex; +	pthread_cond_t	*cond; +	const sigset_t	*sigwait;	/* Waiting on a signal in sigwait */ +	struct { +		short	fd;		/* Used when thread waiting on fd */ +		short	branch;		/* Line number, for debugging.    */ +		char	*fname;		/* Source file name for debugging.*/ +	} fd; +	struct pthread_select_data * select_data; +}; + +/* + * Thread structure. + */ +struct pthread { +	/* +	 * Pointer to the next thread in the thread linked list. +	 */ +	struct pthread	*nxt; + +	/* +	 * Thread start routine, argument, stack pointer and thread +	 * attributes. +	 */ +	void		*(*start_routine)(void *); +	void		*arg; +	void		*stack; +	pthread_attr_t	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 +	 * saved in the signal context. +	 */ +	char	saved_fp[108]; +#endif + +	/* +	 * Saved signal context used in call to sigreturn by +	 * _thread_kern_sched if sig_saved is TRUE. +	 */ +	struct  sigcontext saved_sigcontext; + +	/*  +	 * Saved jump buffer used in call to longjmp by _thread_kern_sched +	 * if sig_saved is FALSE. +	 */ +	jmp_buf	saved_jmp_buf; + +	/* +	 * TRUE if the last state saved was a signal context. FALSE if the +	 * last state saved was a jump buffer. +	 */ +	int	sig_saved; + +	/* +	 * Current signal mask and array of 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; + +	/* Thread state: */ +	enum pthread_state	state; + +	/* Time that this thread was last made active. */ +	struct  timeval		last_active; + +	/* Time that this thread was last made inactive. */ +	struct  timeval		last_inactive; + +	/* +	 * Number of microseconds accumulated by this thread when +	 * time slicing is active. +	 */ +	long	slice_usec; + +	/* +	 * Incremental priority accumulated by thread while it is ready to +	 * run but is denied being run. +	 */ +	int	inc_prio; + +	/* +	 * Time to wake up thread. This is used for sleeping threads and +	 * for any operation which may time out (such as select). +	 */ +	struct timespec	wakeup_time; + +	/* TRUE if operation has timed out. */ +	int	timeout; + +	/* +	 * Error variable used instead of errno. The function __error() +	 * returns a pointer to this.  +	 */ +	int	error; + +	/* Join queue for waiting threads: */ +	struct pthread_queue	join_queue; + +	/* +	 * The current thread can belong to only one queue at a time. +	 * +	 * Pointer to queue (if any) on which the current thread is waiting. +	 */ +	struct pthread_queue	*queue; + +	/* Pointer to next element in queue. */ +	struct pthread	*qnxt; + +	/* Wait data. */ +	union pthread_wait_data data; + +	/* Miscellaneous data. */ +	char		flags; +	char		pthread_priority; +	void		*ret; +	const void	**specific_data; +	int		specific_data_count; + +	/* Cleanup handlers Link List */ +	struct pthread_cleanup *cleanup; +}; + +/* + * Global variables for the uthread kernel. + */ + +/* Kernel thread structure used when there are no running threads: */ +SCLASS struct pthread   _thread_kern_thread; + +/* Ptr to the thread structure for the running thread: */ +SCLASS struct pthread   *_thread_run +#ifdef GLOBAL_PTHREAD_PRIVATE += &_thread_kern_thread; +#else +; +#endif + +/* Ptr to the first thread in the thread linked list: */ +SCLASS struct pthread   *_thread_link_list +#ifdef GLOBAL_PTHREAD_PRIVATE += NULL; +#else +; +#endif + +/* + * Array of kernel pipe file descriptors that are used to ensure that + * no signals are missed in calls to _thread_sys_select. + */ +SCLASS int              _thread_kern_pipe[2] +#ifdef GLOBAL_PTHREAD_PRIVATE += { +	-1, +	-1 +}; +#else +; +#endif +SCLASS int              _thread_kern_in_select +#ifdef GLOBAL_PTHREAD_PRIVATE += 0; +#else +; +#endif + +/* Last time that an incremental priority update was performed: */ +SCLASS struct timeval   kern_inc_prio_time +#ifdef GLOBAL_PTHREAD_PRIVATE += { 0, 0 }; +#else +; +#endif + +/* Dead threads: */ +SCLASS struct pthread *_thread_dead +#ifdef GLOBAL_PTHREAD_PRIVATE += NULL; +#else +; +#endif + +/* Initial thread: */ +SCLASS struct pthread *_thread_initial +#ifdef GLOBAL_PTHREAD_PRIVATE += NULL; +#else +; +#endif + +/* Default thread attributes: */ +SCLASS pthread_attr_t pthread_attr_default +#ifdef GLOBAL_PTHREAD_PRIVATE += { SCHED_RR, PTHREAD_DEFAULT_PRIORITY, PTHREAD_CREATE_RUNNING, +	PTHREAD_CREATE_JOINABLE, NULL, NULL, NULL, PTHREAD_STACK_DEFAULT }; +#else +; +#endif + +/* File table information: */ +SCLASS struct fd_table_entry **_thread_fd_table +#ifdef GLOBAL_PTHREAD_PRIVATE += NULL; +#else +; +#endif + +SCLASS const int dtablecount +#ifdef GLOBAL_PTHREAD_PRIVATE += 4096/sizeof(struct fd_table_entry); +#else +; +#endif +SCLASS int    _thread_dtablesize        /* Descriptor table size.           */ +#ifdef GLOBAL_PTHREAD_PRIVATE += 1024; +#else +; +#endif + +/* Undefine the storage class specifier: */ +#undef  SCLASS + +/* + * Function prototype definitions. + */ +__BEGIN_DECLS +char    *__ttyname_basic(int); +char    *__ttyname_r_basic(int, char *, size_t); +char    *ttyname_r(int, char *, size_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); +int     nanosleep(struct timespec *, struct timespec *); +void    _thread_exit(char *, int, char *); +void    _thread_fd_unlock(int, int); +void    *_thread_cleanup(pthread_t); +void    _thread_cleanupspecific(void); +void    _thread_dump_info(void); +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_cleanup_pop(int); +void    _thread_sig_handler(int, int, struct sigcontext *); +void    _thread_start(void); +void    _thread_start_sig_handler(void); +void	_thread_seterrno(pthread_t,int); +void    _thread_queue_init(struct pthread_queue *); +void    _thread_queue_enq(struct pthread_queue *, struct pthread *); +int     _thread_queue_remove(struct pthread_queue *, struct pthread *); +int     _thread_fd_table_init(int fd); +struct pthread *_thread_queue_get(struct pthread_queue *); +struct pthread *_thread_queue_deq(struct pthread_queue *); + +/* #include <signal.h> */ +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 *); +void    (*_thread_sys_signal(int, void (*)(int)))(int); + +/* #include <sys/stat.h> */ +#ifdef  _SYS_STAT_H_ +int     _thread_sys_fchmod(int, mode_t); +int     _thread_sys_fstat(int, struct stat *); +int     _thread_sys_fchflags(int, u_long); +#endif + +/* #include <sys/mount.h> */ +#ifdef  _SYS_MOUNT_H_ +int     _thread_sys_fstatfs(int, struct statfs *); +#endif +int     _thread_sys_pipe(int *); + +/* #include <sys/socket.h> */ +#ifdef  _SYS_SOCKET_H_ +int     _thread_sys_accept(int, struct sockaddr *, int *); +int     _thread_sys_bind(int, const struct sockaddr *, int); +int     _thread_sys_connect(int, const struct sockaddr *, int); +int     _thread_sys_getpeername(int, struct sockaddr *, int *); +int     _thread_sys_getsockname(int, struct sockaddr *, int *); +int     _thread_sys_getsockopt(int, int, int, void *, int *); +int     _thread_sys_listen(int, int); +int     _thread_sys_setsockopt(int, int, int, const void *, int); +int     _thread_sys_shutdown(int, int); +int     _thread_sys_socket(int, int, int); +int     _thread_sys_socketpair(int, int, int, int *); +ssize_t _thread_sys_recv(int, void *, size_t, int); +ssize_t _thread_sys_recvfrom(int, void *, size_t, int, struct sockaddr *, int *); +ssize_t _thread_sys_recvmsg(int, struct msghdr *, int); +ssize_t _thread_sys_send(int, const void *, size_t, int); +ssize_t _thread_sys_sendmsg(int, const struct msghdr *, int); +ssize_t _thread_sys_sendto(int, const void *,size_t, int, const struct sockaddr *, int); +#endif + +/* #include <stdio.h> */ +#ifdef  _STDIO_H_ +void    _thread_flockfile(FILE *fp,char *fname,int lineno); +void    _thread_funlockfile(FILE *fp); +FILE    *_thread_sys_fdopen(int, const char *); +FILE    *_thread_sys_fopen(const char *, const char *); +FILE    *_thread_sys_freopen(const char *, const char *, FILE *); +FILE    *_thread_sys_popen(const char *, const char *); +FILE    *_thread_sys_tmpfile(void); +char    *_thread_sys_ctermid(char *); +char    *_thread_sys_cuserid(char *); +char    *_thread_sys_fgetln(FILE *, size_t *); +char    *_thread_sys_fgets(char *, int, FILE *); +char    *_thread_sys_gets(char *); +char    *_thread_sys_tempnam(const char *, const char *); +char    *_thread_sys_tmpnam(char *); +int     _thread_sys_fclose(FILE *); +int     _thread_sys_feof(FILE *); +int     _thread_sys_ferror(FILE *); +int     _thread_sys_fflush(FILE *); +int     _thread_sys_fgetc(FILE *); +int     _thread_sys_fgetpos(FILE *, fpos_t *); +int     _thread_sys_fileno(FILE *); +int     _thread_sys_fprintf(FILE *, const char *, ...); +int     _thread_sys_fpurge(FILE *); +int     _thread_sys_fputc(int, FILE *); +int     _thread_sys_fputs(const char *, FILE *); +int     _thread_sys_fscanf(FILE *, const char *, ...); +int     _thread_sys_fseek(FILE *, long, int); +int     _thread_sys_fsetpos(FILE *, const fpos_t *); +int     _thread_sys_getc(FILE *); +int     _thread_sys_getchar(void); +int     _thread_sys_getw(FILE *); +int     _thread_sys_pclose(FILE *); +int     _thread_sys_printf(const char *, ...); +int     _thread_sys_putc(int, FILE *); +int     _thread_sys_putchar(int); +int     _thread_sys_puts(const char *); +int     _thread_sys_putw(int, FILE *); +int     _thread_sys_remove(const char *); +int     _thread_sys_rename (const char *, const char *); +int     _thread_sys_scanf(const char *, ...); +int     _thread_sys_setlinebuf(FILE *); +int     _thread_sys_setvbuf(FILE *, char *, int, size_t); +int     _thread_sys_snprintf(char *, size_t, const char *, ...); +int     _thread_sys_sprintf(char *, const char *, ...); +int     _thread_sys_sscanf(const char *, const char *, ...); +int     _thread_sys_ungetc(int, FILE *); +int     _thread_sys_vfprintf(FILE *, const char *, _BSD_VA_LIST_); +int     _thread_sys_vprintf(const char *, _BSD_VA_LIST_); +int     _thread_sys_vscanf(const char *, _BSD_VA_LIST_); +int     _thread_sys_vsnprintf(char *, size_t, const char *, _BSD_VA_LIST_); +int     _thread_sys_vsprintf(char *, const char *, _BSD_VA_LIST_); +int     _thread_sys_vsscanf(const char *, const char *, _BSD_VA_LIST_); +long    _thread_sys_ftell(FILE *); +size_t  _thread_sys_fread(void *, size_t, size_t, FILE *); +size_t  _thread_sys_fwrite(const void *, size_t, size_t, FILE *); +void    _thread_sys_clearerr(FILE *); +void    _thread_sys_perror(const char *); +void    _thread_sys_rewind(FILE *); +void    _thread_sys_setbuf(FILE *, char *); +void    _thread_sys_setbuffer(FILE *, char *, int); +#endif + +/* #include <unistd.h> */ +#ifdef  _UNISTD_H_ +char    *_thread_sys_ttyname(int); +int     _thread_sys_close(int); +int     _thread_sys_dup(int); +int     _thread_sys_dup2(int, int); +int     _thread_sys_exect(const char *, char * const *, char * const *); +int     _thread_sys_execve(const char *, char * const *, char * const *); +int     _thread_sys_fchdir(int); +int     _thread_sys_fchown(int, uid_t, gid_t); +int     _thread_sys_fsync(int); +int     _thread_sys_ftruncate(int, off_t); +int     _thread_sys_pause(void); +int     _thread_sys_pipe(int *); +int     _thread_sys_select(int, fd_set *, fd_set *, fd_set *, struct timeval *); +off_t   _thread_sys_lseek(int, off_t, int); +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); +#endif + +/* #include <fcntl.h> */ +#ifdef  _SYS_FCNTL_H_ +int     _thread_sys_creat(const char *, mode_t); +int     _thread_sys_fcntl(int, int, ...); +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, ...); +#endif + +/* #include <dirent.h> */ +#ifdef  _DIRENT_H_ +DIR     *___thread_sys_opendir2(const char *, int); +DIR     *_thread_sys_opendir(const char *); +int     _thread_sys_alphasort(const void *, const void *); +int     _thread_sys_scandir(const char *, struct dirent ***, +	int (*)(struct dirent *), int (*)(const void *, const void *)); +int     _thread_sys_closedir(DIR *); +int     _thread_sys_getdirentries(int, char *, int, long *); +long    _thread_sys_telldir(const DIR *); +struct  dirent *_thread_sys_readdir(DIR *); +void    _thread_sys_rewinddir(DIR *); +void    _thread_sys_seekdir(DIR *, long); +#endif + +/* #include <sys/uio.h> */ +#ifdef  _SYS_UIO_H_ +ssize_t _thread_sys_readv(int, const struct iovec *, int); +ssize_t _thread_sys_writev(int, const struct iovec *, int); +#endif + +/* #include <sys/wait.h> */ +#ifdef  WNOHANG +pid_t   _thread_sys_wait(int *); +pid_t   _thread_sys_waitpid(pid_t, int *, int); +pid_t   _thread_sys_wait3(int *, int, struct rusage *); +pid_t   _thread_sys_wait4(pid_t, int *, int, struct rusage *); +#endif +__END_DECLS + +#endif  /* !_PTHREAD_PRIVATE_H */ diff --git a/lib/libpthread/thread/thr_read.c b/lib/libpthread/thread/thr_read.c new file mode 100644 index 000000000000..91588441f8be --- /dev/null +++ b/lib/libpthread/thread/thr_read.c @@ -0,0 +1,74 @@ +/* + * 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 <sys/types.h> +#include <sys/fcntl.h> +#include <sys/uio.h> +#include <errno.h> +#include <unistd.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +ssize_t +read(int fd, void *buf, size_t nbytes) +{ +	int             nonblock; +	int             ret; +	int             status; +	if (fd < 0 || fd > _thread_dtablesize || _thread_fd_table[fd] == NULL) { +		_thread_seterrno(_thread_run, EBADF); +		ret = -1; +	} else if ((nonblock = _thread_fd_table[fd]->flags & O_NONBLOCK) == 0 && (ret = _thread_fd_lock(fd, FD_READ, NULL, __FILE__, __LINE__)) != 0) { +		/* Cannot lock file descriptor. */ +	} else { +		while ((ret = _thread_sys_read(fd, buf, nbytes)) < 0) { +			if (nonblock == 0 && (errno == EWOULDBLOCK || errno == EAGAIN)) { +				_thread_kern_sig_block(&status); +				_thread_run->data.fd.fd = fd; +				_thread_kern_set_timeout(NULL); +				_thread_kern_sched_state(PS_FDR_WAIT, __FILE__, __LINE__); +				if (errno == EINTR) { +					ret = -1; +					break; +				} +			} else { +				break; +			} +		} +		if (nonblock == 0) { +			_thread_fd_unlock(fd, FD_READ); +		} +	} +	return (ret); +} +#endif diff --git a/lib/libpthread/thread/thr_readv.c b/lib/libpthread/thread/thr_readv.c new file mode 100644 index 000000000000..acb72ac2b1b8 --- /dev/null +++ b/lib/libpthread/thread/thr_readv.c @@ -0,0 +1,74 @@ +/* + * 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 <sys/types.h> +#include <sys/fcntl.h> +#include <sys/uio.h> +#include <errno.h> +#include <unistd.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +ssize_t +readv(int fd, const struct iovec * iov, int iovcnt) +{ +	int             nonblock; +	int             ret; +	int             status; +	if (fd < 0 || fd > _thread_dtablesize || _thread_fd_table[fd] == NULL) { +		_thread_seterrno(_thread_run, EBADF); +		ret = -1; +	} else if ((nonblock = _thread_fd_table[fd]->flags & O_NONBLOCK) == 0 && (ret = _thread_fd_lock(fd, FD_READ, NULL, __FILE__, __LINE__)) != 0) { +		/* Cannot lock file descriptor. */ +	} else { +		while ((ret = _thread_sys_readv(fd, iov, iovcnt)) < 0) { +			if (nonblock == 0 && (errno == EWOULDBLOCK || errno == EAGAIN)) { +				_thread_kern_sig_block(&status); +				_thread_run->data.fd.fd = fd; +				_thread_kern_set_timeout(NULL); +				_thread_kern_sched_state(PS_FDR_WAIT, __FILE__, __LINE__); +				if (errno == EINTR) { +					ret = -1; +					break; +				} +			} else { +				break; +			} +		} +		if (nonblock == 0) { +			_thread_fd_unlock(fd, FD_READ); +		} +	} +	return (ret); +} +#endif diff --git a/lib/libpthread/thread/thr_select.c b/lib/libpthread/thread/thr_select.c new file mode 100644 index 000000000000..b3f548373e99 --- /dev/null +++ b/lib/libpthread/thread/thr_select.c @@ -0,0 +1,179 @@ +/* + * 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 <unistd.h> +#include <errno.h> +#include <string.h> +#include <sys/types.h> +#include <sys/time.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +int  +select(int numfds, fd_set * readfds, fd_set * writefds, +       fd_set * exceptfds, struct timeval * timeout) +{ +	fd_set          read_locks, write_locks, rdwr_locks; +	struct timespec ts; +	struct timeval  zero_timeout = {0, 0}; +	int             i, ret = 0, got_all_locks = 1; +	struct pthread_select_data data; + +	if (numfds > _thread_dtablesize) { +		numfds = _thread_dtablesize; +	} +	/* Check if a timeout was specified: */ +	if (timeout) { +		/* Convert the timeval to a timespec: */ +		TIMEVAL_TO_TIMESPEC(timeout, &ts); + +		/* Set the wake up time: */ +		_thread_kern_set_timeout(&ts); +	} else { +		/* Wait for ever: */ +		_thread_kern_set_timeout(NULL); +	} + +	FD_ZERO(&read_locks); +	FD_ZERO(&write_locks); +	FD_ZERO(&rdwr_locks); + +	/* lock readfds */ +	if (readfds || writefds || exceptfds) { +		for (i = 0; i < numfds; i++) { +			if ((readfds && (FD_ISSET(i, readfds))) || (exceptfds && FD_ISSET(i, exceptfds))) { +				if (writefds && FD_ISSET(i, writefds)) { +					if ((ret = _thread_fd_lock(i, FD_RDWR, NULL, __FILE__, __LINE__)) != 0) { +						got_all_locks = 0; +						break; +					} +					FD_SET(i, &rdwr_locks); +				} else { +					if ((ret = _thread_fd_lock(i, FD_READ, NULL, __FILE__, __LINE__)) != 0) { +						got_all_locks = 0; +						break; +					} +					FD_SET(i, &read_locks); +				} +			} else { +				if (writefds && FD_ISSET(i, writefds)) { +					if ((ret = _thread_fd_lock(i, FD_WRITE, NULL, __FILE__, __LINE__)) != 0) { +						got_all_locks = 0; +						break; +					} +					FD_SET(i, &write_locks); +				} +			} +		} +	} +	if (got_all_locks) { +		data.nfds = numfds; +		FD_ZERO(&data.readfds); +		FD_ZERO(&data.writefds); +		FD_ZERO(&data.exceptfds); +		if (readfds != NULL) { +			memcpy(&data.readfds, readfds, sizeof(data.readfds)); +		} +		if (writefds != NULL) { +			memcpy(&data.writefds, writefds, sizeof(data.writefds)); +		} +		if (exceptfds != NULL) { +			memcpy(&data.exceptfds, exceptfds, sizeof(data.exceptfds)); +		} +		if ((ret = _thread_sys_select(data.nfds, &data.readfds, &data.writefds, &data.exceptfds, &zero_timeout)) == 0) { +			data.nfds = numfds; +			FD_ZERO(&data.readfds); +			FD_ZERO(&data.writefds); +			FD_ZERO(&data.exceptfds); +			if (readfds != NULL) { +				memcpy(&data.readfds, readfds, sizeof(data.readfds)); +			} +			if (writefds != NULL) { +				memcpy(&data.writefds, writefds, sizeof(data.writefds)); +			} +			if (exceptfds != NULL) { +				memcpy(&data.exceptfds, exceptfds, sizeof(data.exceptfds)); +			} +			_thread_run->data.select_data = &data; +			_thread_kern_sched_state(PS_SELECT_WAIT, __FILE__, __LINE__); +			ret = data.nfds; +		} +	} +	/* clean up the locks */ +	for (i = 0; i < numfds; i++) +		if (FD_ISSET(i, &read_locks)) +			_thread_fd_unlock(i, FD_READ); +	for (i = 0; i < numfds; i++) +		if (FD_ISSET(i, &rdwr_locks)) +			_thread_fd_unlock(i, FD_RDWR); +	for (i = 0; i < numfds; i++) +		if (FD_ISSET(i, &write_locks)) +			_thread_fd_unlock(i, FD_WRITE); + +	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 (writefds != NULL) { +			FD_ZERO(writefds); +			for (i = 0; i < numfds; i++) { +				if (FD_ISSET(i, &data.writefds)) { +					FD_SET(i, writefds); +				} +			} +		} +		if (exceptfds != NULL) { +			FD_ZERO(exceptfds); +			for (i = 0; i < numfds; i++) { +				if (FD_ISSET(i, &data.exceptfds)) { +					FD_SET(i, exceptfds); +				} +			} +		} +	} else { +		if (exceptfds != NULL) +			FD_ZERO(exceptfds); +		if (writefds != NULL) +			FD_ZERO(writefds); +		if (readfds != NULL) +			FD_ZERO(readfds); +	} + +	return (ret); +} +#endif diff --git a/lib/libpthread/thread/thr_self.c b/lib/libpthread/thread/thr_self.c new file mode 100644 index 000000000000..a0a2d2aded6e --- /dev/null +++ b/lib/libpthread/thread/thr_self.c @@ -0,0 +1,43 @@ +/* + * 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. + * + */ +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +pthread_t +pthread_self(void) +{ +	/* Return the running thread pointer: */ +	return (_thread_run); +} +#endif diff --git a/lib/libpthread/thread/thr_seterrno.c b/lib/libpthread/thread/thr_seterrno.c new file mode 100644 index 000000000000..c4fe08b6cc36 --- /dev/null +++ b/lib/libpthread/thread/thr_seterrno.c @@ -0,0 +1,61 @@ +/* + * 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. + * + */ +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +/* + * This function needs to reference the global error variable which is + * normally hidden from the user.  + */ +#ifdef errno +#undef errno; +#endif +extern int      errno; + +void +_thread_seterrno(pthread_t thread, int error) +{ +	/* Check for the initial thread: */ +	if (thread == _thread_initial) { +		/* The initial thread always uses the global error variable: */ +		errno = error; +	} 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 new file mode 100644 index 000000000000..e052ec34c5d2 --- /dev/null +++ b/lib/libpthread/thread/thr_setprio.c @@ -0,0 +1,80 @@ +/* + * 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_setprio(pthread_t pthread, int prio) +{ +	int             rval = 0; +	int             status; +	pthread_t       pthread_p; + +	/* Check if the priority is invalid: */ +	if (prio < PTHREAD_MIN_PRIORITY || prio > PTHREAD_MAX_PRIORITY) { +		/* Return an invalid argument error: */ +		_thread_seterrno(_thread_run, EINVAL); +		rval = -1; +	} else { +		/* 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 a 'search' error: */ +			_thread_seterrno(_thread_run, ESRCH); +			rval = -1; +		} else { +			/* Set the thread priority: */ +			pthread->pthread_priority = prio; +		} + +		/* Unblock signals: */ +		_thread_kern_sig_unblock(status); +	} + +	/* Return the error status: */ +	return (rval); +} +#endif diff --git a/lib/libpthread/thread/thr_sig.c b/lib/libpthread/thread/thr_sig.c new file mode 100644 index 000000000000..77ec713b63d9 --- /dev/null +++ b/lib/libpthread/thread/thr_sig.c @@ -0,0 +1,128 @@ +/* + * 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 <signal.h> +#include <errno.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +void +_thread_sig_handler(int sig, int code, struct sigcontext * scp) +{ +	char            c; +	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 +	 * signal interrupted it:  +	 */ +	if (_thread_kern_in_select) { +		/* Cast the signal number to a character variable: */ +		c = sig; + +		/* +		 * 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 +		 * immediately.  +		 */ +		if (_thread_sys_write(_thread_kern_pipe[1], &c, 1) != 1) { +		} +	} +	/* Check if the signal requires a dump of thread information: */ +	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: +			/* +			 * Don't add the signal to any thread.  Just want to +			 * call    +			 */ +			/* the scheduler: */ +			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; + +			/* Signals to send to all threads: */ +		default: +			/* +			 * 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; +			} +			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); + +			/* +			 * This point should not be reached, so abort the +			 * process:  +			 */ +			PANIC("Returned to signal function from scheduler"); +		} +	} + +	/* Returns nothing. */ +	return; +} +#endif diff --git a/lib/libpthread/thread/thr_sigaction.c b/lib/libpthread/thread/thr_sigaction.c new file mode 100644 index 000000000000..c7336677ff9c --- /dev/null +++ b/lib/libpthread/thread/thr_sigaction.c @@ -0,0 +1,82 @@ +/* + * 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 <signal.h> +#include <errno.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +int +sigaction(int sig, const struct sigaction * act, struct sigaction * oact) +{ +	int             ret = 0; +	int             status; + +	/* Check if the signal number is out of range: */ +	if (sig < 1 || sig > NSIG) { +		/* Return an invalid argument: */ +		_thread_seterrno(_thread_run, EINVAL); +		ret = -1; +	} else { +		/* +		 * Check if the existing signal action structure contents are +		 * to be returned:  +		 */ +		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; +		} +		/* 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; + +			/* +			 * Unblock signals to allow the new signal handler to +			 * take effect:  +			 */ +			_thread_kern_sig_unblock(status); +		} +	} + +	/* Return the completion status: */ +	return (ret); +} +#endif diff --git a/lib/libpthread/thread/thr_sigprocmask.c b/lib/libpthread/thread/thr_sigprocmask.c new file mode 100644 index 000000000000..d6e3197d2e40 --- /dev/null +++ b/lib/libpthread/thread/thr_sigprocmask.c @@ -0,0 +1,92 @@ +/* + * 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 <signal.h> +#include <errno.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +int +sigprocmask(int how, const sigset_t * set, sigset_t * oset) +{ +	int             ret = 0; +	int             status; + +	/* Check if the existing signal process mask is to be returned: */ +	if (oset != NULL) { +		/* Return the current mask: */ +		*oset = _thread_run->sigmask; +	} +	/* 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: */ +		case SIG_BLOCK: +			/* Add signals to the existing mask: */ +			_thread_run->sigmask |= *set; +			break; + +			/* Unblock signals: */ +		case SIG_UNBLOCK: +			/* Clear signals from the existing mask: */ +			_thread_run->sigmask &= ~(*set); +			break; + +			/* Set the signal process mask: */ +		case SIG_SETMASK: +			/* Set the new mask: */ +			_thread_run->sigmask = *set; +			break; + +			/* Trap invalid actions: */ +		default: +			/* Return an invalid argument: */ +			_thread_seterrno(_thread_run, EINVAL); +			ret = -1; +			break; +		} + +		/* +		 * Schedule the next thread in case there are signals that +		 * now need to be acted on:  +		 */ +		_thread_kern_sched(NULL); +	} +	/* Return the completion status: */ +	return (ret); +} +#endif diff --git a/lib/libpthread/thread/thr_sigsuspend.c b/lib/libpthread/thread/thr_sigsuspend.c new file mode 100644 index 000000000000..ee2d0b5671df --- /dev/null +++ b/lib/libpthread/thread/thr_sigsuspend.c @@ -0,0 +1,63 @@ +/* + * 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 <signal.h> +#include <errno.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +int +sigsuspend(const sigset_t * set) +{ +	int             ret = -1; +	sigset_t        oset; + +	/* Check if a new signal set was provided by the caller: */ +	if (set != NULL) { +		/* Save the current sigmal mask: */ +		oset = _thread_run->sigmask; + +		/* Wait for a signal: */ +		_thread_kern_sched_state(PS_SIGWAIT, __FILE__, __LINE__); + +		/* Restore the signal mask: */ +		_thread_run->sigmask = oset; +	} else { +		/* Return an invalid argument error: */ +		_thread_seterrno(_thread_run, EINVAL); +	} + +	/* Return the completion status: */ +	return (ret); +} +#endif diff --git a/lib/libpthread/thread/thr_spec.c b/lib/libpthread/thread/thr_spec.c new file mode 100644 index 000000000000..e7c45d2953c7 --- /dev/null +++ b/lib/libpthread/thread/thr_spec.c @@ -0,0 +1,237 @@ +/* + * 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 <signal.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +/* Static variables: */ +static struct pthread_key key_table[PTHREAD_DATAKEYS_MAX]; + +int +pthread_keycreate(pthread_key_t * key, void (*destructor) (void *)) +{ +	for ((*key) = 0; (*key) < PTHREAD_DATAKEYS_MAX; (*key)++) { +		if (key_table[(*key)].count == 0) { +			key_table[(*key)].count++; +			key_table[(*key)].destructor = destructor; +			return (0); +		} +	} +	return (EAGAIN); +} + +int +pthread_key_delete(pthread_key_t key) +{ +	int             ret; +	int             status; + +	/* Block signals: */ +	_thread_kern_sig_block(&status); + +	if (key < PTHREAD_DATAKEYS_MAX) { +		switch (key_table[key].count) { +		case 1: +			key_table[key].destructor = NULL; +			key_table[key].count = 0; +		case 0: +			ret = 0; +			break; +		default: +			ret = EBUSY; +		} +	} else { +		ret = EINVAL; +	} + +	/* Unblock signals: */ +	_thread_kern_sig_unblock(status); +	return (ret); +} + +void  +_thread_cleanupspecific(void) +{ +	void           *data; +	int             key; +	int             itr; +	int             status; + +	/* Block signals: */ +	_thread_kern_sig_block(&status); + +	for (itr = 0; itr < _POSIX_THREAD_DESTRUTOR_ITERATIONS; itr++) { +		for (key = 0; key < PTHREAD_DATAKEYS_MAX; key++) { +			if (_thread_run->specific_data_count) { +				if (_thread_run->specific_data[key]) { +					data = (void *) _thread_run->specific_data[key]; +					_thread_run->specific_data[key] = NULL; +					_thread_run->specific_data_count--; +					if (key_table[key].destructor) { +						key_table[key].destructor(data); +					} +					key_table[key].count--; +				} +			} 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 ** +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); +	} +	return (new_data); +} + +int  +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 ((key < PTHREAD_DATAKEYS_MAX) && (key_table)) { +			if (key_table[key].count) { +				if (pthread->specific_data[key] == NULL) { +					if (value != NULL) { +						pthread->specific_data_count++; +						key_table[key].count++; +					} +				} else { +					if (value == NULL) { +						pthread->specific_data_count--; +						key_table[key].count--; +					} +				} +				pthread->specific_data[key] = value; +				ret = 0; +			} else { +				ret = EINVAL; +			} +		} else { +			ret = EINVAL; +		} +	} else { +		ret = ENOMEM; +	} + +	/* Unblock signals: */ +	_thread_kern_sig_unblock(status); +	return (ret); +} + +int +pthread_getspecific(pthread_key_t key, void **p_data) +{ +	pthread_t       pthread; +	int             rval = 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; +	} + +	/* Check for errors: */ +	if (pthread == NULL || p_data == NULL) { +		/* Return an invalid argument error: */ +		_thread_seterrno(_thread_run, EINVAL); +		rval = -1; +	} +	/* Check if there is specific data: */ +	else if (pthread->specific_data != NULL && (key < PTHREAD_DATAKEYS_MAX) && (key_table)) { +		/* Check if this key has been used before: */ +		if (key_table[key].count) { +			/* Return the value: */ +			*p_data = (void *) pthread->specific_data[key]; +		} else { +			/* +			 * This key has not been used before, so return NULL +			 * instead:  +			 */ +			*p_data = NULL; +		} +	} else { +		/* No specific data has been created, so just return NULL: */ +		*p_data = NULL; +	} + +	/* Unblock signals: */ +	_thread_kern_sig_unblock(status); +	return (rval); +} +#endif diff --git a/lib/libpthread/thread/thr_wait4.c b/lib/libpthread/thread/thr_wait4.c new file mode 100644 index 000000000000..0a721af4fda9 --- /dev/null +++ b/lib/libpthread/thread/thr_wait4.c @@ -0,0 +1,61 @@ +/* + * 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> +#include <sys/wait.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +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) { +		/* 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) { +			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 new file mode 100644 index 000000000000..fb6912997911 --- /dev/null +++ b/lib/libpthread/thread/thr_write.c @@ -0,0 +1,74 @@ +/* + * 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 <sys/types.h> +#include <sys/fcntl.h> +#include <sys/uio.h> +#include <errno.h> +#include <unistd.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +ssize_t +write(int fd, const void *buf, size_t nbytes) +{ +	int             nonblock; +	int             ret; +	int             status; +	if (fd < 0 || fd > _thread_dtablesize || _thread_fd_table[fd] == NULL) { +		_thread_seterrno(_thread_run, EBADF); +		ret = -1; +	} else if ((nonblock = _thread_fd_table[fd]->flags & O_NONBLOCK) == 0 && (ret = _thread_fd_lock(fd, FD_RDWR, NULL, __FILE__, __LINE__)) != 0) { +		/* Cannot lock file descriptor. */ +	} else { +		while ((ret = _thread_sys_write(fd, buf, nbytes)) < 0) { +			if (nonblock == 0 && (errno == EWOULDBLOCK || errno == EAGAIN)) { +				_thread_kern_sig_block(&status); +				_thread_run->data.fd.fd = fd; +				_thread_kern_set_timeout(NULL); +				_thread_kern_sched_state(PS_FDW_WAIT, __FILE__, __LINE__); +				if (errno == EINTR) { +					ret = -1; +					break; +				} +			} else { +				break; +			} +		} +		if (nonblock == 0) { +			_thread_fd_unlock(fd, FD_RDWR); +		} +	} +	return (ret); +} +#endif diff --git a/lib/libpthread/thread/thr_writev.c b/lib/libpthread/thread/thr_writev.c new file mode 100644 index 000000000000..f40e611d98fe --- /dev/null +++ b/lib/libpthread/thread/thr_writev.c @@ -0,0 +1,74 @@ +/* + * 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 <sys/types.h> +#include <sys/fcntl.h> +#include <sys/uio.h> +#include <errno.h> +#include <unistd.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +ssize_t +writev(int fd, const struct iovec * iov, int iovcnt) +{ +	int             nonblock; +	int             ret; +	int             status; +	if (fd < 0 || fd > _thread_dtablesize || _thread_fd_table[fd] == NULL) { +		_thread_seterrno(_thread_run, EBADF); +		ret = -1; +	} else if ((nonblock = _thread_fd_table[fd]->flags & O_NONBLOCK) == 0 && (ret = _thread_fd_lock(fd, FD_RDWR, NULL, __FILE__, __LINE__)) != 0) { +		/* Cannot lock file descriptor. */ +	} else { +		while ((ret = _thread_sys_writev(fd, iov, iovcnt)) < 0) { +			if (nonblock == 0 && (errno == EWOULDBLOCK || errno == EAGAIN)) { +				_thread_kern_sig_block(&status); +				_thread_run->data.fd.fd = fd; +				_thread_kern_set_timeout(NULL); +				_thread_kern_sched_state(PS_FDW_WAIT, __FILE__, __LINE__); +				if (errno == EINTR) { +					ret = -1; +					break; +				} +			} else { +				break; +			} +		} +		if (nonblock == 0) { +			_thread_fd_unlock(fd, FD_RDWR); +		} +	} +	return (ret); +} +#endif diff --git a/lib/libpthread/thread/thr_yield.c b/lib/libpthread/thread/thr_yield.c new file mode 100644 index 000000000000..a88a94836b7a --- /dev/null +++ b/lib/libpthread/thread/thr_yield.c @@ -0,0 +1,49 @@ +/* + * 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. + * + */ +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +void +pthread_yield(void) +{ +	/* Reset the accumulated time slice value for the current thread: */ +	_thread_run->slice_usec = -1; + +	/* Schedule the next thread: */ +	_thread_kern_sched(NULL); + +	/* Nothing to return. */ +	return; +} +#endif | 
