From 0f7d684755aefbcfd70b45d24efc2d39bc505c4c Mon Sep 17 00:00:00 2001 From: Julian Elischer Date: Tue, 20 Aug 1996 08:22:01 +0000 Subject: Submitted by: John Birrell Here are the diffs for libc_r to get it one step closer to P1003.1c These make most of the thread/mutex/condvar structures opaque to the user. There are three functions which have been renamed with _np suffixes because they are extensions to P1003.1c (I did them for JAVA, which needs to suspend/resume threads and also start threads suspended). I've created a new header (pthread_np.h) for the non-POSIX stuff. The egrep tags stuff in /usr/src/lib/libc_r/Makefile that I uncommented doesn't work. I think its best to delete it. I don't think libc_r needs tags anyway, 'cause most of the source is in libc which does have tags. also: Here's the first batch of man pages for the thread functions. The diff to /usr/src/lib/libc_r/Makefile removes some stuff that was inherited from /usr/src/lib/libc/Makefile that should only be done with libc. also: I should have sent this diff with the pthread(3) man page. It allows people to type make -DWANT_LIBC_R world to get libc_r built with the rest of the world. I put this in the pthread(3) man page. The default is still not to build libc_r. also: The diff attached adds a pthread(3) man page to /usr/src/share/man/man3. The idea is that without libc_r installed, this man page will give people enough info to know that they have to build libc_r. --- lib/libkse/Makefile | 21 +- lib/libkse/sys/Makefile.inc | 46 ++- lib/libkse/thread/Makefile.inc | 8 +- lib/libkse/thread/thr_attr_destroy.c | 52 +++ lib/libkse/thread/thr_attr_init.c | 54 +++ lib/libkse/thread/thr_attr_setcreatesuspend_np.c | 51 +++ lib/libkse/thread/thr_attr_setstacksize.c | 50 +++ lib/libkse/thread/thr_close.c | 52 ++- lib/libkse/thread/thr_cond.c | 334 +++++++++------- lib/libkse/thread/thr_create.c | 21 +- lib/libkse/thread/thr_exit.c | 38 ++ lib/libkse/thread/thr_fcntl.c | 1 + lib/libkse/thread/thr_fork.c | 2 + lib/libkse/thread/thr_init.c | 12 - lib/libkse/thread/thr_kern.c | 231 ++++++++++- lib/libkse/thread/thr_multi_np.c | 44 +++ lib/libkse/thread/thr_mutex.c | 465 ++++++++++++----------- lib/libkse/thread/thr_nanosleep.c | 143 +++++-- lib/libkse/thread/thr_open.c | 11 +- lib/libkse/thread/thr_private.h | 148 +++++++- lib/libkse/thread/thr_resume_np.c | 70 ++++ lib/libkse/thread/thr_select.c | 25 +- lib/libkse/thread/thr_sig.c | 49 ++- lib/libkse/thread/thr_sigsuspend.c | 3 + lib/libkse/thread/thr_single_np.c | 44 +++ lib/libkse/thread/thr_spec.c | 20 +- lib/libkse/thread/thr_suspend_np.c | 67 ++++ 27 files changed, 1568 insertions(+), 494 deletions(-) create mode 100644 lib/libkse/thread/thr_attr_destroy.c create mode 100644 lib/libkse/thread/thr_attr_init.c create mode 100644 lib/libkse/thread/thr_attr_setcreatesuspend_np.c create mode 100644 lib/libkse/thread/thr_attr_setstacksize.c create mode 100644 lib/libkse/thread/thr_multi_np.c create mode 100644 lib/libkse/thread/thr_resume_np.c create mode 100644 lib/libkse/thread/thr_single_np.c create mode 100644 lib/libkse/thread/thr_suspend_np.c (limited to 'lib/libkse') diff --git a/lib/libkse/Makefile b/lib/libkse/Makefile index 3fd14d80844a..373fe6592b22 100644 --- a/lib/libkse/Makefile +++ b/lib/libkse/Makefile @@ -20,6 +20,7 @@ PRECIOUSLIB= yes .include "${.CURDIR}/gen/Makefile.inc" .include "${.CURDIR}/gmon/Makefile.inc" .include "${.CURDIR}/locale/Makefile.inc" +.include "${.CURDIR}/man/Makefile.inc" .include "${.CURDIR}/net/Makefile.inc" .include "${.CURDIR}/nls/Makefile.inc" .include "${.CURDIR}/quad/Makefile.inc" @@ -38,24 +39,8 @@ CFLAGS+= -DYP .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 +beforeinstall: tags + ${INSTALL} ${COPY} -o bin -g bin -m 444 tags /var/db/libc_r.tags tags: ${SRCS} ctags ${.ALLSRC:M*.c} diff --git a/lib/libkse/sys/Makefile.inc b/lib/libkse/sys/Makefile.inc index 3aa9a003e3e1..bca46e44f510 100644 --- a/lib/libkse/sys/Makefile.inc +++ b/lib/libkse/sys/Makefile.inc @@ -1,5 +1,4 @@ # @(#)Makefile.inc 8.1 (Berkeley) 6/17/93 -# $Id: $ # sys sources .PATH: ${.CURDIR}/../libc/${MACHINE}/sys ${.CURDIR}/../libc/sys \ @@ -40,16 +39,18 @@ THREADASM= accept.o bind.o close.o connect.o dup.o dup2.o \ shutdown.o sigaction.o sigaltstack.o socket.o socketpair.o \ wait4.o write.o writev.o -PSEUDO= _exit.o _getlogin.o +PSEUDO= _getlogin.o -OBJS+= ${ASM} ${THREADASM} ${PSEUDO} +THREADPSEUDO= _exit.o + +OBJS+= ${ASM} ${THREADASM} ${PSEUDO} ${THREADPSEUDO} ${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 -f a.out ${.PREFIX}.o + @mv a.out ${.PREFIX}.o PASM= ${ASM:.o=.po} ${PASM}: ${.CURDIR}/../libc/${MACHINE}/SYS.h /usr/include/sys/syscall.h @@ -57,7 +58,7 @@ ${PASM}: ${.CURDIR}/../libc/${MACHINE}/SYS.h /usr/include/sys/syscall.h @printf '#include "SYS.h"\nRSYSCALL(${.PREFIX})\n' | \ ${CPP} -DPROF ${CFLAGS:M-[ID]*} ${AINC} | ${AS} -o ${.PREFIX}.po @${LD} -x -r ${.PREFIX}.po - @mv -f a.out ${.PREFIX}.po + @mv a.out ${.PREFIX}.po SASM= ${ASM:.o=.so} ${SASM}: ${.CURDIR}/../libc/${MACHINE}/SYS.h /usr/include/sys/syscall.h @@ -67,23 +68,23 @@ ${SASM}: ${.CURDIR}/../libc/${MACHINE}/SYS.h /usr/include/sys/syscall.h ${THREADASM}: ${.CURDIR}/../libc/${MACHINE}/SYS.h /usr/include/sys/syscall.h @${ECHO} creating ${.PREFIX}.o - @printf '#include "SYS.h"\nPRSYSCALL(${.PREFIX},_thread_sys_${.PREFIX})\n' | \ + @printf '#include "SYS.h"\nPRSYSCALL(${.PREFIX})\n' | \ ${CPP} ${CFLAGS:M-[ID]*} ${AINC} | ${AS} -o ${.PREFIX}.o @${LD} -x -r ${.PREFIX}.o - @mv -f a.out ${.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},_thread_sys_${.PREFIX})\n' | \ + @printf '#include "SYS.h"\nPRSYSCALL(${.PREFIX})\n' | \ ${CPP} -DPROF ${CFLAGS:M-[ID]*} ${AINC} | ${AS} -o ${.PREFIX}.po @${LD} -x -r ${.PREFIX}.po - @mv -f a.out ${.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},_thread_sys_${.PREFIX})\n' | \ + @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 @@ -91,7 +92,7 @@ ${PSEUDO}: ${.CURDIR}/../libc/${MACHINE}/SYS.h /usr/include/sys/syscall.h @printf '#include "SYS.h"\nPSEUDO(${.PREFIX},${.PREFIX:S/_//})\n' | \ ${CPP} ${CFLAGS:M-[ID]*} ${AINC} | ${AS} -o ${.PREFIX}.o @${LD} -x -r ${.PREFIX}.o - @mv -f a.out ${.PREFIX}.o + @mv a.out ${.PREFIX}.o PPSEUDO=${PSEUDO:.o=.po} ${PPSEUDO}: ${.CURDIR}/../libc/${MACHINE}/SYS.h /usr/include/sys/syscall.h @@ -99,10 +100,31 @@ ${PPSEUDO}: ${.CURDIR}/../libc/${MACHINE}/SYS.h /usr/include/sys/syscall.h @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 -f a.out ${.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 + +${THREADPSEUDO}: ${.CURDIR}/../libc/${MACHINE}/SYS.h /usr/include/sys/syscall.h + @${ECHO} creating ${.PREFIX}.o + @printf '#include "SYS.h"\nPPSEUDO(${.PREFIX},${.PREFIX:S/_//})\n' | \ + ${CPP} ${CFLAGS:M-[ID]*} ${AINC} | ${AS} -o ${.PREFIX}.o + @${LD} -x -r ${.PREFIX}.o + @mv a.out ${.PREFIX}.o + +THREADPPSEUDO=${THREADPSEUDO:.o=.po} +${THREADPPSEUDO}: ${.CURDIR}/../libc/${MACHINE}/SYS.h /usr/include/sys/syscall.h + @${ECHO} creating ${.PREFIX}.po + @printf '#include "SYS.h"\nPPSEUDO(${.PREFIX},${.PREFIX:S/_//})\n' | \ + ${CPP} -DPROF ${CFLAGS:M-[ID]*} ${AINC} | ${AS} -o ${.PREFIX}.po + @${LD} -x -r ${.PREFIX}.po + @mv a.out ${.PREFIX}.po + +THREADSPSEUDO=${THREADPSEUDO:.o=.so} +${THREADSPSEUDO}: ${.CURDIR}/../libc/${MACHINE}/SYS.h /usr/include/sys/syscall.h + @${ECHO} creating ${.PREFIX}.so + @printf '#include "SYS.h"\nPPSEUDO(${.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 index f37a21fbc58a..72a6e57a56c5 100644 --- a/lib/libkse/thread/Makefile.inc +++ b/lib/libkse/thread/Makefile.inc @@ -1,4 +1,4 @@ -# $Id: Makefile.inc,v 1.1 1996/01/22 00:23:03 julian Exp $ +# $Id: Makefile.inc,v 1.2 1996/02/17 02:19:35 jdp Exp $ CPLUSPLUSLIB= cpluspluslib @@ -7,7 +7,7 @@ CPLUSPLUSLIB= cpluspluslib SRCS+= \ uthread_accept.c \ - uthread_attr_setcreatesuspend.c \ + uthread_attr_setcreatesuspend_np.c \ uthread_autoinit.cc \ uthread_bind.c \ uthread_clean.c \ @@ -52,7 +52,7 @@ SRCS+= \ uthread_read.c \ uthread_readv.c \ uthread_recvfrom.c \ - uthread_resume.c \ + uthread_resume_np.c \ uthread_select.c \ uthread_self.c \ uthread_sendto.c \ @@ -71,7 +71,7 @@ SRCS+= \ uthread_socket.c \ uthread_socketpair.c \ uthread_spec.c \ - uthread_suspend.c \ + uthread_suspend_np.c \ uthread_wait4.c \ uthread_write.c \ uthread_writev.c \ diff --git a/lib/libkse/thread/thr_attr_destroy.c b/lib/libkse/thread/thr_attr_destroy.c new file mode 100644 index 000000000000..be6b2a2d7dcb --- /dev/null +++ b/lib/libkse/thread/thr_attr_destroy.c @@ -0,0 +1,52 @@ +/* + * Copyright (c) 1996 John Birrell . + * 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 +#include +#ifdef _THREAD_SAFE +#include +#include "pthread_private.h" + +int pthread_attr_destroy(pthread_attr_t *attr) +{ + int ret; + if (attr == NULL || *attr == NULL) { + errno = EINVAL; + ret = -1; + } else { + free(*attr); + *attr = NULL; + ret = 0; + } + return(ret); +} +#endif diff --git a/lib/libkse/thread/thr_attr_init.c b/lib/libkse/thread/thr_attr_init.c new file mode 100644 index 000000000000..7dade978a48f --- /dev/null +++ b/lib/libkse/thread/thr_attr_init.c @@ -0,0 +1,54 @@ +/* + * Copyright (c) 1996 John Birrell . + * 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 +#include +#include +#ifdef _THREAD_SAFE +#include +#include "pthread_private.h" + +int pthread_attr_init(pthread_attr_t *attr) +{ + int ret; + pthread_attr_t pattr; + if ((pattr = (pthread_attr_t) malloc(sizeof(struct pthread_attr))) == NULL) { + errno = ENOMEM; + ret = -1; + } else { + memcpy(pattr, &pthread_attr_default, sizeof(struct pthread_attr)); + *attr = pattr; + ret = 0; + } + return(ret); +} +#endif diff --git a/lib/libkse/thread/thr_attr_setcreatesuspend_np.c b/lib/libkse/thread/thr_attr_setcreatesuspend_np.c new file mode 100644 index 000000000000..afe6b23c3cb2 --- /dev/null +++ b/lib/libkse/thread/thr_attr_setcreatesuspend_np.c @@ -0,0 +1,51 @@ +/* + * Copyright (c) 1995 John Birrell . + * 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 +#ifdef _THREAD_SAFE +#include +#include "pthread_private.h" + +int +pthread_attr_setcreatesuspend_np(pthread_attr_t *attr) +{ + int ret; + if (attr == NULL || *attr == NULL) { + errno = EINVAL; + ret = -1; + } else { + (*attr)->suspend = PTHREAD_CREATE_SUSPENDED; + ret = 0; + } + return(ret); +} +#endif diff --git a/lib/libkse/thread/thr_attr_setstacksize.c b/lib/libkse/thread/thr_attr_setstacksize.c new file mode 100644 index 000000000000..5e59798f579b --- /dev/null +++ b/lib/libkse/thread/thr_attr_setstacksize.c @@ -0,0 +1,50 @@ +/* + * Copyright (c) 1996 John Birrell . + * 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 +#ifdef _THREAD_SAFE +#include +#include "pthread_private.h" + +int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize) +{ + int ret; + if (attr == NULL || *attr == NULL || stacksize < PTHREAD_STACK_MIN) { + errno = EINVAL; + ret = -1; + } else { + (*attr)->stacksize_attr = stacksize; + ret = 0; + } + return(ret); +} +#endif diff --git a/lib/libkse/thread/thr_close.c b/lib/libkse/thread/thr_close.c index f98e056aaab3..26a8fbfd5904 100644 --- a/lib/libkse/thread/thr_close.c +++ b/lib/libkse/thread/thr_close.c @@ -30,7 +30,10 @@ * SUCH DAMAGE. * */ +#include #include +#include +#include #ifdef _THREAD_SAFE #include #include "pthread_private.h" @@ -38,10 +41,55 @@ int close(int fd) { - int ret; + int flags; + int ret; + int status; + struct stat sb; + + /* Lock the file descriptor while the file is closed: */ if ((ret = _thread_fd_lock(fd, FD_RDWR, NULL, __FILE__, __LINE__)) == 0) { + /* Block signals: */ + _thread_kern_sig_block(&status); + + /* Get file descriptor status. */ + fstat(fd, &sb); + + /* + * Check if the file should be left as blocking. + * + * This is so that the file descriptors shared with a parent + * process aren't left set to non-blocking if the child + * closes them prior to exit. An example where this causes + * problems with /bin/sh is when a child closes stdin. + * + * Setting a file as blocking causes problems if a threaded + * parent accesses the file descriptor before the child exits. + * Once the threaded parent receives a SIGCHLD then it resets + * all of its files to non-blocking, and so it is then safe + * to access them. + * + * Pipes are not set to blocking when they are closed, as + * the parent and child will normally close the file + * descriptor of the end of the pipe that they are not + * using, which would then cause any reads to block + * indefinitely. + */ + if ((S_ISREG(sb.st_mode) || S_ISCHR(sb.st_mode)) && (_thread_fd_table[fd]->flags & O_NONBLOCK) == 0) { + /* Get the current flags: */ + flags = _thread_sys_fcntl(fd, F_GETFL, NULL); + /* Clear the nonblocking file descriptor flag: */ + _thread_sys_fcntl(fd, F_SETFL, flags & ~O_NONBLOCK); + } + + /* Close the file descriptor: */ ret = _thread_sys_close(fd); - _thread_fd_unlock(fd, FD_RDWR); + + /* Free the file descriptor table entry: */ + free(_thread_fd_table[fd]); + _thread_fd_table[fd] = NULL; + + /* Unblock signals again: */ + _thread_kern_sig_unblock(status); } return (ret); } diff --git a/lib/libkse/thread/thr_cond.c b/lib/libkse/thread/thr_cond.c index 930f31aea623..0f9f30230ba0 100644 --- a/lib/libkse/thread/thr_cond.c +++ b/lib/libkse/thread/thr_cond.c @@ -40,41 +40,56 @@ int pthread_cond_init(pthread_cond_t * cond, const pthread_condattr_t * cond_attr) { enum pthread_cond_type type; + pthread_cond_t pcond; int rval = 0; - /* - * Check if a pointer to a condition variable attribute structure was - * passed by the caller: - */ - if (cond_attr != NULL) { - /* Default to a fast condition variable: */ - type = cond_attr->c_type; + if (cond == NULL) { + errno = EINVAL; + rval = -1; } else { - /* Default to a fast condition variable: */ - type = COND_TYPE_FAST; - } - - /* Process according to condition variable type: */ - switch (type) { - /* Fast condition variable: */ - case COND_TYPE_FAST: - /* Nothing to do here. */ - break; + /* + * Check if a pointer to a condition variable attribute structure was + * passed by the caller: + */ + if (cond_attr != NULL && *cond_attr != NULL) { + /* Default to a fast condition variable: */ + type = (*cond_attr)->c_type; + } else { + /* Default to a fast condition variable: */ + type = COND_TYPE_FAST; + } - /* Trap invalid condition variable types: */ - default: - /* Return an invalid argument error: */ - _thread_seterrno(_thread_run, EINVAL); - rval = -1; - break; - } + /* Process according to condition variable type: */ + switch (type) { + /* Fast condition variable: */ + case COND_TYPE_FAST: + /* Nothing to do here. */ + break; + + /* Trap invalid condition variable types: */ + default: + /* Return an invalid argument error: */ + errno = EINVAL; + rval = -1; + break; + } - /* Check for no errors: */ - if (rval == 0) { - /* Initialise the condition variable structure: */ - _thread_queue_init(&cond->c_queue); - cond->c_flags |= COND_FLAGS_INITED; - cond->c_type = type; + /* Check for no errors: */ + if (rval == 0) { + if ((pcond = (pthread_cond_t) malloc(sizeof(struct pthread_cond))) == NULL) { + errno = ENOMEM; + rval = -1; + } else { + /* + * Initialise the condition variable + * structure: + */ + _thread_queue_init(&pcond->c_queue); + pcond->c_flags |= COND_FLAGS_INITED; + pcond->c_type = type; + *cond = pcond; + } + } } /* Return the completion status: */ return (rval); @@ -85,26 +100,33 @@ pthread_cond_destroy(pthread_cond_t * cond) { int rval = 0; - /* Process according to condition variable type: */ - switch (cond->c_type) { - /* Fast condition variable: */ - case COND_TYPE_FAST: - /* Nothing to do here. */ - break; - - /* Trap invalid condition variable types: */ - default: - /* Return an invalid argument error: */ - _thread_seterrno(_thread_run, EINVAL); + if (cond == NULL || *cond == NULL) { + errno = EINVAL; rval = -1; - break; - } + } else { + /* Process according to condition variable type: */ + switch ((*cond)->c_type) { + /* Fast condition variable: */ + case COND_TYPE_FAST: + /* Nothing to do here. */ + break; + + /* Trap invalid condition variable types: */ + default: + /* Return an invalid argument error: */ + errno = EINVAL; + rval = -1; + break; + } - /* Check for errors: */ - if (rval == 0) { - /* Destroy the contents of the condition structure: */ - _thread_queue_init(&cond->c_queue); - cond->c_flags = 0; + /* Check for errors: */ + if (rval == 0) { + /* Destroy the contents of the condition structure: */ + _thread_queue_init(&(*cond)->c_queue); + (*cond)->c_flags = 0; + free(*cond); + *cond = NULL; + } } /* Return the completion status: */ return (rval); @@ -116,40 +138,45 @@ pthread_cond_wait(pthread_cond_t * cond, pthread_mutex_t * mutex) int rval = 0; int status; - /* Block signals: */ - _thread_kern_sig_block(&status); + if (cond == NULL || *cond == NULL) { + errno = EINVAL; + rval = -1; + } else { + /* Block signals: */ + _thread_kern_sig_block(&status); - /* Process according to condition variable type: */ - switch (cond->c_type) { - /* Fast condition variable: */ - case COND_TYPE_FAST: - /* Queue the running thread for the condition variable: */ - _thread_queue_enq(&cond->c_queue, _thread_run); + /* Process according to condition variable type: */ + switch ((*cond)->c_type) { + /* Fast condition variable: */ + case COND_TYPE_FAST: + /* Queue the running thread for the condition variable: */ + _thread_queue_enq(&(*cond)->c_queue, _thread_run); - /* Unlock the mutex: */ - pthread_mutex_unlock(mutex); + /* Unlock the mutex: */ + pthread_mutex_unlock(mutex); - /* Schedule the next thread: */ - _thread_kern_sched_state(PS_COND_WAIT, __FILE__, __LINE__); + /* Schedule the next thread: */ + _thread_kern_sched_state(PS_COND_WAIT, __FILE__, __LINE__); - /* Block signals: */ - _thread_kern_sig_block(NULL); + /* Block signals: */ + _thread_kern_sig_block(NULL); - /* Lock the mutex: */ - rval = pthread_mutex_lock(mutex); - break; + /* Lock the mutex: */ + rval = pthread_mutex_lock(mutex); + break; + + /* Trap invalid condition variable types: */ + default: + /* Return an invalid argument error: */ + errno = EINVAL; + rval = -1; + break; + } - /* Trap invalid condition variable types: */ - default: - /* Return an invalid argument error: */ - _thread_seterrno(_thread_run, EINVAL); - rval = -1; - break; + /* Unblock signals: */ + _thread_kern_sig_unblock(status); } - /* Unblock signals: */ - _thread_kern_sig_unblock(status); - /* Return the completion status: */ return (rval); } @@ -161,60 +188,70 @@ pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex, int rval = 0; int status; - /* Block signals: */ - _thread_kern_sig_block(&status); - - /* Process according to condition variable type: */ - switch (cond->c_type) { - /* Fast condition variable: */ - case COND_TYPE_FAST: - /* Set the wakeup time: */ - _thread_run->wakeup_time.ts_sec = abstime->ts_sec; - _thread_run->wakeup_time.ts_nsec = abstime->ts_nsec; - - /* Reset the timeout flag: */ - _thread_run->timeout = 0; - - /* Queue the running thread for the condition variable: */ - _thread_queue_enq(&cond->c_queue, _thread_run); - - /* Unlock the mutex: */ - if ((rval = pthread_mutex_unlock(mutex)) != 0) { - /* - * Cannot unlock the mutex, so remove the running - * thread from the condition variable queue: - */ - _thread_queue_deq(&cond->c_queue); - } else { - /* Schedule the next thread: */ - _thread_kern_sched_state(PS_COND_WAIT, __FILE__, __LINE__); - - /* Block signals: */ - _thread_kern_sig_block(NULL); + if (cond == NULL || *cond == NULL) { + errno = EINVAL; + rval = -1; + } else { + /* Block signals: */ + _thread_kern_sig_block(&status); + + /* Process according to condition variable type: */ + switch ((*cond)->c_type) { + /* Fast condition variable: */ + case COND_TYPE_FAST: + /* Set the wakeup time: */ +#if defined(__FreeBSD__) + _thread_run->wakeup_time.ts_sec = abstime->ts_sec; + _thread_run->wakeup_time.ts_nsec = abstime->ts_nsec; +#else + _thread_run->wakeup_time.tv_sec = abstime->tv_sec; + _thread_run->wakeup_time.tv_nsec = abstime->tv_nsec; +#endif - /* Lock the mutex: */ - if ((rval = pthread_mutex_lock(mutex)) != 0) { - } - /* Check if the wait timed out: */ - else if (_thread_run->timeout) { - /* Return a timeout error: */ - _thread_seterrno(_thread_run, EAGAIN); - rval = -1; + /* Reset the timeout flag: */ + _thread_run->timeout = 0; + + /* Queue the running thread for the condition variable: */ + _thread_queue_enq(&(*cond)->c_queue, _thread_run); + + /* Unlock the mutex: */ + if ((rval = pthread_mutex_unlock(mutex)) != 0) { + /* + * Cannot unlock the mutex, so remove the running + * thread from the condition variable queue: + */ + _thread_queue_deq(&(*cond)->c_queue); + } else { + /* Schedule the next thread: */ + _thread_kern_sched_state(PS_COND_WAIT, __FILE__, __LINE__); + + /* Block signals: */ + _thread_kern_sig_block(NULL); + + /* Lock the mutex: */ + if ((rval = pthread_mutex_lock(mutex)) != 0) { + } + /* Check if the wait timed out: */ + else if (_thread_run->timeout) { + /* Return a timeout error: */ + errno = EAGAIN; + rval = -1; + } } + break; + + /* Trap invalid condition variable types: */ + default: + /* Return an invalid argument error: */ + errno = EINVAL; + rval = -1; + break; } - break; - /* Trap invalid condition variable types: */ - default: - /* Return an invalid argument error: */ - _thread_seterrno(_thread_run, EINVAL); - rval = -1; - break; + /* Unblock signals: */ + _thread_kern_sig_unblock(status); } - /* Unblock signals: */ - _thread_kern_sig_unblock(status); - /* Return the completion status: */ return (rval); } @@ -226,31 +263,36 @@ pthread_cond_signal(pthread_cond_t * cond) int status; pthread_t pthread; - /* Block signals: */ - _thread_kern_sig_block(&status); - - /* Process according to condition variable type: */ - switch (cond->c_type) { - /* Fast condition variable: */ - case COND_TYPE_FAST: - /* Bring the next thread off the condition queue: */ - if ((pthread = _thread_queue_deq(&cond->c_queue)) != NULL) { - /* Allow the thread to run: */ - pthread->state = PS_RUNNING; + if (cond == NULL || *cond == NULL) { + errno = EINVAL; + rval = -1; + } else { + /* Block signals: */ + _thread_kern_sig_block(&status); + + /* Process according to condition variable type: */ + switch ((*cond)->c_type) { + /* Fast condition variable: */ + case COND_TYPE_FAST: + /* Bring the next thread off the condition queue: */ + if ((pthread = _thread_queue_deq(&(*cond)->c_queue)) != NULL) { + /* Allow the thread to run: */ + pthread->state = PS_RUNNING; + } + break; + + /* Trap invalid condition variable types: */ + default: + /* Return an invalid argument error: */ + errno = EINVAL; + rval = -1; + break; } - break; - /* Trap invalid condition variable types: */ - default: - /* Return an invalid argument error: */ - _thread_seterrno(_thread_run, EINVAL); - rval = -1; - break; + /* Unblock signals: */ + _thread_kern_sig_unblock(status); } - /* Unblock signals: */ - _thread_kern_sig_unblock(status); - /* Return the completion status: */ return (rval); } @@ -266,11 +308,11 @@ pthread_cond_broadcast(pthread_cond_t * cond) _thread_kern_sig_block(&status); /* Process according to condition variable type: */ - switch (cond->c_type) { + switch ((*cond)->c_type) { /* Fast condition variable: */ case COND_TYPE_FAST: /* Enter a loop to bring all threads off the condition queue: */ - while ((pthread = _thread_queue_deq(&cond->c_queue)) != NULL) { + while ((pthread = _thread_queue_deq(&(*cond)->c_queue)) != NULL) { /* Allow the thread to run: */ pthread->state = PS_RUNNING; } @@ -279,7 +321,7 @@ pthread_cond_broadcast(pthread_cond_t * cond) /* Trap invalid condition variable types: */ default: /* Return an invalid argument error: */ - _thread_seterrno(_thread_run, EINVAL); + errno = EINVAL; rval = -1; break; } diff --git a/lib/libkse/thread/thr_create.c b/lib/libkse/thread/thr_create.c index e6db38144f64..1d57f8a1626d 100644 --- a/lib/libkse/thread/thr_create.c +++ b/lib/libkse/thread/thr_create.c @@ -49,6 +49,7 @@ _thread_create(pthread_t * thread, const pthread_attr_t * attr, int ret = 0; int status; pthread_t new_thread; + pthread_attr_t pattr; void *stack; /* Block signals: */ @@ -60,15 +61,17 @@ _thread_create(pthread_t * thread, const pthread_attr_t * attr, ret = EAGAIN; } else { /* Check if default thread attributes are required: */ - if (attr == NULL) { + if (attr == NULL || *attr == NULL) { /* Use the default thread attributes: */ - attr = &pthread_attr_default; + pattr = &pthread_attr_default; + } else { + pattr = *attr; } /* Check if a stack was specified in the thread attributes: */ - if ((stack = attr->stackaddr_attr) != NULL) { + if ((stack = pattr->stackaddr_attr) != NULL) { } /* Allocate memory for the stack: */ - else if ((stack = (void *) malloc(attr->stacksize_attr)) == NULL) { + else if ((stack = (void *) malloc(pattr->stacksize_attr)) == NULL) { /* Insufficient memory to create a thread: */ ret = EAGAIN; free(new_thread); @@ -83,7 +86,7 @@ _thread_create(pthread_t * thread, const pthread_attr_t * attr, new_thread->stack = stack; new_thread->start_routine = start_routine; new_thread->arg = arg; - if (attr->suspend == PTHREAD_CREATE_SUSPENDED) { + if (pattr->suspend == PTHREAD_CREATE_SUSPENDED) { new_thread->state = PS_SUSPENDED; } else { new_thread->state = PS_RUNNING; @@ -148,19 +151,19 @@ _thread_create(pthread_t * thread, const pthread_attr_t * attr, /* The stack starts high and builds down: */ #if defined(__FreeBSD__) - new_thread->saved_jmp_buf[0]._jb[2] = (int) (new_thread->stack + attr->stacksize_attr - sizeof(double)); + new_thread->saved_jmp_buf[0]._jb[2] = (int) (new_thread->stack + pattr->stacksize_attr - sizeof(double)); #elif defined(__NetBSD__) #if defined(__alpha) - new_thread->saved_jmp_buf[4 + R_SP] = (long) new_thread->stack + attr->stacksize_attr - sizeof(double); + new_thread->saved_jmp_buf[4 + R_SP] = (long) new_thread->stack + pattr->stacksize_attr - sizeof(double); #else - new_thread->saved_jmp_buf[2] = (long) new_thread->stack + attr->stacksize_attr - sizeof(double); + new_thread->saved_jmp_buf[2] = (long) new_thread->stack + pattr->stacksize_attr - sizeof(double); #endif #else #error "Don't recognize this operating system!" #endif /* Copy the thread attributes: */ - memcpy(&new_thread->attr, attr, sizeof(pthread_attr_t)); + memcpy(&new_thread->attr, pattr, sizeof(struct pthread_attr)); /* * Check if this thread is to inherit the scheduling diff --git a/lib/libkse/thread/thr_exit.c b/lib/libkse/thread/thr_exit.c index 292fce9c0fb8..60662060e01e 100644 --- a/lib/libkse/thread/thr_exit.c +++ b/lib/libkse/thread/thr_exit.c @@ -31,11 +31,49 @@ * */ #include +#include +#include #include #ifdef _THREAD_SAFE #include #include "pthread_private.h" +void _exit(int status) +{ + int flags; + int i; + struct itimerval itimer; + + /* Disable the interval timer: */ + itimer.it_interval.tv_sec = 0; + itimer.it_interval.tv_usec = 0; + itimer.it_value.tv_sec = 0; + itimer.it_value.tv_usec = 0; + setitimer(ITIMER_VIRTUAL, &itimer, NULL); + + /* Close the pthread kernel pipe: */ + _thread_sys_close(_thread_kern_pipe[0]); + _thread_sys_close(_thread_kern_pipe[1]); + + /* + * Enter a loop to set all file descriptors to blocking + * if they were not created as non-blocking: + */ + for (i = 0; i < _thread_dtablesize; i++) { + /* Check if this file descriptor is in use: */ + if (_thread_fd_table[i] != NULL && + !(_thread_fd_table[i]->flags & O_NONBLOCK)) { + /* Get the current flags: */ + flags = _thread_sys_fcntl(i, F_GETFL, NULL); + /* Clear the nonblocking file descriptor flag: */ + _thread_sys_fcntl(i, F_SETFL, flags & ~O_NONBLOCK); + } + } + + /* Call the _exit syscall: */ + _thread_sys__exit(status); +} + void _thread_exit(char *fname, int lineno, char *string) { diff --git a/lib/libkse/thread/thr_fcntl.c b/lib/libkse/thread/thr_fcntl.c index ae069b8e36a9..f83ee5098f37 100644 --- a/lib/libkse/thread/thr_fcntl.c +++ b/lib/libkse/thread/thr_fcntl.c @@ -31,6 +31,7 @@ * */ #include +#include #include #ifdef _THREAD_SAFE #include diff --git a/lib/libkse/thread/thr_fork.c b/lib/libkse/thread/thr_fork.c index 6e7ca0d43b44..19f674d39552 100644 --- a/lib/libkse/thread/thr_fork.c +++ b/lib/libkse/thread/thr_fork.c @@ -31,6 +31,8 @@ * */ #include +#include +#include #include #ifdef _THREAD_SAFE #include diff --git a/lib/libkse/thread/thr_init.c b/lib/libkse/thread/thr_init.c index 6139935176e1..d044063ce9d4 100644 --- a/lib/libkse/thread/thr_init.c +++ b/lib/libkse/thread/thr_init.c @@ -202,18 +202,6 @@ _thread_main(int argc, char *argv[], char *env) _thread_init(); return (main(argc, argv, env)); } -#else -/* - * Force our auto-initialization module to be pulled in from the library, - * by referencing a symbol that is defined in it. - * - * The auto-initialization module is a small C++ module. It has a static - * constructor that calls _thread_init() automatically, at the beginning - * of program execution. That eliminates the need for any special hooks - * in crt0.o. - */ -extern int _thread_autoinit_dummy_decl; -static int *_thread_autoinit_dummy_ref = &_thread_autoinit_dummy_decl; #endif #else /* diff --git a/lib/libkse/thread/thr_kern.c b/lib/libkse/thread/thr_kern.c index 35e8e29b9711..c6759cfe3b3d 100644 --- a/lib/libkse/thread/thr_kern.c +++ b/lib/libkse/thread/thr_kern.c @@ -250,18 +250,30 @@ __asm__("fnsave %0": :"m"(*fdata)); pthread->state == PS_FDW_WAIT || pthread->state == PS_SELECT_WAIT) { /* Check if this thread is to wait forever: */ +#if defined(__FreeBSD__) if (pthread->wakeup_time.ts_sec == -1) { +#else + if (pthread->wakeup_time.tv_sec == -1) { +#endif } /* * Check if this thread is to wakeup * immediately or if it is past its wakeup * time: */ +#if defined(__FreeBSD__) else if ((pthread->wakeup_time.ts_sec == 0 && pthread->wakeup_time.ts_nsec == 0) || (ts.ts_sec > pthread->wakeup_time.ts_sec) || ((ts.ts_sec == pthread->wakeup_time.ts_sec) && (ts.ts_nsec >= pthread->wakeup_time.ts_nsec))) { +#else + else if ((pthread->wakeup_time.tv_sec == 0 && + pthread->wakeup_time.tv_nsec == 0) || + (ts.tv_sec > pthread->wakeup_time.tv_sec) || + ((ts.tv_sec == pthread->wakeup_time.tv_sec) && + (ts.tv_nsec >= pthread->wakeup_time.tv_nsec))) { +#endif /* * Check if this thread is waiting on * select: @@ -364,9 +376,48 @@ __asm__("fnsave %0": :"m"(*fdata)); } /* * Enter a loop to look for the first thread of the highest - * priority: + * priority that is ready to run: */ for (pthread = _thread_link_list; pthread != NULL; pthread = pthread->nxt) { + /* Check if in single-threaded mode: */ + if (_thread_single != NULL) { + /* + * Check if the current thread is + * the thread for which single-threaded + * mode is enabled: + */ + if (pthread == _thread_single) { + /* + * This thread is allowed + * to run. + */ + } else { + /* + * Walk up the signal handler + * parent thread tree to see + * if the current thread is + * descended from the thread + * for which single-threaded + * mode is enabled. + */ + pthread_nxt = pthread; + while(pthread_nxt != NULL && + pthread_nxt != _thread_single) { + pthread_nxt = pthread->parent_thread; + } + /* + * Check if the current + * thread is not descended + * from the thread for which + * single-threaded mode is + * enabled. + */ + if (pthread_nxt == NULL) + /* Ignore this thread. */ + continue; + } + } + /* Check if the current thread is unable to run: */ if (pthread->state != PS_RUNNING) { } @@ -392,6 +443,45 @@ __asm__("fnsave %0": :"m"(*fdata)); * least recently. */ for (pthread = _thread_link_list; pthread != NULL; pthread = pthread->nxt) { + /* Check if in single-threaded mode: */ + if (_thread_single != NULL) { + /* + * Check if the current thread is + * the thread for which single-threaded + * mode is enabled: + */ + if (pthread == _thread_single) { + /* + * This thread is allowed + * to run. + */ + } else { + /* + * Walk up the signal handler + * parent thread tree to see + * if the current thread is + * descended from the thread + * for which single-threaded + * mode is enabled. + */ + pthread_nxt = pthread; + while(pthread_nxt != NULL && + pthread_nxt != _thread_single) { + pthread_nxt = pthread->parent_thread; + } + /* + * Check if the current + * thread is not descended + * from the thread for which + * single-threaded mode is + * enabled. + */ + if (pthread_nxt == NULL) + /* Ignore this thread. */ + continue; + } + } + /* Check if the current thread is unable to run: */ if (pthread->state != PS_RUNNING) { /* Ignore threads that are not ready to run. */ @@ -446,6 +536,45 @@ __asm__("fnsave %0": :"m"(*fdata)); * priority. 3. Became inactive least recently. */ for (pthread = _thread_link_list; pthread != NULL; pthread = pthread->nxt) { + /* Check if in single-threaded mode: */ + if (_thread_single != NULL) { + /* + * Check if the current thread is + * the thread for which single-threaded + * mode is enabled: + */ + if (pthread == _thread_single) { + /* + * This thread is allowed + * to run. + */ + } else { + /* + * Walk up the signal handler + * parent thread tree to see + * if the current thread is + * descended from the thread + * for which single-threaded + * mode is enabled. + */ + pthread_nxt = pthread; + while(pthread_nxt != NULL && + pthread_nxt != _thread_single) { + pthread_nxt = pthread->parent_thread; + } + /* + * Check if the current + * thread is not descended + * from the thread for which + * single-threaded mode is + * enabled. + */ + if (pthread_nxt == NULL) + /* Ignore this thread. */ + continue; + } + } + /* * Check if the current thread is unable to * run: @@ -565,22 +694,37 @@ __asm__("fnsave %0": :"m"(*fdata)); * Check if this thread is to * wait forever: */ +#if defined(__FreeBSD__) if (pthread->wakeup_time.ts_sec == -1) { +#else + if (pthread->wakeup_time.tv_sec == -1) { +#endif } /* * Check if this thread is to * wakeup immediately: */ +#if defined(__FreeBSD__) else if (pthread->wakeup_time.ts_sec == 0 && pthread->wakeup_time.ts_nsec == 0) { +#else + else if (pthread->wakeup_time.tv_sec == 0 && + pthread->wakeup_time.tv_nsec == 0) { +#endif } /* * Check if the current time * is after the wakeup time: */ +#if defined(__FreeBSD__) else if ((ts.ts_sec > pthread->wakeup_time.ts_sec) || ((ts.ts_sec == pthread->wakeup_time.ts_sec) && (ts.ts_nsec > pthread->wakeup_time.ts_nsec))) { +#else + else if ((ts.tv_sec > pthread->wakeup_time.tv_sec) || + ((ts.tv_sec == pthread->wakeup_time.tv_sec) && + (ts.tv_nsec > pthread->wakeup_time.tv_nsec))) { +#endif } else { /* * Calculate the time @@ -589,16 +733,26 @@ __asm__("fnsave %0": :"m"(*fdata)); * for the clock * resolution: */ +#if defined(__FreeBSD__) ts1.ts_sec = pthread->wakeup_time.ts_sec - ts.ts_sec; ts1.ts_nsec = pthread->wakeup_time.ts_nsec - ts.ts_nsec + CLOCK_RES_NSEC; +#else + ts1.tv_sec = pthread->wakeup_time.tv_sec - ts.tv_sec; + ts1.tv_nsec = pthread->wakeup_time.tv_nsec - ts.tv_nsec + + CLOCK_RES_NSEC; +#endif /* * Check for * underflow of the * nanosecond field: */ +#if defined(__FreeBSD__) if (ts1.ts_nsec < 0) { +#else + if (ts1.tv_nsec < 0) { +#endif /* * Allow for * the @@ -607,15 +761,24 @@ __asm__("fnsave %0": :"m"(*fdata)); * nanosecond * field: */ +#if defined(__FreeBSD__) ts1.ts_sec--; ts1.ts_nsec += 1000000000; +#else + ts1.tv_sec--; + ts1.tv_nsec += 1000000000; +#endif } /* * Check for overflow * of the nanosecond * field: */ +#if defined(__FreeBSD__) if (ts1.ts_nsec >= 1000000000) { +#else + if (ts1.tv_nsec >= 1000000000) { +#endif /* * Allow for * the @@ -624,8 +787,13 @@ __asm__("fnsave %0": :"m"(*fdata)); * nanosecond * field: */ +#if defined(__FreeBSD__) ts1.ts_sec++; ts1.ts_nsec -= 1000000000; +#else + ts1.tv_sec++; + ts1.tv_nsec -= 1000000000; +#endif } /* * Convert the @@ -1100,11 +1268,20 @@ _thread_kern_select(int wait_reqd) */ if (wait_reqd && settimeout) { /* Check if this thread wants to wait forever: */ +#if defined(__FreeBSD__) if (pthread->wakeup_time.ts_sec == -1) { +#else + if (pthread->wakeup_time.tv_sec == -1) { +#endif } /* Check if this thread doesn't want to wait at all: */ +#if defined(__FreeBSD__) else if (pthread->wakeup_time.ts_sec == 0 && pthread->wakeup_time.ts_nsec == 0) { +#else + else if (pthread->wakeup_time.tv_sec == 0 && + pthread->wakeup_time.tv_nsec == 0) { +#endif /* Override the caller's request to wait: */ wait_reqd = 0; } else { @@ -1112,33 +1289,57 @@ _thread_kern_select(int wait_reqd) * Calculate the time until this thread is * ready, allowing for the clock resolution: */ +#if defined(__FreeBSD__) ts1.ts_sec = pthread->wakeup_time.ts_sec - ts.ts_sec; ts1.ts_nsec = pthread->wakeup_time.ts_nsec - ts.ts_nsec + CLOCK_RES_NSEC; +#else + ts1.tv_sec = pthread->wakeup_time.tv_sec - ts.tv_sec; + ts1.tv_nsec = pthread->wakeup_time.tv_nsec - ts.tv_nsec + + CLOCK_RES_NSEC; +#endif /* * Check for underflow of the nanosecond * field: */ +#if defined(__FreeBSD__) if (ts1.ts_nsec < 0) { +#else + if (ts1.tv_nsec < 0) { +#endif /* * Allow for the underflow of the * nanosecond field: */ +#if defined(__FreeBSD__) ts1.ts_sec--; ts1.ts_nsec += 1000000000; +#else + ts1.tv_sec--; + ts1.tv_nsec += 1000000000; +#endif } /* * Check for overflow of the nanosecond * field: */ +#if defined(__FreeBSD__) if (ts1.ts_nsec >= 1000000000) { +#else + if (ts1.tv_nsec >= 1000000000) { +#endif /* * Allow for the overflow of the * nanosecond field: */ +#if defined(__FreeBSD__) ts1.ts_sec++; ts1.ts_nsec -= 1000000000; +#else + ts1.tv_sec++; + ts1.tv_nsec -= 1000000000; +#endif } /* * Convert the timespec structure to a @@ -1552,28 +1753,56 @@ _thread_kern_set_timeout(struct timespec * timeout) * Set the wakeup time to something that can be recognised as * different to an actual time of day: */ +#if defined(__FreeBSD__) _thread_run->wakeup_time.ts_sec = -1; _thread_run->wakeup_time.ts_nsec = -1; +#else + _thread_run->wakeup_time.tv_sec = -1; + _thread_run->wakeup_time.tv_nsec = -1; +#endif } /* Check if no waiting is required: */ +#if defined(__FreeBSD__) else if (timeout->ts_sec == 0 && timeout->ts_nsec == 0) { +#else + else if (timeout->tv_sec == 0 && timeout->tv_nsec == 0) { +#endif /* Set the wake up time to 'immediately': */ +#if defined(__FreeBSD__) _thread_run->wakeup_time.ts_sec = 0; _thread_run->wakeup_time.ts_nsec = 0; +#else + _thread_run->wakeup_time.tv_sec = 0; + _thread_run->wakeup_time.tv_nsec = 0; +#endif } else { /* Get the current time: */ gettimeofday(&tv, NULL); TIMEVAL_TO_TIMESPEC(&tv, ¤t_time); /* Calculate the time for the current thread to wake up: */ +#if defined(__FreeBSD__) _thread_run->wakeup_time.ts_sec = current_time.ts_sec + timeout->ts_sec; _thread_run->wakeup_time.ts_nsec = current_time.ts_nsec + timeout->ts_nsec; +#else + _thread_run->wakeup_time.tv_sec = current_time.tv_sec + timeout->tv_sec; + _thread_run->wakeup_time.tv_nsec = current_time.tv_nsec + timeout->tv_nsec; +#endif /* Check if the nanosecond field needs to wrap: */ +#if defined(__FreeBSD__) if (_thread_run->wakeup_time.ts_nsec >= 1000000000) { +#else + if (_thread_run->wakeup_time.tv_nsec >= 1000000000) { +#endif /* Wrap the nanosecond field: */ +#if defined(__FreeBSD__) _thread_run->wakeup_time.ts_sec += 1; _thread_run->wakeup_time.ts_nsec -= 1000000000; +#else + _thread_run->wakeup_time.tv_sec += 1; + _thread_run->wakeup_time.tv_nsec -= 1000000000; +#endif } } return; diff --git a/lib/libkse/thread/thr_multi_np.c b/lib/libkse/thread/thr_multi_np.c new file mode 100644 index 000000000000..64f360fdacfe --- /dev/null +++ b/lib/libkse/thread/thr_multi_np.c @@ -0,0 +1,44 @@ +/* + * Copyright (c) 1996 John Birrell . + * 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 +#ifdef _THREAD_SAFE +#include +#include "pthread_private.h" + +int pthread_multi_np() +{ + /* Return to multi-threaded scheduling mode: */ + _thread_single = NULL; + return(0); +} +#endif diff --git a/lib/libkse/thread/thr_mutex.c b/lib/libkse/thread/thr_mutex.c index 0fc9fbba3e50..dc9be3c5ff78 100644 --- a/lib/libkse/thread/thr_mutex.c +++ b/lib/libkse/thread/thr_mutex.c @@ -41,35 +41,95 @@ pthread_mutex_init(pthread_mutex_t * mutex, const pthread_mutexattr_t * mutex_attr) { enum pthread_mutextype type; + pthread_mutex_t pmutex; int ret = 0; int status; - /* Check if the mutex attributes specify some mutex other than fast: */ - if (mutex_attr != NULL && mutex_attr->m_type != MUTEX_TYPE_FAST) { - /* Check if the mutex type is out of range: */ - if (mutex_attr->m_type >= MUTEX_TYPE_MAX) { + if (mutex == NULL) { + errno = EINVAL; + ret = -1; + } else { + /* Check if default mutex attributes: */ + if (mutex_attr == NULL || *mutex_attr == NULL) { + /* Default to a fast mutex: */ + type = MUTEX_TYPE_FAST; + } else if ((*mutex_attr)->m_type >= MUTEX_TYPE_MAX) { /* Return an invalid argument error: */ - _thread_seterrno(_thread_run, EINVAL); + errno = EINVAL; ret = -1; } else { /* Use the requested mutex type: */ - type = mutex_attr->m_type; + type = (*mutex_attr)->m_type; + } + + /* Check no errors so far: */ + if (ret == 0) { + if ((pmutex = (pthread_mutex_t) malloc(sizeof(struct pthread_mutex))) == NULL) { + errno = ENOMEM; + ret = -1; + } else { + /* Reset the mutex flags: */ + pmutex->m_flags = 0; + + /* Block signals: */ + _thread_kern_sig_block(&status); + + /* Process according to mutex type: */ + switch (type) { + /* Fast mutex: */ + case MUTEX_TYPE_FAST: + /* Nothing to do here. */ + break; + + /* Counting mutex: */ + case MUTEX_TYPE_COUNTING_FAST: + /* Reset the mutex count: */ + pmutex->m_data.m_count = 0; + break; + + /* Trap invalid mutex types: */ + default: + /* Return an invalid argument error: */ + errno = EINVAL; + ret = -1; + break; + } + if (ret == 0) { + /* Initialise the rest of the mutex: */ + _thread_queue_init(&pmutex->m_queue); + pmutex->m_flags |= MUTEX_FLAGS_INITED; + pmutex->m_owner = NULL; + pmutex->m_type = type; + *mutex = pmutex; + } else { + free(pmutex); + *mutex = NULL; + } + + /* Unblock signals: */ + _thread_kern_sig_unblock(status); + } } - } else { - /* Default to a fast mutex: */ - type = MUTEX_TYPE_FAST; } + /* Return the completion status: */ + return (ret); +} - /* Check no errors so far: */ - if (ret == 0) { - /* Reset the mutex flags: */ - mutex->m_flags = 0; +int +pthread_mutex_destroy(pthread_mutex_t * mutex) +{ + int ret = 0; + int status; + if (mutex == NULL || *mutex == NULL) { + errno = EINVAL; + ret = -1; + } else { /* Block signals: */ _thread_kern_sig_block(&status); /* Process according to mutex type: */ - switch (type) { + switch ((*mutex)->m_type) { /* Fast mutex: */ case MUTEX_TYPE_FAST: /* Nothing to do here. */ @@ -78,67 +138,25 @@ pthread_mutex_init(pthread_mutex_t * mutex, /* Counting mutex: */ case MUTEX_TYPE_COUNTING_FAST: /* Reset the mutex count: */ - mutex->m_data.m_count = 0; + (*mutex)->m_data.m_count = 0; break; - /* Trap invalid mutex types: */ + /* Trap undefined mutex types: */ default: /* Return an invalid argument error: */ - _thread_seterrno(_thread_run, EINVAL); + errno = EINVAL; ret = -1; break; } - /* Initialise the rest of the mutex: */ - _thread_queue_init(&mutex->m_queue); - mutex->m_flags |= MUTEX_FLAGS_INITED; - mutex->m_owner = NULL; - mutex->m_type = type; + /* Clean up the mutex in case that others want to use it: */ + _thread_queue_init(&(*mutex)->m_queue); + (*mutex)->m_owner = NULL; + (*mutex)->m_flags = 0; /* Unblock signals: */ _thread_kern_sig_unblock(status); } - /* Return the completion status: */ - return (ret); -} - -int -pthread_mutex_destroy(pthread_mutex_t * mutex) -{ - int ret = 0; - int status; - - /* Block signals: */ - _thread_kern_sig_block(&status); - - /* Process according to mutex type: */ - switch (mutex->m_type) { - /* Fast mutex: */ - case MUTEX_TYPE_FAST: - /* Nothing to do here. */ - break; - - /* Counting mutex: */ - case MUTEX_TYPE_COUNTING_FAST: - /* Reset the mutex count: */ - mutex->m_data.m_count = 0; - break; - - /* Trap undefined mutex types: */ - default: - /* Return an invalid argument error: */ - _thread_seterrno(_thread_run, EINVAL); - ret = -1; - break; - } - - /* Clean up the mutex in case that others want to use it: */ - _thread_queue_init(&mutex->m_queue); - mutex->m_owner = NULL; - mutex->m_flags = 0; - - /* Unblock signals: */ - _thread_kern_sig_unblock(status); /* Return the completion status: */ return (ret); @@ -150,56 +168,61 @@ pthread_mutex_trylock(pthread_mutex_t * mutex) int ret = 0; int status; - /* Block signals: */ - _thread_kern_sig_block(&status); + if (mutex == NULL || *mutex == NULL) { + errno = EINVAL; + ret = -1; + } else { + /* Block signals: */ + _thread_kern_sig_block(&status); - /* Process according to mutex type: */ - switch (mutex->m_type) { + /* Process according to mutex type: */ + switch ((*mutex)->m_type) { /* Fast mutex: */ - case MUTEX_TYPE_FAST: - /* Check if this mutex is not locked: */ - if (mutex->m_owner == NULL) { - /* Lock the mutex for the running thread: */ - mutex->m_owner = _thread_run; - } else { - /* Return a busy error: */ - _thread_seterrno(_thread_run, EBUSY); - ret = -1; - } - break; - - /* Counting mutex: */ - case MUTEX_TYPE_COUNTING_FAST: - /* Check if this mutex is locked: */ - if (mutex->m_owner != NULL) { - /* - * Check if the mutex is locked by the running - * thread: - */ - if (mutex->m_owner == _thread_run) { - /* Increment the lock count: */ - mutex->m_data.m_count++; + case MUTEX_TYPE_FAST: + /* Check if this mutex is not locked: */ + if ((*mutex)->m_owner == NULL) { + /* Lock the mutex for the running thread: */ + (*mutex)->m_owner = _thread_run; } else { /* Return a busy error: */ - _thread_seterrno(_thread_run, EBUSY); + errno = EBUSY; ret = -1; } - } else { - /* Lock the mutex for the running thread: */ - mutex->m_owner = _thread_run; - } - break; + break; + + /* Counting mutex: */ + case MUTEX_TYPE_COUNTING_FAST: + /* Check if this mutex is locked: */ + if ((*mutex)->m_owner != NULL) { + /* + * Check if the mutex is locked by the running + * thread: + */ + if ((*mutex)->m_owner == _thread_run) { + /* Increment the lock count: */ + (*mutex)->m_data.m_count++; + } else { + /* Return a busy error: */ + errno = EBUSY; + ret = -1; + } + } else { + /* Lock the mutex for the running thread: */ + (*mutex)->m_owner = _thread_run; + } + break; /* Trap invalid mutex types: */ - default: - /* Return an invalid argument error: */ - _thread_seterrno(_thread_run, EINVAL); - ret = -1; - break; - } + default: + /* Return an invalid argument error: */ + errno = EINVAL; + ret = -1; + break; + } - /* Unblock signals: */ - _thread_kern_sig_unblock(status); + /* Unblock signals: */ + _thread_kern_sig_unblock(status); + } /* Return the completion status: */ return (ret); @@ -211,81 +234,86 @@ pthread_mutex_lock(pthread_mutex_t * mutex) int ret = 0; int status; - /* Block signals: */ - _thread_kern_sig_block(&status); + if (mutex == NULL || *mutex == NULL) { + errno = EINVAL; + ret = -1; + } else { + /* Block signals: */ + _thread_kern_sig_block(&status); - /* Process according to mutex type: */ - switch (mutex->m_type) { + /* Process according to mutex type: */ + switch ((*mutex)->m_type) { /* Fast mutexes do not check for any error conditions: */ - case MUTEX_TYPE_FAST: - /* - * Enter a loop to wait for the mutex to be locked by the - * current thread: - */ - while (mutex->m_owner != _thread_run) { - /* Check if the mutex is not locked: */ - if (mutex->m_owner == NULL) { - /* Lock the mutex for this thread: */ - mutex->m_owner = _thread_run; - } else { - /* - * Join the queue of threads waiting to lock - * the mutex: - */ - _thread_queue_enq(&mutex->m_queue, _thread_run); - - /* Block signals: */ - _thread_kern_sched_state(PS_MUTEX_WAIT, __FILE__, __LINE__); - - /* Block signals: */ - _thread_kern_sig_block(NULL); + case MUTEX_TYPE_FAST: + /* + * Enter a loop to wait for the mutex to be locked by the + * current thread: + */ + while ((*mutex)->m_owner != _thread_run) { + /* Check if the mutex is not locked: */ + if ((*mutex)->m_owner == NULL) { + /* Lock the mutex for this thread: */ + (*mutex)->m_owner = _thread_run; + } else { + /* + * Join the queue of threads waiting to lock + * the mutex: + */ + _thread_queue_enq(&(*mutex)->m_queue, _thread_run); + + /* Block signals: */ + _thread_kern_sched_state(PS_MUTEX_WAIT, __FILE__, __LINE__); + + /* Block signals: */ + _thread_kern_sig_block(NULL); + } } - } - break; + break; /* Counting mutex: */ - case MUTEX_TYPE_COUNTING_FAST: - /* - * Enter a loop to wait for the mutex to be locked by the - * current thread: - */ - while (mutex->m_owner != _thread_run) { - /* Check if the mutex is not locked: */ - if (mutex->m_owner == NULL) { - /* Lock the mutex for this thread: */ - mutex->m_owner = _thread_run; - - /* Reset the lock count for this mutex: */ - mutex->m_data.m_count = 0; - } else { - /* - * Join the queue of threads waiting to lock - * the mutex: - */ - _thread_queue_enq(&mutex->m_queue, _thread_run); - - /* Block signals: */ - _thread_kern_sched_state(PS_MUTEX_WAIT, __FILE__, __LINE__); - - /* Block signals: */ - _thread_kern_sig_block(NULL); + case MUTEX_TYPE_COUNTING_FAST: + /* + * Enter a loop to wait for the mutex to be locked by the + * current thread: + */ + while ((*mutex)->m_owner != _thread_run) { + /* Check if the mutex is not locked: */ + if ((*mutex)->m_owner == NULL) { + /* Lock the mutex for this thread: */ + (*mutex)->m_owner = _thread_run; + + /* Reset the lock count for this mutex: */ + (*mutex)->m_data.m_count = 0; + } else { + /* + * Join the queue of threads waiting to lock + * the mutex: + */ + _thread_queue_enq(&(*mutex)->m_queue, _thread_run); + + /* Block signals: */ + _thread_kern_sched_state(PS_MUTEX_WAIT, __FILE__, __LINE__); + + /* Block signals: */ + _thread_kern_sig_block(NULL); + } } - } - /* Increment the lock count for this mutex: */ - mutex->m_data.m_count++; - break; + /* Increment the lock count for this mutex: */ + (*mutex)->m_data.m_count++; + break; /* Trap invalid mutex types: */ - default: - /* Return an invalid argument error: */ - _thread_seterrno(_thread_run, EINVAL); - ret = -1; - break; - } + default: + /* Return an invalid argument error: */ + errno = EINVAL; + ret = -1; + break; + } - /* Unblock signals: */ - _thread_kern_sig_unblock(status); + /* Unblock signals: */ + _thread_kern_sig_unblock(status); + } /* Return the completion status: */ return (ret); @@ -297,63 +325,68 @@ pthread_mutex_unlock(pthread_mutex_t * mutex) int ret = 0; int status; - /* Block signals: */ - _thread_kern_sig_block(&status); + if (mutex == NULL || *mutex == NULL) { + errno = EINVAL; + ret = -1; + } else { + /* Block signals: */ + _thread_kern_sig_block(&status); - /* Process according to mutex type: */ - switch (mutex->m_type) { + /* Process according to mutex type: */ + switch ((*mutex)->m_type) { /* Fast mutexes do not check for any error conditions: */ - case MUTEX_TYPE_FAST: - /* Check if the running thread is not the owner of the mutex: */ - if (mutex->m_owner != _thread_run) { - /* Return an invalid argument error: */ - _thread_seterrno(_thread_run, EINVAL); - ret = -1; - } - /* - * Get the next thread from the queue of threads waiting on - * the mutex: - */ - else if ((mutex->m_owner = _thread_queue_deq(&mutex->m_queue)) != NULL) { - /* Allow the new owner of the mutex to run: */ - mutex->m_owner->state = PS_RUNNING; - } - break; + case MUTEX_TYPE_FAST: + /* Check if the running thread is not the owner of the mutex: */ + if ((*mutex)->m_owner != _thread_run) { + /* Return an invalid argument error: */ + errno = EINVAL; + ret = -1; + } + /* + * Get the next thread from the queue of threads waiting on + * the mutex: + */ + else if (((*mutex)->m_owner = _thread_queue_deq(&(*mutex)->m_queue)) != NULL) { + /* Allow the new owner of the mutex to run: */ + (*mutex)->m_owner->state = PS_RUNNING; + } + break; /* Counting mutex: */ - case MUTEX_TYPE_COUNTING_FAST: - /* Check if the running thread is not the owner of the mutex: */ - if (mutex->m_owner != _thread_run) { + case MUTEX_TYPE_COUNTING_FAST: + /* Check if the running thread is not the owner of the mutex: */ + if ((*mutex)->m_owner != _thread_run) { + /* Return an invalid argument error: */ + errno = EINVAL; + ret = -1; + } + /* Check if there are still counts: */ + else if ((*mutex)->m_data.m_count) { + /* Decrement the count: */ + (*mutex)->m_data.m_count--; + } + /* + * Get the next thread from the queue of threads waiting on + * the mutex: + */ + else if (((*mutex)->m_owner = _thread_queue_deq(&(*mutex)->m_queue)) != NULL) { + /* Allow the new owner of the mutex to run: */ + (*mutex)->m_owner->state = PS_RUNNING; + } + break; + + /* Trap invalid mutex types: */ + default: /* Return an invalid argument error: */ - _thread_seterrno(_thread_run, EINVAL); + errno = EINVAL; ret = -1; + break; } - /* Check if there are still counts: */ - else if (mutex->m_data.m_count) { - /* Decrement the count: */ - mutex->m_data.m_count--; - } - /* - * Get the next thread from the queue of threads waiting on - * the mutex: - */ - else if ((mutex->m_owner = _thread_queue_deq(&mutex->m_queue)) != NULL) { - /* Allow the new owner of the mutex to run: */ - mutex->m_owner->state = PS_RUNNING; - } - break; - /* Trap invalid mutex types: */ - default: - /* Return an invalid argument error: */ - _thread_seterrno(_thread_run, EINVAL); - ret = -1; - break; + /* Unblock signals: */ + _thread_kern_sig_unblock(status); } - /* Unblock signals: */ - _thread_kern_sig_unblock(status); - /* Return the completion status: */ return (ret); } diff --git a/lib/libkse/thread/thr_nanosleep.c b/lib/libkse/thread/thr_nanosleep.c index e91ca5765113..58ade9888c35 100644 --- a/lib/libkse/thread/thr_nanosleep.c +++ b/lib/libkse/thread/thr_nanosleep.c @@ -31,6 +31,7 @@ * */ #include +#include #ifdef _THREAD_SAFE #include #include "pthread_private.h" @@ -38,50 +39,138 @@ int nanosleep(struct timespec * time_to_sleep, struct timespec * time_remaining) { + int ret = 0; struct timespec current_time; struct timespec current_time1; + struct timespec remaining_time; struct timeval tv; - /* Get the current time: */ - gettimeofday(&tv, NULL); - TIMEVAL_TO_TIMESPEC(&tv, ¤t_time); + /* Check if the time to sleep is legal: */ +#if defined(__FreeBSD__) + if (time_to_sleep == NULL || time_to_sleep->ts_nsec < 0 || time_to_sleep->ts_nsec > 1000000000) { +#else + if (time_to_sleep == NULL || time_to_sleep->tv_nsec < 0 || time_to_sleep->tv_nsec > 1000000000) { +#endif + /* Return an EINVAL error : */ + errno = EINVAL; + ret = -1; + } else { + /* Get the current time: */ + gettimeofday(&tv, NULL); + TIMEVAL_TO_TIMESPEC(&tv, ¤t_time); - /* Calculate the time for the current thread to wake up: */ - _thread_run->wakeup_time.ts_sec = current_time.ts_sec + time_to_sleep->ts_sec; - _thread_run->wakeup_time.ts_nsec = current_time.ts_nsec + time_to_sleep->ts_nsec; + /* Calculate the time for the current thread to wake up: */ +#if defined(__FreeBSD__) + _thread_run->wakeup_time.ts_sec = current_time.ts_sec + time_to_sleep->ts_sec; + _thread_run->wakeup_time.ts_nsec = current_time.ts_nsec + time_to_sleep->ts_nsec; +#else + _thread_run->wakeup_time.tv_sec = current_time.tv_sec + time_to_sleep->tv_sec; + _thread_run->wakeup_time.tv_nsec = current_time.tv_nsec + time_to_sleep->tv_nsec; +#endif - /* Check if the nanosecond field has overflowed: */ - if (_thread_run->wakeup_time.ts_nsec >= 1000000000) { - /* Wrap the nanosecond field: */ - _thread_run->wakeup_time.ts_sec += 1; - _thread_run->wakeup_time.ts_nsec -= 1000000000; - } - /* Reschedule the current thread to sleep: */ - _thread_kern_sched_state(PS_SLEEP_WAIT, __FILE__, __LINE__); + /* Check if the nanosecond field has overflowed: */ +#if defined(__FreeBSD__) + if (_thread_run->wakeup_time.ts_nsec >= 1000000000) { +#else + if (_thread_run->wakeup_time.tv_nsec >= 1000000000) { +#endif + /* Wrap the nanosecond field: */ +#if defined(__FreeBSD__) + _thread_run->wakeup_time.ts_sec += 1; + _thread_run->wakeup_time.ts_nsec -= 1000000000; +#else + _thread_run->wakeup_time.tv_sec += 1; + _thread_run->wakeup_time.tv_nsec -= 1000000000; +#endif + } + + /* Reschedule the current thread to sleep: */ + _thread_kern_sched_state(PS_SLEEP_WAIT, __FILE__, __LINE__); - /* Check if the time remaining is to be returned: */ - if (time_remaining != NULL) { /* Get the current time: */ gettimeofday(&tv, NULL); TIMEVAL_TO_TIMESPEC(&tv, ¤t_time1); - /* Return the actual time slept: */ - time_remaining->ts_sec = time_to_sleep->ts_sec + current_time1.ts_sec - current_time.ts_sec; - time_remaining->ts_nsec = time_to_sleep->ts_nsec + current_time1.ts_nsec - current_time.ts_nsec; + /* Calculate the remaining time to sleep: */ +#if defined(__FreeBSD__) + remaining_time.ts_sec = time_to_sleep->ts_sec + current_time.ts_sec - current_time1.ts_sec; + remaining_time.ts_nsec = time_to_sleep->ts_nsec + current_time.ts_nsec - current_time1.ts_nsec; +#else + remaining_time.tv_sec = time_to_sleep->tv_sec + current_time.tv_sec - current_time1.tv_sec; + remaining_time.tv_nsec = time_to_sleep->tv_nsec + current_time.tv_nsec - current_time1.tv_nsec; +#endif /* Check if the nanosecond field has underflowed: */ - if (time_remaining->ts_nsec < 0) { +#if defined(__FreeBSD__) + if (remaining_time.ts_nsec < 0) { +#else + if (remaining_time.tv_nsec < 0) { +#endif /* Handle the underflow: */ - time_remaining->ts_sec -= 1; - time_remaining->ts_nsec += 1000000000; +#if defined(__FreeBSD__) + remaining_time.ts_sec -= 1; + remaining_time.ts_nsec += 1000000000; +#else + remaining_time.tv_sec -= 1; + remaining_time.tv_nsec += 1000000000; +#endif } + + /* Check if the nanosecond field has overflowed: */ +#if defined(__FreeBSD__) + if (remaining_time.ts_nsec >= 1000000000) { +#else + if (remaining_time.tv_nsec >= 1000000000) { +#endif + /* Handle the overflow: */ +#if defined(__FreeBSD__) + remaining_time.ts_sec += 1; + remaining_time.ts_nsec -= 1000000000; +#else + remaining_time.tv_sec += 1; + remaining_time.tv_nsec -= 1000000000; +#endif + } + /* Check if the sleep was longer than the required time: */ - if (time_remaining->ts_sec < 0) { - /* Reset the time teft: */ - time_remaining->ts_sec = 0; - time_remaining->ts_nsec = 0; +#if defined(__FreeBSD__) + if (remaining_time.ts_sec < 0) { +#else + if (remaining_time.tv_sec < 0) { +#endif + /* Reset the time left: */ +#if defined(__FreeBSD__) + remaining_time.ts_sec = 0; + remaining_time.ts_nsec = 0; +#else + remaining_time.tv_sec = 0; + remaining_time.tv_nsec = 0; +#endif + } + + /* Check if the time remaining is to be returned: */ + if (time_remaining != NULL) { + /* Return the actual time slept: */ +#if defined(__FreeBSD__) + time_remaining->ts_sec = remaining_time.ts_sec; + time_remaining->ts_nsec = remaining_time.ts_nsec; +#else + time_remaining->tv_sec = remaining_time.tv_sec; + time_remaining->tv_nsec = remaining_time.tv_nsec; +#endif + } + + /* Check if the entire sleep was not completed: */ +#if defined(__FreeBSD__) + if (remaining_time.ts_nsec != 0 || remaining_time.ts_sec != 0) { +#else + if (remaining_time.tv_nsec != 0 || remaining_time.tv_sec != 0) { +#endif + /* Return an EINTR error : */ + errno = EINTR; + ret = -1; } } - return (0); + return (ret); } #endif diff --git a/lib/libkse/thread/thr_open.c b/lib/libkse/thread/thr_open.c index ead651ea3d9e..00bb91335755 100644 --- a/lib/libkse/thread/thr_open.c +++ b/lib/libkse/thread/thr_open.c @@ -31,6 +31,7 @@ * */ #include +#include #include #include #ifdef _THREAD_SAFE @@ -55,8 +56,8 @@ open(const char *path, int flags,...) mode = va_arg(ap, int); va_end(ap); } - /* Open the file, forcing it to use non-blocking I/O operations: */ - if ((fd = _thread_sys_open(path, flags | O_NONBLOCK, mode)) < 0) { + /* Open the file: */ + if ((fd = _thread_sys_open(path, flags, mode)) < 0) { } /* Initialise the file descriptor table entry: */ else if (_thread_fd_table_init(fd) != 0) { @@ -65,12 +66,6 @@ open(const char *path, int flags,...) /* Reset the file descriptor: */ fd = -1; - } else { - /* - * Save the file open flags so that they can be checked - * later: - */ - _thread_fd_table[fd]->flags = flags; } /* Unblock signals: */ diff --git a/lib/libkse/thread/thr_private.h b/lib/libkse/thread/thr_private.h index fc8ba276a42c..48e70ce00d1e 100644 --- a/lib/libkse/thread/thr_private.h +++ b/lib/libkse/thread/thr_private.h @@ -58,6 +58,129 @@ */ #define PANIC(string) _thread_exit(__FILE__,__LINE__,string) +/* + * Queue definitions. + */ +struct pthread_queue { + struct pthread *q_next; + struct pthread *q_last; + void *q_data; +}; + +/* + * Static queue initialization values. + */ +#define PTHREAD_QUEUE_INITIALIZER { NULL, NULL, NULL } + +/* + * Mutex definitions. + */ +enum pthread_mutextype { + MUTEX_TYPE_FAST = 1, + MUTEX_TYPE_COUNTING_FAST = 2, /* Recursive */ + MUTEX_TYPE_MAX +}; + +union pthread_mutex_data { + void *m_ptr; + int m_count; +}; + +struct pthread_mutex { + enum pthread_mutextype m_type; + struct pthread_queue m_queue; + struct pthread *m_owner; + union pthread_mutex_data m_data; + long m_flags; +}; + +/* + * Flags for mutexes. + */ +#define MUTEX_FLAGS_PRIVATE 0x01 +#define MUTEX_FLAGS_INITED 0x02 +#define MUTEX_FLAGS_BUSY 0x04 + +/* + * Static mutex initialization values. + */ +#define PTHREAD_MUTEX_INITIALIZER \ + { MUTEX_TYPE_FAST, PTHREAD_QUEUE_INITIALIZER, \ + NULL, { NULL }, MUTEX_FLAGS_INITED } + +struct pthread_mutex_attr { + enum pthread_mutextype m_type; + long m_flags; +}; + +/* + * Condition variable definitions. + */ +enum pthread_cond_type { + COND_TYPE_FAST, + COND_TYPE_MAX +}; + +struct pthread_cond { + enum pthread_cond_type c_type; + struct pthread_queue c_queue; + void *c_data; + long c_flags; +}; + +struct pthread_cond_attr { + enum pthread_cond_type c_type; + long c_flags; +}; + +/* + * Flags for condition variables. + */ +#define COND_FLAGS_PRIVATE 0x01 +#define COND_FLAGS_INITED 0x02 +#define COND_FLAGS_BUSY 0x04 + +/* + * Static cond initialization values. + */ +#define PTHREAD_COND_INITIALIZER \ + { COND_TYPE_FAST, PTHREAD_QUEUE_INITIALIZER, NULL, COND_FLAGS_INITED } + +/* + * Cleanup definitions. + */ +struct pthread_cleanup { + struct pthread_cleanup *next; + void (*routine) (); + void *routine_arg; +}; + +/* + * Scheduling definitions. + */ +enum schedparam_policy { + SCHED_RR, + SCHED_IO, + SCHED_FIFO, + SCHED_OTHER +}; + +struct pthread_attr { + enum schedparam_policy schedparam_policy; + int prio; + int suspend; + int flags; + void *arg_attr; + void (*cleanup_attr) (); + void *stackaddr_attr; + size_t stacksize_attr; +}; + +struct sched_param { + int prio; + void *no_data; +}; + /* * Thread creation state attributes. */ @@ -67,14 +190,11 @@ /* * Miscellaneous definitions. */ -#define PTHREAD_STACK_MIN 1024 #define PTHREAD_STACK_DEFAULT 65536 -#define PTHREAD_DATAKEYS_MAX 256 #define PTHREAD_DEFAULT_PRIORITY 64 #define PTHREAD_MAX_PRIORITY 126 #define PTHREAD_MIN_PRIORITY 0 #define _POSIX_THREAD_ATTR_STACKSIZE -#define _POSIX_THREAD_DESTRUTOR_ITERATIONS 4 /* * Clock resolution in nanoseconds. @@ -190,10 +310,10 @@ struct pthread { * Thread start routine, argument, stack pointer and thread * attributes. */ - void *(*start_routine)(void *); - void *arg; - void *stack; - pthread_attr_t attr; + void *(*start_routine)(void *); + void *arg; + void *stack; + struct pthread_attr attr; /* * Thread-specific signal handler interface: @@ -319,6 +439,17 @@ SCLASS struct pthread *_thread_run ; #endif +/* + * Ptr to the thread running in single-threaded mode or NULL if + * running multi-threaded (default POSIX behaviour). + */ +SCLASS struct pthread *_thread_single +#ifdef GLOBAL_PTHREAD_PRIVATE += NULL; +#else +; +#endif + /* Ptr to the first thread in the thread linked list: */ SCLASS struct pthread *_thread_link_list #ifdef GLOBAL_PTHREAD_PRIVATE @@ -372,7 +503,7 @@ SCLASS struct pthread *_thread_initial #endif /* Default thread attributes: */ -SCLASS pthread_attr_t pthread_attr_default +SCLASS struct pthread_attr pthread_attr_default #ifdef GLOBAL_PTHREAD_PRIVATE = { SCHED_RR, PTHREAD_DEFAULT_PRIORITY, PTHREAD_CREATE_RUNNING, PTHREAD_CREATE_JOINABLE, NULL, NULL, NULL, PTHREAD_STACK_DEFAULT }; @@ -570,6 +701,7 @@ pid_t _thread_sys_fork(void); pid_t _thread_sys_tcgetpgrp(int); ssize_t _thread_sys_read(int, void *, size_t); ssize_t _thread_sys_write(int, const void *, size_t); +void _thread_sys__exit(int); #endif /* #include */ diff --git a/lib/libkse/thread/thr_resume_np.c b/lib/libkse/thread/thr_resume_np.c new file mode 100644 index 000000000000..a254814163af --- /dev/null +++ b/lib/libkse/thread/thr_resume_np.c @@ -0,0 +1,70 @@ +/* + * Copyright (c) 1995 John Birrell . + * 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 +#ifdef _THREAD_SAFE +#include +#include "pthread_private.h" + +int +pthread_resume_np(pthread_t thread) +{ + int ret = -1; + pthread_t pthread; + /* + * Search for the thread in the linked list. + */ + for (pthread = _thread_link_list; pthread != NULL && ret == -1; pthread = pthread->nxt) { + /* Is this the thread? */ + if (pthread == thread) { + /* Found the thread. Is it suspended? */ + if (pthread->state == PS_SUSPENDED) { + /* Allow the thread to run. */ + pthread->state = PS_RUNNING; + ret = 0; + } else if (pthread->state == PS_RUNNING) { + /* Thread is already running. */ + ret = 0; + } else { + /* Thread is in some other state. */ + _thread_seterrno(_thread_run,EINVAL); + } + } + } + /* Check if thread was not found. */ + if (ret == -1) { + /* No such thread */ + _thread_seterrno(_thread_run,ESRCH); + } + return(ret); +} +#endif diff --git a/lib/libkse/thread/thr_select.c b/lib/libkse/thread/thr_select.c index b3f548373e99..7db3ed2f2444 100644 --- a/lib/libkse/thread/thr_select.c +++ b/lib/libkse/thread/thr_select.c @@ -142,36 +142,29 @@ select(int numfds, fd_set * readfds, fd_set * writefds, if (ret > 0) { if (readfds != NULL) { - FD_ZERO(readfds); for (i = 0; i < numfds; i++) { - if (FD_ISSET(i, &data.readfds)) { - FD_SET(i, readfds); + if (FD_ISSET(i, readfds) && + !FD_ISSET(i, &data.readfds)) { + FD_CLR(i, readfds); } } } if (writefds != NULL) { - FD_ZERO(writefds); for (i = 0; i < numfds; i++) { - if (FD_ISSET(i, &data.writefds)) { - FD_SET(i, writefds); + if (FD_ISSET(i, writefds) && + !FD_ISSET(i, &data.writefds)) { + FD_CLR(i, writefds); } } } if (exceptfds != NULL) { - FD_ZERO(exceptfds); for (i = 0; i < numfds; i++) { - if (FD_ISSET(i, &data.exceptfds)) { - FD_SET(i, exceptfds); + if (FD_ISSET(i, exceptfds) && + !FD_ISSET(i, &data.exceptfds)) { + FD_CLR(i, exceptfds); } } } - } else { - if (exceptfds != NULL) - FD_ZERO(exceptfds); - if (writefds != NULL) - FD_ZERO(writefds); - if (readfds != NULL) - FD_ZERO(readfds); } return (ret); diff --git a/lib/libkse/thread/thr_sig.c b/lib/libkse/thread/thr_sig.c index 77ec713b63d9..c3ec1919077e 100644 --- a/lib/libkse/thread/thr_sig.c +++ b/lib/libkse/thread/thr_sig.c @@ -31,6 +31,8 @@ * */ #include +#include +#include #include #ifdef _THREAD_SAFE #include @@ -40,6 +42,7 @@ void _thread_sig_handler(int sig, int code, struct sigcontext * scp) { char c; + int i; pthread_t pthread; /* @@ -67,16 +70,52 @@ _thread_sig_handler(int sig, int code, struct sigcontext * scp) } else { /* Handle depending on signal type: */ switch (sig) { - /* Interval timer used for timeslicing: */ + /* Interval timer used for timeslicing: */ case SIGVTALRM: /* * Don't add the signal to any thread. Just want to - * call + * call the scheduler: */ - /* the scheduler: */ break; - /* Signals specific to the running thread: */ + /* Child termination: */ + case SIGCHLD: + /* + * Enter a loop to process each thread in the linked + * list: + */ + for (pthread = _thread_link_list; pthread != NULL; + pthread = pthread->nxt) { + /* + * Add the signal to the set of pending + * signals: + */ + pthread->sigpend[sig] += 1; + if (pthread->state == PS_WAIT_WAIT) { + /* Reset the error: */ + /* There should be another flag so that this is not required! ### */ + _thread_seterrno(pthread, 0); + + /* Change the state of the thread to run: */ + pthread->state = PS_RUNNING; + } + } + + /* + * Go through the file list and set all files + * to non-blocking again in case the child + * set some of them to block. Sigh. + */ + for (i = 0; i < _thread_dtablesize; i++) { + /* Check if this file is used: */ + if (_thread_fd_table[i] != NULL) { + /* Set the file descriptor to non-blocking: */ + _thread_sys_fcntl(i, F_SETFL, _thread_fd_table[i]->flags | O_NONBLOCK); + } + } + break; + + /* Signals specific to the running thread: */ case SIGBUS: case SIGEMT: case SIGFPE: @@ -88,7 +127,7 @@ _thread_sig_handler(int sig, int code, struct sigcontext * scp) _thread_run->sigpend[sig] += 1; break; - /* Signals to send to all threads: */ + /* Signals to send to all threads: */ default: /* * Enter a loop to process each thread in the linked diff --git a/lib/libkse/thread/thr_sigsuspend.c b/lib/libkse/thread/thr_sigsuspend.c index ee2d0b5671df..a26b6b99bf4b 100644 --- a/lib/libkse/thread/thr_sigsuspend.c +++ b/lib/libkse/thread/thr_sigsuspend.c @@ -47,6 +47,9 @@ sigsuspend(const sigset_t * set) /* Save the current sigmal mask: */ oset = _thread_run->sigmask; + /* Combine the caller's mask with the current one: */ + _thread_run->sigmask |= *set; + /* Wait for a signal: */ _thread_kern_sched_state(PS_SIGWAIT, __FILE__, __LINE__); diff --git a/lib/libkse/thread/thr_single_np.c b/lib/libkse/thread/thr_single_np.c new file mode 100644 index 000000000000..e36c856c6376 --- /dev/null +++ b/lib/libkse/thread/thr_single_np.c @@ -0,0 +1,44 @@ +/* + * Copyright (c) 1996 John Birrell . + * 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 +#ifdef _THREAD_SAFE +#include +#include "pthread_private.h" + +int pthread_single_np() +{ + /* Enter single-threaded (non-POSIX) scheduling mode: */ + _thread_single = _thread_run; + return(0); +} +#endif diff --git a/lib/libkse/thread/thr_spec.c b/lib/libkse/thread/thr_spec.c index e7c45d2953c7..cc83c6066ee0 100644 --- a/lib/libkse/thread/thr_spec.c +++ b/lib/libkse/thread/thr_spec.c @@ -39,12 +39,12 @@ #include "pthread_private.h" /* Static variables: */ -static struct pthread_key key_table[PTHREAD_DATAKEYS_MAX]; +static struct pthread_key key_table[PTHREAD_KEYS_MAX]; int -pthread_keycreate(pthread_key_t * key, void (*destructor) (void *)) +pthread_key_create(pthread_key_t * key, void (*destructor) (void *)) { - for ((*key) = 0; (*key) < PTHREAD_DATAKEYS_MAX; (*key)++) { + for ((*key) = 0; (*key) < PTHREAD_KEYS_MAX; (*key)++) { if (key_table[(*key)].count == 0) { key_table[(*key)].count++; key_table[(*key)].destructor = destructor; @@ -63,7 +63,7 @@ pthread_key_delete(pthread_key_t key) /* Block signals: */ _thread_kern_sig_block(&status); - if (key < PTHREAD_DATAKEYS_MAX) { + if (key < PTHREAD_KEYS_MAX) { switch (key_table[key].count) { case 1: key_table[key].destructor = NULL; @@ -94,8 +94,8 @@ _thread_cleanupspecific(void) /* Block signals: */ _thread_kern_sig_block(&status); - for (itr = 0; itr < _POSIX_THREAD_DESTRUTOR_ITERATIONS; itr++) { - for (key = 0; key < PTHREAD_DATAKEYS_MAX; key++) { + for (itr = 0; itr < PTHREAD_DESTRUCTOR_ITERATIONS; itr++) { + for (key = 0; key < PTHREAD_KEYS_MAX; key++) { if (_thread_run->specific_data_count) { if (_thread_run->specific_data[key]) { data = (void *) _thread_run->specific_data[key]; @@ -125,8 +125,8 @@ static inline const void ** pthread_key_allocate_data(void) { const void **new_data; - if ((new_data = (const void **) malloc(sizeof(void *) * PTHREAD_DATAKEYS_MAX)) != NULL) { - memset((void *) new_data, 0, sizeof(void *) * PTHREAD_DATAKEYS_MAX); + if ((new_data = (const void **) malloc(sizeof(void *) * PTHREAD_KEYS_MAX)) != NULL) { + memset((void *) new_data, 0, sizeof(void *) * PTHREAD_KEYS_MAX); } return (new_data); } @@ -154,7 +154,7 @@ pthread_setspecific(pthread_key_t key, const void *value) } if ((pthread->specific_data) || (pthread->specific_data = pthread_key_allocate_data())) { - if ((key < PTHREAD_DATAKEYS_MAX) && (key_table)) { + if ((key < PTHREAD_KEYS_MAX) && (key_table)) { if (key_table[key].count) { if (pthread->specific_data[key] == NULL) { if (value != NULL) { @@ -213,7 +213,7 @@ pthread_getspecific(pthread_key_t key, void **p_data) rval = -1; } /* Check if there is specific data: */ - else if (pthread->specific_data != NULL && (key < PTHREAD_DATAKEYS_MAX) && (key_table)) { + else if (pthread->specific_data != NULL && (key < PTHREAD_KEYS_MAX) && (key_table)) { /* Check if this key has been used before: */ if (key_table[key].count) { /* Return the value: */ diff --git a/lib/libkse/thread/thr_suspend_np.c b/lib/libkse/thread/thr_suspend_np.c new file mode 100644 index 000000000000..fb90c1d494d2 --- /dev/null +++ b/lib/libkse/thread/thr_suspend_np.c @@ -0,0 +1,67 @@ +/* + * Copyright (c) 1995 John Birrell . + * 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 +#ifdef _THREAD_SAFE +#include +#include "pthread_private.h" + +int +pthread_suspend_np(pthread_t thread) +{ + int ret = -1; + pthread_t pthread; + /* + * Search for the thread in the linked list. + */ + for (pthread = _thread_link_list; pthread != NULL && ret == -1; pthread = pthread->nxt) { + /* Is this the thread? */ + if (pthread == thread) { + /* Found the thread. Is it running? */ + if (pthread->state != PS_RUNNING && + pthread->state != PS_SUSPENDED) { + /* The thread operation has been interrupted */ + _thread_seterrno(pthread,EINTR); + } + /* Suspend the thread. */ + pthread->state = PS_SUSPENDED; + ret = 0; + } + } + /* Check if thread was not found. */ + if (ret == -1) { + /* No such thread */ + _thread_seterrno(_thread_run,ESRCH); + } + return(ret); +} +#endif -- cgit v1.2.3