diff options
author | julian <julian@FreeBSD.org> | 1996-01-22 00:23:58 +0000 |
---|---|---|
committer | julian <julian@FreeBSD.org> | 1996-01-22 00:23:58 +0000 |
commit | 529743d354ac402b1302b397159146fa46c180c5 (patch) | |
tree | d93df8a19a0cab699bfc2c0b9e4bc691251efa16 /lib/libkse | |
parent | 619b731f5bb5e09dcf1eaf1fbd96383ca64398fd (diff) | |
download | FreeBSD-src-529743d354ac402b1302b397159146fa46c180c5.zip FreeBSD-src-529743d354ac402b1302b397159146fa46c180c5.tar.gz |
Reviewed by: julian
Submitted by: john birrel
One version of the pthreads library
another will follow with differnt actions under some cases..
not QUITE complete
Diffstat (limited to 'lib/libkse')
38 files changed, 6198 insertions, 0 deletions
diff --git a/lib/libkse/Makefile b/lib/libkse/Makefile new file mode 100644 index 0000000..c0fd385 --- /dev/null +++ b/lib/libkse/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/libkse/sys/Makefile.inc b/lib/libkse/sys/Makefile.inc new file mode 100644 index 0000000..2b22537 --- /dev/null +++ b/lib/libkse/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/libkse/thread/Makefile.inc b/lib/libkse/thread/Makefile.inc new file mode 100644 index 0000000..a3f6ff9 --- /dev/null +++ b/lib/libkse/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/libkse/thread/thr_clean.c b/lib/libkse/thread/thr_clean.c new file mode 100644 index 0000000..99893f6 --- /dev/null +++ b/lib/libkse/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/libkse/thread/thr_close.c b/lib/libkse/thread/thr_close.c new file mode 100644 index 0000000..f98e056 --- /dev/null +++ b/lib/libkse/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/libkse/thread/thr_cond.c b/lib/libkse/thread/thr_cond.c new file mode 100644 index 0000000..930f31a --- /dev/null +++ b/lib/libkse/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/libkse/thread/thr_create.c b/lib/libkse/thread/thr_create.c new file mode 100644 index 0000000..e6db381 --- /dev/null +++ b/lib/libkse/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/libkse/thread/thr_detach.c b/lib/libkse/thread/thr_detach.c new file mode 100644 index 0000000..f24d16f --- /dev/null +++ b/lib/libkse/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/libkse/thread/thr_equal.c b/lib/libkse/thread/thr_equal.c new file mode 100644 index 0000000..99ffb5d --- /dev/null +++ b/lib/libkse/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/libkse/thread/thr_exit.c b/lib/libkse/thread/thr_exit.c new file mode 100644 index 0000000..292fce9 --- /dev/null +++ b/lib/libkse/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/libkse/thread/thr_fcntl.c b/lib/libkse/thread/thr_fcntl.c new file mode 100644 index 0000000..ae069b8 --- /dev/null +++ b/lib/libkse/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/libkse/thread/thr_fork.c b/lib/libkse/thread/thr_fork.c new file mode 100644 index 0000000..6e7ca0d --- /dev/null +++ b/lib/libkse/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/libkse/thread/thr_fsync.c b/lib/libkse/thread/thr_fsync.c new file mode 100644 index 0000000..51078e5 --- /dev/null +++ b/lib/libkse/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/libkse/thread/thr_getprio.c b/lib/libkse/thread/thr_getprio.c new file mode 100644 index 0000000..345f6ce --- /dev/null +++ b/lib/libkse/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/libkse/thread/thr_info.c b/lib/libkse/thread/thr_info.c new file mode 100644 index 0000000..e69145f --- /dev/null +++ b/lib/libkse/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/libkse/thread/thr_init.c b/lib/libkse/thread/thr_init.c new file mode 100644 index 0000000..d044063 --- /dev/null +++ b/lib/libkse/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/libkse/thread/thr_join.c b/lib/libkse/thread/thr_join.c new file mode 100644 index 0000000..d0093ae --- /dev/null +++ b/lib/libkse/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/libkse/thread/thr_kern.c b/lib/libkse/thread/thr_kern.c new file mode 100644 index 0000000..35e8e29 --- /dev/null +++ b/lib/libkse/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/libkse/thread/thr_mutex.c b/lib/libkse/thread/thr_mutex.c new file mode 100644 index 0000000..0fc9fbb --- /dev/null +++ b/lib/libkse/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/libkse/thread/thr_nanosleep.c b/lib/libkse/thread/thr_nanosleep.c new file mode 100644 index 0000000..e91ca57 --- /dev/null +++ b/lib/libkse/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/libkse/thread/thr_once.c b/lib/libkse/thread/thr_once.c new file mode 100644 index 0000000..c55ba9e --- /dev/null +++ b/lib/libkse/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/libkse/thread/thr_open.c b/lib/libkse/thread/thr_open.c new file mode 100644 index 0000000..ead651e --- /dev/null +++ b/lib/libkse/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/libkse/thread/thr_private.h b/lib/libkse/thread/thr_private.h new file mode 100644 index 0000000..fc8ba27 --- /dev/null +++ b/lib/libkse/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/libkse/thread/thr_read.c b/lib/libkse/thread/thr_read.c new file mode 100644 index 0000000..9158844 --- /dev/null +++ b/lib/libkse/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/libkse/thread/thr_readv.c b/lib/libkse/thread/thr_readv.c new file mode 100644 index 0000000..acb72ac --- /dev/null +++ b/lib/libkse/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/libkse/thread/thr_select.c b/lib/libkse/thread/thr_select.c new file mode 100644 index 0000000..b3f5483 --- /dev/null +++ b/lib/libkse/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/libkse/thread/thr_self.c b/lib/libkse/thread/thr_self.c new file mode 100644 index 0000000..a0a2d2a --- /dev/null +++ b/lib/libkse/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/libkse/thread/thr_seterrno.c b/lib/libkse/thread/thr_seterrno.c new file mode 100644 index 0000000..c4fe08b6 --- /dev/null +++ b/lib/libkse/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/libkse/thread/thr_setprio.c b/lib/libkse/thread/thr_setprio.c new file mode 100644 index 0000000..e052ec3 --- /dev/null +++ b/lib/libkse/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/libkse/thread/thr_sig.c b/lib/libkse/thread/thr_sig.c new file mode 100644 index 0000000..77ec713 --- /dev/null +++ b/lib/libkse/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/libkse/thread/thr_sigaction.c b/lib/libkse/thread/thr_sigaction.c new file mode 100644 index 0000000..c733667 --- /dev/null +++ b/lib/libkse/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/libkse/thread/thr_sigprocmask.c b/lib/libkse/thread/thr_sigprocmask.c new file mode 100644 index 0000000..d6e3197 --- /dev/null +++ b/lib/libkse/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/libkse/thread/thr_sigsuspend.c b/lib/libkse/thread/thr_sigsuspend.c new file mode 100644 index 0000000..ee2d0b5 --- /dev/null +++ b/lib/libkse/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/libkse/thread/thr_spec.c b/lib/libkse/thread/thr_spec.c new file mode 100644 index 0000000..e7c45d2 --- /dev/null +++ b/lib/libkse/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/libkse/thread/thr_wait4.c b/lib/libkse/thread/thr_wait4.c new file mode 100644 index 0000000..0a721af4f --- /dev/null +++ b/lib/libkse/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/libkse/thread/thr_write.c b/lib/libkse/thread/thr_write.c new file mode 100644 index 0000000..fb69129 --- /dev/null +++ b/lib/libkse/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/libkse/thread/thr_writev.c b/lib/libkse/thread/thr_writev.c new file mode 100644 index 0000000..f40e611 --- /dev/null +++ b/lib/libkse/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/libkse/thread/thr_yield.c b/lib/libkse/thread/thr_yield.c new file mode 100644 index 0000000..a88a948 --- /dev/null +++ b/lib/libkse/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 |