diff options
Diffstat (limited to 'lib/libpthread')
160 files changed, 22319 insertions, 0 deletions
diff --git a/lib/libpthread/Makefile b/lib/libpthread/Makefile new file mode 100644 index 0000000..4c06007 --- /dev/null +++ b/lib/libpthread/Makefile @@ -0,0 +1,46 @@ +# $FreeBSD$ +# +# 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= 4 +SHLIB_MINOR= 0 +CFLAGS+=-DLIBC_RCS -DSYSLIBC_RCS -I${.CURDIR}/../libc/include +CFLAGS+=-DPTHREAD_KERNEL -D_THREAD_SAFE -I${.CURDIR}/uthread +CFLAGS+=-I${.CURDIR}/../../include + +# Uncomment this if you want libc_r to contain debug information for +# thread locking. +CFLAGS+=-D_LOCK_DEBUG + +# enable extra internal consistancy checks +# CFLAGS+=-D_PTHREADS_INVARIANTS + +AINC= -I${.CURDIR}/../libc/${MACHINE_ARCH} -I${.CURDIR}/uthread +PRECIOUSLIB= yes + +# +# This is a list of syscalls that are renamed as _thread_sys_{syscall} +# so that libc_r can provide replacement functions. +# +HIDDEN_SYSCALLS= aio_suspend.o accept.o bind.o close.o connect.o dup.o dup2.o \ + execve.o fchflags.o fchmod.o fchown.o fcntl.o \ + flock.o fpathconf.o fstat.o fstatfs.o fsync.o getdirentries.o \ + getlogin.o getpeername.o getsockname.o getsockopt.o ioctl.o \ + kevent.o listen.o \ + msync.o nanosleep.o nfssvc.o open.o poll.o read.o readv.o recvfrom.o \ + recvmsg.o sched_yield.o select.o sendfile.o sendmsg.o sendto.o \ + setsockopt.o shutdown.o sigaction.o sigaltstack.o \ + signanosleep.o sigpending.o sigprocmask.o sigreturn.o sigsetmask.o \ + sigsuspend.o socket.o \ + socketpair.o wait4.o write.o writev.o + +.include "${.CURDIR}/../libc/Makefile.inc" +.include "${.CURDIR}/man/Makefile.inc" +.include "${.CURDIR}/uthread/Makefile.inc" +.include "${.CURDIR}/sys/Makefile.inc" + +.include <bsd.lib.mk> diff --git a/lib/libpthread/arch/alpha/alpha/_atomic_lock.S b/lib/libpthread/arch/alpha/alpha/_atomic_lock.S new file mode 100644 index 0000000..1cfb52f --- /dev/null +++ b/lib/libpthread/arch/alpha/alpha/_atomic_lock.S @@ -0,0 +1,45 @@ +/* + * Copyright (c) 1998 John Birrell <jb@cimlogic.com.au>. + * All rights reserved. + * copyright Douglas Santry 1996 + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the above copyright is retained + * in the source form. + * + * THIS SOFTWARE IS PROVIDED BY Douglas Santry 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 Douglas Santry 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. + * + * $FreeBSD$ + * + */ + +#include "SYS.h" + +/* + * Atomicly lock a location with an identifier provided the location + * is not currently locked. + * + * long _atomic_lock(long *); + * v0 will contain the return value (zero if lock obtained). + */ +LEAF(_atomic_lock,0) + LDGP(pv) + +0: ldq_l v0, 0(a0) /* read existing lock value */ + mov 1, t0 /* locked value to store */ + stq_c t0, 0(a0) /* attempt to store, status in t0 */ + beq t0, 1f /* branch foward to optimise prediction */ + mb /* sync with other processors */ + RET /* return with v0==0 if lock obtained */ +1: br 0b /* loop to try again */ +END(_atomic_lock) diff --git a/lib/libpthread/arch/i386/i386/_atomic_lock.S b/lib/libpthread/arch/i386/i386/_atomic_lock.S new file mode 100644 index 0000000..afaec71 --- /dev/null +++ b/lib/libpthread/arch/i386/i386/_atomic_lock.S @@ -0,0 +1,45 @@ +/* + * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>. + * All rights reserved. + * copyright Douglas Santry 1996 + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the above copyright is retained + * in the source form. + * + * THIS SOFTWARE IS PROVIDED BY Douglas Santry 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 Douglas Santry 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. + * + * $FreeBSD$ + * + */ + +#if defined(LIBC_RCS) && !defined(lint) + .text + .asciz "$FreeBSD$" +#endif /* LIBC_RCS and not lint */ + +#include "DEFS.h" + +/* + * Atomicly lock a location with an identifier provided the location + * is not currently locked. + * + * long _atomic_lock(long *); + * eax will contain the return value (zero if lock obtained). + */ +ENTRY(_atomic_lock) + movl 4(%esp), %ecx + movl $1, %eax + xchg %eax, (%ecx) + ret + diff --git a/lib/libpthread/man/Makefile.inc b/lib/libpthread/man/Makefile.inc new file mode 100644 index 0000000..9cc74d7 --- /dev/null +++ b/lib/libpthread/man/Makefile.inc @@ -0,0 +1,94 @@ +# $FreeBSD$ + +# POSIX thread man files + +.PATH: ${.CURDIR}/man + +MAN3+= pthread_attr.3 \ + pthread_cancel.3 \ + pthread_cleanup_pop.3 \ + pthread_cleanup_push.3 \ + pthread_condattr.3 \ + pthread_cond_broadcast.3 \ + pthread_cond_destroy.3 \ + pthread_cond_init.3 \ + pthread_cond_signal.3 \ + pthread_cond_timedwait.3 \ + pthread_cond_wait.3 \ + pthread_create.3 \ + pthread_detach.3 \ + pthread_equal.3 \ + pthread_exit.3 \ + pthread_getspecific.3 \ + pthread_join.3 \ + pthread_key_create.3 \ + pthread_key_delete.3 \ + pthread_kill.3 \ + pthread_mutexattr.3 \ + pthread_mutex_destroy.3 \ + pthread_mutex_init.3 \ + pthread_mutex_lock.3 \ + pthread_mutex_trylock.3 \ + pthread_mutex_unlock.3 \ + pthread_once.3 \ + pthread_rwlock_destroy.3 \ + pthread_rwlock_init.3 \ + pthread_rwlock_rdlock.3 \ + pthread_rwlock_unlock.3 \ + pthread_rwlock_wrlock.3 \ + pthread_rwlockattr_destroy.3 \ + pthread_rwlockattr_getpshared.3 \ + pthread_rwlockattr_init.3 \ + pthread_rwlockattr_setpshared.3 \ + pthread_schedparam.3 \ + pthread_self.3 \ + pthread_setspecific.3 \ + pthread_sigmask.3 \ + pthread_testcancel.3 \ + sem_destroy.3 \ + sem_getvalue.3 \ + sem_init.3 \ + sem_open.3 \ + sem_post.3 \ + sem_wait.3 \ + sigwait.3 + +MLINKS+= \ + pthread_attr.3 pthread_attr_destroy.3 \ + pthread_attr.3 pthread_attr_getdetachstate.3 \ + pthread_attr.3 pthread_attr_getinheritsched.3 \ + pthread_attr.3 pthread_attr_getschedparam.3 \ + pthread_attr.3 pthread_attr_getschedpolicy.3 \ + pthread_attr.3 pthread_attr_getscope.3 \ + pthread_attr.3 pthread_attr_getstackaddr.3 \ + pthread_attr.3 pthread_attr_getstacksize.3 \ + pthread_attr.3 pthread_attr_init.3 \ + pthread_attr.3 pthread_attr_setdetachstate.3 \ + pthread_attr.3 pthread_attr_setinheritsched.3 \ + pthread_attr.3 pthread_attr_setschedparam.3 \ + pthread_attr.3 pthread_attr_setschedpolicy.3 \ + pthread_attr.3 pthread_attr_setscope.3 \ + pthread_attr.3 pthread_attr_setstackaddr.3 \ + pthread_attr.3 pthread_attr_setstacksize.3 \ + pthread_condattr.3 pthread_condattr_init.3 \ + pthread_condattr.3 pthread_condattr_destroy.3 \ + pthread_mutexattr.3 pthread_mutexattr_init.3 \ + pthread_mutexattr.3 pthread_mutexattr_destroy.3 \ + pthread_mutexattr.3 pthread_mutexattr_getprioceiling.3 \ + pthread_mutexattr.3 pthread_mutexattr_getprotocol.3 \ + pthread_mutexattr.3 pthread_mutexattr_getpshared.3 \ + pthread_mutexattr.3 pthread_mutexattr_gettype.3 \ + pthread_mutexattr.3 pthread_mutexattr_setprioceiling.3 \ + pthread_mutexattr.3 pthread_mutexattr_setprotocol.3 \ + pthread_mutexattr.3 pthread_mutexattr_setpshared.3 \ + pthread_mutexattr.3 pthread_mutexattr_settype.3 \ + pthread_rwlock_rdlock.3 pthread_rwlock_tryrdlock.3 \ + pthread_rwlock_wrlock.3 pthread_rwlock_trywrlock.3 \ + pthread_schedparam.3 pthread_getschedparam.3 \ + pthread_schedparam.3 pthread_setschedparam.3 \ + pthread_testcancel.3 pthread_getcancelstate.3 \ + pthread_testcancel.3 pthread_setcancelstate.3 \ + pthread_testcancel.3 pthread_setcanceltype.3 \ + sem_open.3 sem_close.3 \ + sem_open.3 sem_unlink.3 \ + sem_wait.3 sem_trywait.3 diff --git a/lib/libpthread/man/pthread_attr.3 b/lib/libpthread/man/pthread_attr.3 new file mode 100644 index 0000000..18740e8 --- /dev/null +++ b/lib/libpthread/man/pthread_attr.3 @@ -0,0 +1,213 @@ +.\" Copyright (C) 2000 Jason Evans <jasone@freebsd.org>. +.\" 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(s), this list of conditions and the following disclaimer as +.\" the first lines of this file unmodified other than the possible +.\" addition of one or more copyright notices. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice(s), this list of conditions and the following disclaimer in +.\" the documentation and/or other materials provided with the +.\" distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``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 COPYRIGHT HOLDER(S) 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. +.\" +.\" $FreeBSD$ +.Dd April 28, 2000 +.Dt PTHREAD_ATTR 3 +.Os +.Sh NAME +.Nm pthread_attr_init , +.Nm pthread_attr_destroy , +.Nm pthread_attr_setstacksize , +.Nm pthread_attr_getstacksize , +.Nm pthread_attr_setstackaddr , +.Nm pthread_attr_getstackaddr , +.Nm pthread_attr_setdetachstate , +.Nm pthread_attr_getdetachstate , +.Nm pthread_attr_setinheritsched , +.Nm pthread_attr_getinheritsched , +.Nm pthread_attr_setschedparam , +.Nm pthread_attr_getschedparam , +.Nm pthread_attr_setschedpolicy , +.Nm pthread_attr_getschedpolicy , +.Nm pthread_attr_setscope , +.Nm pthread_attr_getscope +.Nd thread attribute operations +.Sh LIBRARY +.Lb libc_r +.Sh SYNOPSIS +.Fd #include <pthread.h> +.Ft int +.Fn pthread_attr_init "pthread_attr_t *attr" +.Ft int +.Fn pthread_attr_destroy "pthread_attr_t *attr" +.Ft int +.Fn pthread_attr_setstacksize "pthread_attr_t *attr" "size_t stacksize" +.Ft int +.Fn pthread_attr_getstacksize "const pthread_attr_t *attr" "size_t *stacksize" +.Ft int +.Fn pthread_attr_setstackaddr "pthread_attr_t *attr" "void *stackaddr" +.Ft int +.Fn pthread_attr_getstackaddr "const pthread_attr_t *attr" "void **stackaddr" +.Ft int +.Fn pthread_attr_setdetachstate "pthread_attr_t *attr" "int detachstate" +.Ft int +.Fn pthread_attr_getdetachstate "const pthread_attr_t *attr" "int *detachstate" +.Ft int +.Fn pthread_attr_setinheritsched "pthread_attr_t *attr" "int inheritsched" +.Ft int +.Fn pthread_attr_getinheritsched "const pthread_attr_t *attr" "int *inheritsched" +.Ft int +.Fn pthread_attr_setschedparam "pthread_attr_t *attr" "const struct sched_param *param" +.Ft int +.Fn pthread_attr_getschedparam "const pthread_attr_t *attr" "struct sched_param *param" +.Ft int +.Fn pthread_attr_setschedpolicy "pthread_attr_t *attr" "int policy" +.Ft int +.Fn pthread_attr_getschedpolicy "const pthread_attr_t *attr" "int *policy" +.Ft int +.Fn pthread_attr_setscope "pthread_attr_t *attr" "int contentionscope" +.Ft int +.Fn pthread_attr_getscope "const pthread_attr_t *attr" "int *contentionscope" +.Sh DESCRIPTION +Thread attributes are used to specify parameters to +.Fn pthread_create . +One attribute object can be used in multiple calls to +.Fn pthread_create , +with or without modifications between calls. +.Pp +The +.Fn pthread_attr_init +function initializes +.Fa attr +with all the default thread attributes. +.Pp +The +.Fn pthread_attr_destroy +function destroys +.Fa attr . +.Pp +The +.Fn pthread_attr_set* +functions set the attribute that corresponds to each function name. +.Pp +The +.Fn pthread_attr_get* +functions copy the value of the attribute that corresponds to each function name +to the location pointed to by the second function parameter. +.Sh RETURN VALUES +If successful, these functions return 0. +Otherwise, an error number is returned to indicate the error. +.Sh ERRORS +.Fn pthread_attr_init +will fail if: +.Bl -tag -width Er +.It Bq Er ENOMEM +Out of memory. +.El +.Pp +.Fn pthread_attr_destroy +will fail if: +.Bl -tag -width Er +.It Bq Er EINVAL +Invalid value for +.Fa attr . +.El +.Pp +.Fn pthread_attr_setstacksize +will fail if: +.Bl -tag -width Er +.It Bq Er EINVAL +.Fa stacksize +is less than +.Dv PTHREAD_STACK_MIN . +.El +.Pp +.Fn pthread_attr_setdetachstate +will fail if: +.Bl -tag -width Er +.It Bq Er EINVAL +Invalid value for +.Fa detachstate . +.El +.Pp +.Fn pthread_attr_setinheritsched +will fail if: +.Bl -tag -width Er +.It Bq Er EINVAL +Invalid value for +.Fa attr . +.El +.Pp +.Fn pthread_attr_setschedparam +will fail if: +.Bl -tag -width Er +.It Bq Er EINVAL +Invalid value for +.Fa attr . +.It Bq Er ENOTSUP +Invalid value for +.Fa param . +.El +.Pp +.Fn pthread_attr_setschedpolicy +will fail if: +.Bl -tag -width Er +.It Bq Er EINVAL +Invalid value for +.Fa attr . +.It Bq Er ENOTSUP +Invalid or unsupported value for +.Fa policy . +.El +.Pp +.Fn pthread_attr_setscope +will fail if: +.Bl -tag -width Er +.It Bq Er EINVAL +Invalid value for +.Fa attr . +.It Bq Er ENOTSUP +Invalid or unsupported value for +.Fa contentionscope . +.El +.Sh SEE ALSO +.Xr pthread_create 3 +.Sh STANDARDS +.Fn pthread_attr_init , +.Fn pthread_attr_destroy , +.Fn pthread_attr_setstacksize , +.Fn pthread_attr_getstacksize , +.Fn pthread_attr_setstackaddr , +.Fn pthread_attr_getstackaddr , +.Fn pthread_attr_setdetachstate , +and +.Fn pthread_attr_getdetachstate +conform to +.St -iso9945-1 +.Pp +.Fn pthread_attr_setinheritsched , +.Fn pthread_attr_getinheritsched , +.Fn pthread_attr_setschedparam , +.Fn pthread_attr_getschedparam , +.Fn pthread_attr_setschedpolicy , +.Fn pthread_attr_getschedpolicy , +.Fn pthread_attr_setscope , +and +.Fn pthread_attr_getscope +conform to +.St -susv2 diff --git a/lib/libpthread/man/pthread_cancel.3 b/lib/libpthread/man/pthread_cancel.3 new file mode 100644 index 0000000..9a741d8 --- /dev/null +++ b/lib/libpthread/man/pthread_cancel.3 @@ -0,0 +1,80 @@ +.\" $FreeBSD$ +.Dd January 17, 1999 +.Dt PTHREAD_CANCEL 3 +.Os +.Sh NAME +.Nm pthread_cancel +.Nd cancel execution of a thread +.Sh LIBRARY +.Lb libc_r +.Sh SYNOPSIS +.Fd #include <pthread.h> +.Ft int +.Fn pthread_cancel "pthread_t thread" +.Sh DESCRIPTION +The +.Fn pthread_cancel +function requests that +.Fa thread +be canceled. +The target thread's cancelability state and type determines +when the cancellation takes effect. +When the cancellation is acted on, +the cancellation cleanup handlers for +.Fa thread +are called. +When the last cancellation cleanup handler returns, +the thread-specific data destructor functions will be called for +.Fa thread . +When the last destructor function returns, +.Fa thread +will be terminated. +.Pp +The cancellation processing in the target thread runs asynchronously with +respect to the calling thread returning from +.Fn pthread_cancel . +.Pp +A status of +.Dv PTHREAD_CANCELED +is made available to any threads joining with the target. +The symbolic +constant +.Dv PTHREAD_CANCELED +expands to a constant expression of type +.Ft "(void *)" , +whose value matches no pointer to an object in memory nor the value +.Dv NULL . +.Sh RETURN VALUES +If successful, the +.Fn pthread_cancel +functions will return zero. +Otherwise an error number will be returned to +indicate the error. +.Sh ERRORS +.Fn pthread_cancel +will fail if: +.Bl -tag -width Er +.It Bq Er ESRCH +No thread could be found corresponding to that specified by the given +thread ID. +.El +.Sh SEE ALSO +.Xr pthread_cleanup_pop 3 , +.Xr pthread_cleanup_push 3 , +.Xr pthread_exit 3 , +.Xr pthread_join 3 , +.Xr pthread_setcancelstate 3 , +.Xr pthread_setcanceltype 3 , +.Xr pthread_testcancel 3 +.Sh STANDARDS +.Fn pthread_cancel +conforms to ISO/IEC 9945-1 ANSI/IEEE +.Pq Dq Tn POSIX +Std 1003.1 Second Edition 1996-07-12. +.Sh AUTHORS +This man page was written by +.An David Leonard Aq d@openbsd.org +for the +.Ox +implementation of +.Fn pthread_cancel . diff --git a/lib/libpthread/man/pthread_cleanup_pop.3 b/lib/libpthread/man/pthread_cleanup_pop.3 new file mode 100644 index 0000000..a2f7894 --- /dev/null +++ b/lib/libpthread/man/pthread_cleanup_pop.3 @@ -0,0 +1,65 @@ +.\" Copyright (c) 1997 Brian Cully <shmit@kublai.com> +.\" 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. 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. +.\" +.\" $FreeBSD$ +.\" +.Dd July 30, 1998 +.Dt PTHREAD_CLEANUP_POP 3 +.Os BSD 4 +.Sh NAME +.Nm pthread_cleanup_pop +.Nd call the first cleanup routine +.Sh LIBRARY +.Lb libc_r +.Sh SYNOPSIS +.Fd #include <pthread.h> +.Ft void +.Fn pthread_cleanup_pop "int execute" +.Sh DESCRIPTION +The +.Fn pthread_cleanup_pop +function pops the top cleanup routine off of the current threads cleanup +routine stack, and, if +.Fa execute +is non-zero, it will execute the function. +If there is no cleanup routine +then +.Fn pthread_cleanup_pop +does nothing. +.Sh RETURN VALUES +.Fn pthread_cleanup_pop +does not return any value. +.Sh ERRORS +None +.Sh SEE ALSO +.Xr pthread_cleanup_push 3 , +.Xr pthread_exit 3 +.Sh STANDARDS +.Fn pthread_cleanup_pop +conforms to ISO/IEC 9945-1 ANSI/IEEE +.Pq Dq Tn POSIX +Std 1003.1 Second Edition 1996-07-12. diff --git a/lib/libpthread/man/pthread_cleanup_push.3 b/lib/libpthread/man/pthread_cleanup_push.3 new file mode 100644 index 0000000..103daa6 --- /dev/null +++ b/lib/libpthread/man/pthread_cleanup_push.3 @@ -0,0 +1,67 @@ +.\" Copyright (c) 1997 Brian Cully <shmit@kublai.com> +.\" 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. 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. +.\" +.\" $FreeBSD$ +.\" +.Dd July 30, 1998 +.Dt PTHREAD_CLEANUP_PUSH 3 +.Os BSD 4 +.Sh NAME +.Nm pthread_cleanup_push +.Nd add a cleanup function for thread exit +.Sh LIBRARY +.Lb libc_r +.Sh SYNOPSIS +.Fd #include <pthread.h> +.Ft void +.Fn pthread_cleanup_push "void (*cleanup_routine)(void *)" "void *arg" +.Sh DESCRIPTION +The +.Fn pthread_cleanup_push +function adds +.Fa cleanup_routine +to the top of the stack of cleanup handlers that +get called when the current thread exits. +.Pp +When +.Fn pthread_cleanup_push +is called, it is passed +.Fa arg +as its only argument. +.Sh RETURN VALUES +.Fn pthread_cleanup_push +does not return any value. +.Sh ERRORS +None +.Sh SEE ALSO +.Xr pthread_cleanup_pop 3 , +.Xr pthread_exit 3 +.Sh STANDARDS +.Fn pthread_cleanup_push +conforms to ISO/IEC 9945-1 ANSI/IEEE +.Pq Dq Tn POSIX +Std 1003.1 Second Edition 1996-07-12. diff --git a/lib/libpthread/man/pthread_cond_broadcast.3 b/lib/libpthread/man/pthread_cond_broadcast.3 new file mode 100644 index 0000000..c380ece --- /dev/null +++ b/lib/libpthread/man/pthread_cond_broadcast.3 @@ -0,0 +1,72 @@ +.\" Copyright (c) 1997 Brian Cully <shmit@kublai.com> +.\" 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. 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. +.\" +.\" $FreeBSD$ +.\" +.Dd July 28, 1998 +.Dt PTHREAD_COND_BROADCAST 3 +.Os BSD 4 +.Sh NAME +.Nm pthread_cond_broadcast +.Nd unblock all threads waiting for a condition variable +.Sh LIBRARY +.Lb libc_r +.Sh SYNOPSIS +.Fd #include <pthread.h> +.Ft int +.Fn pthread_cond_broadcast "pthread_cond_t *cond" +.Sh DESCRIPTION +The +.Fn pthread_cond_broadcast +function unblocks all threads waiting for the condition variable +.Fa cond . +.Sh RETURN VALUES +If successful, the +.Fn pthread_cond_broadcast +function will return zero, otherwise an error number will be returned +to indicate the error. +.Sh ERRORS +.Fn pthread_cond_broadcast +will fail if: +.Bl -tag -width Er +.It Bq Er EINVAL +The value specified by +.Fa cond +is invalid. +.El +.Pp +.Sh SEE ALSO +.Xr pthread_cond_destroy 3 , +.Xr pthread_cond_init 3 , +.Xr pthread_cond_signal 3 , +.Xr pthread_cond_timedwait 3 , +.Xr pthread_cond_wait 3 +.Sh STANDARDS +.Fn pthread_cond_broadcast +conforms to ISO/IEC 9945-1 ANSI/IEEE +.Pq Dq Tn POSIX +Std 1003.1 Second Edition 1996-07-12. diff --git a/lib/libpthread/man/pthread_cond_destroy.3 b/lib/libpthread/man/pthread_cond_destroy.3 new file mode 100644 index 0000000..bf8bbf3 --- /dev/null +++ b/lib/libpthread/man/pthread_cond_destroy.3 @@ -0,0 +1,76 @@ +.\" Copyright (c) 1997 Brian Cully <shmit@kublai.com> +.\" 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. 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. +.\" +.\" $FreeBSD$ +.\" +.Dd July 28, 1998 +.Dt PTHREAD_COND_DESTROY 3 +.Os BSD 4 +.Sh NAME +.Nm pthread_cond_destroy +.Nd destroy a condition variable +.Sh LIBRARY +.Lb libc_r +.Sh SYNOPSIS +.Fd #include <pthread.h> +.Ft int +.Fn pthread_cond_destroy "pthread_cond_t *cond" +.Sh DESCRIPTION +The +.Fn pthread_cond_destroy +function frees the resources allocated by the condition variable +.Fa cond . +.Sh RETURN VALUES +If successful, the +.Fn pthread_cond_destroy +function will return zero, otherwise an error number will be returned +to indicate the error. +.Sh ERRORS +.Fn pthread_cond_destroy +will fail if: +.Bl -tag -width Er +.It Bq Er EINVAL +The value specified by +.Fa cond +is invalid. +.It Bq Er EBUSY +The variable +.Fa cond +is locked by another thread. +.El +.Pp +.Sh SEE ALSO +.Xr pthread_cond_broadcast 3 , +.Xr pthread_cond_init 3 , +.Xr pthread_cond_signal 3 , +.Xr pthread_cond_timedwait 3 , +.Xr pthread_cond_wait 3 +.Sh STANDARDS +.Fn pthread_cond_destroy +conforms to ISO/IEC 9945-1 ANSI/IEEE +.Pq Dq Tn POSIX +Std 1003.1 Second Edition 1996-07-12. diff --git a/lib/libpthread/man/pthread_cond_init.3 b/lib/libpthread/man/pthread_cond_init.3 new file mode 100644 index 0000000..6c7ccca --- /dev/null +++ b/lib/libpthread/man/pthread_cond_init.3 @@ -0,0 +1,81 @@ +.\" Copyright (c) 1997 Brian Cully <shmit@kublai.com> +.\" 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. 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. +.\" +.\" $FreeBSD$ +.\" +.Dd July 28, 1998 +.Dt PTHREAD_COND_INIT 3 +.Os BSD 4 +.Sh NAME +.Nm pthread_cond_init +.Nd create a condition variable +.Sh LIBRARY +.Lb libc_r +.Sh SYNOPSIS +.Fd #include <pthread.h> +.Ft int +.Fn pthread_cond_init "pthread_cond_t *cond" "const pthread_condattr_t *attr" +.Sh DESCRIPTION +The +.Fn pthread_cond_init +function creates a new condition variable, with attributes specified with +.Fa attr . +If +.Fa attr +is NULL the default attributes are used. +.Sh RETURN VALUES +If successful, the +.Fn pthread_cond_init +function will return zero and put the new condition variable id into +.Fa cond , +otherwise an error number will be returned to indicate the error. +.Sh ERRORS +.Fn pthread_cond_init +will fail if: +.Bl -tag -width Er +.It Bq Er EINVAL +The value specified by +.Fa attr +is invalid. +.It Bq Er ENOMEM +The process cannot allocate enough memory to create another condition +variable. +.It Bq Er EAGAIN +The temporarily lacks the resources to create another condition variable. +.El +.Pp +.Sh SEE ALSO +.Xr pthread_cond_broadcast 3 , +.Xr pthread_cond_destroy 3 , +.Xr pthread_cond_signal 3 , +.Xr pthread_cond_timedwait 3 , +.Xr pthread_cond_wait 3 +.Sh STANDARDS +.Fn pthread_cond_init +conforms to ISO/IEC 9945-1 ANSI/IEEE +.Pq Dq Tn POSIX +Std 1003.1 Second Edition 1996-07-12. diff --git a/lib/libpthread/man/pthread_cond_signal.3 b/lib/libpthread/man/pthread_cond_signal.3 new file mode 100644 index 0000000..7ad985e --- /dev/null +++ b/lib/libpthread/man/pthread_cond_signal.3 @@ -0,0 +1,72 @@ +.\" Copyright (c) 1997 Brian Cully <shmit@kublai.com> +.\" 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. 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. +.\" +.\" $FreeBSD$ +.\" +.Dd July 28, 1998 +.Dt PTHREAD_COND_SIGNAL 3 +.Os BSD 4 +.Sh NAME +.Nm pthread_cond_signal +.Nd unblock a thread waiting for a condition variable +.Sh LIBRARY +.Lb libc_r +.Sh SYNOPSIS +.Fd #include <pthread.h> +.Ft int +.Fn pthread_cond_signal "pthread_cond_t *cond" +.Sh DESCRIPTION +The +.Fn pthread_cond_signal +function unblocks one thread waiting for the condition variable +.Fa cond . +.Sh RETURN VALUES +If successful, the +.Fn pthread_cond_signal +function will return zero, otherwise an error number will be returned +to indicate the error. +.Sh ERRORS +.Fn pthread_cond_signal +will fail if: +.Bl -tag -width Er +.It Bq Er EINVAL +The value specified by +.Fa cond +is invalid. +.El +.Pp +.Sh SEE ALSO +.Xr pthread_cond_broadcast 3 , +.Xr pthread_cond_destroy 3 , +.Xr pthread_cond_init 3 , +.Xr pthread_cond_timedwait 3 , +.Xr pthread_cond_wait 3 +.Sh STANDARDS +.Fn pthread_cond_signal +conforms to ISO/IEC 9945-1 ANSI/IEEE +.Pq Dq Tn POSIX +Std 1003.1 Second Edition 1996-07-12. diff --git a/lib/libpthread/man/pthread_cond_timedwait.3 b/lib/libpthread/man/pthread_cond_timedwait.3 new file mode 100644 index 0000000..e80c2bf --- /dev/null +++ b/lib/libpthread/man/pthread_cond_timedwait.3 @@ -0,0 +1,91 @@ +.\" Copyright (c) 1997 Brian Cully <shmit@kublai.com> +.\" 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. 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. +.\" +.\" $FreeBSD$ +.\" +.Dd July 28, 1998 +.Dt PTHREAD_COND_TIMEDWAIT 3 +.Os BSD 4 +.Sh NAME +.Nm pthread_cond_timedwait +.Nd "wait on a condition variable for a specific amount of time" +.Sh LIBRARY +.Lb libc_r +.Sh SYNOPSIS +.Fd #include <pthread.h> +.Ft int +.Fn pthread_cond_timedwait "pthread_cond_t *cond" "pthread_mutex_t *mutex" "const struct timespec *abstime" +.Sh DESCRIPTION +The +.Fn pthread_cond_timedwait +function atomically blocks the current thread waiting on the condition +variable specified by +.Fa cond , +and unblocks the mutex specified by +.Fa mutex . +The waiting thread unblocks only after another thread calls +.Xr pthread_cond_signal 3 , +or +.Xr pthread_cond_broadcast 3 +with the same condition variable, or if the system time reaches the +time specified in +.Fa abstime , +and the current thread requires the lock on +.Fa mutex . +.Sh RETURN VALUES +If successful, the +.Fn pthread_cond_timedwait +function will return zero. +Otherwise an error number will be returned to +indicate the error. +.Sh ERRORS +.Fn pthread_cond_timedwait +will fail if: +.Bl -tag -width Er +.It Bq Er EINVAL +The value specified by +.Fa cond , +.Fa mutex +or +.Fa abstime +is invalid. +.It Bq Er ETIMEDOUT +The system time has reached or exceeded the time specified in +.Fa abstime . +.El +.Pp +.Sh SEE ALSO +.Xr pthread_cond_broadcast 3 , +.Xr pthread_cond_destroy 3 , +.Xr pthread_cond_init 3 , +.Xr pthread_cond_signal 3 , +.Xr pthread_cond_wait 3 +.Sh STANDARDS +.Fn pthread_cond_timedwait +conforms to ISO/IEC 9945-1 ANSI/IEEE +.Pq Dq Tn POSIX +Std 1003.1 Second Edition 1996-07-12. diff --git a/lib/libpthread/man/pthread_cond_wait.3 b/lib/libpthread/man/pthread_cond_wait.3 new file mode 100644 index 0000000..9d70318 --- /dev/null +++ b/lib/libpthread/man/pthread_cond_wait.3 @@ -0,0 +1,84 @@ +.\" Copyright (c) 1997 Brian Cully <shmit@kublai.com> +.\" 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. 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. +.\" +.\" $FreeBSD$ +.\" +.Dd July 28, 1998 +.Dt PTHREAD_COND_WAIT 3 +.Os BSD 4 +.Sh NAME +.Nm pthread_cond_wait +.Nd wait on a condition variable +.Sh LIBRARY +.Lb libc_r +.Sh SYNOPSIS +.Fd #include <pthread.h> +.Ft int +.Fn pthread_cond_wait "pthread_cond_t *cond" "pthread_mutex_t *mutex" +.Sh DESCRIPTION +The +.Fn pthread_cond_wait +function atomically blocks the current thread waiting on the condition +variable specified by +.Fa cond , +and unblocks the mutex specified by +.Fa mutex . +The waiting thread unblocks only after another thread calls +.Xr pthread_cond_signal 3 , or +.Xr pthread_cond_broadcast 3 +with the same condition variable, and the current thread requires the lock +on +.Fa mutex . +.Sh RETURN VALUES +If successful, the +.Fn pthread_cond_wait +function will return zero. +Otherwise an error number will be returned to +indicate the error. +.Sh ERRORS +.Fn pthread_cond_wait +will fail if: +.Bl -tag -width Er +.It Bq Er EINVAL +The value specified by +.Fa cond +or the value specified by +.Fa mutex +is invalid. +.El +.Pp +.Sh SEE ALSO +.Xr pthread_cond_broadcast 3 , +.Xr pthread_cond_destroy 3 , +.Xr pthread_cond_init 3 , +.Xr pthread_cond_signal 3 , +.Xr pthread_cond_timedwait 3 +.Sh STANDARDS +.Fn pthread_cond_wait +conforms to ISO/IEC 9945-1 ANSI/IEEE +.Pq Dq Tn POSIX +Std 1003.1 Second Edition 1996-07-12. diff --git a/lib/libpthread/man/pthread_condattr.3 b/lib/libpthread/man/pthread_condattr.3 new file mode 100644 index 0000000..9aa9a52 --- /dev/null +++ b/lib/libpthread/man/pthread_condattr.3 @@ -0,0 +1,83 @@ +.\" Copyright (C) 2000 Jason Evans <jasone@freebsd.org>. +.\" 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(s), this list of conditions and the following disclaimer as +.\" the first lines of this file unmodified other than the possible +.\" addition of one or more copyright notices. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice(s), this list of conditions and the following disclaimer in +.\" the documentation and/or other materials provided with the +.\" distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``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 COPYRIGHT HOLDER(S) 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. +.\" +.\" $FreeBSD$ +.Dd April 28, 2000 +.Dt PTHREAD_CONDATTR 3 +.Os +.Sh NAME +.Nm pthread_condattr_init , +.Nm pthread_condattr_destroy +.Nd condition attribute operations +.Sh LIBRARY +.Lb libc_r +.Sh SYNOPSIS +.Fd #include <pthread.h> +.Ft int +.Fn pthread_condattr_init "pthread_condattr_t *attr" +.Ft int +.Fn pthread_condattr_destroy "pthread_condattr_t *attr" +.Sh DESCRIPTION +Condition attribute objects are used to specify parameters to +.Fn pthread_cond_init . +FreeBSD's implementation of conditions does not support any non-default +attributes, so these functions are not very useful, though they are required to +to be present by +.Tn POSIX . +.Pp +The +.Fn pthread_condattr_init +function initializes a condition attribute object with the default attributes. +.Pp +The +.Fn pthread_condattr_destroy +function destroys a condition attribute object. +.Sh RETURN VALUES +If successful, these functions return 0. +Otherwise, an error number is returned to indicate the error. +.Sh ERRORS +.Fn pthread_condattr_init +will fail if: +.Bl -tag -width Er +.It Bq Er ENOMEM +Out of memory. +.El +.Pp +.Fn pthread_condattr_destroy +will fail if: +.Bl -tag -width Er +.It Bq Er EINVAL +Invalid value for +.Fa attr . +.Sh SEE ALSO +.Xr pthread_cond_init 3 +.Sh STANDARDS +.Fn pthread_condattr_init +and +.Fn pthread_condattr_destroy +conform to +.St -iso9945-1 diff --git a/lib/libpthread/man/pthread_create.3 b/lib/libpthread/man/pthread_create.3 new file mode 100644 index 0000000..2f760d0 --- /dev/null +++ b/lib/libpthread/man/pthread_create.3 @@ -0,0 +1,123 @@ +.\" Copyright (c) 1996 John Birrell <jb@cimlogic.com.au>. +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by John Birrell. +.\" 4. Neither the name of the author nor the names of any co-contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" +.Dd April 4, 1996 +.Dt PTHREAD_CREATE 3 +.Os BSD 4 +.Sh NAME +.Nm pthread_create +.Nd create a new thread +.Sh LIBRARY +.Lb libc_r +.Sh SYNOPSIS +.Fd #include <pthread.h> +.Ft int +.Fn pthread_create "pthread_t *thread" "const pthread_attr_t *attr" "void *(*start_routine)(void *)" "void *arg" +.Sh DESCRIPTION +The +.Fn pthread_create +function is used to create a new thread, with attributes specified by +.Fa attr , +within a process. +If +.Fa attr +is NULL, the default attributes are used. +If the attributes specified by +.Fa attr +are modified later, the thread's attributes are not affected. +Upon +successful completion +.Fn pthread_create +will store the ID of the created thread in the location specified by +.Fa thread . +.Pp +The thread is created executing +.Fa start_routine +with +.Fa arg +as its sole argument. +If the +.Fa start_routine +returns, the effect is as if there was an implicit call to +.Fn pthread_exit +using the return value of +.Fa start_routine +as the exit status. +Note that the thread in which +.Fn main +was originally invoked differs from this. +When it returns from +.Fn main , +the effect is as if there was an implicit call to +.Fn exit +using the return value of +.Fn main +as the exit status. +.Pp +The signal state of the new thread is initialized as: +.Bl -bullet -offset indent +.It +The signal mask is inherited from the creating thread. +.It +The set of signals pending for the new thread is empty. +.El +.Sh RETURN VALUES +If successful, the +.Fn pthread_create +function will return zero. +Otherwise an error number will be returned to +indicate the error. +.Sh ERRORS +.Fn pthread_create +will fail if: +.Bl -tag -width Er +.It Bq Er EAGAIN +The system lacked the necessary resources to create another thread, or +the system-imposed limit on the total number of threads in a process +[PTHREAD_THREADS_MAX] would be exceeded. +.It Bq Er EINVAL +The value specified by +.Fa attr +is invalid. +.El +.Pp +.Sh SEE ALSO +.Xr fork 2 , +.Xr pthread_cleanup_pop 3 , +.Xr pthread_cleanup_push 3 , +.Xr pthread_exit 3 , +.Xr pthread_join 3 +.Sh STANDARDS +.Fn pthread_create +conforms to ISO/IEC 9945-1 ANSI/IEEE +.Pq Dq Tn POSIX +Std 1003.1 Second Edition 1996-07-12. diff --git a/lib/libpthread/man/pthread_detach.3 b/lib/libpthread/man/pthread_detach.3 new file mode 100644 index 0000000..05154fc --- /dev/null +++ b/lib/libpthread/man/pthread_detach.3 @@ -0,0 +1,91 @@ +.\" Copyright (c) 1996-1998 John Birrell <jb@cimlogic.com.au>. +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by John Birrell. +.\" 4. Neither the name of the author nor the names of any co-contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" +.Dd April 4, 1996 +.Dt PTHREAD_DETACH 3 +.Os BSD 4 +.Sh NAME +.Nm pthread_detach +.Nd detach a thread +.Sh LIBRARY +.Lb libc_r +.Sh SYNOPSIS +.Fd #include <pthread.h> +.Ft int +.Fn pthread_detach "pthread_t thread" +.Sh DESCRIPTION +The +.Fn pthread_detach +function is used to indicate to the implementation that storage for the +thread +.Fa thread +can be reclaimed when the thread terminates. +If +.Fa thread +has not terminated, +.Fn pthread_detach +will not cause it to terminate. +The effect of multiple +.Fn pthread_detach +calls on the same target thread is unspecified. +.Sh RETURN VALUES +If successful, the +.Fn pthread_detach +function will return zero. +Otherwise an error number will be returned to +indicate the error. +Note that the function does not change the value +of errno as it did for some drafts of the standard. +These early drafts +also passed a pointer to pthread_t as the argument. +Beware! +.Sh ERRORS +.Fn pthread_detach +will fail if: +.Bl -tag -width Er +.It Bq Er EINVAL +The implementation has detected that the value specified by +.Fa thread +does not refer to a joinable thread. +.It Bq Er ESRCH +No thread could be found corresponding to that specified by the given +thread ID, +.Fa thread . +.El +.Pp +.Sh SEE ALSO +.Xr pthread_join 3 +.Sh STANDARDS +.Fn pthread_detach +conforms to ISO/IEC 9945-1 ANSI/IEEE +.Pq Dq Tn POSIX +Std 1003.1 Second Edition 1996-07-12. diff --git a/lib/libpthread/man/pthread_equal.3 b/lib/libpthread/man/pthread_equal.3 new file mode 100644 index 0000000..9e9f5c7 --- /dev/null +++ b/lib/libpthread/man/pthread_equal.3 @@ -0,0 +1,70 @@ +.\" Copyright (c) 1996 John Birrell <jb@cimlogic.com.au>. +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by John Birrell. +.\" 4. Neither the name of the author nor the names of any co-contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" +.Dd April 4, 1996 +.Dt PTHREAD_EQUAL 3 +.Os BSD 4 +.Sh NAME +.Nm pthread_equal +.Nd compare thread IDs +.Sh LIBRARY +.Lb libc_r +.Sh SYNOPSIS +.Fd #include <pthread.h> +.Ft int +.Fn pthread_equal "pthread_t t1" "pthread_t t2" +.Sh DESCRIPTION +The +.Fn pthread_equal +function compares the thread IDs +.Fa t1 +and +.Fa t2 . +.Sh RETURN VALUES +The +.Fn pthread_equal +function will non-zero if the thread IDs +.Fa t1 +and +.Fa t2 +correspond to the same thread, otherwise it will return zero. +.Sh ERRORS +None. +.Pp +.Sh SEE ALSO +.Xr pthread_create 3 , +.Xr pthread_exit 3 +.Sh STANDARDS +.Fn pthread_equal +conforms to ISO/IEC 9945-1 ANSI/IEEE +.Pq Dq Tn POSIX +Std 1003.1 Second Edition 1996-07-12. diff --git a/lib/libpthread/man/pthread_exit.3 b/lib/libpthread/man/pthread_exit.3 new file mode 100644 index 0000000..6f95e9d --- /dev/null +++ b/lib/libpthread/man/pthread_exit.3 @@ -0,0 +1,107 @@ +.\" Copyright (c) 1996 John Birrell <jb@cimlogic.com.au>. +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by John Birrell. +.\" 4. Neither the name of the author nor the names of any co-contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" +.Dd April 4, 1996 +.Dt PTHREAD_EXIT 3 +.Os BSD 4 +.Sh NAME +.Nm pthread_exit +.Nd terminate the calling thread +.Sh LIBRARY +.Lb libc_r +.Sh SYNOPSIS +.Fd #include <pthread.h> +.Ft void +.Fn pthread_exit "void *value_ptr" +.Sh DESCRIPTION +The +.Fn pthread_exit +function terminates the calling thread and makes the value +.Fa value_ptr +available to any successful join with the terminating thread. +Any +cancellation cleanup handlers that have been pushed and are not yet popped +are popped in the reverse order that they were pushed and then executed. +After all cancellation handlers have been executed, if the thread has any +thread-specific data, appropriate destructor functions are called in an +unspecified order. +Thread termination does not release any application +visible process resources, including, but not limited to, mutexes and +file descriptors, nor does it perform any process level cleanup +actions, including, but not limited to, calling +.Fn atexit +routines that may exist. +.Pp +An implicit call to +.Fn pthread_exit +is made when a thread other than the thread in which +.Fn main +was first invoked returns from the start routine that was used to create +it. The function's return value serves as the thread's exit status. +.Pp +The behavior of +.Fn pthread_exit +is undefined if called from a cancellation handler or destructor function +that was invoked as the result of an implicit or explicit call to +.Fn pthread_exit . +.Pp +After a thread has terminated, the result of access to local (auto) +variables of the thread is undefined. +Thus, references to local variables +of the exiting thread should not be used for the +.Fn pthread_exit +.Fa value_ptr +parameter value. +.Pp +The process will exit with an exit status of 0 after the last thread has +been terminated. +The behavior is as if the implementation called +.Fn exit +with a zero argument at thread termination time. +.Pp +.Sh RETURN VALUES +The +.Fn pthread_exit +function cannot return to its caller. +.Sh ERRORS +None. +.Pp +.Sh SEE ALSO +.Xr _exit 2 , +.Xr exit 3 , +.Xr pthread_create 3 , +.Xr pthread_join 3 +.Sh STANDARDS +.Fn pthread_exit +conforms to ISO/IEC 9945-1 ANSI/IEEE +.Pq Dq Tn POSIX +Std 1003.1 Second Edition 1996-07-12. diff --git a/lib/libpthread/man/pthread_getspecific.3 b/lib/libpthread/man/pthread_getspecific.3 new file mode 100644 index 0000000..9900d29 --- /dev/null +++ b/lib/libpthread/man/pthread_getspecific.3 @@ -0,0 +1,84 @@ +.\" Copyright (c) 1996 John Birrell <jb@cimlogic.com.au>. +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by John Birrell. +.\" 4. Neither the name of the author nor the names of any co-contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" +.Dd April 4, 1996 +.Dt PTHREAD_GETSPECIFIC 3 +.Os BSD 4 +.Sh NAME +.Nm pthread_getspecific +.Nd get a thread-specific data value +.Sh LIBRARY +.Lb libc_r +.Sh SYNOPSIS +.Fd #include <pthread.h> +.Ft void * +.Fn pthread_getspecific "pthread_key_t key" +.Sh DESCRIPTION +The +.Fn pthread_getspecific +function returns the value currently bound to the specified +.Fa key +on behalf of the calling thread. +.Pp +The effect of calling +.Fn pthread_getspecific +with a +.Fa key +value not obtained from +.Fn pthread_key_create +or after +.Fa key +has been deleted with +.Fn pthread_key_delete +is undefined. +.Pp +.Fn pthread_getspecific +may be called from a thread-specific data destructor function. +.Sh RETURN VALUES +The +.Fn pthread_getspecific +function will return the thread-specific data value associated with the given +.Fa key . +If no thread-specific data value is associated with +.Fa key , +then the value NULL is returned. +.Sh ERRORS +None. +.Sh SEE ALSO +.Xr pthread_key_create 3 , +.Xr pthread_key_delete 3 , +.Xr pthread_setspecific 3 +.Sh STANDARDS +.Fn pthread_getspecific +conforms to ISO/IEC 9945-1 ANSI/IEEE +.Pq Dq Tn POSIX +Std 1003.1 Second Edition 1996-07-12. diff --git a/lib/libpthread/man/pthread_join.3 b/lib/libpthread/man/pthread_join.3 new file mode 100644 index 0000000..d6a42e5 --- /dev/null +++ b/lib/libpthread/man/pthread_join.3 @@ -0,0 +1,107 @@ +.\" Copyright (c) 1996-1998 John Birrell <jb@cimlogic.com.au>. +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by John Birrell. +.\" 4. Neither the name of the author nor the names of any co-contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" +.Dd April 4, 1996 +.Dt PTHREAD_JOIN 3 +.Os BSD 4 +.Sh NAME +.Nm pthread_join +.Nd wait for thread termination +.Sh LIBRARY +.Lb libc_r +.Sh SYNOPSIS +.Fd #include <pthread.h> +.Ft int +.Fn pthread_join "pthread_t thread" "void **value_ptr" +.Sh DESCRIPTION +The +.Fn pthread_join +function suspends execution of the calling thread until the target +.Fa thread +terminates unless the target +.Fa thread +has already terminated. +.Pp +On return from a successful +.Fn pthread_join +call with a non-NULL +.Fa value_ptr +argument, the value passed to +.Fn pthread_exit +by the terminating thread is stored in the location referenced by +.Fa value_ptr . +When a +.Fn pthread_join +returns successfully, the target thread has been terminated. +The results +of multiple simultaneous calls to +.Fn pthread_join +specifying the same target thread are undefined. +If the thread calling +.Fn pthread_join +is cancelled, then the target thread is not detached. +.Pp +A thread that has exited but remains unjoined counts against +[_POSIX_THREAD_THREADS_MAX]. +.Pp +.Sh RETURN VALUES +If successful, the +.Fn pthread_join +function will return zero. +Otherwise an error number will be returned to +indicate the error. +.Sh ERRORS +.Fn pthread_join +will fail if: +.Bl -tag -width Er +.It Bq Er EINVAL +The implementation has detected that the value specified by +.Fa thread +does not refer to a joinable thread. +.It Bq Er ESRCH +No thread could be found corresponding to that specified by the given +thread ID, +.Fa thread . +.It Bq Er EDEADLK +A deadlock was detected or the value of +.Fa thread +specifies the calling thread. +.El +.Pp +.Sh SEE ALSO +.Xr wait 2 , +.Xr pthread_create 3 +.Sh STANDARDS +.Fn pthread_join +conforms to ISO/IEC 9945-1 ANSI/IEEE +.Pq Dq Tn POSIX +Std 1003.1 Second Edition 1996-07-12. diff --git a/lib/libpthread/man/pthread_key_create.3 b/lib/libpthread/man/pthread_key_create.3 new file mode 100644 index 0000000..f6a1d9c --- /dev/null +++ b/lib/libpthread/man/pthread_key_create.3 @@ -0,0 +1,109 @@ +.\" Copyright (c) 1996 John Birrell <jb@cimlogic.com.au>. +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by John Birrell. +.\" 4. Neither the name of the author nor the names of any co-contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" +.Dd April 4, 1996 +.Dt PTHREAD_KEY_CREATE 3 +.Os BSD 4 +.Sh NAME +.Nm pthread_key_create +.Nd thread-specific data key creation +.Sh LIBRARY +.Lb libc_r +.Sh SYNOPSIS +.Fd #include <pthread.h> +.Ft int +.Fn pthread_key_create "pthread_key_t *key" "void (*destructor)(void *)" +.Sh DESCRIPTION +The +.Fn pthread_key_create +function creates a thread-specific data key visible to all threads in the +process. +Key values provided by +.Fn pthread_key_create +are opaque objects used to locate thread-specific data. +Although the same +key value may be used by different threads, the values bound to the key +by +.Fn pthread_setspecific +are maintained on a per-thread basis and persist for the life of the calling +thread. +.Pp +Upon key creation, the value NULL is associated with the new key in all +active threads. +Upon thread creation, the value NULL is associated with all +defined keys in the new thread. +.Pp +An optional destructor function may be associated with each key value. +At +thread exit, if a key value has a non-NULL destructor pointer, and the +thread has a non-NULL value associated with the key, the function pointed +to is called with the current associated value as its sole argument. +The +order of destructor calls is unspecified if more than one destructor exists +for a thread when it exits. +.Pp +If, after all the destructors have been called for all non-NULL values +with associated destructors, there are still some non-NULL values with +associated destructors, then the process is repeated. +If, after at least +[PTHREAD_DESTRUCTOR_ITERATIONS] iterations of destructor calls for +outstanding non-NULL values, there are still some non-NULL values with +associated destructors, the implementation stops calling destructors. +.Sh RETURN VALUES +If successful, the +.Fn pthread_key_create +function will store the newly created key value at the location specified by +.Fa key +and returns zero. +Otherwise an error number will be returned to indicate +the error. +.Sh ERRORS +.Fn pthread_key_create +will fail if: +.Bl -tag -width Er +.It Bq Er EAGAIN +The system lacked the necessary resources to create another thread-specific +data key, or the system-imposed limit on the total number of keys per process +[PTHREAD_KEYS_MAX] would be exceeded. +.It Bq Er ENOMEM +Insufficient memory exists to create the key. +.El +.Pp +.Sh SEE ALSO +.Xr pthread_getspecific 3 , +.Xr pthread_key_delete 3 , +.Xr pthread_setspecific 3 +.Sh STANDARDS +.Fn pthread_key_create +conforms to ISO/IEC 9945-1 ANSI/IEEE +.Pq Dq Tn POSIX +Std 1003.1 Second Edition 1996-07-12. diff --git a/lib/libpthread/man/pthread_key_delete.3 b/lib/libpthread/man/pthread_key_delete.3 new file mode 100644 index 0000000..e735eb6 --- /dev/null +++ b/lib/libpthread/man/pthread_key_delete.3 @@ -0,0 +1,100 @@ +.\" Copyright (c) 1996 John Birrell <jb@cimlogic.com.au>. +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by John Birrell. +.\" 4. Neither the name of the author nor the names of any co-contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" +.Dd April 4, 1996 +.Dt PTHREAD_KEY_DELETE 3 +.Os BSD 4 +.Sh NAME +.Nm pthread_key_delete +.Nd delete a thread-specific data key +.Sh LIBRARY +.Lb libc_r +.Sh SYNOPSIS +.Fd #include <pthread.h> +.Ft int +.Fn pthread_key_delete "pthread_key_t key" +.Sh DESCRIPTION +The +.Fn pthread_key_delete +function deletes a thread-specific data key previously returned by +.Fn pthread_key_create . +The thread-specific data values associated with +.Fa key +need not be NULL at the time that +.Fn pthread_key_delete +is called. +It is the responsibility of the application to free any +application storage or perform any cleanup actions for data structures +related to the deleted key or associated thread-specific data in any threads; +this cleanup can be done either before or after +.Fn pthread_key_delete +is called. +Any attempt to use +.Fa key +following the call to +.Fn pthread_key_delete +results in undefined behavior. +.Pp +The +.Fn pthread_key_delete +function is callable from within destructor functions. +Destructor functions +are not invoked by +.Fn pthread_key_delete . +Any destructor function that may have been associated with +.Fa key +will no longer be called upon thread exit. +.Sh RETURN VALUES +If successful, the +.Fn pthread_key_delete +function will return zero. +Otherwise an error number will be returned to +indicate the error. +.Sh ERRORS +.Fn pthread_key_delete +will fail if: +.Bl -tag -width Er +.It Bq Er EINVAL +The +.Fa key +value is invalid. +.El +.Pp +.Sh SEE ALSO +.Xr pthread_getspecific 3 , +.Xr pthread_key_create 3 , +.Xr pthread_setspecific 3 +.Sh STANDARDS +.Fn pthread_key_delete +conforms to ISO/IEC 9945-1 ANSI/IEEE +.Pq Dq Tn POSIX +Std 1003.1 Second Edition 1996-07-12. diff --git a/lib/libpthread/man/pthread_kill.3 b/lib/libpthread/man/pthread_kill.3 new file mode 100644 index 0000000..233c65b --- /dev/null +++ b/lib/libpthread/man/pthread_kill.3 @@ -0,0 +1,75 @@ +.\" Copyright (C) 2000 Jason Evans <jasone@freebsd.org>. +.\" 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(s), this list of conditions and the following disclaimer as +.\" the first lines of this file unmodified other than the possible +.\" addition of one or more copyright notices. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice(s), this list of conditions and the following disclaimer in +.\" the documentation and/or other materials provided with the +.\" distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``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 COPYRIGHT HOLDER(S) 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. +.\" +.\" $FreeBSD$ +.Dd April 27, 2000 +.Dt PTHREAD_KILL 3 +.Os +.Sh NAME +.Nm pthread_kill +.Nd send a signal to a specified thread +.Sh LIBRARY +.Lb libc_r +.Sh SYNOPSIS +.Fd #include <pthread.h> +.Fd #include <signal.h> +.Ft int +.Fn pthread_kill "pthread_t thread" "int sig" +.Sh DESCRIPTION +The +.Fn pthread_kill +function sends a signal, specified by +.Fa sig , +to a thread, specified by +.Fa thread . +If +.Fa sig +is 0, error checking is performed, but no signal is actually sent. +.Sh RETURN VALUES +If successful, +.Fn pthread_kill +returns 0. +Otherwise, an error number is returned. +.Sh ERRORS +.Fn pthread_kill +will fail if: +.Bl -tag -width Er +.It Bq Er ESRCH +.Fa thread +is an invalid thread ID. +.It Bq Er EINVAL +.Fa sig +is an invalid or unsupported signal number. +.El +.Sh SEE ALSO +.Xr kill 2 , +.Xr pthread_self 3 , +.Xr raise 3 +.Sh STANDARDS +.Fn pthread_kill +conforms to +.St -iso9945-1 diff --git a/lib/libpthread/man/pthread_mutex_destroy.3 b/lib/libpthread/man/pthread_mutex_destroy.3 new file mode 100644 index 0000000..87384dc --- /dev/null +++ b/lib/libpthread/man/pthread_mutex_destroy.3 @@ -0,0 +1,74 @@ +.\" Copyright (c) 1997 Brian Cully <shmit@kublai.com> +.\" 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. 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. +.\" +.\" $FreeBSD$ +.\" +.Dd July 29, 1998 +.Dt PTHREAD_MUTEX_DESTROY 3 +.Os BSD 4 +.Sh NAME +.Nm pthread_mutex_destroy +.Nd free resources allocated for a mutex +.Sh LIBRARY +.Lb libc_r +.Sh SYNOPSIS +.Fd #include <pthread.h> +.Ft int +.Fn pthread_mutex_destroy "pthread_mutex_t *mutex" +.Sh DESCRIPTION +The +.Fn pthread_mutex_destroy +function frees the resources allocated for +.Fa mutex . +.Sh RETURN VALUES +If successful, +.Fn pthread_mutex_destroy +will return zero, otherwise an error number will be returned to +indicate the error. +.Sh ERRORS +.Fn pthread_mutex_destroy +will fail if: +.Bl -tag -width Er +.It Bq Er EINVAL +The value specified by +.Fa mutex +is invalid. +.It Bq Er EBUSY +.Fa Mutex +is locked by another thread. +.El +.Pp +.Sh SEE ALSO +.Xr pthread_mutex_init 3 , +.Xr pthread_mutex_lock 3 , +.Xr pthread_mutex_trylock 3 , +.Xr pthread_mutex_unlock 3 +.Sh STANDARDS +.Fn pthread_mutex_destroy +conforms to ISO/IEC 9945-1 ANSI/IEEE +.Pq Dq Tn POSIX +Std 1003.1 Second Edition 1996-07-12. diff --git a/lib/libpthread/man/pthread_mutex_init.3 b/lib/libpthread/man/pthread_mutex_init.3 new file mode 100644 index 0000000..ba19e3b --- /dev/null +++ b/lib/libpthread/man/pthread_mutex_init.3 @@ -0,0 +1,79 @@ +.\" Copyright (c) 1997 Brian Cully <shmit@kublai.com> +.\" 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. 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. +.\" +.\" $FreeBSD$ +.\" +.Dd July 29, 1998 +.Dt PTHREAD_MUTEX_INIT 3 +.Os BSD 4 +.Sh NAME +.Nm pthread_mutex_init +.Nd create a mutex +.Sh LIBRARY +.Lb libc_r +.Sh SYNOPSIS +.Fd #include <pthread.h> +.Ft int +.Fn pthread_mutex_init "pthread_mutex_t *mutex" "const pthread_mutexattr_t *attr" +.Sh DESCRIPTION +The +.Fn pthread_mutex_init +function creates a new mutex, with attributes specified with +.Fa attr . +If +.Fa attr +is NULL the default attributes are used. +.Sh RETURN VALUES +If successful, +.Fn pthread_mutex_init +will return zero and put the new mutex id into +.Fa mutex , +otherwise an error number will be returned to indicate the error. +.Sh ERRORS +.Fn pthread_mutex_init +will fail if: +.Bl -tag -width Er +.It Bq Er EINVAL +The value specified by +.Fa attr +is invalid. +.It Bq Er ENOMEM +The process cannot allocate enough memory to create another mutex. +.It Bq Er EAGAIN +The temporarily lacks the resources to create another mutex. +.El +.Pp +.Sh SEE ALSO +.Xr pthread_mutex_destroy 3 , +.Xr pthread_mutex_lock 3 , +.Xr pthread_mutex_trylock 3 , +.Xr pthread_mutex_unlock 3 +.Sh STANDARDS +.Fn pthread_mutex_init +conforms to ISO/IEC 9945-1 ANSI/IEEE +.Pq Dq Tn POSIX +Std 1003.1 Second Edition 1996-07-12. diff --git a/lib/libpthread/man/pthread_mutex_lock.3 b/lib/libpthread/man/pthread_mutex_lock.3 new file mode 100644 index 0000000..0c6419a --- /dev/null +++ b/lib/libpthread/man/pthread_mutex_lock.3 @@ -0,0 +1,76 @@ +.\" Copyright (c) 1997 Brian Cully <shmit@kublai.com> +.\" 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. 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. +.\" +.\" $FreeBSD$ +.\" +.Dd July 30, 1998 +.Dt PTHREAD_MUTEX_LOCK 3 +.Os BSD 4 +.Sh NAME +.Nm pthread_mutex_lock +.Nd lock a mutex +.Sh LIBRARY +.Lb libc_r +.Sh SYNOPSIS +.Fd #include <pthread.h> +.Ft int +.Fn pthread_mutex_lock "pthread_mutex_t *mutex" +.Sh DESCRIPTION +The +.Fn pthread_mutex_lock +function locks +.Fa mutex . +If the mutex is already locked, the calling thread will block until the +mutex becomes available. +.Sh RETURN VALUES +If successful, +.Fn pthread_mutex_lock +will return zero, otherwise an error number will be returned to +indicate the error. +.Sh ERRORS +.Fn pthread_mutex_lock +will fail if: +.Bl -tag -width Er +.It Bq Er EINVAL +The value specified by +.Fa mutex +is invalid. +.It Bq Er EDEADLK +A deadlock would occur if the thread blocked waiting for +.Fa mutex . +.El +.Pp +.Sh SEE ALSO +.Xr pthread_mutex_destroy 3 , +.Xr pthread_mutex_init 3 , +.Xr pthread_mutex_trylock 3 , +.Xr pthread_mutex_unlock 3 +.Sh STANDARDS +.Fn pthread_mutex_lock +conforms to ISO/IEC 9945-1 ANSI/IEEE +.Pq Dq Tn POSIX +Std 1003.1 Second Edition 1996-07-12. diff --git a/lib/libpthread/man/pthread_mutex_trylock.3 b/lib/libpthread/man/pthread_mutex_trylock.3 new file mode 100644 index 0000000..268a558 --- /dev/null +++ b/lib/libpthread/man/pthread_mutex_trylock.3 @@ -0,0 +1,77 @@ +.\" Copyright (c) 1997 Brian Cully <shmit@kublai.com> +.\" 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. 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. +.\" +.\" $FreeBSD$ +.\" +.Dd July 30, 1998 +.Dt PTHREAD_MUTEX_TRYLOCK 3 +.Os BSD 4 +.Sh NAME +.Nm pthread_mutex_trylock +.Nd attempt to lock a mutex without blocking +.Sh LIBRARY +.Lb libc_r +.Sh SYNOPSIS +.Fd #include <pthread.h> +.Ft int +.Fn pthread_mutex_trylock "pthread_mutex_t *mutex" +.Sh DESCRIPTION +The +.Fn pthread_mutex_trylock +function locks +.Fa mutex . +If the mutex is already locked, +.Fn pthread_mutex_trylock +will not block waiting for the mutex, but will return an error condition. +.Sh RETURN VALUES +If successful, +.Fn pthread_mutex_trylock +will return zero, otherwise an error number will be returned to +indicate the error. +.Sh ERRORS +.Fn pthread_mutex_trylock +will fail if: +.Bl -tag -width Er +.It Bq Er EINVAL +The value specified by +.Fa mutex +is invalid. +.It Bq Er EBUSY +.Fa Mutex +is already locked. +.El +.Pp +.Sh SEE ALSO +.Xr pthread_mutex_destroy 3 , +.Xr pthread_mutex_init 3 , +.Xr pthread_mutex_lock 3 , +.Xr pthread_mutex_unlock 3 +.Sh STANDARDS +.Fn pthread_mutex_trylock +conforms to ISO/IEC 9945-1 ANSI/IEEE +.Pq Dq Tn POSIX +Std 1003.1 Second Edition 1996-07-12. diff --git a/lib/libpthread/man/pthread_mutex_unlock.3 b/lib/libpthread/man/pthread_mutex_unlock.3 new file mode 100644 index 0000000..29d5c61 --- /dev/null +++ b/lib/libpthread/man/pthread_mutex_unlock.3 @@ -0,0 +1,76 @@ +.\" Copyright (c) 1997 Brian Cully <shmit@kublai.com> +.\" 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. 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. +.\" +.\" $FreeBSD$ +.\" +.Dd July 30, 1998 +.Dt PTHREAD_MUTEX_UNLOCK 3 +.Os BSD 4 +.Sh NAME +.Nm pthread_mutex_unlock +.Nd unlock a mutex +.Sh LIBRARY +.Lb libc_r +.Sh SYNOPSIS +.Fd #include <pthread.h> +.Ft int +.Fn pthread_mutex_unlock "pthread_mutex_t *mutex" +.Sh DESCRIPTION +If the current thread holds the lock on +.Fa mutex , +then the +.Fn pthread_mutex_unlock +function unlocks +.Fa mutex . +.Sh RETURN VALUES +If successful, +.Fn pthread_mutex_unlock +will return zero, otherwise an error number will be returned to +indicate the error. +.Sh ERRORS +.Fn pthread_mutex_trylock +will fail if: +.Bl -tag -width Er +.It Bq Er EINVAL +The value specified by +.Fa mutex +is invalid. +.It Bq Er EPERM +The current thread does not hold a lock on +.Fa mutex . +.El +.Pp +.Sh SEE ALSO +.Xr pthread_mutex_destroy 3 , +.Xr pthread_mutex_init 3 , +.Xr pthread_mutex_lock 3 , +.Xr pthread_mutex_trylock 3 +.Sh STANDARDS +.Fn pthread_mutex_unlock +conforms to ISO/IEC 9945-1 ANSI/IEEE +.Pq Dq Tn POSIX +Std 1003.1 Second Edition 1996-07-12. diff --git a/lib/libpthread/man/pthread_mutexattr.3 b/lib/libpthread/man/pthread_mutexattr.3 new file mode 100644 index 0000000..dfbc279 --- /dev/null +++ b/lib/libpthread/man/pthread_mutexattr.3 @@ -0,0 +1,177 @@ +.\" Copyright (C) 2000 Jason Evans <jasone@freebsd.org>. +.\" 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(s), this list of conditions and the following disclaimer as +.\" the first lines of this file unmodified other than the possible +.\" addition of one or more copyright notices. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice(s), this list of conditions and the following disclaimer in +.\" the documentation and/or other materials provided with the +.\" distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``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 COPYRIGHT HOLDER(S) 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. +.\" +.\" $FreeBSD$ +.Dd May 1, 2000 +.Dt PTHREAD_MUTEXATTR 3 +.Os +.Sh NAME +.Nm pthread_mutexattr_init , +.Nm pthread_mutexattr_destroy , +.Nm pthread_mutexattr_setprioceiling , +.Nm pthread_mutexattr_getprioceiling , +.Nm pthread_mutexattr_setprotocol , +.Nm pthread_mutexattr_getprotocol , +.Nm pthread_mutexattr_settype , +.Nm pthread_mutexattr_gettype +.Nd mutex attribute operations +.Sh LIBRARY +.Lb libc_r +.Sh SYNOPSIS +.Fd #include <pthread.h> +.Ft int +.Fn pthread_mutexattr_init "pthread_mutexattr_t *attr" +.Ft int +.Fn pthread_mutexattr_destroy "pthread_mutexattr_t *attr" +.Ft int +.Fn pthread_mutexattr_setprioceiling "pthread_mutexattr_t *attr" "int prioceiling" +.Ft int +.Fn pthread_mutexattr_getprioceiling "pthread_mutexattr_t *attr" "int *prioceiling" +.Ft int +.Fn pthread_mutexattr_setprotocol "pthread_mutexattr_t *attr" "int protocol" +.Ft int +.Fn pthread_mutexattr_getprotocol "pthread_mutexattr_t *attr" "int *protocol" +.Ft int +.Fn pthread_mutexattr_settype "pthread_mutexattr_t *attr" "int type" +.Ft int +.Fn pthread_mutexattr_gettype "pthread_mutexattr_t *attr" "int *type" +.Sh DESCRIPTION +Mutex attributes are used to specify parameters to +.Fn pthread_mutex_init . +One attribute object can be used in multiple calls to +.Fn pthread_mutex_init , +with or without modifications between calls. +.Pp +The +.Fn pthread_mutexattr_init +function initializes +.Fa attr +with all the default mutex attributes. +.Pp +The +.Fn pthread_mutexattr_destroy +function destroys +.Fa attr . +.Pp +The +.Fn pthread_mutexattr_set* +functions set the attribute that corresponds to each function name. +.Pp +The +.Fn pthread_mutexattr_get* +functions copy the value of the attribute that corresponds to each function name +to the location pointed to by the second function parameter. +.Sh RETURN VALUES +If successful, these functions return 0. +Otherwise, an error number is returned to indicacte the error. +.Sh ERRORS +.Fn pthread_mutexattr_init +will fail if: +.Bl -tag -width Er +.It Bq Er ENOMEM +Out of memory. +.El +.Pp +.Fn pthread_mutexattr_destroy +will fail if: +.Bl -tag -width Er +.It Bq Er EINVAL +Invalid value for +.Fa attr . +.El +.Pp +.Fn pthread_mutexattr_setprioceiling +will fail if: +.Bl -tag -width Er +.It Bq Er EINVAL +Invalid value for +.Fa attr , +or invalid value for +.Fa prioceiling . +.El +.Pp +.Fn pthread_mutexattr_getprioceiling +will fail if: +.Bl -tag -width Er +.It Bq Er EINVAL +Invalid value for +.Fa attr . +.El +.Pp +.Fn pthread_mutexattr_setprotocol +will fail if: +.Bl -tag -width Er +.It Bq Er EINVAL +Invalid value for +.Fa attr , +or invalid value for +.Fa protocol . +.El +.Pp +.Fn pthread_mutexattr_getprotocol +will fail if: +.Bl -tag -width Er +.It Bq Er EINVAL +Invalid value for +.Fa attr . +.El +.Pp +.Fn pthread_mutexattr_settype +will fail if: +.Bl -tag -width Er +.It Bq Er EINVAL +Invalid value for +.Fa attr , +or invalid value for +.Fa type . +.El +.Pp +.Fn pthread_mutexattr_gettype +will fail if: +.Bl -tag -width Er +.It Bq Er EINVAL +Invalid value for +.Fa attr . +.El +.Sh SEE ALSO +.Xr pthread_mutex_init 3 +.Sh STANDARDS +.Fn pthread_mutexattr_init +and +.Fn pthread_mutexattr_destroy +conform to +.St -iso9945-1 +.Pp +.Fn pthread_mutexattr_setprioceiling , +.Fn pthread_mutexattr_getprioceiling , +.Fn pthread_mutexattr_setprotocol , +.Fn pthread_mutexattr_getprotocol , +.Fn pthread_mutexattr_settype , +and +.Fn pthread_mutexattr_gettype +conform to +.St -susv2 diff --git a/lib/libpthread/man/pthread_once.3 b/lib/libpthread/man/pthread_once.3 new file mode 100644 index 0000000..e77e180 --- /dev/null +++ b/lib/libpthread/man/pthread_once.3 @@ -0,0 +1,108 @@ +.\" Copyright (c) 1996 John Birrell <jb@cimlogic.com.au>. +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by John Birrell. +.\" 4. Neither the name of the author nor the names of any co-contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" +.Dd April 4, 1996 +.Dt PTHREAD_ONCE 3 +.Os BSD 4 +.Sh NAME +.Nm pthread_once +.Nd dynamic package initialization +.Sh LIBRARY +.Lb libc_r +.Sh SYNOPSIS +.Fd #include <pthread.h> +.Pp +pthread_once_t +.Fa once_control += PTHREAD_ONCE_INIT; +.Ft int +.Fn pthread_once "pthread_once_t *once_control" "void (*init_routine)(void)" +.Sh DESCRIPTION +The first call to +.Fn pthread_once +by any thread in a process, with a given +.Fa once_control , +will call the +.Fn init_routine +with no arguments. +Subsequent calls to +.Fn pthread_once +with the same +.Fa once_control +will not call the +.Fn init_routine . +On return from +.Fn pthread_once , +it is guaranteed that +.Fn init_routine +has completed. +The +.Fa once_control +parameter is used to determine whether the associated initialization +routine has been called. +.Pp +The function +.Fn pthread_once +is not a cancellation point. +However, if +.Fn init_routine +is a cancellation point and is cancelled, the effect on +.Fa once_control is as if +.Fn pthread_once +was never called. +.Pp +The constant +.Fa PTHREAD_ONCE_INIT +is defined by header +.Aq Pa pthread.h . +.Pp +The behavior of +.Fn pthread_once +is undefined if +.Fa once_control +has automatic storage duration or is not initialized by +.Fa PTHREAD_ONCE_INIT . +.Pp +.Sh RETURN VALUES +If successful, the +.Fn pthread_once +function will return zero. +Otherwise an error number will be returned to +indicate the error. +.Sh ERRORS +None. +.Pp +.Sh STANDARDS +.Fn pthread_once +conforms to ISO/IEC 9945-1 ANSI/IEEE +.Pq Dq Tn POSIX +Std 1003.1 Second Edition 1996-07-12. diff --git a/lib/libpthread/man/pthread_rwlock_destroy.3 b/lib/libpthread/man/pthread_rwlock_destroy.3 new file mode 100644 index 0000000..bd1bfe8 --- /dev/null +++ b/lib/libpthread/man/pthread_rwlock_destroy.3 @@ -0,0 +1,82 @@ +.\" Copyright (c) 1998 Alex Nash +.\" 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. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. +.\" +.\" $FreeBSD$ +.\" +.Dd August 4, 1998 +.Dt PTHREAD_RWLOCK_DESTROY 3 +.Os +.Sh NAME +.Nm pthread_rwlock_destroy +.Nd destroy a read/write lock +.Sh LIBRARY +.Lb libc_r +.Sh SYNOPSIS +.Fd #include <pthread.h> +.Ft int +.Fn pthread_rwlock_destroy "pthread_rwlock_t *lock" +.Sh DESCRIPTION +The +.Fn pthread_rwlock_destroy +function is used to destroy a read/write lock previously created with +.Fn pthread_rwlock_init . +.Sh RETURN VALUES +If successful, the +.Fn pthread_rwlock_destroy +function will return zero. Otherwise an error number will be returned +to indicate the error. +.Sh SEE ALSO +.Xr pthread_rwlock_init 3 +.Sh STANDARDS +The +.Fn pthread_rwlock_destroy +function is expected to conform to +.St -susv2 . +.Sh ERRORS +The +.Fn pthread_rwlock_destroy +function will fail if: +.Bl -tag -width Er +.It Bq Er EPERM +The caller does not have the privilege to perform the operation. +.El +.Pp +The +.Fn pthread_rwlock_destroy +function may fail if: +.Bl -tag -width Er +.It Bq Er EBUSY +The system has detected an attempt to destroy the object referenced by +.Fa lock +while it is locked. +.It Bq Er EINVAL +The value specified by +.Fa lock +is invalid. +.El +.Sh HISTORY +The +.Fn pthread_rwlock_destroy +function first appeared in +.Fx 3.0 . diff --git a/lib/libpthread/man/pthread_rwlock_init.3 b/lib/libpthread/man/pthread_rwlock_init.3 new file mode 100644 index 0000000..128f5d1 --- /dev/null +++ b/lib/libpthread/man/pthread_rwlock_init.3 @@ -0,0 +1,101 @@ +.\" Copyright (c) 1998 Alex Nash +.\" 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. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. +.\" +.\" $FreeBSD$ +.\" +.Dd August 4, 1998 +.Dt PTHREAD_RWLOCK_INIT 3 +.Os +.Sh NAME +.Nm pthread_rwlock_init +.Nd initialize a read/write lock +.Sh LIBRARY +.Lb libc_r +.Sh SYNOPSIS +.Fd #include <pthread.h> +.Ft int +.Fn pthread_rwlock_init "pthread_rwlock_t *lock" "const pthread_rwlockattr_t *attr" +.Sh DESCRIPTION +The +.Fn pthread_rwlock_init +function is used to initialize a read/write lock, with attributes +specified by +.Fa attr . +If +.Fa attr +is NULL, the default read/write lock attributes are used. +.Pp +The results of calling +.Fn pthread_rwlock_init +with an already initialized lock are undefined. +.Sh RETURN VALUES +If successful, the +.Fn pthread_rwlock_init +function will return zero. Otherwise an error number will be returned +to indicate the error. +.Sh SEE ALSO +.Xr pthread_rwlock_destroy 3 , +.Xr pthread_rwlockattr_init 3 , +.Xr pthread_rwlockattr_setpshared 3 +.Sh STANDARDS +The +.Fn pthread_rwlock_init +function is expected to conform to +.St -susv2 . +.Sh ERRORS +The +.Fn pthread_rwlock_init +function will fail if: +.Bl -tag -width Er +.It Bq Er EAGAIN +The system lacked the necessary resources (other than memory) to +initialize the lock. +.It Bq Er ENOMEM +Insufficient memory exists to initialize the lock. +.It Bq Er EPERM +The caller does not have sufficient privilege to perform the +operation. +.El +.Pp +The +.Fn pthread_rwlock_init +function may fail if: +.Bl -tag -width Er +.It Bq Er EBUSY +The system has detected an attempt to re-initialize the object +referenced by +.Fa lock , +a previously initialized but not yet destroyed read/write lock. +.It Bq Er EINVAL +The value specified by +.Fa attr +is invalid. +.El +.Sh HISTORY +The +.Fn pthread_rwlock_init +function first appeared in +.Fx 3.0 . +.Sh BUGS +The PTHREAD_PROCESS_SHARED attribute is not supported. diff --git a/lib/libpthread/man/pthread_rwlock_rdlock.3 b/lib/libpthread/man/pthread_rwlock_rdlock.3 new file mode 100644 index 0000000..d3ec9ef --- /dev/null +++ b/lib/libpthread/man/pthread_rwlock_rdlock.3 @@ -0,0 +1,124 @@ +.\" Copyright (c) 1998 Alex Nash +.\" 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. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. +.\" +.\" $FreeBSD$ +.\" +.Dd August 4, 1998 +.Dt PTHREAD_RWLOCK_RDLOCK 3 +.Os +.Sh NAME +.Nm pthread_rwlock_rdlock , +.Nm pthread_rwlock_tryrdlock +.Nd acquire a read/write lock for reading +.Sh LIBRARY +.Lb libc_r +.Sh SYNOPSIS +.Fd #include <pthread.h> +.Ft int +.Fn pthread_rwlock_rdlock "pthread_rwlock_t *lock" +.Ft int +.Fn pthread_rwlock_tryrdlock "pthread_rwlock_t *lock" +.Sh DESCRIPTION +The +.Fn pthread_rwlock_rdlock +function acquires a read lock on +.Fa lock +provided that +.Fa lock +is not presently held for writing and no writer threads are +presently blocked on the lock. If the read lock cannot be +immediately acquired, the calling thread blocks until it can +acquire the lock. +.Pp +The +.Fn pthread_rwlock_tryrdlock +function performs the same action, but does not block if the lock +cannot be immediately obtained (i.e. the lock is held for writing +or there are waiting writers). +.Pp +A thread may hold multiple concurrent read locks. If so, +.Fn pthread_rwlock_unlock +must be called once for each lock obtained. +.Pp +The results of acquiring a read lock while the calling thread holds +a write lock are undefined. +.Sh IMPLEMENTATION NOTES +To prevent writer starvation, writers are favored over readers. +.Sh RETURN VALUES +If successful, the +.Fn pthread_rwlock_rdlock +and +.Fn pthread_rwlock_tryrdlock +functions will return zero. Otherwise an error number will be returned +to indicate the error. +.Sh SEE ALSO +.Xr pthread_rwlock_init 3 , +.Xr pthread_rwlock_trywrlock 3 , +.Xr pthread_rwlock_unlock 3 , +.Xr pthread_rwlock_wrlock 3 +.Sh STANDARDS +The +.Fn pthread_rwlock_rdlock +and +.Fn pthread_rwlock_tryrdlock +functions are expected to conform to +.St -susv2 . +.Sh ERRORS +The +.Fn pthread_rwlock_tryrdlock +function will fail if: +.Bl -tag -width Er +.It Bq Er EBUSY +The lock could not be acquired because a writer holds the lock or +was blocked on it. +.El +.Pp +The +.Fn pthread_rwlock_rdlock +and +.Fn pthread_rwlock_tryrdlock +functions may fail if: +.Bl -tag -width Er +.It Bq Er EAGAIN +The lock could not be acquired because the maximum number of read locks +against +.Fa lock +has been exceeded. +.It Bq Er EDEADLK +The current thread already owns +.Fa lock +for writing. +.It Bq Er EINVAL +The value specified by +.Fa lock +is invalid. +.It Bq Er ENOMEM +Insufficient memory exists to initialize the lock (applies to +statically initialized locks only). +.El +.Sh HISTORY +The +.Fn pthread_rwlock_rdlock +function first appeared in +.Fx 3.0 . diff --git a/lib/libpthread/man/pthread_rwlock_unlock.3 b/lib/libpthread/man/pthread_rwlock_unlock.3 new file mode 100644 index 0000000..f99b955 --- /dev/null +++ b/lib/libpthread/man/pthread_rwlock_unlock.3 @@ -0,0 +1,81 @@ +.\" Copyright (c) 1998 Alex Nash +.\" 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. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. +.\" +.\" $FreeBSD$ +.\" +.Dd August 4, 1998 +.Dt PTHREAD_RWLOCK_UNLOCK 3 +.Os +.Sh NAME +.Nm pthread_rwlock_unlock +.Nd release a read/write lock +.Sh LIBRARY +.Lb libc_r +.Sh SYNOPSIS +.Fd #include <pthread.h> +.Ft int +.Fn pthread_rwlock_unlock "pthread_rwlock_t *lock" +.Sh DESCRIPTION +The +.Fn pthread_rwlock_unlock +function is used to release the read/write lock previously obtained by +.Fn pthread_rwlock_rdlock , +.Fn pthread_rwlock_wrlock , +.Fn pthread_rwlock_tryrdlock , +or +.Fn pthread_rwlock_trywrlock . +.Sh RETURN VALUES +If successful, the +.Fn pthread_rwlock_unlock +function will return zero. Otherwise an error number will be returned +to indicate the error. +.Pp +The results are undefined if +.Fa lock +is not held by the calling thread. +.Sh SEE ALSO +.Xr pthread_rwlock_rdlock 3 , +.Xr pthread_rwlock_wrlock 3 +.Sh STANDARDS +The +.Fn pthread_rwlock_unlock +function is expected to conform to +.St -susv2 . +.Sh ERRORS +The +.Fn pthread_rwlock_unlock +function may fail if: +.Bl -tag -width Er +.It Bq Er EINVAL +The value specified by +.Fa lock +is invalid. +.It Bq Er EPERM +The current thread does not own the read/write lock. +.El +.Sh HISTORY +The +.Fn pthread_rwlock_unlock +function first appeared in +.Fx 3.0 . diff --git a/lib/libpthread/man/pthread_rwlock_wrlock.3 b/lib/libpthread/man/pthread_rwlock_wrlock.3 new file mode 100644 index 0000000..149a7a0 --- /dev/null +++ b/lib/libpthread/man/pthread_rwlock_wrlock.3 @@ -0,0 +1,104 @@ +.\" Copyright (c) 1998 Alex Nash +.\" 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. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. +.\" +.\" $FreeBSD$ +.\" +.Dd August 4, 1998 +.Dt PTHREAD_RWLOCK_WRLOCK 3 +.Os +.Sh NAME +.Nm pthread_rwlock_wrlock , +.Nm pthread_rwlock_trywrlock +.Nd acquire a read/write lock for writing +.Sh LIBRARY +.Lb libc_r +.Sh SYNOPSIS +.Fd #include <pthread.h> +.Ft int +.Fn pthread_rwlock_wrlock "pthread_rwlock_t *lock" +.Ft int +.Fn pthread_rwlock_trywrlock "pthread_rwlock_t *lock" +.Sh DESCRIPTION +The +.Fn pthread_rwlock_wrlock +function blocks until a write lock can be acquired against +.Fa lock . +The +.Fn pthread_rwlock_trywrlock +function performs the same action, but does not block if the lock +cannot be immediately obtained. +.Pp +The results are undefined if the calling thread already holds the +lock at the time the call is made. +.Sh IMPLEMENTATION NOTES +To prevent writer starvation, writers are favored over readers. +.Sh RETURN VALUES +If successful, the +.Fn pthread_rwlock_wrlock +and +.Fn pthread_rwlock_trywrlock +functions will return zero. Otherwise an error number will be returned +to indicate the error. +.Sh SEE ALSO +.Xr pthread_rwlock_trywrlock 3 , +.Xr pthread_rwlock_unlock 3 , +.Xr pthread_rwlock_wrlock 3 +.Sh STANDARDS +The +.Fn pthread_rwlock_wrlock +and +.Fn pthread_rwlock_trywrlock +functions are expected to conform to +.St -susv2 . +.Sh ERRORS +The +.Fn pthread_rwlock_trywrlock +function will fail if: +.Bl -tag -width Er +.It Bq Er EBUSY +The calling thread is not able to acquire the lock without blocking. +.El +.Pp +The +.Fn pthread_rwlock_wrlock +and +.Fn pthread_rwlock_trywrlock +functions may fail if: +.Bl -tag -width Er +.It Bq Er EDEADLK +The calling thread already owns the read/write lock (for reading +or writing). +.It Bq Er EINVAL +The value specified by +.Fa lock +is invalid. +.It Bq Er ENOMEM +Insufficient memory exists to initialize the lock (applies to +statically initialized locks only). +.El +.Sh HISTORY +The +.Fn pthread_rwlock_wrlock +function first appeared in +.Fx 3.0 . diff --git a/lib/libpthread/man/pthread_rwlockattr_destroy.3 b/lib/libpthread/man/pthread_rwlockattr_destroy.3 new file mode 100644 index 0000000..80db1a9 --- /dev/null +++ b/lib/libpthread/man/pthread_rwlockattr_destroy.3 @@ -0,0 +1,70 @@ +.\" Copyright (c) 1998 Alex Nash +.\" 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. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. +.\" +.\" $FreeBSD$ +.\" +.Dd August 4, 1998 +.Dt PTHREAD_RWLOCKATTR_DESTROY 3 +.Os +.Sh NAME +.Nm pthread_rwlockattr_destroy +.Nd destroy a read/write lock +.Sh LIBRARY +.Lb libc_r +.Sh SYNOPSIS +.Fd #include <pthread.h> +.Ft int +.Fn pthread_rwlockattr_destroy "pthread_rwlockattr_t *attr" +.Sh DESCRIPTION +The +.Fn pthread_rwlockattr_destroy +function is used to destroy a read/write lock attribute object +previously created with +.Fn pthread_rwlockattr_init . +.Sh RETURN VALUES +If successful, the +.Fn pthread_rwlockattr_destroy +function will return zero. Otherwise an error number will be returned +to indicate the error. +.Sh SEE ALSO +.Xr pthread_rwlockattr_init 3 +.Sh STANDARDS +The +.Fn pthread_rwlockattr_destroy +function is expected to conform to +.St -susv2 . +.Sh ERRORS +.Fn pthread_rwlockattr_destroy +may fail if: +.Bl -tag -width Er +.It Bq Er EINVAL +The value specified by +.Fa attr +is invalid. +.El +.Sh HISTORY +The +.Fn pthread_rwlockattr_destroy +function first appeared in +.Fx 3.0 . diff --git a/lib/libpthread/man/pthread_rwlockattr_getpshared.3 b/lib/libpthread/man/pthread_rwlockattr_getpshared.3 new file mode 100644 index 0000000..7637a4f --- /dev/null +++ b/lib/libpthread/man/pthread_rwlockattr_getpshared.3 @@ -0,0 +1,82 @@ +.\" Copyright (c) 1998 Alex Nash +.\" 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. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. +.\" +.\" $FreeBSD$ +.\" +.Dd March 22, 1999 +.Dt PTHREAD_RWLOCKATTR_GETPSHARED 3 +.Os +.Sh NAME +.Nm pthread_rwlockattr_getpshared +.Nd get the process shared attribute +.Sh LIBRARY +.Lb libc_r +.Sh SYNOPSIS +.Fd #include <pthread.h> +.Ft int +.Fn pthread_rwlockattr_getpshared "const pthread_rwlockattr_t *attr" "int *pshared" +.Sh DESCRIPTION +The +.Fn pthread_rwlockattr_getpshared +function is used to get the process shared setting of a read/write +lock attribute object. The setting is returned via +.Fa pshared , +and may be one of two values: +.Bl -hang -offset flag -width 123456789012345678901234 +.It Ar PTHREAD_PROCESS_SHARED +Any thread of any process that has access to the memory where the +read/write lock resides can manipulate the lock. +.It Ar PTHREAD_PROCESS_PRIVATE +Only threads created within the same process as the thread that +initialized the read/write lock can manipulate the lock. This is +the default value. +.El +.Sh RETURN VALUES +If successful, the +.Fn pthread_rwlockattr_getpshared +function will return zero. Otherwise an error number will be returned +to indicate the error. +.Sh SEE ALSO +.Xr pthread_rwlock_init 3 , +.Xr pthread_rwlockattr_init 3 , +.Xr pthread_rwlockattr_setpshared 3 +.Sh STANDARDS +The +.Fn pthread_rwlockattr_getpshared +function is expected to conform to +.St -susv2 . +.Sh ERRORS +.Fn pthread_rwlockattr_getpshared +may fail if: +.Bl -tag -width Er +.It Bq Er EINVAL +The value specified by +.Fa attr +is invalid. +.El +.Sh HISTORY +The +.Fn pthread_rwlockattr_getpshared +function first appeared in +.Fx 3.0 . diff --git a/lib/libpthread/man/pthread_rwlockattr_init.3 b/lib/libpthread/man/pthread_rwlockattr_init.3 new file mode 100644 index 0000000..c355104 --- /dev/null +++ b/lib/libpthread/man/pthread_rwlockattr_init.3 @@ -0,0 +1,69 @@ +.\" Copyright (c) 1998 Alex Nash +.\" 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. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. +.\" +.\" $FreeBSD$ +.\" +.Dd August 4, 1998 +.Dt PTHREAD_RWLOCKATTR_INIT 3 +.Os +.Sh NAME +.Nm pthread_rwlockattr_init +.Nd initialize a read/write lock +.Sh LIBRARY +.Lb libc_r +.Sh SYNOPSIS +.Fd #include <pthread.h> +.Ft int +.Fn pthread_rwlockattr_init "pthread_rwlockattr_t *attr" +.Sh DESCRIPTION +The +.Fn pthread_rwlockattr_init +function is used to initialize a read/write lock attributes object. +.Sh RETURN VALUES +If successful, the +.Fn pthread_rwlockattr_init +function will return zero. Otherwise an error number will be returned +to indicate the error. +.Sh SEE ALSO +.Xr pthread_rwlock_init 3 , +.Xr pthread_rwlockattr_destroy 3 , +.Xr pthread_rwlockattr_getpshared 3 , +.Xr pthread_rwlockattr_setpshared 3 +.Sh STANDARDS +The +.Fn pthread_rwlockattr_init +function is expected to conform to +.St -susv2 . +.Sh ERRORS +.Fn pthread_rwlockattr_init +will fail if: +.Bl -tag -width Er +.It Bq Er ENOMEM +Insufficient memory exists to initialize the attribute object. +.El +.Sh HISTORY +The +.Fn pthread_rwlockattr_init +function first appeared in +.Fx 3.0 . diff --git a/lib/libpthread/man/pthread_rwlockattr_setpshared.3 b/lib/libpthread/man/pthread_rwlockattr_setpshared.3 new file mode 100644 index 0000000..b2c16eb --- /dev/null +++ b/lib/libpthread/man/pthread_rwlockattr_setpshared.3 @@ -0,0 +1,88 @@ +.\" Copyright (c) 1998 Alex Nash +.\" 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. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. +.\" +.\" $FreeBSD$ +.\" +.Dd August 4, 1998 +.Dt PTHREAD_RWLOCKATTR_SETPSHARED 3 +.Os +.Sh NAME +.Nm pthread_rwlockattr_setpshared +.Nd set the process shared attribute +.Sh LIBRARY +.Lb libc_r +.Sh SYNOPSIS +.Fd #include <pthread.h> +.Ft int +.Fn pthread_rwlockattr_setpshared "pthread_rwlockattr_t *attr" "int pshared" +.Sh DESCRIPTION +The +.Fn pthread_rwlockattr_setpshared +function sets the process shared attribute of +.Fa attr +to the value referenced by +.Fa pshared . +.Fa pshared +may be one of two values: +.Bl -hang -offset flag -width 123456789012345678901234 +.It Ar PTHREAD_PROCESS_SHARED +Any thread of any process that has access to the memory where the +read/write lock resides can manipulate the lock. +.It Ar PTHREAD_PROCESS_PRIVATE +Only threads created within the same process as the thread that +initialized the read/write lock can manipulate the lock. This is +the default value. +.El +.Sh RETURN VALUES +If successful, the +.Fn pthread_rwlockattr_setpshared +function will return zero. Otherwise an error number will be returned +to indicate the error. +.Sh SEE ALSO +.Xr pthread_rwlock_init 3 , +.Xr pthread_rwlockattr_init 3 , +.Xr pthread_rwlockattr_setpshared 3 +.Sh STANDARDS +The +.Fn pthread_rwlockattr_setpshared +function is expected to conform to +.St -susv2 . +.Sh ERRORS +.Fn pthread_rwlockattr_setpshared +will fail if: +.Bl -tag -width Er +.It Bq Er EINVAL +The value specified by +.Fa attr +or +.Fa pshared +is invalid. +.El +.Sh HISTORY +The +.Fn pthread_rwlockattr_setpshared +function first appeared in +.Fx 3.0 . +.Sh BUGS +The PTHREAD_PROCESS_SHARED attribute is not supported. diff --git a/lib/libpthread/man/pthread_schedparam.3 b/lib/libpthread/man/pthread_schedparam.3 new file mode 100644 index 0000000..3e2e32e --- /dev/null +++ b/lib/libpthread/man/pthread_schedparam.3 @@ -0,0 +1,90 @@ +.\" Copyright (C) 2000 Jason Evans <jasone@freebsd.org>. +.\" 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(s), this list of conditions and the following disclaimer as +.\" the first lines of this file unmodified other than the possible +.\" addition of one or more copyright notices. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice(s), this list of conditions and the following disclaimer in +.\" the documentation and/or other materials provided with the +.\" distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``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 COPYRIGHT HOLDER(S) 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. +.\" +.\" $FreeBSD$ +.Dd May 1, 2000 +.Dt PTHREAD_SCHEDPARAM 3 +.Os +.Sh NAME +.Nm pthread_setschedparam , +.Nm pthread_getschedparam +.Nd thread scheduling parameter manipulation +.Sh LIBRARY +.Lb libc_r +.Sh SYNOPSIS +.Fd #include <pthread.h> +.Ft int +.Fn pthread_setschedparam "pthread_t thread" "int policy" "const struct sched_param *param" +.Ft int +.Fn pthread_getschedparam "pthread_t thread" "int *policy" "struct sched_param *param" +.Sh DESCRIPTION +The +.Fn pthread_setschedparam +and +.Fn pthread_getschedparam +functions set and get the scheduling parameters of individual threads. +The scheduling policy for a thread can either be +.Dv SCHED_FIFO +(first in, first out) or +.Dv SCHED_RR +(round-robin). +The thread priority (accessed via +.Va param->sched_priority ) +must be at least +.Dv PTHREAD_MIN_PRIORITY +and no more than +.Dv PTHREAD_MAX_PRIORITY . +.Sh RETURN VALUES +If successful, these functions return 0. +Otherwise, an error number is returned to indicate the error. +.Sh ERRORS +.Fn pthread_setschedparam +will fail if: +.Bl -tag -width Er +.It Bq Er EINVAL +Invalid value for +.Va policy . +.It Bq Er ENOTSUP +Invalid value for scheduling parameters. +.It Bq Er ESRCH +Non-existent thread +.Va thread . +.El +.Pp +.Fn pthread_getschedparam +will fail if: +.Bl -tag -width Er +.It Bq Er ESRCH +Non-existent thread +.Va thread . +.El +.Sh STANDARDS +.Fn pthread_setschedparam +and +.Fn pthread_getschedparam +conform to +.St -susv2 diff --git a/lib/libpthread/man/pthread_self.3 b/lib/libpthread/man/pthread_self.3 new file mode 100644 index 0000000..c196875 --- /dev/null +++ b/lib/libpthread/man/pthread_self.3 @@ -0,0 +1,63 @@ +.\" Copyright (c) 1996 John Birrell <jb@cimlogic.com.au>. +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by John Birrell. +.\" 4. Neither the name of the author nor the names of any co-contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" +.Dd April 4, 1996 +.Dt PTHREAD_SELF 3 +.Os BSD 4 +.Sh NAME +.Nm pthread_self +.Nd get the calling thread's ID +.Sh LIBRARY +.Lb libc_r +.Sh SYNOPSIS +.Fd #include <pthread.h> +.Ft pthread_t +.Fn pthread_self "void" +.Sh DESCRIPTION +The +.Fn pthread_self +function returns the thread ID of the calling thread. +.Sh RETURN VALUES +The +.Fn pthread_self +function returns the thread ID of the calling thread. +.Sh ERRORS +None. +.Pp +.Sh SEE ALSO +.Xr pthread_create 3 , +.Xr pthread_equal 3 +.Sh STANDARDS +.Fn pthread_self +conforms to ISO/IEC 9945-1 ANSI/IEEE +.Pq Dq Tn POSIX +Std 1003.1 Second Edition 1996-07-12. diff --git a/lib/libpthread/man/pthread_setspecific.3 b/lib/libpthread/man/pthread_setspecific.3 new file mode 100644 index 0000000..2ab28de --- /dev/null +++ b/lib/libpthread/man/pthread_setspecific.3 @@ -0,0 +1,97 @@ +.\" Copyright (c) 1996 John Birrell <jb@cimlogic.com.au>. +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by John Birrell. +.\" 4. Neither the name of the author nor the names of any co-contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" +.Dd April 4, 1996 +.Dt PTHREAD_SETSPECIFIC 3 +.Os BSD 4 +.Sh NAME +.Nm pthread_setspecific +.Nd set a thread-specific data value +.Sh LIBRARY +.Lb libc_r +.Sh SYNOPSIS +.Fd #include <pthread.h> +.Ft int +.Fn pthread_setspecific "pthread_key_t key" "const void *value" +.Sh DESCRIPTION +The +.Fn pthread_setspecific +function associates a thread-specific value with a +.Fa key +obtained via a previous call to +.Fn pthread_key_create . +Different threads man bind different values to the same key. +These values are +typically pointers to blocks of dynamically allocated memory that have been +reserved for use by the calling thread. +.Pp +The effect of calling +.Fn pthread_setspecific +with a key value not obtained from +.Fn pthread_key_create +or after +.Fa key +has been deleted with +.Fn pthread_key_delete +is undefined. +.Pp +.Fn pthread_setspecific +may be called from a thread-specific data destructor function, however this +may result in lost storage or infinite loops. +.Sh RETURN VALUES +If successful, the +.Fn pthread_setspecific +function will return zero. +Otherwise an error number will be returned to +indicate the error. +.Sh ERRORS +.Fn pthread_setspecific +will fail if: +.Bl -tag -width Er +.It Bq Er ENOMEM +Insufficient memory exists to associate the value with the +.Fa key . +.It Bq Er EINVAL +The +.Fa key +value is invalid. +.El +.Pp +.Sh SEE ALSO +.Xr pthread_getspecific 3 , +.Xr pthread_key_create 3 , +.Xr pthread_key_delete 3 +.Sh STANDARDS +.Fn pthread_setspecific +conforms to ISO/IEC 9945-1 ANSI/IEEE +.Pq Dq Tn POSIX +Std 1003.1 Second Edition 1996-07-12. diff --git a/lib/libpthread/man/pthread_sigmask.3 b/lib/libpthread/man/pthread_sigmask.3 new file mode 100644 index 0000000..73aa69a --- /dev/null +++ b/lib/libpthread/man/pthread_sigmask.3 @@ -0,0 +1,96 @@ +.\" Copyright (C) 2000 Jason Evans <jasone@freebsd.org>. +.\" 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(s), this list of conditions and the following disclaimer as +.\" the first lines of this file unmodified other than the possible +.\" addition of one or more copyright notices. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice(s), this list of conditions and the following disclaimer in +.\" the documentation and/or other materials provided with the +.\" distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``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 COPYRIGHT HOLDER(S) 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. +.\" +.\" $FreeBSD$ +.Dd April 27, 2000 +.Dt PTHREAD_SIGMASK 3 +.Os +.Sh NAME +.Nm pthread_sigmask +.Nd examine and/or change a thread's signal mask +.Sh LIBRARY +.Lb libc_r +.Sh SYNOPSIS +.Fd #include <pthread.h> +.Fd #include <signal.h> +.Ft int +.Fn pthread_sigmask "int how" "const sigset_t *set" "sigset_t *oset" +.Sh DESCRIPTION +The +.Fn pthread_sigmask +function examines and/or changes the calling thread's signal mask. +.Pp +If +.Fa set +is not +.Dv NULL , +it specifies a set of signals to be modified, and +.Fa how +specifies what to set the signal mask to: +.Bl -tag -width SIG_UNBLOCK +.It Dv SIG_BLOCK +Union of the current mask and +.Fa set . +.It Dv SIG_UNBLOCK +Intersection of the current mask and the complement of +.Fa set . +.It Dv SIG_SETMASK +.Fa set . +.El +.Pp +If +.Fa oset +is not NULL, the previous signal mask is stored in the location pointed to by +.Fa oset . +.Pp +.Dv SIGKILL +and +.Dv SIGSTOP +cannot be blocked, and will be silently ignored if included in the signal mask. +.Sh RETURN VALUES +If successful, +.Fn pthread_sigmask +returns 0. +Otherwise, an error is returned. +.Sh ERRORS +.Fn pthread_sigmask +will fail if: +.Bl -tag -width Er +.It Bq Er EINVAL +.Fa how +is not one of the defined values. +.El +.Sh SEE ALSO +.Xr sigaction 2 , +.Xr sigpending 2 , +.Xr sigprocmask 2 , +.Xr sigsetops 3 , +.Xr sigsuspend 2 +.Sh STANDARDS +.Fn pthread_sigmask +conforms to +.St -iso9945-1 diff --git a/lib/libpthread/man/pthread_testcancel.3 b/lib/libpthread/man/pthread_testcancel.3 new file mode 100644 index 0000000..c1bbc7d --- /dev/null +++ b/lib/libpthread/man/pthread_testcancel.3 @@ -0,0 +1,199 @@ +.\" $FreeBSD$ +.Dd January 17, 1999 +.Dt PTHREAD_TESTCANCEL 3 +.Os +.Sh NAME +.Nm pthread_setcancelstate , +.Nm pthread_setcanceltype , +.Nm pthread_testcancel +.Nd set cancelability state +.Sh LIBRARY +.Lb libc_r +.Sh SYNOPSIS +.Fd #include <pthread.h> +.Ft int +.Fn pthread_setcancelstate "int state" "int *oldstate" +.Ft int +.Fn pthread_setcanceltype "int type" "int *oldtype" +.Ft void +.Fn pthread_testcancel "void" +.Sh DESCRIPTION +The +.Fn pthread_setcancelstate +function atomically both sets the calling thread's cancelability state +to the indicated +.Fa state +and returns the previous cancelability state at the location referenced by +.Fa oldstate . +Legal values for +.Fa state +are +.Dv PTHREAD_CANCEL_ENABLE +and +.Dv PTHREAD_CANCEL_DISABLE . +.Pp +The +.Fn pthread_setcanceltype +function atomically both sets the calling thread's cancelability type +to the indicated +.Fa type +and returns the previous cancelability type at the location referenced by +.Fa oldtype . +Legal values for +.Fa type +are +.Dv PTHREAD_CANCEL_DEFERRED +and +.Dv PTHREAD_CANCEL_ASYNCHRONOUS . +.Pp +The cancelability state and type of any newly created threads, including the +thread in which +.Fn main +was first invoked, are +.Dv PTHREAD_CANCEL_ENABLE +and +.Dv PTHREAD_CANCEL_DEFERRED +respectively. +.Pp +The +.Fn pthread_testcancel +function creates a cancellation point in the calling thread. +The +.Fn pthread_testcancel +function has no effect if cancelability is disabled. +.Pp +.Ss Cancelability States +The cancelability state of a thread determines the action taken upon +receipt of a cancellation request. +The thread may control cancellation in +a number of ways. +.Pp +Each thread maintains its own +.Dq cancelability state +which may be encoded in two bits: +.Bl -hang +.It Em Cancelability Enable +When cancelability is +.Dv PTHREAD_CANCEL_DISABLE , +cancellation requests against the target thread are held pending. +.It Em Cancelability Type +When cancelability is enabled and the cancelability type is +.Dv PTHREAD_CANCEL_ASYNCHRONOUS , +new or pending cancellation requests may be acted upon at any time. +When cancelability is enabled and the cancelability type is +.Dv PTHREAD_CANCEL_DEFERRED , +cancellation requests are held pending until a cancellation point (see +below) is reached. +If cancelability is disabled, the setting of the +cancelability type has no immediate effect as all cancellation requests +are held pending; however, once cancelability is enabled again the new +type will be in effect. +.El +.Ss Cancellation Points +Cancellation points will occur when a thread is executing the following +functions: +.Fn close , +.Fn creat , +.Fn fcntl , +.Fn fsync , +.Fn msync , +.Fn nanosleep , +.Fn open , +.Fn pause , +.Fn pthread_cond_timedwait , +.Fn pthread_cond_wait , +.Fn pthread_join , +.Fn pthread_testcancel , +.Fn read , +.Fn sigwaitinfo , +.Fn sigsuspend , +.Fn sigwait , +.Fn sleep , +.Fn system , +.Fn tcdrain , +.Fn wait , +.Fn waitpid , +.Fn write . +.Sh RETURN VALUES +If successful, the +.Fn pthread_setcancelstate +and +.Fn pthread_setcanceltype +functions will return zero. +Otherwise, an error number shall be returned to +indicate the error. +.Pp +The +.Fn pthread_setcancelstate +and +.Fn pthread_setcanceltype +functions are used to control the points at which a thread may be +asynchronously canceled. +For cancellation control to be usable in modular +fashion, some rules must be followed. +.Pp +For purposes of this discussion, consider an object to be a generalization +of a procedure. +It is a set of procedures and global variables written as +a unit and called by clients not known by the object. +Objects may depend +on other objects. +.Pp +First, cancelability should only be disabled on entry to an object, never +explicitly enabled. +On exit from an object, the cancelability state should +always be restored to its value on entry to the object. +.Pp +This follows from a modularity argument: if the client of an object (or the +client of an object that uses that object) has disabled cancelability, it is +because the client doesn't want to have to worry about how to clean up if the +thread is canceled while executing some sequence of actions. +If an object +is called in such a state and it enables cancelability and a cancellation +request is pending for that thread, then the thread will be canceled, +contrary to the wish of the client that disabled. +.Pp +Second, the cancelability type may be explicitly set to either +.Em deferred +or +.Em asynchronous +upon entry to an object. +But as with the cancelability state, on exit from +an object that cancelability type should always be restored to its value on +entry to the object. +.Pp +Finally, only functions that are cancel-safe may be called from a thread that +is asynchronously cancelable. +.Sh ERRORS +The function +.Fn pthread_setcancelstate +may fail with: +.Bl -tag -width Er +.It Bq Er EINVAL +The specified state is not +.Dv PTHREAD_CANCEL_ENABLE +or +.Dv PTHREAD_CANCEL_DISABLE . +.El +.Pp +The function +.Fn pthread_setcanceltype +may fail with: +.Bl -tag -width Er +.It Bq Er EINVAL +The specified state is not +.Dv PTHREAD_CANCEL_DEFERRED +or +.Dv PTHREAD_CANCEL_ASYNCHRONOUS . +.El +.Sh SEE ALSO +.Xr pthread_cancel 3 +.Sh STANDARDS +.Fn pthread_testcancel +conforms to ISO/IEC 9945-1 ANSI/IEEE +.Pq Dq Tn POSIX +Std 1003.1 Second Edition 1996-07-12. +.Sh AUTHORS +This man page was written by +.An David Leonard <d@openbsd.org> +for the OpenBSD implementation of pthread_cancel. diff --git a/lib/libpthread/man/sem_destroy.3 b/lib/libpthread/man/sem_destroy.3 new file mode 100644 index 0000000..56e9204 --- /dev/null +++ b/lib/libpthread/man/sem_destroy.3 @@ -0,0 +1,85 @@ +.\" Copyright (C) 2000 Jason Evans <jasone@freebsd.org>. +.\" 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(s), this list of conditions and the following disclaimer as +.\" the first lines of this file unmodified other than the possible +.\" addition of one or more copyright notices. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice(s), this list of conditions and the following disclaimer in +.\" the documentation and/or other materials provided with the +.\" distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``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 COPYRIGHT HOLDER(S) 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. +.\" +.\" $FreeBSD$ +.Dd February 15, 2000 +.Dt SEM_DESTROY 3 +.Os +.Sh NAME +.Nm sem_destroy +.Nd destroy an unnamed semaphore +.Sh LIBRARY +.Lb libc_r +.Sh SYNOPSIS +.Fd #include <semaphore.h> +.Ft int +.Fn sem_destroy "sem_t *sem" +.Sh DESCRIPTION +The +.Fn sem_destroy +function destroys the unnamed semaphore pointed to by +.Fa sem . +After a successful call to +.Fn sem_destroy , +.Fa sem +is unuseable until re-initialized by another call to +.Fn sem_init . +.Sh RETURN VALUES +If successful, +.Fn sem_destroy +returns 0. Otherwise, -1 is returned and +.Va errno +is set to indicate the type of +error. +.Sh ERRORS +.Fn sem_destroy +will fail if: +.Bl -tag -width Er +.It Bq Er EINVAL +.Fa sem +points to an invalid semaphore. +.It Bq Er EBUSY +There are currently threads blocked on the semaphore that +.Fa sem +points to. +.El +.Sh SEE ALSO +.Xr sem_init 3 +.Sh STANDARDS +.Fn sem_destroy +conforms to ISO/IEC 9945-1 ANSI/IEEE +.Pq Dq Tn POSIX +Std 1003.1 1996 Edition. +.Pp +POSIX does not define the behavior of +.Fn sem_destroy +if called while there are threads blocked on +.Fa sem , +but this implementation is guaranteed to return -1 and set +.Va errno +to EBUSY if there are threads blocked on +.Fa sem . diff --git a/lib/libpthread/man/sem_getvalue.3 b/lib/libpthread/man/sem_getvalue.3 new file mode 100644 index 0000000..9e2c560 --- /dev/null +++ b/lib/libpthread/man/sem_getvalue.3 @@ -0,0 +1,79 @@ +.\" Copyright (C) 2000 Jason Evans <jasone@freebsd.org>. +.\" 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(s), this list of conditions and the following disclaimer as +.\" the first lines of this file unmodified other than the possible +.\" addition of one or more copyright notices. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice(s), this list of conditions and the following disclaimer in +.\" the documentation and/or other materials provided with the +.\" distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``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 COPYRIGHT HOLDER(S) 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. +.\" +.\" $FreeBSD$ +.Dd February 15, 2000 +.Dt SEM_GETVALUE 3 +.Os +.Sh NAME +.Nm sem_getvalue +.Nd get the value of a semaphore +.Sh LIBRARY +.Lb libc_r +.Sh SYNOPSIS +.Fd #include <semaphore.h> +.Ft int +.Fn sem_getvalue "sem_t *sem" "int *sval" +.Sh DESCRIPTION +The +.Fn sem_getvalue +function sets the variable pointed to by +.Fa sval +to the current value of the semaphore pointed to by +.Fa sem , +as of the time that the call to +.Fn sem_getvalue +is actually run. +.Sh RETURN VALUES +If successful, +.Fn sem_getvalue +returns 0. Otherwise, -1 is returned and +.Va errno +is set to indicate the type of +error. +.Sh ERRORS +.Fn sem_getvalue +will fail if: +.Bl -tag -width Er +.It Bq Er EINVAL +.Fa sem +points to an invalid semaphore. +.El +.Sh SEE ALSO +.Xr sem_post 3 , +.Xr sem_trywait 3 , +.Xr sem_wait 3 +.Sh STANDARDS +.Fn sem_getvalue +conforms to ISO/IEC 9945-1 ANSI/IEEE +.Pq Dq Tn POSIX +Std 1003.1 1996 Edition. +.Pp +The value of the semaphore is never negative, even if there are threads blocked +on the semaphore. POSIX is somewhat ambiguous in its wording with regard to +what the value of the semaphore should be if there are blocked waiting threads, +but this behavior is conformant, given the wording of the specification. diff --git a/lib/libpthread/man/sem_init.3 b/lib/libpthread/man/sem_init.3 new file mode 100644 index 0000000..2449ce0 --- /dev/null +++ b/lib/libpthread/man/sem_init.3 @@ -0,0 +1,102 @@ +.\" Copyright (C) 2000 Jason Evans <jasone@freebsd.org>. +.\" 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(s), this list of conditions and the following disclaimer as +.\" the first lines of this file unmodified other than the possible +.\" addition of one or more copyright notices. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice(s), this list of conditions and the following disclaimer in +.\" the documentation and/or other materials provided with the +.\" distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``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 COPYRIGHT HOLDER(S) 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. +.\" +.\" $FreeBSD$ +.Dd February 15, 2000 +.Dt SEM_INIT 3 +.Os +.Sh NAME +.Nm sem_init +.Nd initialize an unnamed semaphore +.Sh LIBRARY +.Lb libc_r +.Sh SYNOPSIS +.Fd #include <semaphore.h> +.Ft int +.Fn sem_init "sem_t *sem" "int pshared" "unsigned int value" +.Sh DESCRIPTION +The +.Fn sem_init +function initializes the unnamed semaphore pointed to by +.Fa sem +to have the value +.Fa value . +A non-zero value for +.Fa pshared +specifies a shared semaphore that can be used by multiple processes, which this +implementation is not capable of. +.Pp +Following a successful call to +.Fn sem_init , +.Fa sem +can be used as an argument in subsequent calls to +.Fa sem_wait , +.Fa sem_trywait , +.Fa sem_post , +and +.Fa sem_destroy . +.Fa sem +is no longer valid after a successful call to +.Fa sem_destroy . +.Sh RETURN VALUES +If successful, +.Fn sem_init +returns 0. Otherwise, -1 is returned and +.Va errno +is set to indicate the type of +error. +.Sh ERRORS +.Fn sem_init +will fail if: +.Bl -tag -width Er +.It Bq Er EINVAL +.Fa value +exceeds SEM_VALUE_MAX. +.It Bq Er ENOSPC +Memory allocation error. +.It Bq Er EPERM +Unable to initialize a shared semaphore. +.El +.Sh SEE ALSO +.Xr sem_destroy 3 , +.Xr sem_post 3 , +.Xr sem_trywait 3 , +.Xr sem_wait 3 +.Sh STANDARDS +.Fn sem_init +conforms to ISO/IEC 9945-1 ANSI/IEEE +.Pq Dq Tn POSIX +Std 1003.1 1996 Edition. +.Pp +This implementation does not support shared semaphores, and reports this fact +by setting +.Va errno +to EPERM. This is perhaps a stretch of the intention of POSIX, but is +compliant, with the caveat that +.Fn sem_init +always reports a permissions error when an attempt to create a shared semaphore +is made. diff --git a/lib/libpthread/man/sem_open.3 b/lib/libpthread/man/sem_open.3 new file mode 100644 index 0000000..a948bdc --- /dev/null +++ b/lib/libpthread/man/sem_open.3 @@ -0,0 +1,82 @@ +.\" Copyright (C) 2000 Jason Evans <jasone@freebsd.org>. +.\" 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(s), this list of conditions and the following disclaimer as +.\" the first lines of this file unmodified other than the possible +.\" addition of one or more copyright notices. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice(s), this list of conditions and the following disclaimer in +.\" the documentation and/or other materials provided with the +.\" distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``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 COPYRIGHT HOLDER(S) 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. +.\" +.\" $FreeBSD$ +.Dd February 15, 2000 +.Dt SEM_OPEN 3 +.Os +.Sh NAME +.Nm sem_open , +.Nm sem_close , +.Nm sem_unlink +.Nd named semaphore operations +.Sh LIBRARY +.Lb libc_r +.Sh SYNOPSIS +.Fd #include <semaphore.h> +.Ft sem_t * +.Fn sem_open "const char *name" "int oflag" "..." +.Ft int +.Fn sem_close "sem_t *sem" +.Ft int +.Fn sem_unlink "const char *name" +.Sh DESCRIPTION +The +.Fn sem_open , +.Fn sem_close , +and +.Fn sem_unlink +functions are not supported by this implementation. +.Sh RETURN VALUES +.Fn sem_open +returns SEM_FAILED and sets +.Va errno +to indicate an error. +.Fn sem_close +and +.Fn sem_unlink +return -1 and set +.Va errno +to indicate an error. +.Sh ERRORS +.Fn sem_open , +.Fn sem_close , +and +.Fn sem_unlink +will fail: +.Bl -tag -width Er +.It Bq Er ENOSYS +Function not supported by this implementation. +.El +.Sh STANDARDS +.Fn sem_open , +.Fn sem_close , +and +.Fn sem_unlink +conform to ISO/IEC 9945-1 ANSI/IEEE +.Pq Dq Tn POSIX +Std 1003.1 1996 Edition. diff --git a/lib/libpthread/man/sem_post.3 b/lib/libpthread/man/sem_post.3 new file mode 100644 index 0000000..34fef83 --- /dev/null +++ b/lib/libpthread/man/sem_post.3 @@ -0,0 +1,76 @@ +.\" Copyright (C) 2000 Jason Evans <jasone@freebsd.org>. +.\" 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(s), this list of conditions and the following disclaimer as +.\" the first lines of this file unmodified other than the possible +.\" addition of one or more copyright notices. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice(s), this list of conditions and the following disclaimer in +.\" the documentation and/or other materials provided with the +.\" distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``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 COPYRIGHT HOLDER(S) 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. +.\" +.\" $FreeBSD$ +.Dd February 15, 2000 +.Dt SEM_POST 3 +.Os +.Sh NAME +.Nm sem_post +.Nd increment (unlock) a semaphore +.Sh LIBRARY +.Lb libc_r +.Sh SYNOPSIS +.Fd #include <semaphore.h> +.Ft int +.Fn sem_post "sem_t *sem" +.Sh DESCRIPTION +The +.Fn sem_post +function increments (unlocks) the semaphore pointed to by +.Fa sem . +If there are threads blocked on the semaphore when +.Fn sem_post +is called, then the highest priority thread that has been blocked the longest on +the semaphore will be allowed to return from +.Fn sem_wait . +.Pp +.Fn sem_post +is signal-reentrant and may be called within signal handlers. +.Sh RETURN VALUES +If successful, +.Fn sem_post +returns 0. Otherwise, -1 is returned and +.Va errno +is set to indicate the type of +error. +.Sh ERRORS +.Fn sem_post +will fail if: +.Bl -tag -width Er +.It Bq Er EINVAL +.Fa sem +points to an invalid semaphore. +.El +.Sh SEE ALSO +.Xr sem_trywait 3 , +.Xr sem_wait 3 +.Sh STANDARDS +.Fn sem_post +conforms to ISO/IEC 9945-1 ANSI/IEEE +.Pq Dq Tn POSIX +Std 1003.1 1996 Edition. diff --git a/lib/libpthread/man/sem_wait.3 b/lib/libpthread/man/sem_wait.3 new file mode 100644 index 0000000..ab08582 --- /dev/null +++ b/lib/libpthread/man/sem_wait.3 @@ -0,0 +1,94 @@ +.\" Copyright (C) 2000 Jason Evans <jasone@freebsd.org>. +.\" 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(s), this list of conditions and the following disclaimer as +.\" the first lines of this file unmodified other than the possible +.\" addition of one or more copyright notices. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice(s), this list of conditions and the following disclaimer in +.\" the documentation and/or other materials provided with the +.\" distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``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 COPYRIGHT HOLDER(S) 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. +.\" +.\" $FreeBSD$ +.Dd February 15, 2000 +.Dt SEM_WAIT 3 +.Os +.Sh NAME +.Nm sem_wait , +.Nm sem_trywait +.Nd decrement (lock) a semaphore +.Sh LIBRARY +.Lb libc_r +.Sh SYNOPSIS +.Fd #include <semaphore.h> +.Ft int +.Fn sem_wait "sem_t *sem" +.Ft int +.Fn sem_trywait "sem_t *sem" +.Sh DESCRIPTION +The +.Fn sem_wait +function decrements (locks) the semaphore pointed to by +.Fa sem , +but blocks if the value of +.Fa sem +is zero, until the value is non-zero and the value can be decremented. +.Pp +The +.Fn sem_trywait +function decrements (locks) the semaphore pointed to by +.Fa sem +only if the value is non-zero. Otherwise, the semaphore is not decremented and +an error is returned. +.Sh RETURN VALUES +If successful, +.Fn sem_wait +and +.Fn sem_trywait +return 0. Otherwise, -1 is returned and +.Va errno +is set to indicate the type of +error. +.Sh ERRORS +.Fn sem_wait +and +.Fn sem_trywait +will fail if: +.Bl -tag -width Er +.It Bq Er EINVAL +.Fa sem +points to an invalid semaphore. +.El +.Pp +Additionally, +.Fn sem_trywait +will fail if: +.Bl -tag -width Er +.It Bq Er EAGAIN +The semaphore value was zero, and thus could not be decremented. +.El +.Sh SEE ALSO +.Xr sem_post 3 +.Sh STANDARDS +.Fn sem_wait +and +.Fn sem_trywait +conform to ISO/IEC 9945-1 ANSI/IEEE +.Pq Dq Tn POSIX +Std 1003.1 1996 Edition. diff --git a/lib/libpthread/man/sigwait.3 b/lib/libpthread/man/sigwait.3 new file mode 100644 index 0000000..3852bd9 --- /dev/null +++ b/lib/libpthread/man/sigwait.3 @@ -0,0 +1,84 @@ +.\" Copyright (C) 2000 Jason Evans <jasone@freebsd.org>. +.\" 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(s), this list of conditions and the following disclaimer as +.\" the first lines of this file unmodified other than the possible +.\" addition of one or more copyright notices. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice(s), this list of conditions and the following disclaimer in +.\" the documentation and/or other materials provided with the +.\" distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``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 COPYRIGHT HOLDER(S) 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. +.\" +.\" $FreeBSD$ +.Dd April 27, 2000 +.Dt SIGWAIT 3 +.Os +.Sh NAME +.Nm sigwait +.Nd select a set of signals +.Sh LIBRARY +.Lb libc_r +.Sh SYNOPSIS +.Fd #include <signal.h> +.Ft int +.Fn sigwait "const sigset_t *set" "int *sig" +.Sh DESCRIPTION +The +.Fn sigwait +function selects a set of signals, specified by +.Fa set . +If none of the selected signals are pending, +.Fn sigwait +waits until one or more of the selected signals has been generated. +Then +.Fn sigwait +atomically clears one of the selected signals from the set of pending signals +for the process and sets the location pointed to by +.Fa sig +to the signal number that was cleared. +.Pp +The signals specified by +.Fa set +should be blocked at the time of the call to +.Fn sigwait . +.Sh RETURN VALUES +If successful, +.Fn sigwait +returns 0 and sets the location pointed to by +.Fa sig +to the cleared signal number. +Otherwise, an error number is returned. +.Sh ERRORS +.Fn sigwait +will fail if: +.Bl -tag -width Er +.It Bq Er EINVAL +.Fa set +specifies one or more invalid signal numbers. +.El +.Sh SEE ALSO +.Xr sigaction 2 , +.Xr sigpending 2 , +.Xr sigsuspend 2 , +.Xr pause 3 , +.Xr pthread_sigmask 3 +.Sh STANDARDS +.Fn sigwait +conforms to +.St -iso9945-1 diff --git a/lib/libpthread/sys/Makefile.inc b/lib/libpthread/sys/Makefile.inc new file mode 100644 index 0000000..e608afa --- /dev/null +++ b/lib/libpthread/sys/Makefile.inc @@ -0,0 +1,6 @@ +# $FreeBSD$ + +.PATH: ${.CURDIR}/sys ${.CURDIR}/arch/${MACHINE_ARCH} + +SRCS+= uthread_error.c _atomic_lock.S + diff --git a/lib/libpthread/sys/thr_error.c b/lib/libpthread/sys/thr_error.c new file mode 100644 index 0000000..0d08ae8 --- /dev/null +++ b/lib/libpthread/sys/thr_error.c @@ -0,0 +1,51 @@ +/* + * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>. + * Copyright (c) 1994 by Chris Provenzano, proven@mit.edu + * 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 + * and Chris Provenzano. + * 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. + * + * $FreeBSD$ + */ +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" +extern int errno; + +int * __error() +{ + int *p_errno; + if (_thread_run == _thread_initial) { + p_errno = &errno; + } else { + p_errno = &_thread_run->error; + } + return(p_errno); +} +#endif diff --git a/lib/libpthread/test/Makefile b/lib/libpthread/test/Makefile new file mode 100644 index 0000000..db2f046 --- /dev/null +++ b/lib/libpthread/test/Makefile @@ -0,0 +1,123 @@ +# +# $FreeBSD$ +# +# Automated test suite for libc_r (pthreads). +# + +# File lists. + +# Diff mode tests written in C. +CDTESTS := hello_d.c mutex_d.c sem_d.c sigsuspend_d.c sigwait_d.c + +# Sequence mode tests written in C. +CSTESTS := hello_s.c + +# C programs that are used internally by the perl-based tests. The build +# system merely compiles these. +BTESTS := hello_b.c + +# Diff mode tests written in perl. +PDTESTS := + +# Sequence mode tests written in perl. +PSTESTS := propagate_s.pl + +# Munge the file lists to their final executable names (strip the .c). +CDTESTS := $(CDTESTS:R) +CSTESTS := $(CSTESTS:R) +BTESTS := $(BTESTS:R) + +CPPFLAGS := -D_LIBC_R_ +CFLAGS := -Wall -pipe -g3 +LDFLAGS_A := -static +LDFLAGS_P := -pg +LDFLAGS_S := +LIBS := -pthread + +# Flags passed to verify. "-v" or "-u" may be useful. +VFLAGS := + +all : default + +# Only use the following suffixes, in order to avoid any strange built-in rules. +.SUFFIXES : +.SUFFIXES : .c .o .d .pl + +# Clear out all paths, then set just one (default path) for the main build +# directory. +.PATH : +.PATH : . + +# Build the C programs. +.for bin in $(CDTESTS) $(CSTESTS) $(BTESTS) +$(bin)_a : $(bin:S/$/&.c/) + $(CC) $(CFLAGS) $(CPPFLAGS) -c $(bin:S/$/&.c/) -o $(@:S/$/&.o/) + $(CC) -o $@ $(@:S/$/&.o/) $(LDFLAGS_A) $(LIBS) + @$(SHELL) -ec "$(CC) -M $(CPPFLAGS) $(bin:S/$/&.c/) | sed \"s/\($(bin:T)\)\.o\([ :]*\)/$(bin:H:S!/!\\/!g)\/\1_a.o \2/g\" > $(@:R:S/$/&.d/)" + +$(bin)_p : $(bin:S/$/&.c/) + $(CC) $(CFLAGS) $(CPPFLAGS) -c $(bin:S/$/&.c/) -o $(@:S/$/&.o/) + $(CC) -o $@ $(@:S/$/&.o/) $(LDFLAGS_P) $(LIBS) + @$(SHELL) -ec "$(CC) -M $(CPPFLAGS) $(bin:S/$/&.c/) | sed \"s/\($(bin:T)\)\.o\([ :]*\)/$(bin:H:S!/!\\/!g)\/\1_p.o \2/g\" > $(@:R:S/$/&.d/)" + +$(bin)_s : $(bin:S/$/&.c/) + $(CC) $(CFLAGS) $(CPPFLAGS) -c $(bin:S/$/&.c/) -o $(@:S/$/&.o/) + $(CC) -o $@ $(@:S/$/&.o/) $(LDFLAGS_S) $(LIBS) + @$(SHELL) -ec "$(CC) -M $(CPPFLAGS) $(bin:S/$/&.c/) | sed \"s/\($(bin:T)\)\.o\([ :]*\)/$(bin:H:S!/!\\/!g)\/\1_s.o \2/g\" > $(@:R:S/$/&.d/)" +.endfor + +# Dependency file inclusion. +.for depfile in $(CDTESTS:R:S/$/&_a.d/) $(CSTESTS:R:S/$/&_a.d/) \ + $(BTESTS:R:S/$/&_a.d/) $(CDTESTS:R:S/$/&_p.d/) \ + $(CSTESTS:R:S/$/&_p.d/) $(BTESTS:R:S/$/&_p.d/) \ + $(CDTESTS:R:S/$/&_s.d/) $(CSTESTS:R:S/$/&_s.d/) \ + $(BTESTS:R:S/$/&_s.d/) +.if exists($(depfile)) +.include "$(depfile)" +.endif +.endfor + +default : check + +tests_a : $(CDTESTS:S/$/&_a/) $(CSTESTS:S/$/&_a/) $(BTESTS:S/$/&_a/) +tests_p : $(CDTESTS:S/$/&_p/) $(CSTESTS:S/$/&_p/) $(BTESTS:S/$/&_p/) +tests_s : $(CDTESTS:S/$/&_s/) $(CSTESTS:S/$/&_s/) $(BTESTS:S/$/&_s/) + +tests : tests_a tests_p tests_s + +check_a : tests_a +.for bin in $(CDTESTS) $(CSTESTS) $(BTESTS) + @cp $(bin)_a $(bin) +.endfor + @echo "Test static library:" + @./verify $(VFLAGS) -- -d $(CDTESTS) $(PDTESTS) -s $(CSTESTS) $(PSTESTS) + +check_p : tests_p +.for bin in $(CDTESTS) $(CSTESTS) $(BTESTS) + @cp $(bin)_p $(bin) +.endfor + @echo "Test profile library:" + @./verify $(VFLAGS) -- -d $(CDTESTS) $(PDTESTS) -s $(CSTESTS) $(PSTESTS) + +check_s : tests_s +.for bin in $(CDTESTS) $(CSTESTS) $(BTESTS) + @cp $(bin)_s $(bin) +.endfor + @echo "Test shared library:" + @./verify $(VFLAGS) -- -d $(CDTESTS) $(PDTESTS) -s $(CSTESTS) $(PSTESTS) + +check : check_a check_p check_s + +clean : + rm -f *~ + rm -f *.core + rm -f *.out + rm -f *.perf + rm -f *.diff + rm -f *.gmon + rm -f $(CDTESTS) $(CSTESTS) $(BTESTS) + rm -f $(CDTESTS:S/$/&_a/) $(CSTESTS:S/$/&_a/) $(BTESTS:S/$/&_a/) + rm -f $(CDTESTS:S/$/&_p/) $(CSTESTS:S/$/&_p/) $(BTESTS:S/$/&_p/) + rm -f $(CDTESTS:S/$/&_s/) $(CSTESTS:S/$/&_s/) $(BTESTS:S/$/&_s/) + rm -f *.d + rm -f *.o diff --git a/lib/libpthread/test/README b/lib/libpthread/test/README new file mode 100644 index 0000000..507ea4e --- /dev/null +++ b/lib/libpthread/test/README @@ -0,0 +1,28 @@ +$FreeBSD$ + +This test suite is meant to test general functionality of pthreads, as well as +provide a simple framework for regression tests. In general, this test suite +can be used with any pthreads library, but in reality there are a number of +libc_r-specific aspects to this test suite which would require some effort to +get around if testing another pthreads library. + +This test suite assumes that libc_r is installed. + +There are two forms of test that the 'verify' script understands. The simpler +form is the diff format, where the output of the test program is diff'ed with +the correspondingly named .exp file. If there is diff output, the test fails. +The sequence test format is somewhat more complex, and is documented in the +command line usage output for verify. The advantage of this format is that it +allows multiple tests to pass/fail within one program. + +There is no driving need for test naming consistency, but the existing tests +generally follow these conventions: + +<name>_d.c <name>_d.exp : Diff mode C test and expected output file. +<name>_s.c : Sequence mode C test. +<name>_b*.c : Back end C program used by perl tests. +<name>_d.pl <name>_d.pl.exp : Diff mode perl test and expected output file. +<name>_s.pl : Sequence mode perl test. + +<name> is something descriptive, such as "pr14685" in the case of a PR-related +regression test, or "mutex" in the case of a test of mutexes. diff --git a/lib/libpthread/test/hello_b.c b/lib/libpthread/test/hello_b.c new file mode 100644 index 0000000..2eefa7f --- /dev/null +++ b/lib/libpthread/test/hello_b.c @@ -0,0 +1,13 @@ +/**************************************************************************** + * + * Back end C programs can be anything compilable. + * + * $FreeBSD$ + * + ****************************************************************************/ + +int +main() +{ + return 0; +} diff --git a/lib/libpthread/test/hello_d.c b/lib/libpthread/test/hello_d.c new file mode 100644 index 0000000..6d77526 --- /dev/null +++ b/lib/libpthread/test/hello_d.c @@ -0,0 +1,38 @@ +/**************************************************************************** + * + * Simple diff mode test. + * + * $FreeBSD$ + * + ****************************************************************************/ + +#include <stdio.h> +#include <string.h> +#include <pthread.h> + +void * +entry(void * a_arg) +{ + fprintf(stderr, "Hello world\n"); + + return NULL; +} + +int +main() +{ + pthread_t thread; + int error; + + error = pthread_create(&thread, NULL, entry, NULL); + if (error) + fprintf(stderr, "Error in pthread_create(): %s\n", + strerror(error)); + + error = pthread_join(thread, NULL); + if (error) + fprintf(stderr, "Error in pthread_join(): %s\n", + strerror(error)); + + return 0; +} diff --git a/lib/libpthread/test/hello_d.exp b/lib/libpthread/test/hello_d.exp new file mode 100644 index 0000000..802992c --- /dev/null +++ b/lib/libpthread/test/hello_d.exp @@ -0,0 +1 @@ +Hello world diff --git a/lib/libpthread/test/hello_s.c b/lib/libpthread/test/hello_s.c new file mode 100644 index 0000000..942bf2d --- /dev/null +++ b/lib/libpthread/test/hello_s.c @@ -0,0 +1,47 @@ +/**************************************************************************** + * + * Simple sequence mode test. + * + * $FreeBSD$ + * + ****************************************************************************/ + +#include <stdio.h> +#include <string.h> +#include <pthread.h> + +void * +entry(void * a_arg) +{ + fprintf(stderr, "ok 1\n"); + fprintf(stderr, "ok \n"); + fprintf(stderr, "ok 3\n"); + + return NULL; +} + +int +main() +{ + pthread_t thread; + int error; + + fprintf(stderr, "1..3\n"); + + fprintf(stderr, "Some random text\n"); + + error = pthread_create(&thread, NULL, entry, NULL); + fprintf(stderr, "More unimportant text\n"); + if (error) + fprintf(stderr,"Error in pthread_create(): %s\n", + strerror(error)); + + error = pthread_join(thread, NULL); + if (error) + fprintf(stderr, "Error in pthread_join(): %s\n", + strerror(error)); + + fprintf(stderr, "Hello world\n"); + + return 0; +} diff --git a/lib/libpthread/test/mutex_d.c b/lib/libpthread/test/mutex_d.c new file mode 100644 index 0000000..ea31299 --- /dev/null +++ b/lib/libpthread/test/mutex_d.c @@ -0,0 +1,1549 @@ +/* + * Copyright (c) 1998 Daniel M. Eischen <eischen@vigrid.com> + * 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 Daniel M. Eischen. + * 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 DANIEL M. EISCHEN 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <stdlib.h> +#include <unistd.h> + +#include <sys/ioctl.h> +#include <assert.h> +#include <errno.h> +#include "pthread.h" +#include <sched.h> +#include <signal.h> +#include <stdarg.h> +#include <stdio.h> +#include <string.h> +#include <sysexits.h> + +#if defined(_LIBC_R_) +#include <pthread_np.h> +#endif + +#ifndef NELEMENTS +#define NELEMENTS(arr) (sizeof (arr) / sizeof (arr[0])) +#endif + +#ifndef NUM_THREADS +#define NUM_THREADS 10 +#endif + +#define MAX_THREAD_CMDS 10 + + +/*------------------------------------------------------------ + * Types + *----------------------------------------------------------*/ + +typedef enum { + STAT_INITIAL, /* initial state */ + STAT_WAITCONDVAR, /* waiting for condition variable signal */ + STAT_WAITMUTEX /* waiting for mutex lock */ +} thread_status_t; + +typedef enum { + FLAGS_REPORT_WAITCONDMUTEX = 0x01, + FLAGS_REPORT_WAITCONDVAR = 0x02, + FLAGS_REPORT_WAITMUTEX = 0x04, + FLAGS_REPORT_BUSY_LOOP = 0x08, + FLAGS_IS_BUSY = 0x10, + FLAGS_WAS_BUSY = 0x20 +} thread_flags_t; + +typedef enum { + CMD_NONE, + CMD_TAKE_MUTEX, + CMD_RELEASE_MUTEX, + CMD_WAIT_FOR_SIGNAL, + CMD_BUSY_LOOP, + CMD_PROTECTED_OP, + CMD_RELEASE_ALL +} thread_cmd_id_t; + +typedef struct { + thread_cmd_id_t cmd_id; + pthread_mutex_t *mutex; + pthread_cond_t *cond; +} thread_cmd_t; + +typedef struct { + pthread_cond_t cond_var; + thread_status_t status; + thread_cmd_t cmd; + int flags; + int priority; + int ret; + pthread_t tid; + u_int8_t id; +} thread_state_t; + +typedef enum { + M_POSIX, + M_SS2_DEFAULT, + M_SS2_ERRORCHECK, + M_SS2_NORMAL, + M_SS2_RECURSIVE +} mutex_kind_t; + + +/*------------------------------------------------------------ + * Constants + *----------------------------------------------------------*/ + +const char *protocol_strs[] = { + "PTHREAD_PRIO_NONE", + "PTHREAD_PRIO_INHERIT", + "PTHREAD_PRIO_PROTECT" +}; + +const int protocols[] = { + PTHREAD_PRIO_NONE, + PTHREAD_PRIO_INHERIT, + PTHREAD_PRIO_PROTECT +}; + +const char *mutextype_strs[] = { + "POSIX (type not specified)", + "SS2 PTHREAD_MUTEX_DEFAULT", + "SS2 PTHREAD_MUTEX_ERRORCHECK", + "SS2 PTHREAD_MUTEX_NORMAL", + "SS2 PTHREAD_MUTEX_RECURSIVE" +}; + +const int mutex_types[] = { + 0, /* M_POSIX */ + PTHREAD_MUTEX_DEFAULT, /* M_SS2_DEFAULT */ + PTHREAD_MUTEX_ERRORCHECK, /* M_SS2_ERRORCHECK */ + PTHREAD_MUTEX_NORMAL, /* M_SS2_NORMAL */ + PTHREAD_MUTEX_RECURSIVE /* M_SS2_RECURSIVE */ +}; + + +/*------------------------------------------------------------ + * Objects + *----------------------------------------------------------*/ + +static int done = 0; +static int trace_enabled = 0; +static int use_global_condvar = 0; +static thread_state_t states[NUM_THREADS]; +static int pipefd[2]; + +static pthread_mutex_t waiter_mutex; +static pthread_mutex_t cond_mutex; +static pthread_cond_t cond_var; + +static FILE *logfile = stdout; +static int error_count = 0, pass_count = 0, total = 0; + + +/*------------------------------------------------------------ + * Prototypes + *----------------------------------------------------------*/ +extern char *strtok_r(char *str, const char *sep, char **last); + + +/*------------------------------------------------------------ + * Functions + *----------------------------------------------------------*/ + +#ifdef DEBUG +static void +kern_switch (pthread_t pthread_out, pthread_t pthread_in) +{ + if (pthread_out != NULL) + printf ("Swapping out thread 0x%x, ", (int) pthread_out); + else + printf ("Swapping out kernel thread, "); + + if (pthread_in != NULL) + printf ("swapping in thread 0x%x\n", (int) pthread_in); + else + printf ("swapping in kernel thread.\n"); +} +#endif + + +static void +log_error (const char *fmt, ...) +{ + va_list ap; + + va_start (ap, fmt); + fprintf (logfile, "FAIL: "); + vfprintf (logfile, fmt, ap); + error_count = error_count + 1; + total = total + 1; +} + + +static void +log_pass (void) +{ + fprintf (logfile, "PASS\n"); + pass_count = pass_count + 1; + total = total + 1; +} + + +static void +log_trace (const char *fmt, ...) +{ + va_list ap; + + if (trace_enabled) { + va_start (ap, fmt); + vfprintf (logfile, fmt, ap); + } +} + + +static void +log (const char *fmt, ...) +{ + va_list ap; + + va_start (ap, fmt); + vfprintf (logfile, fmt, ap); +} + + +static void +check_result (int expected, int actual) +{ + if (expected != actual) + log_error ("expected %d, returned %d\n", expected, actual); + else + log_pass (); +} + + +/* + * Check to see that the threads ran in the specified order. + */ +static void +check_run_order (char *order) +{ + const char *sep = ":,"; + char *tok, *last, *idstr, *endptr; + int expected_id, bytes, count = 0, errors = 0; + u_int8_t id; + + assert ((tok = (char *) malloc (strlen(order) + 1)) != NULL); + strcpy (tok, order); /* tok has to be larger than order */ + assert (ioctl (pipefd[0], FIONREAD, &bytes) == 0); + log_trace ("%d bytes read from FIFO.\n", bytes); + + for (idstr = strtok_r (tok, sep, &last); + (idstr != NULL) && (count < bytes); + idstr = strtok_r (NULL, sep, &last)) { + + /* Get the expected id: */ + expected_id = (int) strtol (idstr, &endptr, 10); + assert ((endptr != NULL) && (*endptr == '\0')); + + /* Read the actual id from the pipe: */ + assert (read (pipefd[0], &id, sizeof (id)) == sizeof (id)); + count = count + sizeof (id); + + if (id != expected_id) { + log_trace ("Thread %d ran out of order.\n", id); + errors = errors + 1; + } + else { + log_trace ("Thread %d at priority %d reporting.\n", + (int) id, states[id].priority); + } + } + + if (count < bytes) { + /* Clear the pipe: */ + while (count < bytes) { + read (pipefd[0], &id, sizeof (id)); + count = count + 1; + errors = errors + 1; + } + } + else if (bytes < count) + errors = errors + count - bytes; + + if (errors == 0) + log_pass (); + else + log_error ("%d threads ran out of order", errors); +} + + +static void * +waiter (void *arg) +{ + thread_state_t *statep = (thread_state_t *) arg; + pthread_mutex_t *held_mutex[MAX_THREAD_CMDS]; + int held_mutex_owned[MAX_THREAD_CMDS]; + sigset_t mask; + struct timeval tv1, tv2; + thread_cmd_t cmd; + int i, mutex_count = 0; + + statep->status = STAT_INITIAL; + + /* Block all signals except for interrupt.*/ + sigfillset (&mask); + sigdelset (&mask, SIGINT); + sigprocmask (SIG_BLOCK, &mask, NULL); + + while (done == 0) { + /* Wait for signal from the main thread to continue. */ + statep->status = STAT_WAITMUTEX; + log_trace ("Thread %d: locking cond_mutex.\n", + (int) statep->id); + pthread_mutex_lock (&cond_mutex); + + /* Do we report our status. */ + if (statep->flags & FLAGS_REPORT_WAITCONDMUTEX) + write (pipefd[1], &statep->id, sizeof (statep->id)); + log_trace ("Thread %d: waiting for cond_var.\n", + (int) statep->id); + + /* Wait for a command. */ + statep->status = STAT_WAITCONDVAR; + + /* + * The threads are allowed commanded to wait either on + * their own unique condition variable (so they may be + * separately signaled) or on one global condition variable + * (so they may be signaled together). + */ + if (use_global_condvar != 0) + pthread_cond_wait (&cond_var, &cond_mutex); + else + pthread_cond_wait (&statep->cond_var, &cond_mutex); + + /* Do we report our status? */ + if (statep->flags & FLAGS_REPORT_WAITCONDVAR) { + write (pipefd[1], &statep->id, sizeof (statep->id)); + log_trace ("Thread %d: wrote %d to pipe.\n", + (int) statep->id); + } + log_trace ("Thread %d: received cond_var signal.\n", + (int) statep->id); + + /* Get a copy of the command before releasing the mutex. */ + cmd = statep->cmd; + + /* Clear the command after copying it. */ + statep->cmd.cmd_id = CMD_NONE; + + /* Unlock the condition variable mutex. */ + assert (pthread_mutex_unlock (&cond_mutex) == 0); + + /* Peform the command.*/ + switch (cmd.cmd_id) { + case CMD_TAKE_MUTEX: + statep->ret = pthread_mutex_lock (cmd.mutex); + if (statep->ret == 0) { + assert (mutex_count < sizeof (held_mutex)); + held_mutex[mutex_count] = cmd.mutex; + held_mutex_owned[mutex_count] = 1; + mutex_count++; + } + else { + held_mutex_owned[mutex_count] = 0; + log_trace ("Thread id %d unable to lock mutex, " + "error = %d\n", (int) statep->id, + statep->ret); + } + break; + + case CMD_RELEASE_MUTEX: + assert ((mutex_count <= sizeof (held_mutex)) && + (mutex_count > 0)); + mutex_count--; + if (held_mutex_owned[mutex_count] != 0) + assert (pthread_mutex_unlock + (held_mutex[mutex_count]) == 0); + break; + + case CMD_WAIT_FOR_SIGNAL: + assert (pthread_mutex_lock (cmd.mutex) == 0); + assert (pthread_cond_wait (cmd.cond, cmd.mutex) == 0); + assert (pthread_mutex_unlock (cmd.mutex) == 0); + break; + + case CMD_BUSY_LOOP: + log_trace ("Thread %d: Entering busy loop.\n", + (int) statep->id); + /* Spin for 15 seconds. */ + assert (gettimeofday (&tv2, NULL) == 0); + tv1.tv_sec = tv2.tv_sec + 5; + tv1.tv_usec = tv2.tv_usec; + statep->flags |= FLAGS_IS_BUSY; + while (timercmp (&tv2, &tv1,<)) { + assert (gettimeofday (&tv2, NULL) == 0); + } + statep->flags &= ~FLAGS_IS_BUSY; + statep->flags |= FLAGS_WAS_BUSY; + + /* Do we report our status? */ + if (statep->flags & FLAGS_REPORT_BUSY_LOOP) + write (pipefd[1], &statep->id, + sizeof (statep->id)); + + log_trace ("Thread %d: Leaving busy loop.\n", + (int) statep->id); + break; + + case CMD_PROTECTED_OP: + assert (pthread_mutex_lock (cmd.mutex) == 0); + statep->flags |= FLAGS_WAS_BUSY; + /* Do we report our status? */ + if (statep->flags & FLAGS_REPORT_BUSY_LOOP) + write (pipefd[1], &statep->id, + sizeof (statep->id)); + + assert (pthread_mutex_unlock (cmd.mutex) == 0); + break; + + case CMD_RELEASE_ALL: + assert ((mutex_count <= sizeof (held_mutex)) && + (mutex_count > 0)); + for (i = mutex_count - 1; i >= 0; i--) { + if (held_mutex_owned[i] != 0) + assert (pthread_mutex_unlock + (held_mutex[i]) == 0); + } + mutex_count = 0; + break; + + case CMD_NONE: + default: + break; + } + + /* Wait for the big giant waiter lock. */ + statep->status = STAT_WAITMUTEX; + log_trace ("Thread %d: waiting for big giant lock.\n", + (int) statep->id); + pthread_mutex_lock (&waiter_mutex); + if (statep->flags & FLAGS_REPORT_WAITMUTEX) + write (pipefd[1], &statep->id, sizeof (statep->id)); + log_trace ("Thread %d: got big giant lock.\n", + (int) statep->id); + statep->status = STAT_INITIAL; + pthread_mutex_unlock (&waiter_mutex); + } + + log_trace ("Thread %d: Exiting thread 0x%x\n", (int) statep->id, + (int) pthread_self()); + pthread_exit (arg); + return (NULL); +} + + +static void * +lock_twice (void *arg) +{ + thread_state_t *statep = (thread_state_t *) arg; + sigset_t mask; + + statep->status = STAT_INITIAL; + + /* Block all signals except for interrupt.*/ + sigfillset (&mask); + sigdelset (&mask, SIGINT); + sigprocmask (SIG_BLOCK, &mask, NULL); + + /* Wait for a signal to continue. */ + log_trace ("Thread %d: locking cond_mutex.\n", (int) statep->id); + pthread_mutex_lock (&cond_mutex); + + log_trace ("Thread %d: waiting for cond_var.\n", (int) statep->id); + statep->status = STAT_WAITCONDVAR; + pthread_cond_wait (&cond_var, &cond_mutex); + + log_trace ("Thread %d: received cond_var signal.\n", (int) statep->id); + + /* Unlock the condition variable mutex. */ + assert (pthread_mutex_unlock (&cond_mutex) == 0); + + statep->status = STAT_WAITMUTEX; + /* Lock the mutex once. */ + assert (pthread_mutex_lock (statep->cmd.mutex) == 0); + + /* Lock it again and capture the error. */ + statep->ret = pthread_mutex_lock (statep->cmd.mutex); + statep->status = 0; + + assert (pthread_mutex_unlock (statep->cmd.mutex) == 0); + + /* Unlock it again if it is locked recursively. */ + if (statep->ret == 0) + pthread_mutex_unlock (statep->cmd.mutex); + + log_trace ("Thread %d: Exiting thread 0x%x\n", (int) statep->id, + (int) pthread_self()); + pthread_exit (arg); + return (NULL); +} + + +static void +sighandler (int signo) +{ + log ("Signal handler caught signal %d, thread id 0x%x\n", + signo, (int) pthread_self()); + + if (signo == SIGINT) + done = 1; +} + + +static void +send_cmd (int id, thread_cmd_id_t cmd) +{ + assert (pthread_mutex_lock (&cond_mutex) == 0); + assert (states[id].status == STAT_WAITCONDVAR); + states[id].cmd.cmd_id = cmd; + states[id].cmd.mutex = NULL; + states[id].cmd.cond = NULL; + /* Clear the busy flags. */ + states[id].flags &= ~(FLAGS_WAS_BUSY | FLAGS_IS_BUSY); + assert (pthread_cond_signal (&states[id].cond_var) == 0); + assert (pthread_mutex_unlock (&cond_mutex) == 0); +} + + +static void +send_mutex_cmd (int id, thread_cmd_id_t cmd, pthread_mutex_t *m) +{ + assert (pthread_mutex_lock (&cond_mutex) == 0); + assert (states[id].status == STAT_WAITCONDVAR); + states[id].cmd.cmd_id = cmd; + states[id].cmd.mutex = m; + states[id].cmd.cond = NULL; + /* Clear the busy flags. */ + states[id].flags &= ~(FLAGS_WAS_BUSY | FLAGS_IS_BUSY); + assert (pthread_cond_signal (&states[id].cond_var) == 0); + assert (pthread_mutex_unlock (&cond_mutex) == 0); +} + + +static void +send_mutex_cv_cmd (int id, thread_cmd_id_t cmd, pthread_mutex_t *m, + pthread_cond_t *cv) +{ + assert (pthread_mutex_lock (&cond_mutex) == 0); + assert (states[id].status == STAT_WAITCONDVAR); + states[id].cmd.cmd_id = cmd; + states[id].cmd.mutex = m; + states[id].cmd.cond = cv; + /* Clear the busy flags. */ + states[id].flags &= ~(FLAGS_WAS_BUSY | FLAGS_IS_BUSY); + assert (pthread_cond_signal (&states[id].cond_var) == 0); + assert (pthread_mutex_unlock (&cond_mutex) == 0); +} + + +static void +mutex_init_test (void) +{ + pthread_mutexattr_t mattr; + pthread_mutex_t mutex; + mutex_kind_t mkind; + int mproto, ret; + + /* + * Initialize a mutex attribute. + * + * pthread_mutexattr_init not tested for: ENOMEM + */ + assert (pthread_mutexattr_init (&mattr) == 0); + + /* + * Initialize a mutex. + * + * pthread_mutex_init not tested for: EAGAIN ENOMEM EPERM EBUSY + */ + log ("Testing pthread_mutex_init\n"); + log ("--------------------------\n"); + + for (mproto = 0; mproto < NELEMENTS(protocols); mproto++) { + for (mkind = M_POSIX; mkind <= M_SS2_RECURSIVE; mkind++) { + /* Initialize the mutex attribute. */ + assert (pthread_mutexattr_init (&mattr) == 0); + assert (pthread_mutexattr_setprotocol (&mattr, + protocols[mproto]) == 0); + + /* + * Ensure that the first mutex type is a POSIX + * compliant mutex. + */ + if (mkind != M_POSIX) { + assert (pthread_mutexattr_settype (&mattr, + mutex_types[mkind]) == 0); + } + + log (" Protocol %s, Type %s - ", + protocol_strs[mproto], mutextype_strs[mkind]); + ret = pthread_mutex_init (&mutex, &mattr); + check_result (/* expected */ 0, ret); + assert (pthread_mutex_destroy (&mutex) == 0); + + /* + * Destroy a mutex attribute. + * + * XXX - There should probably be a magic number + * associated with a mutex attribute so that + * destroy can be reasonably sure the attribute + * is valid. + * + * pthread_mutexattr_destroy not tested for: EINVAL + */ + assert (pthread_mutexattr_destroy (&mattr) == 0); + } + } +} + + +static void +mutex_destroy_test (void) +{ + pthread_mutexattr_t mattr; + pthread_mutex_t mutex; + pthread_condattr_t cattr; + pthread_cond_t cv; + pthread_attr_t pattr; + int mproto, ret; + mutex_kind_t mkind; + thread_state_t state; + + /* + * Destroy a mutex. + * + * XXX - There should probably be a magic number associated + * with a mutex so that destroy can be reasonably sure + * the mutex is valid. + * + * pthread_mutex_destroy not tested for: + */ + log ("Testing pthread_mutex_destroy\n"); + log ("-----------------------------\n"); + + assert (pthread_attr_init (&pattr) == 0); + assert (pthread_attr_setdetachstate (&pattr, + PTHREAD_CREATE_DETACHED) == 0); + state.flags = 0; /* No flags yet. */ + + for (mproto = 0; mproto < NELEMENTS(protocols); mproto++) { + for (mkind = M_POSIX; mkind <= M_SS2_RECURSIVE; mkind++) { + /* Initialize the mutex attribute. */ + assert (pthread_mutexattr_init (&mattr) == 0); + assert (pthread_mutexattr_setprotocol (&mattr, + protocols[mproto]) == 0); + + /* + * Ensure that the first mutex type is a POSIX + * compliant mutex. + */ + if (mkind != M_POSIX) { + assert (pthread_mutexattr_settype (&mattr, + mutex_types[mkind]) == 0); + } + + /* Create the mutex. */ + assert (pthread_mutex_init (&mutex, &mattr) == 0); + + log (" Protocol %s, Type %s\n", + protocol_strs[mproto], mutextype_strs[mkind]); + + log (" Destruction of unused mutex - "); + assert (pthread_mutex_init (&mutex, &mattr) == 0); + ret = pthread_mutex_destroy (&mutex); + check_result (/* expected */ 0, ret); + + log (" Destruction of mutex locked by self - "); + assert (pthread_mutex_init (&mutex, &mattr) == 0); + assert (pthread_mutex_lock (&mutex) == 0); + ret = pthread_mutex_destroy (&mutex); + check_result (/* expected */ EBUSY, ret); + assert (pthread_mutex_unlock (&mutex) == 0); + assert (pthread_mutex_destroy (&mutex) == 0); + + log (" Destruction of mutex locked by another " + "thread - "); + assert (pthread_mutex_init (&mutex, &mattr) == 0); + send_mutex_cmd (0, CMD_TAKE_MUTEX, &mutex); + sleep (1); + ret = pthread_mutex_destroy (&mutex); + check_result (/* expected */ EBUSY, ret); + send_cmd (0, CMD_RELEASE_ALL); + sleep (1); + assert (pthread_mutex_destroy (&mutex) == 0); + + log (" Destruction of mutex while being used in " + "cond_wait - "); + assert (pthread_mutex_init (&mutex, &mattr) == 0); + assert (pthread_condattr_init (&cattr) == 0); + assert (pthread_cond_init (&cv, &cattr) == 0); + send_mutex_cv_cmd (0, CMD_WAIT_FOR_SIGNAL, &mutex, &cv); + sleep (1); + ret = pthread_mutex_destroy (&mutex); + check_result (/* expected */ EBUSY, ret); + pthread_cond_signal (&cv); + sleep (1); + assert (pthread_mutex_destroy (&mutex) == 0); + } + } +} + + +static void +mutex_lock_test (void) +{ + pthread_mutexattr_t mattr; + pthread_mutex_t mutex; + pthread_attr_t pattr; + int mproto, ret; + mutex_kind_t mkind; + thread_state_t state; + + /* + * Lock a mutex. + * + * pthread_lock not tested for: + */ + log ("Testing pthread_mutex_lock\n"); + log ("--------------------------\n"); + + assert (pthread_attr_init (&pattr) == 0); + assert (pthread_attr_setdetachstate (&pattr, + PTHREAD_CREATE_DETACHED) == 0); + state.flags = 0; /* No flags yet. */ + + for (mproto = 0; mproto < NELEMENTS(protocols); mproto++) { + for (mkind = M_POSIX; mkind <= M_SS2_RECURSIVE; mkind++) { + /* Initialize the mutex attribute. */ + assert (pthread_mutexattr_init (&mattr) == 0); + assert (pthread_mutexattr_setprotocol (&mattr, + protocols[mproto]) == 0); + + /* + * Ensure that the first mutex type is a POSIX + * compliant mutex. + */ + if (mkind != M_POSIX) { + assert (pthread_mutexattr_settype (&mattr, + mutex_types[mkind]) == 0); + } + + /* Create the mutex. */ + assert (pthread_mutex_init (&mutex, &mattr) == 0); + + log (" Protocol %s, Type %s\n", + protocol_strs[mproto], mutextype_strs[mkind]); + + log (" Lock on unlocked mutex - "); + ret = pthread_mutex_lock (&mutex); + check_result (/* expected */ 0, ret); + pthread_mutex_unlock (&mutex); + + log (" Lock on invalid mutex - "); + ret = pthread_mutex_lock (NULL); + check_result (/* expected */ EINVAL, ret); + + log (" Lock on mutex held by self - "); + assert (pthread_create (&state.tid, &pattr, lock_twice, + (void *) &state) == 0); + /* Let the thread start. */ + sleep (1); + state.cmd.mutex = &mutex; + state.ret = 0xdeadbeef; + assert (pthread_mutex_lock (&cond_mutex) == 0); + assert (pthread_cond_signal (&cond_var) == 0); + assert (pthread_mutex_unlock (&cond_mutex) == 0); + /* Let the thread receive and process the command. */ + sleep (1); + + switch (mkind) { + case M_POSIX: + check_result (/* expected */ EDEADLK, + state.ret); + break; + case M_SS2_DEFAULT: + check_result (/* expected */ EDEADLK, + state.ret); + break; + case M_SS2_ERRORCHECK: + check_result (/* expected */ EDEADLK, + state.ret); + break; + case M_SS2_NORMAL: + check_result (/* expected */ 0xdeadbeef, + state.ret); + break; + case M_SS2_RECURSIVE: + check_result (/* expected */ 0, state.ret); + break; + } + pthread_mutex_destroy (&mutex); + pthread_mutexattr_destroy (&mattr); + } + } +} + + +static void +mutex_unlock_test (void) +{ + const int test_thread_id = 0; /* ID of test thread */ + pthread_mutexattr_t mattr; + pthread_mutex_t mutex; + int mproto, ret; + mutex_kind_t mkind; + + /* + * Unlock a mutex. + * + * pthread_unlock not tested for: + */ + log ("Testing pthread_mutex_unlock\n"); + log ("----------------------------\n"); + + for (mproto = 0; mproto < NELEMENTS(protocols); mproto++) { + for (mkind = M_POSIX; mkind <= M_SS2_RECURSIVE; mkind++) { + /* Initialize the mutex attribute. */ + assert (pthread_mutexattr_init (&mattr) == 0); + assert (pthread_mutexattr_setprotocol (&mattr, + protocols[mproto]) == 0); + + /* + * Ensure that the first mutex type is a POSIX + * compliant mutex. + */ + if (mkind != M_POSIX) { + assert (pthread_mutexattr_settype (&mattr, + mutex_types[mkind]) == 0); + } + + /* Create the mutex. */ + assert (pthread_mutex_init (&mutex, &mattr) == 0); + + log (" Protocol %s, Type %s\n", + protocol_strs[mproto], mutextype_strs[mkind]); + + log (" Unlock on mutex held by self - "); + assert (pthread_mutex_lock (&mutex) == 0); + ret = pthread_mutex_unlock (&mutex); + check_result (/* expected */ 0, ret); + + log (" Unlock on invalid mutex - "); + ret = pthread_mutex_unlock (NULL); + check_result (/* expected */ EINVAL, ret); + + log (" Unlock on mutex locked by another thread - "); + send_mutex_cmd (test_thread_id, CMD_TAKE_MUTEX, &mutex); + sleep (1); + ret = pthread_mutex_unlock (&mutex); + switch (mkind) { + case M_POSIX: + check_result (/* expected */ EPERM, ret); + break; + case M_SS2_DEFAULT: + check_result (/* expected */ EPERM, ret); + break; + case M_SS2_ERRORCHECK: + check_result (/* expected */ EPERM, ret); + break; + case M_SS2_NORMAL: + check_result (/* expected */ EPERM, ret); + break; + case M_SS2_RECURSIVE: + check_result (/* expected */ EPERM, ret); + break; + } + if (ret == 0) { + /* + * If for some reason we were able to unlock + * the mutex, relock it so that the test + * thread has no problems releasing the mutex. + */ + pthread_mutex_lock (&mutex); + } + send_cmd (test_thread_id, CMD_RELEASE_ALL); + sleep (1); + + pthread_mutex_destroy (&mutex); + pthread_mutexattr_destroy (&mattr); + } + } +} + + +static void +queueing_order_test (void) +{ + int i; + + log ("Testing queueing order\n"); + log ("----------------------\n"); + assert (pthread_mutex_lock (&waiter_mutex) == 0); + /* + * Tell the threads to report when they take the waiters mutex. + */ + assert (pthread_mutex_lock (&cond_mutex) == 0); + for (i = 0; i < NUM_THREADS; i++) { + states[i].flags = FLAGS_REPORT_WAITMUTEX; + assert (pthread_cond_signal (&states[i].cond_var) == 0); + } + assert (pthread_mutex_unlock (&cond_mutex) == 0); + + /* Signal the threads to continue. */ + sleep (1); + + /* Use the global condition variable next time. */ + use_global_condvar = 1; + + /* Release the waiting threads and allow them to run again. */ + assert (pthread_mutex_unlock (&waiter_mutex) == 0); + sleep (1); + + log (" Queueing order on a mutex - "); + check_run_order ("9,8,7,6,5,4,3,2,1,0"); + for (i = 0; i < NUM_THREADS; i = i + 1) { + /* Tell the threads to report when they've been signaled. */ + states[i].flags = FLAGS_REPORT_WAITCONDVAR; + } + + /* + * Prevent the threads from continuing their loop after we + * signal them. + */ + assert (pthread_mutex_lock (&waiter_mutex) == 0); + + + log (" Queueing order on a condition variable - "); + /* + * Signal one thread to run and see that the highest priority + * thread executes. + */ + assert (pthread_mutex_lock (&cond_mutex) == 0); + assert (pthread_cond_signal (&cond_var) == 0); + assert (pthread_mutex_unlock (&cond_mutex) == 0); + sleep (1); + if (states[NUM_THREADS - 1].status != STAT_WAITMUTEX) + log_error ("highest priority thread does not run.\n"); + + /* Signal the remaining threads. */ + assert (pthread_mutex_lock (&cond_mutex) == 0); + assert (pthread_cond_broadcast (&cond_var) == 0); + assert (pthread_mutex_unlock (&cond_mutex) == 0); + sleep (1); + + check_run_order ("9,8,7,6,5,4,3,2,1,0"); + for (i = 0; i < NUM_THREADS; i = i + 1) { + /* Tell the threads not to report anything. */ + states[i].flags = 0; + } + + /* Use the thread unique condition variable next time. */ + use_global_condvar = 0; + + /* Allow the threads to continue their loop. */ + assert (pthread_mutex_unlock (&waiter_mutex) == 0); + sleep (1); +} + + +static void +mutex_prioceiling_test (void) +{ + const int test_thread_id = 0; /* ID of test thread */ + pthread_mutexattr_t mattr; + struct sched_param param; + pthread_mutex_t m[3]; + mutex_kind_t mkind; + int i, ret, policy, my_prio, old_ceiling; + + log ("Testing priority ceilings\n"); + log ("-------------------------\n"); + for (mkind = M_POSIX; mkind <= M_SS2_RECURSIVE; mkind++) { + + log (" Protype PTHREAD_PRIO_PROTECT, Type %s\n", + mutextype_strs[mkind]); + + /* + * Initialize and create a mutex. + */ + assert (pthread_mutexattr_init (&mattr) == 0); + + /* Get this threads current priority. */ + assert (pthread_getschedparam (pthread_self(), &policy, + ¶m) == 0); + my_prio = param.sched_priority; /* save for later use */ + log_trace ("Current scheduling policy %d, priority %d\n", + policy, my_prio); + + /* + * Initialize and create 3 priority protection mutexes with + * default (max priority) ceilings. + */ + assert (pthread_mutexattr_setprotocol(&mattr, + PTHREAD_PRIO_PROTECT) == 0); + + /* + * Ensure that the first mutex type is a POSIX + * compliant mutex. + */ + if (mkind != M_POSIX) { + assert (pthread_mutexattr_settype (&mattr, + mutex_types[mkind]) == 0); + } + + for (i = 0; i < 3; i++) + assert (pthread_mutex_init (&m[i], &mattr) == 0); + + /* + * Set the ceiling priorities for the 3 priority protection + * mutexes to, 5 less than, equal to, and 5 greater than, + * this threads current priority. + */ + for (i = 0; i < 3; i++) + assert (pthread_mutex_setprioceiling (&m[i], + my_prio - 5 + 5*i, &old_ceiling) == 0); + + /* + * Check that if we attempt to take a mutex whose priority + * ceiling is lower than our priority, we get an error. + */ + log (" Lock with ceiling priority < thread priority - "); + ret = pthread_mutex_lock (&m[0]); + check_result (/* expected */ EINVAL, ret); + if (ret == 0) + pthread_mutex_unlock (&m[0]); + + /* + * Check that we can take a mutex whose priority ceiling + * is equal to our priority. + */ + log (" Lock with ceiling priority = thread priority - "); + ret = pthread_mutex_lock (&m[1]); + check_result (/* expected */ 0, ret); + if (ret == 0) + pthread_mutex_unlock (&m[1]); + + /* + * Check that we can take a mutex whose priority ceiling + * is higher than our priority. + */ + log (" Lock with ceiling priority > thread priority - "); + ret = pthread_mutex_lock (&m[2]); + check_result (/* expected */ 0, ret); + if (ret == 0) + pthread_mutex_unlock (&m[2]); + + /* + * Have the test thread go into a busy loop for 5 seconds + * and see that it doesn't block this thread (since the + * priority ceiling of mutex 0 and the priority of the test + * thread are both less than the priority of this thread). + */ + log (" Preemption with ceiling priority < thread " + "priority - "); + /* Have the test thread take mutex 0. */ + send_mutex_cmd (test_thread_id, CMD_TAKE_MUTEX, &m[0]); + sleep (1); + + log_trace ("Sending busy command.\n"); + send_cmd (test_thread_id, CMD_BUSY_LOOP); + log_trace ("Busy sent, yielding\n"); + pthread_yield (); + log_trace ("Returned from yield.\n"); + if (states[test_thread_id].flags & + (FLAGS_IS_BUSY | FLAGS_WAS_BUSY)) + log_error ("test thread inproperly preempted us.\n"); + else { + /* Let the thread finish its busy loop. */ + sleep (6); + if ((states[test_thread_id].flags & FLAGS_WAS_BUSY) == 0) + log_error ("test thread never finished.\n"); + else + log_pass (); + } + states[test_thread_id].flags &= ~FLAGS_WAS_BUSY; + + /* Have the test thread release mutex 0. */ + send_cmd (test_thread_id, CMD_RELEASE_ALL); + sleep (1); + + /* + * Have the test thread go into a busy loop for 5 seconds + * and see that it preempts this thread (since the priority + * ceiling of mutex 1 is the same as the priority of this + * thread). The test thread should not run to completion + * as its time quantum should expire before the 5 seconds + * are up. + */ + log (" Preemption with ceiling priority = thread " + "priority - "); + + /* Have the test thread take mutex 1. */ + send_mutex_cmd (test_thread_id, CMD_TAKE_MUTEX, &m[1]); + sleep (1); + + log_trace ("Sending busy\n"); + send_cmd (test_thread_id, CMD_BUSY_LOOP); + log_trace ("Busy sent, yielding\n"); + pthread_yield (); + log_trace ("Returned from yield.\n"); + if ((states[test_thread_id].flags & FLAGS_IS_BUSY) == 0) + log_error ("test thread did not switch in on yield.\n"); + else if (states[test_thread_id].flags & FLAGS_WAS_BUSY) + log_error ("test thread ran to completion.\n"); + else { + /* Let the thread finish its busy loop. */ + sleep (6); + if ((states[test_thread_id].flags & FLAGS_WAS_BUSY) == 0) + log_error ("test thread never finished.\n"); + else + log_pass (); + } + states[test_thread_id].flags &= ~FLAGS_WAS_BUSY; + + /* Have the test thread release mutex 1. */ + send_cmd (test_thread_id, CMD_RELEASE_ALL); + sleep (1); + + /* + * Set the scheduling policy of the test thread to SCHED_FIFO + * and have it go into a busy loop for 5 seconds. This + * thread is SCHED_RR, and since the priority ceiling of + * mutex 1 is the same as the priority of this thread, the + * test thread should run to completion once it is switched + * in. + */ + log (" SCHED_FIFO scheduling and ceiling priority = " + "thread priority - "); + param.sched_priority = states[test_thread_id].priority; + assert (pthread_setschedparam (states[test_thread_id].tid, + SCHED_FIFO, ¶m) == 0); + + /* Have the test thread take mutex 1. */ + send_mutex_cmd (test_thread_id, CMD_TAKE_MUTEX, &m[1]); + sleep (1); + + log_trace ("Sending busy\n"); + send_cmd (test_thread_id, CMD_BUSY_LOOP); + log_trace ("Busy sent, yielding\n"); + pthread_yield (); + log_trace ("Returned from yield.\n"); + if ((states[test_thread_id].flags & FLAGS_WAS_BUSY) == 0) { + log_error ("test thread did not run to completion.\n"); + /* Let the thread finish it's busy loop. */ + sleep (6); + } + else + log_pass (); + states[test_thread_id].flags &= ~FLAGS_WAS_BUSY; + + /* Restore the test thread scheduling parameters. */ + param.sched_priority = states[test_thread_id].priority; + assert (pthread_setschedparam (states[test_thread_id].tid, + SCHED_RR, ¶m) == 0); + + /* Have the test thread release mutex 1. */ + send_cmd (test_thread_id, CMD_RELEASE_ALL); + sleep (1); + + /* + * Have the test thread go into a busy loop for 5 seconds + * and see that it preempts this thread (since the priority + * ceiling of mutex 2 is the greater than the priority of + * this thread). The test thread should run to completion + * and block this thread because its active priority is + * higher. + */ + log (" SCHED_FIFO scheduling and ceiling priority > " + "thread priority - "); + /* Have the test thread take mutex 2. */ + send_mutex_cmd (test_thread_id, CMD_TAKE_MUTEX, &m[2]); + sleep (1); + + log_trace ("Sending busy\n"); + send_cmd (test_thread_id, CMD_BUSY_LOOP); + log_trace ("Busy sent, yielding\n"); + pthread_yield (); + log_trace ("Returned from yield.\n"); + if ((states[test_thread_id].flags & FLAGS_IS_BUSY) != 0) { + log_error ("test thread did not run to completion.\n"); + /* Let the thread finish it's busy loop. */ + sleep (6); + } + else if ((states[test_thread_id].flags & FLAGS_WAS_BUSY) == 0) + log_error ("test thread never finished.\n"); + else + log_pass (); + states[test_thread_id].flags &= ~FLAGS_WAS_BUSY; + + /* Have the test thread release mutex 2. */ + send_cmd (test_thread_id, CMD_RELEASE_ALL); + sleep (1); + + /* Destroy the mutexes. */ + for (i = 0; i < 3; i++) + assert (pthread_mutex_destroy (&m[i]) == 0); + } +} + + +static void +mutex_prioinherit_test (void) +{ + pthread_mutexattr_t mattr; + struct sched_param param; + pthread_mutex_t m[3]; + mutex_kind_t mkind; + int i, policy, my_prio; + + /* Get this threads current priority. */ + assert (pthread_getschedparam (pthread_self(), &policy, + ¶m) == 0); + my_prio = param.sched_priority; /* save for later use */ + log_trace ("Current scheduling policy %d, priority %d\n", + policy, my_prio); + + log ("Testing priority inheritence\n"); + log ("----------------------------\n"); + for (mkind = M_POSIX; mkind <= M_SS2_RECURSIVE; mkind++) { + + log (" Protype PTHREAD_PRIO_INHERIT, Type %s\n", + mutextype_strs[mkind]); + + /* + * Initialize and create a mutex. + */ + assert (pthread_mutexattr_init (&mattr) == 0); + + /* + * Initialize and create 3 priority inheritence mutexes with + * default (max priority) ceilings. + */ + assert (pthread_mutexattr_setprotocol(&mattr, + PTHREAD_PRIO_INHERIT) == 0); + + /* + * Ensure that the first mutex type is a POSIX + * compliant mutex. + */ + if (mkind != M_POSIX) { + assert (pthread_mutexattr_settype (&mattr, + mutex_types[mkind]) == 0); + } + + for (i = 0; i < 3; i++) + assert (pthread_mutex_init (&m[i], &mattr) == 0); + + /* + * Test setup: + * Thread 4 - take mutex 0, 1 + * Thread 2 - enter protected busy loop with mutex 0 + * Thread 3 - enter protected busy loop with mutex 1 + * Thread 4 - enter protected busy loop with mutex 2 + * Thread 5 - enter busy loop + * Thread 6 - enter protected busy loop with mutex 0 + * Thread 4 - releases mutexes 1 and 0. + * + * Expected results: + * Threads complete in order 4, 6, 5, 3, 2 + */ + log (" Simple inheritence test - "); + + /* + * Command thread 4 to take mutexes 0 and 1. + */ + send_mutex_cmd (4, CMD_TAKE_MUTEX, &m[0]); + sleep (1); /* Allow command to be received. */ + send_mutex_cmd (4, CMD_TAKE_MUTEX, &m[1]); + sleep (1); + + /* + * Tell the threads to report themselves when they are + * at the bottom of their loop (waiting on wait_mutex). + */ + for (i = 0; i < NUM_THREADS; i++) + states[i].flags |= FLAGS_REPORT_WAITMUTEX; + + /* + * Command thread 2 to take mutex 0 and thread 3 to take + * mutex 1, both via a protected operation command. Since + * thread 4 owns mutexes 0 and 1, both threads 2 and 3 + * will block until the mutexes are released by thread 4. + */ + log_trace ("Commanding protected operation to thread 2.\n"); + send_mutex_cmd (2, CMD_PROTECTED_OP, &m[0]); + log_trace ("Commanding protected operation to thread 3.\n"); + send_mutex_cmd (3, CMD_PROTECTED_OP, &m[1]); + sleep (1); + + /* + * Command thread 4 to take mutex 2 via a protected operation + * and thread 5 to enter a busy loop for 5 seconds. Since + * thread 5 has higher priority than thread 4, thread 5 will + * enter the busy loop before thread 4 is activated. + */ + log_trace ("Commanding protected operation to thread 4.\n"); + send_mutex_cmd (4, CMD_PROTECTED_OP, &m[2]); + log_trace ("Commanding busy loop to thread 5.\n"); + send_cmd (5, CMD_BUSY_LOOP); + sleep (1); + if ((states[5].flags & FLAGS_IS_BUSY) == 0) + log_error ("thread 5 is not running.\n"); + log_trace ("Commanding protected operation thread 6.\n"); + send_mutex_cmd (6, CMD_PROTECTED_OP, &m[0]); + sleep (1); + if ((states[4].flags & FLAGS_WAS_BUSY) == 0) + log_error ("thread 4 failed to inherit priority.\n"); + states[4].flags = 0; + send_cmd (4, CMD_RELEASE_ALL); + sleep (5); + check_run_order ("4,6,5,3,2"); + + /* + * Clear the flags. + */ + for (i = 0; i < NUM_THREADS; i++) + states[i].flags = 0; + + /* + * Test setup: + * Thread 2 - enter busy loop (SCHED_FIFO) + * Thread 4 - take mutex 0 + * Thread 4 - priority change to same priority as thread 2 + * Thread 4 - release mutex 0 + * + * Expected results: + * Since thread 4 owns a priority mutex, it should be + * placed at the front of the run queue (for its new + * priority slot) when its priority is lowered to the + * same priority as thread 2. If thread 4 did not own + * a priority mutex, then it would have been added to + * the end of the run queue and thread 2 would have + * executed until it blocked (because it's scheduling + * policy is SCHED_FIFO). + * + */ + log (" Inheritence test with change of priority - "); + + /* + * Change threads 2 and 4 scheduling policies to be + * SCHED_FIFO. + */ + param.sched_priority = states[2].priority; + assert (pthread_setschedparam (states[2].tid, SCHED_FIFO, + ¶m) == 0); + param.sched_priority = states[4].priority; + assert (pthread_setschedparam (states[4].tid, SCHED_FIFO, + ¶m) == 0); + + /* + * Command thread 4 to take mutex 0. + */ + send_mutex_cmd (4, CMD_TAKE_MUTEX, &m[0]); + sleep (1); + + /* + * Command thread 2 to enter busy loop. + */ + send_cmd (2, CMD_BUSY_LOOP); + sleep (1); /* Allow command to be received. */ + + /* + * Command thread 4 to enter busy loop. + */ + send_cmd (4, CMD_BUSY_LOOP); + sleep (1); /* Allow command to be received. */ + + /* Have threads 2 and 4 report themselves. */ + states[2].flags = FLAGS_REPORT_WAITMUTEX; + states[4].flags = FLAGS_REPORT_WAITMUTEX; + + /* Change the priority of thread 4. */ + param.sched_priority = states[2].priority; + assert (pthread_setschedparam (states[4].tid, SCHED_FIFO, + ¶m) == 0); + sleep (5); + check_run_order ("4,2"); + + /* Clear the flags */ + states[2].flags = 0; + states[4].flags = 0; + + /* Reset the policies. */ + param.sched_priority = states[2].priority; + assert (pthread_setschedparam (states[2].tid, SCHED_RR, + ¶m) == 0); + param.sched_priority = states[4].priority; + assert (pthread_setschedparam (states[4].tid, SCHED_RR, + ¶m) == 0); + + send_cmd (4, CMD_RELEASE_MUTEX); + sleep (1); + + /* Destroy the mutexes. */ + for (i = 0; i < 3; i++) + assert (pthread_mutex_destroy (&m[i]) == 0); + } +} + + +int main (int argc, char *argv[]) +{ + pthread_mutexattr_t mattr; + pthread_condattr_t cattr; + pthread_attr_t pattr; + int i, policy, main_prio; + void * exit_status; + sigset_t mask; + struct sigaction act; + struct sched_param param; + + assert (pthread_getschedparam (pthread_self (), &policy, ¶m) == 0); + main_prio = param.sched_priority; + + /* Setupt our signal mask. */ + sigfillset (&mask); + sigdelset (&mask, SIGINT); + sigprocmask (SIG_SETMASK, &mask, NULL); + + /* Install a signal handler for SIGINT */ + sigemptyset (&act.sa_mask); + sigaddset (&act.sa_mask, SIGINT); + act.sa_handler = sighandler; + act.sa_flags = SA_RESTART; + sigaction (SIGINT, &act, NULL); + + /* + * Initialize the thread attribute. + */ + assert (pthread_attr_init (&pattr) == 0); + assert (pthread_attr_setdetachstate (&pattr, + PTHREAD_CREATE_JOINABLE) == 0); + + /* + * Initialize and create the waiter and condvar mutexes. + */ + assert (pthread_mutexattr_init (&mattr) == 0); + assert (pthread_mutex_init (&waiter_mutex, &mattr) == 0); + assert (pthread_mutex_init (&cond_mutex, &mattr) == 0); + + /* + * Initialize and create a condition variable. + */ + assert (pthread_condattr_init (&cattr) == 0); + assert (pthread_cond_init (&cond_var, &cattr) == 0); + + /* Create a pipe to catch the results of thread wakeups. */ + assert (pipe (pipefd) == 0); + +#ifdef DEBUG + assert (pthread_switch_add_np (kern_switch) == 0); +#endif + + /* + * Create the waiting threads. + */ + for (i = 0; i < NUM_THREADS; i++) { + assert (pthread_cond_init (&states[i].cond_var, &cattr) == 0); + states[i].id = (u_int8_t) i; /* NUM_THREADS must be <= 256 */ + states[i].status = 0; + states[i].cmd.cmd_id = CMD_NONE; + states[i].flags = 0; /* No flags yet. */ + assert (pthread_create (&states[i].tid, &pattr, waiter, + (void *) &states[i]) == 0); + param.sched_priority = main_prio - 10 + i; + states[i].priority = param.sched_priority; + assert (pthread_setschedparam (states[i].tid, SCHED_OTHER, + ¶m) == 0); +#if defined(_LIBC_R_) + { + char buf[30]; + + snprintf (buf, sizeof(buf), "waiter_%d", i); + pthread_set_name_np (states[i].tid, buf); + } +#endif + } + + /* Allow the threads to start. */ + sleep (1); + log_trace ("Done creating threads.\n"); + + log ("\n"); + mutex_init_test (); + log ("\n"); + mutex_destroy_test (); + log ("\n"); + mutex_lock_test (); + log ("\n"); + mutex_unlock_test (); + log ("\n"); + queueing_order_test (); + log ("\n"); + mutex_prioinherit_test (); + log ("\n"); + mutex_prioceiling_test (); + log ("\n"); + + log ("Total tests %d, passed %d, failed %d\n", + total, pass_count, error_count); + + /* Set the done flag and signal the threads to exit. */ + log_trace ("Setting done flag.\n"); + done = 1; + + /* + * Wait for the threads to finish. + */ + log_trace ("Trying to join threads.\n"); + for (i = 0; i < NUM_THREADS; i++) { + send_cmd (i, CMD_NONE); + assert (pthread_join (states[i].tid, &exit_status) == 0); + } + + /* Clean up after ourselves. */ + close (pipefd[0]); + close (pipefd[1]); + + if (error_count != 0) + exit (EX_OSERR); /* any better ideas??? */ + else + exit (EX_OK); +} diff --git a/lib/libpthread/test/mutex_d.exp b/lib/libpthread/test/mutex_d.exp new file mode 100644 index 0000000..de8a4e4 --- /dev/null +++ b/lib/libpthread/test/mutex_d.exp @@ -0,0 +1,290 @@ + +Testing pthread_mutex_init +-------------------------- + Protocol PTHREAD_PRIO_NONE, Type POSIX (type not specified) - PASS + Protocol PTHREAD_PRIO_NONE, Type SS2 PTHREAD_MUTEX_DEFAULT - PASS + Protocol PTHREAD_PRIO_NONE, Type SS2 PTHREAD_MUTEX_ERRORCHECK - PASS + Protocol PTHREAD_PRIO_NONE, Type SS2 PTHREAD_MUTEX_NORMAL - PASS + Protocol PTHREAD_PRIO_NONE, Type SS2 PTHREAD_MUTEX_RECURSIVE - PASS + Protocol PTHREAD_PRIO_INHERIT, Type POSIX (type not specified) - PASS + Protocol PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_DEFAULT - PASS + Protocol PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_ERRORCHECK - PASS + Protocol PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_NORMAL - PASS + Protocol PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_RECURSIVE - PASS + Protocol PTHREAD_PRIO_PROTECT, Type POSIX (type not specified) - PASS + Protocol PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_DEFAULT - PASS + Protocol PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_ERRORCHECK - PASS + Protocol PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_NORMAL - PASS + Protocol PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_RECURSIVE - PASS + +Testing pthread_mutex_destroy +----------------------------- + Protocol PTHREAD_PRIO_NONE, Type POSIX (type not specified) + Destruction of unused mutex - PASS + Destruction of mutex locked by self - PASS + Destruction of mutex locked by another thread - PASS + Destruction of mutex while being used in cond_wait - PASS + Protocol PTHREAD_PRIO_NONE, Type SS2 PTHREAD_MUTEX_DEFAULT + Destruction of unused mutex - PASS + Destruction of mutex locked by self - PASS + Destruction of mutex locked by another thread - PASS + Destruction of mutex while being used in cond_wait - PASS + Protocol PTHREAD_PRIO_NONE, Type SS2 PTHREAD_MUTEX_ERRORCHECK + Destruction of unused mutex - PASS + Destruction of mutex locked by self - PASS + Destruction of mutex locked by another thread - PASS + Destruction of mutex while being used in cond_wait - PASS + Protocol PTHREAD_PRIO_NONE, Type SS2 PTHREAD_MUTEX_NORMAL + Destruction of unused mutex - PASS + Destruction of mutex locked by self - PASS + Destruction of mutex locked by another thread - PASS + Destruction of mutex while being used in cond_wait - PASS + Protocol PTHREAD_PRIO_NONE, Type SS2 PTHREAD_MUTEX_RECURSIVE + Destruction of unused mutex - PASS + Destruction of mutex locked by self - PASS + Destruction of mutex locked by another thread - PASS + Destruction of mutex while being used in cond_wait - PASS + Protocol PTHREAD_PRIO_INHERIT, Type POSIX (type not specified) + Destruction of unused mutex - PASS + Destruction of mutex locked by self - PASS + Destruction of mutex locked by another thread - PASS + Destruction of mutex while being used in cond_wait - PASS + Protocol PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_DEFAULT + Destruction of unused mutex - PASS + Destruction of mutex locked by self - PASS + Destruction of mutex locked by another thread - PASS + Destruction of mutex while being used in cond_wait - PASS + Protocol PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_ERRORCHECK + Destruction of unused mutex - PASS + Destruction of mutex locked by self - PASS + Destruction of mutex locked by another thread - PASS + Destruction of mutex while being used in cond_wait - PASS + Protocol PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_NORMAL + Destruction of unused mutex - PASS + Destruction of mutex locked by self - PASS + Destruction of mutex locked by another thread - PASS + Destruction of mutex while being used in cond_wait - PASS + Protocol PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_RECURSIVE + Destruction of unused mutex - PASS + Destruction of mutex locked by self - PASS + Destruction of mutex locked by another thread - PASS + Destruction of mutex while being used in cond_wait - PASS + Protocol PTHREAD_PRIO_PROTECT, Type POSIX (type not specified) + Destruction of unused mutex - PASS + Destruction of mutex locked by self - PASS + Destruction of mutex locked by another thread - PASS + Destruction of mutex while being used in cond_wait - PASS + Protocol PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_DEFAULT + Destruction of unused mutex - PASS + Destruction of mutex locked by self - PASS + Destruction of mutex locked by another thread - PASS + Destruction of mutex while being used in cond_wait - PASS + Protocol PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_ERRORCHECK + Destruction of unused mutex - PASS + Destruction of mutex locked by self - PASS + Destruction of mutex locked by another thread - PASS + Destruction of mutex while being used in cond_wait - PASS + Protocol PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_NORMAL + Destruction of unused mutex - PASS + Destruction of mutex locked by self - PASS + Destruction of mutex locked by another thread - PASS + Destruction of mutex while being used in cond_wait - PASS + Protocol PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_RECURSIVE + Destruction of unused mutex - PASS + Destruction of mutex locked by self - PASS + Destruction of mutex locked by another thread - PASS + Destruction of mutex while being used in cond_wait - PASS + +Testing pthread_mutex_lock +-------------------------- + Protocol PTHREAD_PRIO_NONE, Type POSIX (type not specified) + Lock on unlocked mutex - PASS + Lock on invalid mutex - PASS + Lock on mutex held by self - PASS + Protocol PTHREAD_PRIO_NONE, Type SS2 PTHREAD_MUTEX_DEFAULT + Lock on unlocked mutex - PASS + Lock on invalid mutex - PASS + Lock on mutex held by self - PASS + Protocol PTHREAD_PRIO_NONE, Type SS2 PTHREAD_MUTEX_ERRORCHECK + Lock on unlocked mutex - PASS + Lock on invalid mutex - PASS + Lock on mutex held by self - PASS + Protocol PTHREAD_PRIO_NONE, Type SS2 PTHREAD_MUTEX_NORMAL + Lock on unlocked mutex - PASS + Lock on invalid mutex - PASS + Lock on mutex held by self - PASS + Protocol PTHREAD_PRIO_NONE, Type SS2 PTHREAD_MUTEX_RECURSIVE + Lock on unlocked mutex - PASS + Lock on invalid mutex - PASS + Lock on mutex held by self - PASS + Protocol PTHREAD_PRIO_INHERIT, Type POSIX (type not specified) + Lock on unlocked mutex - PASS + Lock on invalid mutex - PASS + Lock on mutex held by self - PASS + Protocol PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_DEFAULT + Lock on unlocked mutex - PASS + Lock on invalid mutex - PASS + Lock on mutex held by self - PASS + Protocol PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_ERRORCHECK + Lock on unlocked mutex - PASS + Lock on invalid mutex - PASS + Lock on mutex held by self - PASS + Protocol PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_NORMAL + Lock on unlocked mutex - PASS + Lock on invalid mutex - PASS + Lock on mutex held by self - PASS + Protocol PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_RECURSIVE + Lock on unlocked mutex - PASS + Lock on invalid mutex - PASS + Lock on mutex held by self - PASS + Protocol PTHREAD_PRIO_PROTECT, Type POSIX (type not specified) + Lock on unlocked mutex - PASS + Lock on invalid mutex - PASS + Lock on mutex held by self - PASS + Protocol PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_DEFAULT + Lock on unlocked mutex - PASS + Lock on invalid mutex - PASS + Lock on mutex held by self - PASS + Protocol PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_ERRORCHECK + Lock on unlocked mutex - PASS + Lock on invalid mutex - PASS + Lock on mutex held by self - PASS + Protocol PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_NORMAL + Lock on unlocked mutex - PASS + Lock on invalid mutex - PASS + Lock on mutex held by self - PASS + Protocol PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_RECURSIVE + Lock on unlocked mutex - PASS + Lock on invalid mutex - PASS + Lock on mutex held by self - PASS + +Testing pthread_mutex_unlock +---------------------------- + Protocol PTHREAD_PRIO_NONE, Type POSIX (type not specified) + Unlock on mutex held by self - PASS + Unlock on invalid mutex - PASS + Unlock on mutex locked by another thread - PASS + Protocol PTHREAD_PRIO_NONE, Type SS2 PTHREAD_MUTEX_DEFAULT + Unlock on mutex held by self - PASS + Unlock on invalid mutex - PASS + Unlock on mutex locked by another thread - PASS + Protocol PTHREAD_PRIO_NONE, Type SS2 PTHREAD_MUTEX_ERRORCHECK + Unlock on mutex held by self - PASS + Unlock on invalid mutex - PASS + Unlock on mutex locked by another thread - PASS + Protocol PTHREAD_PRIO_NONE, Type SS2 PTHREAD_MUTEX_NORMAL + Unlock on mutex held by self - PASS + Unlock on invalid mutex - PASS + Unlock on mutex locked by another thread - PASS + Protocol PTHREAD_PRIO_NONE, Type SS2 PTHREAD_MUTEX_RECURSIVE + Unlock on mutex held by self - PASS + Unlock on invalid mutex - PASS + Unlock on mutex locked by another thread - PASS + Protocol PTHREAD_PRIO_INHERIT, Type POSIX (type not specified) + Unlock on mutex held by self - PASS + Unlock on invalid mutex - PASS + Unlock on mutex locked by another thread - PASS + Protocol PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_DEFAULT + Unlock on mutex held by self - PASS + Unlock on invalid mutex - PASS + Unlock on mutex locked by another thread - PASS + Protocol PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_ERRORCHECK + Unlock on mutex held by self - PASS + Unlock on invalid mutex - PASS + Unlock on mutex locked by another thread - PASS + Protocol PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_NORMAL + Unlock on mutex held by self - PASS + Unlock on invalid mutex - PASS + Unlock on mutex locked by another thread - PASS + Protocol PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_RECURSIVE + Unlock on mutex held by self - PASS + Unlock on invalid mutex - PASS + Unlock on mutex locked by another thread - PASS + Protocol PTHREAD_PRIO_PROTECT, Type POSIX (type not specified) + Unlock on mutex held by self - PASS + Unlock on invalid mutex - PASS + Unlock on mutex locked by another thread - PASS + Protocol PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_DEFAULT + Unlock on mutex held by self - PASS + Unlock on invalid mutex - PASS + Unlock on mutex locked by another thread - PASS + Protocol PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_ERRORCHECK + Unlock on mutex held by self - PASS + Unlock on invalid mutex - PASS + Unlock on mutex locked by another thread - PASS + Protocol PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_NORMAL + Unlock on mutex held by self - PASS + Unlock on invalid mutex - PASS + Unlock on mutex locked by another thread - PASS + Protocol PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_RECURSIVE + Unlock on mutex held by self - PASS + Unlock on invalid mutex - PASS + Unlock on mutex locked by another thread - PASS + +Testing queueing order +---------------------- + Queueing order on a mutex - PASS + Queueing order on a condition variable - PASS + +Testing priority inheritence +---------------------------- + Protype PTHREAD_PRIO_INHERIT, Type POSIX (type not specified) + Simple inheritence test - PASS + Inheritence test with change of priority - PASS + Protype PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_DEFAULT + Simple inheritence test - PASS + Inheritence test with change of priority - PASS + Protype PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_ERRORCHECK + Simple inheritence test - PASS + Inheritence test with change of priority - PASS + Protype PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_NORMAL + Simple inheritence test - PASS + Inheritence test with change of priority - PASS + Protype PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_RECURSIVE + Simple inheritence test - PASS + Inheritence test with change of priority - PASS + +Testing priority ceilings +------------------------- + Protype PTHREAD_PRIO_PROTECT, Type POSIX (type not specified) + Lock with ceiling priority < thread priority - PASS + Lock with ceiling priority = thread priority - PASS + Lock with ceiling priority > thread priority - PASS + Preemption with ceiling priority < thread priority - PASS + Preemption with ceiling priority = thread priority - PASS + SCHED_FIFO scheduling and ceiling priority = thread priority - PASS + SCHED_FIFO scheduling and ceiling priority > thread priority - PASS + Protype PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_DEFAULT + Lock with ceiling priority < thread priority - PASS + Lock with ceiling priority = thread priority - PASS + Lock with ceiling priority > thread priority - PASS + Preemption with ceiling priority < thread priority - PASS + Preemption with ceiling priority = thread priority - PASS + SCHED_FIFO scheduling and ceiling priority = thread priority - PASS + SCHED_FIFO scheduling and ceiling priority > thread priority - PASS + Protype PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_ERRORCHECK + Lock with ceiling priority < thread priority - PASS + Lock with ceiling priority = thread priority - PASS + Lock with ceiling priority > thread priority - PASS + Preemption with ceiling priority < thread priority - PASS + Preemption with ceiling priority = thread priority - PASS + SCHED_FIFO scheduling and ceiling priority = thread priority - PASS + SCHED_FIFO scheduling and ceiling priority > thread priority - PASS + Protype PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_NORMAL + Lock with ceiling priority < thread priority - PASS + Lock with ceiling priority = thread priority - PASS + Lock with ceiling priority > thread priority - PASS + Preemption with ceiling priority < thread priority - PASS + Preemption with ceiling priority = thread priority - PASS + SCHED_FIFO scheduling and ceiling priority = thread priority - PASS + SCHED_FIFO scheduling and ceiling priority > thread priority - PASS + Protype PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_RECURSIVE + Lock with ceiling priority < thread priority - PASS + Lock with ceiling priority = thread priority - PASS + Lock with ceiling priority > thread priority - PASS + Preemption with ceiling priority < thread priority - PASS + Preemption with ceiling priority = thread priority - PASS + SCHED_FIFO scheduling and ceiling priority = thread priority - PASS + SCHED_FIFO scheduling and ceiling priority > thread priority - PASS + +Total tests 212, passed 212, failed 0 diff --git a/lib/libpthread/test/propagate_s.pl b/lib/libpthread/test/propagate_s.pl new file mode 100755 index 0000000..9cd5fb0 --- /dev/null +++ b/lib/libpthread/test/propagate_s.pl @@ -0,0 +1,74 @@ +#!/usr/bin/perl -w +# +# Copyright (C) 2000 Jason Evans <jasone@freebsd.org>. +# 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(s), this list of conditions and the following disclaimer as +# the first lines of this file unmodified other than the possible +# addition of one or more copyright notices. +# 2. Redistributions in binary form must reproduce the above copyright +# notice(s), this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``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 COPYRIGHT HOLDER(S) 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. +# +########################################################################### +# +# Verify that no cancellation points are propagated inside of libc_r. +# +# $FreeBSD$ +# + +@CPOINTS = ("aio_suspend", "close", "creat", "fcntl", "fsync", "mq_receive", + "mq_send", "msync", "nanosleep", "open", "pause", + "pthread_cond_timedwait", "pthread_cond_wait", "pthread_join", + "pthread_testcancel", "read", "sem_wait", "sigsuspend", + "sigtimedwait", "sigwait", "sigwaitinfo", "sleep", "system", + "tcdrain", "wait", "waitpid", "write"); + +print "1..1\n"; + +$cpoints = join '\|', @CPOINTS; +$regexp = "\" U \\(" . $cpoints . "\\\)\$\""; + +`nm -a /usr/lib/libc.a |grep $regexp >propagate_s.out`; +if (!open (NMOUT, "<./propagate_s.out")) +{ + print "not ok 1\n"; +} +else +{ + $propagations = 0; + + while (<NMOUT>) + { + $propagations++; + print "$_\n"; + } + if ($propagations != 0) + { + print "$propagations propagation(s)\n"; + print "not ok 1\n"; + } + else + { + print "ok 1\n"; + } + close NMOUT; + unlink "propagate_s.out"; +} diff --git a/lib/libpthread/test/sem_d.c b/lib/libpthread/test/sem_d.c new file mode 100644 index 0000000..1551ae8 --- /dev/null +++ b/lib/libpthread/test/sem_d.c @@ -0,0 +1,135 @@ +/**************************************************************************** + * + * Copyright (C) 2000 Jason Evans <jasone@freebsd.org>. + * 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(s), this list of conditions and the following disclaimer as + * the first lines of this file unmodified other than the possible + * addition of one or more copyright notices. + * 2. Redistributions in binary form must reproduce the above copyright + * notice(s), this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``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 COPYRIGHT HOLDER(S) 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. + * + **************************************************************************** + * + * sem test. + * + * $FreeBSD$ + * + ****************************************************************************/ + +#define _REENTRANT + +#include <assert.h> +#include <stdio.h> +#include <fcntl.h> +#include <errno.h> +#include <semaphore.h> +#include <pthread.h> + +#define NTHREADS 10 + +void * +entry(void * a_arg) +{ + sem_t * sem = (sem_t *) a_arg; + + sem_wait(sem); + fprintf(stderr, "Got semaphore\n"); + + return NULL; +} + +int +main() +{ + sem_t sem_a, sem_b; + pthread_t threads[NTHREADS]; + unsigned i; + int val; + + fprintf(stderr, "Test begin\n"); + +#ifdef _LIBC_R_ + assert(-1 == sem_init(&sem_b, 1, 0)); + assert(EPERM == errno); +#endif + + assert(0 == sem_init(&sem_b, 0, 0)); + assert(0 == sem_getvalue(&sem_b, &val)); + assert(0 == val); + + assert(0 == sem_post(&sem_b)); + assert(0 == sem_getvalue(&sem_b, &val)); + assert(1 == val); + + assert(0 == sem_wait(&sem_b)); + assert(-1 == sem_trywait(&sem_b)); + assert(EAGAIN == errno); + assert(0 == sem_post(&sem_b)); + assert(0 == sem_trywait(&sem_b)); + assert(0 == sem_post(&sem_b)); + assert(0 == sem_wait(&sem_b)); + assert(0 == sem_post(&sem_b)); + +#ifdef _LIBC_R_ + assert(SEM_FAILED == sem_open("/foo", O_CREAT | O_EXCL, 0644, 0)); + assert(ENOSYS == errno); + + assert(-1 == sem_close(&sem_b)); + assert(ENOSYS == errno); + + assert(-1 == sem_unlink("/foo")); + assert(ENOSYS == errno); +#endif + + assert(0 == sem_destroy(&sem_b)); + + assert(0 == sem_init(&sem_a, 0, 0)); + + for (i = 0; i < NTHREADS; i++) { + pthread_create(&threads[i], NULL, entry, (void *) &sem_a); + } + + for (i = 0; i < NTHREADS; i++) { + assert(0 == sem_post(&sem_a)); + } + + for (i = 0; i < NTHREADS; i++) { + pthread_join(threads[i], NULL); + } + + for (i = 0; i < NTHREADS; i++) { + pthread_create(&threads[i], NULL, entry, (void *) &sem_a); + } + + for (i = 0; i < NTHREADS; i++) { + assert(0 == sem_post(&sem_a)); + } + + for (i = 0; i < NTHREADS; i++) { + pthread_join(threads[i], NULL); + } + + assert(0 == sem_destroy(&sem_a)); + + fprintf(stderr, "Test end\n"); + return 0; +} diff --git a/lib/libpthread/test/sem_d.exp b/lib/libpthread/test/sem_d.exp new file mode 100644 index 0000000..b0de3da --- /dev/null +++ b/lib/libpthread/test/sem_d.exp @@ -0,0 +1,22 @@ +Test begin +Got semaphore +Got semaphore +Got semaphore +Got semaphore +Got semaphore +Got semaphore +Got semaphore +Got semaphore +Got semaphore +Got semaphore +Got semaphore +Got semaphore +Got semaphore +Got semaphore +Got semaphore +Got semaphore +Got semaphore +Got semaphore +Got semaphore +Got semaphore +Test end diff --git a/lib/libpthread/test/sigsuspend_d.c b/lib/libpthread/test/sigsuspend_d.c new file mode 100644 index 0000000..d2420ed --- /dev/null +++ b/lib/libpthread/test/sigsuspend_d.c @@ -0,0 +1,288 @@ +/* + * Copyright (c) 1998 Daniel M. Eischen <eischen@vigrid.com> + * 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 Daniel M. Eischen. + * 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 DANIEL M. EISCHEN 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. + * + * $FreeBSD$ + */ +#include <stdlib.h> +#include <unistd.h> + +#include <errno.h> +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <string.h> + +#if defined(_LIBC_R_) +#include <pthread_np.h> +#endif + +static int sigcounts[NSIG + 1]; +static int sigfifo[NSIG + 1]; +static int fifo_depth = 0; +static sigset_t suspender_mask; +static pthread_t suspender_tid; + + +static void * +sigsuspender (void *arg) +{ + int save_count, status, i; + sigset_t run_mask; + + /* Run with all signals blocked. */ + sigfillset (&run_mask); + sigprocmask (SIG_SETMASK, &run_mask, NULL); + + /* Allow these signals to wake us up during a sigsuspend. */ + sigfillset (&suspender_mask); /* Default action */ + sigdelset (&suspender_mask, SIGINT); /* terminate */ + sigdelset (&suspender_mask, SIGHUP); /* terminate */ + sigdelset (&suspender_mask, SIGQUIT); /* create core image */ + sigdelset (&suspender_mask, SIGURG); /* ignore */ + sigdelset (&suspender_mask, SIGIO); /* ignore */ + sigdelset (&suspender_mask, SIGUSR2); /* terminate */ + + while (sigcounts[SIGINT] == 0) { + save_count = sigcounts[SIGUSR2]; + + status = sigsuspend (&suspender_mask); + if ((status == 0) || (errno != EINTR)) { + fprintf (stderr, "Unable to suspend for signals, " + "errno %d, return value %d\n", + errno, status); + exit (1); + } + for (i = 0; i < fifo_depth; i++) + fprintf (stderr, "Sigsuspend woke up by signal %d\n", + sigfifo[i]); + fifo_depth = 0; + } + + pthread_exit (arg); + return (NULL); +} + + +static void +sighandler (int signo) +{ + sigset_t set, suspend_set; + pthread_t self; + + if ((signo >= 0) && (signo <= NSIG)) + sigcounts[signo]++; + + /* + * If we are running on behalf of the suspender thread, + * ensure that we have the correct mask set. + */ + self = pthread_self (); + if (self == suspender_tid) { + sigfifo[fifo_depth] = signo; + fifo_depth++; + fprintf (stderr, + " -> Suspender thread signal handler caught signal %d\n", + signo); + + /* Get the current signal mask. */ + sigprocmask (SIG_SETMASK, NULL, &set); + + /* The handler should run with the current signal masked. */ + suspend_set = suspender_mask; + sigaddset(&suspend_set, signo); + + if (memcmp(&set, &suspend_set, sizeof(set))) + fprintf (stderr, + " >>> FAIL: sigsuspender signal handler running " + "with incorrect mask.\n"); + } + else + fprintf (stderr, + " -> Main thread signal handler caught signal %d\n", + signo); +} + + +static void +send_thread_signal (pthread_t tid, int signo) +{ + if (pthread_kill (tid, signo) != 0) { + fprintf (stderr, "Unable to send thread signal, errno %d.\n", + errno); + exit (1); + } +} + + +static void +send_process_signal (int signo) +{ + if (kill (getpid (), signo) != 0) { + fprintf (stderr, "Unable to send process signal, errno %d.\n", + errno); + exit (1); + } +} + + +int main (int argc, char *argv[]) +{ + pthread_attr_t pattr; + void * exit_status; + struct sigaction act; + sigset_t oldset; + sigset_t newset; + + /* Initialize our signal counts. */ + memset ((void *) sigcounts, 0, NSIG * sizeof (int)); + + /* Ignore signal SIGIO. */ + sigemptyset (&act.sa_mask); + sigaddset (&act.sa_mask, SIGIO); + act.sa_handler = SIG_IGN; + act.sa_flags = 0; + sigaction (SIGIO, &act, NULL); + + /* Install a signal handler for SIGURG. */ + sigemptyset (&act.sa_mask); + sigaddset (&act.sa_mask, SIGURG); + act.sa_handler = sighandler; + act.sa_flags = SA_RESTART; + sigaction (SIGURG, &act, NULL); + + /* Install a signal handler for SIGXCPU */ + sigemptyset (&act.sa_mask); + sigaddset (&act.sa_mask, SIGXCPU); + sigaction (SIGXCPU, &act, NULL); + + /* Get our current signal mask. */ + sigprocmask (SIG_SETMASK, NULL, &oldset); + + /* Mask out SIGUSR1 and SIGUSR2. */ + newset = oldset; + sigaddset (&newset, SIGUSR1); + sigaddset (&newset, SIGUSR2); + sigprocmask (SIG_SETMASK, &newset, NULL); + + /* Install a signal handler for SIGUSR1 */ + sigemptyset (&act.sa_mask); + sigaddset (&act.sa_mask, SIGUSR1); + sigaction (SIGUSR1, &act, NULL); + + /* Install a signal handler for SIGUSR2 */ + sigemptyset (&act.sa_mask); + sigaddset (&act.sa_mask, SIGUSR2); + sigaction (SIGUSR2, &act, NULL); + + /* + * Initialize the thread attribute. + */ + if ((pthread_attr_init (&pattr) != 0) || + (pthread_attr_setdetachstate (&pattr, + PTHREAD_CREATE_JOINABLE) != 0)) { + fprintf (stderr, "Unable to initialize thread attributes.\n"); + exit (1); + } + + /* + * Create the sigsuspender thread. + */ + if (pthread_create (&suspender_tid, &pattr, sigsuspender, NULL) != 0) { + fprintf (stderr, "Unable to create thread, errno %d.\n", errno); + exit (1); + } +#if defined(_LIBC_R) + pthread_set_name_np (suspender_tid, "sigsuspender"); +#endif + + /* + * Verify that an ignored signal doesn't cause a wakeup. + * We don't have a handler installed for SIGIO. + */ + send_thread_signal (suspender_tid, SIGIO); + sleep (1); + send_process_signal (SIGIO); + sleep (1); + if (sigcounts[SIGIO] != 0) + fprintf (stderr, "FAIL: sigsuspend wakes up for ignored signal " + "SIGIO.\n"); + + /* + * Verify that a signal with a default action of ignore, for + * which we have a signal handler installed, will release a + * sigsuspend. + */ + send_thread_signal (suspender_tid, SIGURG); + sleep (1); + send_process_signal (SIGURG); + sleep (1); + if (sigcounts[SIGURG] != 2) + fprintf (stderr, + "FAIL: sigsuspend doesn't wake up for SIGURG.\n"); + + /* + * Verify that a SIGUSR2 signal will release a sigsuspended + * thread. + */ + send_thread_signal (suspender_tid, SIGUSR2); + sleep (1); + send_process_signal (SIGUSR2); + sleep (1); + if (sigcounts[SIGUSR2] != 2) + fprintf (stderr, + "FAIL: sigsuspend doesn't wake up for SIGUSR2.\n"); + + /* + * Verify that a signal, blocked in both the main and + * sigsuspender threads, does not cause the signal handler + * to be called. + */ + send_thread_signal (suspender_tid, SIGUSR1); + sleep (1); + send_process_signal (SIGUSR1); + sleep (1); + if (sigcounts[SIGUSR1] != 0) + fprintf (stderr, "FAIL: signal hander called for SIGUSR1.\n"); + + /* + * Verify that we can still kill the process for a signal + * not being waited on by sigwait. + */ + send_process_signal (SIGPIPE); + fprintf (stderr, "FAIL: SIGPIPE did not terminate process.\n"); + + /* + * Wait for the thread to finish. + */ + pthread_join (suspender_tid, &exit_status); + + return (0); +} diff --git a/lib/libpthread/test/sigsuspend_d.exp b/lib/libpthread/test/sigsuspend_d.exp new file mode 100644 index 0000000..901fa50 --- /dev/null +++ b/lib/libpthread/test/sigsuspend_d.exp @@ -0,0 +1,8 @@ + -> Suspender thread signal handler caught signal 16 +Sigsuspend woke up by signal 16 + -> Suspender thread signal handler caught signal 16 +Sigsuspend woke up by signal 16 + -> Suspender thread signal handler caught signal 31 +Sigsuspend woke up by signal 31 + -> Suspender thread signal handler caught signal 31 +Sigsuspend woke up by signal 31 diff --git a/lib/libpthread/test/sigwait_d.c b/lib/libpthread/test/sigwait_d.c new file mode 100644 index 0000000..ab57979 --- /dev/null +++ b/lib/libpthread/test/sigwait_d.c @@ -0,0 +1,304 @@ +/* + * Copyright (c) 1998 Daniel M. Eischen <eischen@vigrid.com> + * 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 Daniel M. Eischen. + * 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 DANIEL M. EISCHEN 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. + * + * $FreeBSD$ + */ +#include <stdlib.h> +#include <unistd.h> + +#include <errno.h> +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <string.h> + +#if defined(_LIBC_R_) +#include <pthread_np.h> +#endif + +static int sigcounts[NSIG + 1]; +static sigset_t wait_mask; +static pthread_mutex_t waiter_mutex; + + +static void * +sigwaiter (void *arg) +{ + int signo; + sigset_t mask; + + /* Block SIGHUP */ + sigemptyset (&mask); + sigaddset (&mask, SIGHUP); + sigprocmask (SIG_BLOCK, &mask, NULL); + + while (sigcounts[SIGINT] == 0) { + if (sigwait (&wait_mask, &signo) != 0) { + fprintf (stderr, + "Unable to wait for signal, errno %d\n", + errno); + exit (1); + } + sigcounts[signo]++; + fprintf (stderr, "Sigwait caught signal %d\n", signo); + + /* Allow the main thread to prevent the sigwait. */ + pthread_mutex_lock (&waiter_mutex); + pthread_mutex_unlock (&waiter_mutex); + } + + pthread_exit (arg); + return (NULL); +} + + +static void +sighandler (int signo) +{ + fprintf (stderr, " -> Signal handler caught signal %d\n", signo); + + if ((signo >= 0) && (signo <= NSIG)) + sigcounts[signo]++; +} + +static void +send_thread_signal (pthread_t tid, int signo) +{ + if (pthread_kill (tid, signo) != 0) { + fprintf (stderr, "Unable to send thread signal, errno %d.\n", + errno); + exit (1); + } +} + +static void +send_process_signal (int signo) +{ + if (kill (getpid (), signo) != 0) { + fprintf (stderr, "Unable to send process signal, errno %d.\n", + errno); + exit (1); + } +} + + +int main (int argc, char *argv[]) +{ + pthread_mutexattr_t mattr; + pthread_attr_t pattr; + pthread_t tid; + void * exit_status; + struct sigaction act; + + /* Initialize our signal counts. */ + memset ((void *) sigcounts, 0, NSIG * sizeof (int)); + + /* Setup our wait mask. */ + sigemptyset (&wait_mask); /* Default action */ + sigaddset (&wait_mask, SIGHUP); /* terminate */ + sigaddset (&wait_mask, SIGINT); /* terminate */ + sigaddset (&wait_mask, SIGQUIT); /* create core image */ + sigaddset (&wait_mask, SIGURG); /* ignore */ + sigaddset (&wait_mask, SIGIO); /* ignore */ + sigaddset (&wait_mask, SIGUSR1); /* terminate */ + + /* Ignore signals SIGHUP and SIGIO. */ + sigemptyset (&act.sa_mask); + sigaddset (&act.sa_mask, SIGHUP); + sigaddset (&act.sa_mask, SIGIO); + act.sa_handler = SIG_IGN; + act.sa_flags = 0; + sigaction (SIGHUP, &act, NULL); + sigaction (SIGIO, &act, NULL); + + /* Install a signal handler for SIGURG */ + sigemptyset (&act.sa_mask); + sigaddset (&act.sa_mask, SIGURG); + act.sa_handler = sighandler; + act.sa_flags = SA_RESTART; + sigaction (SIGURG, &act, NULL); + + /* Install a signal handler for SIGXCPU */ + sigemptyset (&act.sa_mask); + sigaddset (&act.sa_mask, SIGXCPU); + sigaction (SIGXCPU, &act, NULL); + + /* + * Initialize the thread attribute. + */ + if ((pthread_attr_init (&pattr) != 0) || + (pthread_attr_setdetachstate (&pattr, + PTHREAD_CREATE_JOINABLE) != 0)) { + fprintf (stderr, "Unable to initialize thread attributes.\n"); + exit (1); + } + + /* + * Initialize and create a mutex. + */ + if ((pthread_mutexattr_init (&mattr) != 0) || + (pthread_mutex_init (&waiter_mutex, &mattr) != 0)) { + fprintf (stderr, "Unable to create waiter mutex.\n"); + exit (1); + } + + /* + * Create the sigwaiter thread. + */ + if (pthread_create (&tid, &pattr, sigwaiter, NULL) != 0) { + fprintf (stderr, "Unable to create thread.\n"); + exit (1); + } +#if defined(_LIBC_R_) + pthread_set_name_np (tid, "sigwaiter"); +#endif + + /* + * Verify that an ignored signal doesn't cause a wakeup. + * We don't have a handler installed for SIGIO. + */ + send_thread_signal (tid, SIGIO); + sleep (1); + send_process_signal (SIGIO); + sleep (1); + if (sigcounts[SIGIO] != 0) + fprintf (stderr, + "FAIL: sigwait wakes up for ignored signal SIGIO.\n"); + + /* + * Verify that a signal with a default action of ignore, for + * which we have a signal handler installed, will release a sigwait. + */ + send_thread_signal (tid, SIGURG); + sleep (1); + send_process_signal (SIGURG); + sleep (1); + if (sigcounts[SIGURG] != 2) + fprintf (stderr, "FAIL: sigwait doesn't wake up for SIGURG.\n"); + + /* + * Verify that a signal with a default action that terminates + * the process will release a sigwait. + */ + send_thread_signal (tid, SIGUSR1); + sleep (1); + send_process_signal (SIGUSR1); + sleep (1); + if (sigcounts[SIGUSR1] != 2) + fprintf (stderr, + "FAIL: sigwait doesn't wake up for SIGUSR1.\n"); + + /* + * Verify that if we install a signal handler for a previously + * ignored signal, an occurrence of this signal will release + * the (already waiting) sigwait. + */ + + /* Install a signal handler for SIGHUP. */ + sigemptyset (&act.sa_mask); + sigaddset (&act.sa_mask, SIGHUP); + act.sa_handler = sighandler; + act.sa_flags = SA_RESTART; + sigaction (SIGHUP, &act, NULL); + + /* Sending SIGHUP should release the sigwait. */ + send_process_signal (SIGHUP); + sleep (1); + send_thread_signal (tid, SIGHUP); + sleep (1); + if (sigcounts[SIGHUP] != 2) + fprintf (stderr, "FAIL: sigwait doesn't wake up for SIGHUP.\n"); + + /* + * Verify that a pending signal in the waiters mask will + * cause sigwait to return the pending signal. We do this + * by taking the waiters mutex and signaling the waiter to + * release him from the sigwait. The waiter will block + * on taking the mutex, and we can then send the waiter a + * signal which should be added to his pending signals. + * The next time the waiter does a sigwait, he should + * return with the pending signal. + */ + sigcounts[SIGHUP] = 0; + pthread_mutex_lock (&waiter_mutex); + /* Release the waiter from sigwait. */ + send_process_signal (SIGHUP); + sleep (1); + if (sigcounts[SIGHUP] != 1) + fprintf (stderr, "FAIL: sigwait doesn't wake up for SIGHUP.\n"); + /* + * Add SIGHUP to the process pending signals. Since there is + * a signal handler installed for SIGHUP and this signal is + * blocked from the waiter thread and unblocked in the main + * thread, the signal handler should be called once for SIGHUP. + */ + send_process_signal (SIGHUP); + /* Release the waiter thread and allow him to run. */ + pthread_mutex_unlock (&waiter_mutex); + sleep (1); + if (sigcounts[SIGHUP] != 2) + fprintf (stderr, + "FAIL: sigwait doesn't return for pending SIGHUP.\n"); + + /* + * Repeat the above test using pthread_kill and SIGUSR1. + */ + sigcounts[SIGUSR1] = 0; + pthread_mutex_lock (&waiter_mutex); + /* Release the waiter from sigwait. */ + send_thread_signal (tid, SIGUSR1); + sleep (1); + if (sigcounts[SIGUSR1] != 1) + fprintf (stderr, + "FAIL: sigwait doesn't wake up for SIGUSR1.\n"); + /* Add SIGHUP to the waiters pending signals. */ + send_thread_signal (tid, SIGUSR1); + /* Release the waiter thread and allow him to run. */ + pthread_mutex_unlock (&waiter_mutex); + sleep (1); + if (sigcounts[SIGUSR1] != 2) + fprintf (stderr, + "FAIL: sigwait doesn't return for pending SIGUSR1.\n"); + + /* + * Verify that we can still kill the process for a signal + * not being waited on by sigwait. + */ + send_process_signal (SIGPIPE); + fprintf (stderr, "FAIL: SIGPIPE did not terminate process.\n"); + + /* + * Wait for the thread to finish. + */ + pthread_join (tid, &exit_status); + + return (0); +} diff --git a/lib/libpthread/test/sigwait_d.exp b/lib/libpthread/test/sigwait_d.exp new file mode 100644 index 0000000..2e9b2c4 --- /dev/null +++ b/lib/libpthread/test/sigwait_d.exp @@ -0,0 +1,10 @@ +Sigwait caught signal 16 +Sigwait caught signal 16 +Sigwait caught signal 30 +Sigwait caught signal 30 +Sigwait caught signal 1 +Sigwait caught signal 1 +Sigwait caught signal 1 + -> Signal handler caught signal 1 +Sigwait caught signal 30 +Sigwait caught signal 30 diff --git a/lib/libpthread/test/verify b/lib/libpthread/test/verify new file mode 100755 index 0000000..bf8d94a --- /dev/null +++ b/lib/libpthread/test/verify @@ -0,0 +1,505 @@ +#!/usr/bin/perl -w +#-*-mode:perl-*- +############################################################################# +# +# Copyright (C) 1999-2000 Jason Evans <jasone@freebsd.org>. +# 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(s), this list of conditions and the following disclaimer as +# the first lines of this file unmodified other than the possible +# addition of one or more copyright notices. +# 2. Redistributions in binary form must reproduce the above copyright +# notice(s), this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``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 COPYRIGHT HOLDER(S) 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. +# +############################################################################# +# +# Test harness. +# +# $FreeBSD$ +# +############################################################################# + +# Shut off buffering. +select(STDOUT); +$| = 1; + +# +# Parse command-line arguments. +# +use Getopt::Long; +Getopt::Long::config("bundling"); # Allow -hv rather than forcing -h -v. + +# Set option defaults for optional arguments. +$opt_help = 0; +$opt_verbose = 0; +$opt_quiet = 0; +$opt_srcdir = "."; +$opt_ustats = 0; +$opt_zero = 0; + +$opt_retval = +&GetOptions("h|help" => \$opt_help, + "v|verbose" => \$opt_verbose, + "q|quiet" => \$opt_quiet, + "s|srcdir=s" => \$opt_srcdir, + "u|ustats" => \$opt_ustats, + "z|zero" => \$opt_zero + ); + +$mode = "d"; +for ($i = 0; $i <= $#ARGV; $i++) +{ + if (($ARGV[$i] eq "-s") || ($ARGV[$i] eq "--sequence")) + { + $mode = "s"; + } + elsif (($ARGV[$i] eq "-d") || ($ARGV[$i] eq "--diff")) + { + $mode = "d"; + } + elsif (-x $ARGV[$i]) + { + if ($mode eq "s") + { + @STESTS = (@STESTS, $ARGV[$i]); + } + else + { + @DTESTS = (@DTESTS, $ARGV[$i]); + } + } + else + { + if (!$opt_quiet) + { + print STDERR "Cannot run \"$ARGV[$i]\"\n"; + } + } +} + +if ($opt_help) +{ + &usage(); + exit(0); +} + +if ($opt_retval == 0) +{ + &usage(); + exit 1; +} + +if ($opt_verbose && $opt_quiet) +{ + print STDERR "-v and -q are incompatible\n"; + &usage(); + exit 1; +} + +if ($#STESTS + $#DTESTS + 2 == 0) +{ + print STDERR "No tests specified\n"; + &usage(); + exit 1; +} + +if ($opt_verbose) +{ + print STDERR "Option values: h:$opt_help, v:$opt_verbose, q:$opt_quiet, " + . "u:$opt_ustats\n"; + printf STDERR "Sequence tests (%d total): @STESTS\n", $#STESTS + 1; + printf STDERR "Diff tests (%d total): @DTESTS\n", $#DTESTS + 1; +} + +# +# Create and print header. +# +@TSTATS = +( + "--------------------------------------------------------------------------\n", + "Test c_user c_system c_total chng\n", + " passed/FAILED h_user h_system h_total %% chng\n" + ); + +if (!$opt_quiet) +{ + foreach $line (@TSTATS) + { + printf STDOUT "$line"; + } +} + +# +# Run sequence test(s). +# +$total_utime = 0.0; # Total user time. +$total_stime = 0.0; # Total system time. +$total_hutime = 0.0; # Total historical user time. +$total_hstime = 0.0; # Total historical system time. +$total_ntime = 0.0; # Total time for tests that have historical data. + +foreach $test (@STESTS) +{ + # sequence mode. + $okay = 1; + + ($okay, $utime, $stime) = &run_test($test); + + if (open (STEST_OUT, "<./$test.out")) + { + $num_failed_subtests = 0; + + $_ = <STEST_OUT>; + + if ($_ =~ /1\.\.(\d+)/) + { + $num_subtests = $1; + } + else + { + $num_subtests = 0; + $okay = 0; + if ($opt_verbose) + { + print STDERR "Malformed 1..n line: \"$_\"\n"; + } + } + for ($subtest = 1; $subtest <= $num_subtests; $subtest++) + { + while (defined($line = <STEST_OUT>)) + { + if ($line =~ /^not\s+ok\s+(\d+)?/) + { + $not = 1; + $test_num = $1; + last; + } + elsif ($line =~ /^ok\s+(\d+)?/) + { + $not = 0; + $test_num = $1; + last; + } + } + if (defined($line)) + { + if (defined($test_num) && ($test_num != $subtest)) + { + # There was no output printed for one or more tests. + for (; $subtest < $test_num; $subtest++) + { + $num_failed_subtests++; + } + } + if ($not) + { + $num_failed_subtests++; + } + } + else + { + for (; $subtest <= $num_subtests; $subtest++) + { + $num_failed_subtests++; + } + } + } + + if (0 < $num_failed_subtests) + { + $okay = 0; + } + } + else + { + if (!$opt_quiet) + { + print STDERR "Cannot open output file \"$test.out\"\n"; + } + exit 1; + } + + ($hutime, $hstime) = &print_stats($test, $okay, + $num_failed_subtests, $num_subtests, + $utime, $stime); + $total_hutime += $hutime; + $total_hstime += $hstime; + + if ($okay) + { + $total_utime += $utime; + $total_stime += $stime; + } + else + { + @FAILED_TESTS = (@FAILED_TESTS, $test); + } + + # If there were historical data, add the run time to the total time to + # compare against the historical run time. + if (0 < ($hutime + $hstime)) + { + $total_ntime += $utime + $stime; + } +} +foreach $test (@DTESTS) +{ + # Diff mode. + $okay = 1; + + ($okay, $utime, $stime) = &run_test($test); + + if (-e "./$test.out" && -e "$opt_srcdir/$test.exp") + { + `diff ./$test.out $opt_srcdir/$test.exp > ./$test.diff 2>&1`; + if ($?) + { + # diff returns non-zero if there is a difference. + $okay = 0; + } + } + else + { + $okay = 0; + if ($opt_verbose) + { + print STDERR + "Nonexistent expected output file \"$opt_srcdir/$test.exp\"\n"; + print STDERR "\$opt_srcdir is \"$opt_srcdir\"\n"; + } + } + + ($hutime, $hstime) = &print_stats($test, $okay, 0, 0, $utime, $stime); + $total_hutime += $hutime; + $total_hstime += $hstime; + + if ($okay) + { + $total_utime += $utime; + $total_stime += $stime; + } + else + { + @FAILED_TESTS = (@FAILED_TESTS, $test); + } + + # If there were historical data, add the run time to the total time to + # compare against the historical run time. + if (0 < ($hutime + $hstime)) + { + $total_ntime += $utime + $stime; + } +} + +# Print summary stats. +$tt_str = sprintf ("%d / %d passed (%5.2f%%%%)", + ($#STESTS + $#DTESTS + 2) - ($#FAILED_TESTS + 1), + $#STESTS + $#DTESTS + 2, + (($#STESTS + $#DTESTS + 2) - ($#FAILED_TESTS + 1)) + / ($#STESTS + $#DTESTS + 2) * 100); + +$t_str = sprintf ("Totals %7.2f %7.2f %7.2f" + . " %7.2f\n" + . " %s %7.2f %7.2f %7.2f %7.2f%%%%\n", + $total_utime, $total_stime, $total_utime + $total_stime, + ($total_ntime - ($total_hutime + $total_hstime)), + $tt_str . ' ' x (40 - length($tt_str)), + $total_hutime, $total_hstime, $total_hutime + $total_hstime, + ($total_hutime + $total_hstime == 0.0) ? 0.0 : + (($total_ntime + - ($total_hutime + $total_hstime)) + / ($total_hutime + $total_hstime) * 100)); + +@TSTATS = ("--------------------------------------------------------------------------\n", + $t_str, + "--------------------------------------------------------------------------\n" + ); +if (!$opt_quiet) +{ + foreach $line (@TSTATS) + { + printf STDOUT "$line"; + } +} + +# End of main execution. + +sub run_test +{ + my ($test) = @_; + my ($okay) = 1; + my ($tutime, $tstime); + my ($utime, $stime, $cutime, $cstime); + my (@TSTATS); + my ($t_str); + + @TSTATS = ("--------------------------------------------------------------------------\n"); + + $t_str = sprintf ("%s%s", $test, ' ' x (40 - length($test))); + @TSTATS = (@TSTATS, $t_str); + @STATS = (@STATS, @TSTATS); + if (!$opt_quiet) + { + foreach $line (@TSTATS) + { + printf STDOUT "$line"; + } + } + + ($utime, $stime, $cutime, $cstime) = times; + `./$test $opt_srcdir > ./$test.out 2>&1`; + ($utime, $stime, $tutime, $tstime) = times; + + # Subtract the before time from the after time. + $tutime -= $cutime; + $tstime -= $cstime; + + if ($opt_zero) + { + if ($?) + { + $okay = 0; + if ($opt_verbose) + { + print STDERR "\"./$test > ./$test.out 2>&1\" returned $?\n"; + } + } + } + + return ($okay, $tutime, $tstime); +} + +sub print_stats +{ + my ($test, $okay, $failed_subtests, $subtests, $utime, $stime) = @_; + my ($hutime, $hstime); +# my (TEST_PERF); + my (@TSTATS); + my ($t_str, $pass_str); + + $pass_str = $okay ? "passed" : "*** FAILED ***"; + if ((0 != $subtests) && (!$okay)) + { + $pass_str = $pass_str . " ($failed_subtests/$subtests failed)"; + } + $pass_str = $pass_str . ' ' x (39 - length($pass_str)); + + if (-r "$test.perf") + { + if (!open (TEST_PERF, "<./$test.perf")) + { + print STDERR "Unable to open \"./$test.perf\"\n"; + exit 1; + } + $_ = <TEST_PERF>; + + ($hutime, $hstime) = split; + close TEST_PERF; + + $t_str = sprintf (" %7.2f %7.2f %7.2f %7.2f\n" + . " %s %7.2f %7.2f %7.2f %7.2f%%%%\n", + $utime, $stime, $utime + $stime, + ($utime + $stime) - ($hutime + $hstime), + $pass_str, + $hutime, $hstime, $hutime + $hstime, + (($hutime + $hstime) == 0.0) ? 0.0 : + ((($utime + $stime) - ($hutime + $hstime)) + / ($hutime + $hstime) * 100)); + } + else + { + $hutime = 0.0; + $hstime = 0.0; + + $t_str = sprintf (" %7.2f %7.2f %7.2f \n" + . " %s\n", + $utime, $stime, $utime + $stime, + $pass_str); + } + @TSTATS = ($t_str); + if (!$opt_quiet) + { + foreach $line (@TSTATS) + { + printf STDOUT "$line"; + } + } + + if ($okay && $opt_ustats) + { + if (!open (TEST_PERF, ">./$test.perf")) + { + if (!$opt_quiet) + { + print STDERR "Unable to update \"$test.perf\"\n"; + } + } + else + { + print TEST_PERF "$utime $stime\n"; + close TEST_PERF; + } + } + + return ($hutime, $hstime); +} + +sub usage +{ + print <<EOF; +$0 usage: + $0 [<options>] -- {[-s | -d | --sequence | --diff] <test>+}+ + + Option | Description + --------------+------------------------------------------------------------- + -h --help | Print usage and exit. + -v --verbose | Verbose (incompatible with quiet). + -q --quiet | Quiet (incompatible with verbose). + -s --srcdir | Path to source tree (default is "."). + -u --ustats | Update historical statistics (stored in "<test>.perf". + -z --zero | Consider non-zero exit code to be an error. + --------------+------------------------------------------------------------- + + Flag | Description + --------------+------------------------------------------------------------- + -s --sequence | Sequence mode (default). + | Output to stdout of the following form is expected: + | + | ----------------- + | 1..<n> + | {not} ok [1] + | {not} ok [2] + | ... + | {not} ok [n] + | ----------------- + | + | 1 <= <n> < 2^31 + | + | Lines which do not match the patterns shown above are + | ignored, except that the 1..<n> construct must be the first + | line of output seen. + | + -d --diff | Diff mode (incompatible with sequence mode). + | If <test>.exp exists, diff it with the output from <test> to + | determine success or failure. + --------------+------------------------------------------------------------- +EOF +} diff --git a/lib/libpthread/thread/Makefile.inc b/lib/libpthread/thread/Makefile.inc new file mode 100644 index 0000000..fe19b0e --- /dev/null +++ b/lib/libpthread/thread/Makefile.inc @@ -0,0 +1,130 @@ +# $FreeBSD$ + +# uthread sources +.PATH: ${.CURDIR}/uthread + +SRCS+= \ + uthread_accept.c \ + uthread_aio_suspend.c \ + uthread_attr_destroy.c \ + uthread_attr_init.c \ + uthread_attr_getdetachstate.c \ + uthread_attr_getinheritsched.c \ + uthread_attr_getschedparam.c \ + uthread_attr_getschedpolicy.c \ + uthread_attr_getscope.c \ + uthread_attr_getstackaddr.c \ + uthread_attr_getstacksize.c \ + uthread_attr_setcreatesuspend_np.c \ + uthread_attr_setdetachstate.c \ + uthread_attr_setinheritsched.c \ + uthread_attr_setschedparam.c \ + uthread_attr_setschedpolicy.c \ + uthread_attr_setscope.c \ + uthread_attr_setstackaddr.c \ + uthread_attr_setstacksize.c \ + uthread_autoinit.cc \ + uthread_bind.c \ + uthread_cancel.c \ + uthread_clean.c \ + uthread_close.c \ + uthread_cond.c \ + uthread_condattr_destroy.c \ + uthread_condattr_init.c \ + uthread_connect.c \ + uthread_creat.c \ + uthread_create.c \ + uthread_detach.c \ + uthread_dup.c \ + uthread_dup2.c \ + uthread_equal.c \ + uthread_execve.c \ + uthread_exit.c \ + uthread_fchflags.c \ + uthread_fchmod.c \ + uthread_fchown.c \ + uthread_fcntl.c \ + uthread_fd.c \ + uthread_file.c \ + uthread_find_thread.c \ + uthread_flock.c \ + uthread_fork.c \ + uthread_fpathconf.c \ + uthread_fstat.c \ + uthread_fstatfs.c \ + uthread_fsync.c \ + uthread_gc.c \ + uthread_getdirentries.c \ + uthread_getpeername.c \ + uthread_getprio.c \ + uthread_getschedparam.c \ + uthread_getsockname.c \ + uthread_getsockopt.c \ + uthread_info.c \ + uthread_init.c \ + uthread_ioctl.c \ + uthread_jmp.c \ + uthread_join.c \ + uthread_kern.c \ + uthread_kevent.c \ + uthread_kill.c \ + uthread_listen.c \ + uthread_mattr_init.c \ + uthread_mattr_kind_np.c \ + uthread_msync.c \ + uthread_multi_np.c \ + uthread_mutex.c \ + uthread_mutex_prioceiling.c \ + uthread_mutex_protocol.c \ + uthread_mutexattr_destroy.c \ + uthread_nanosleep.c \ + uthread_once.c \ + uthread_open.c \ + uthread_pause.c \ + uthread_pipe.c \ + uthread_poll.c \ + uthread_priority_queue.c \ + uthread_read.c \ + uthread_readv.c \ + uthread_recvfrom.c \ + uthread_recvmsg.c \ + uthread_resume_np.c \ + uthread_rwlock.c \ + uthread_rwlockattr.c \ + uthread_select.c \ + uthread_self.c \ + uthread_sem.c \ + uthread_sendfile.c \ + uthread_sendmsg.c \ + uthread_sendto.c \ + uthread_seterrno.c \ + uthread_setprio.c \ + uthread_setschedparam.c \ + uthread_setsockopt.c \ + uthread_shutdown.c \ + uthread_sig.c \ + uthread_sigaction.c \ + uthread_sigblock.c \ + uthread_sigmask.c \ + uthread_sigpending.c \ + uthread_sigprocmask.c \ + uthread_sigsetmask.c \ + uthread_sigsuspend.c \ + uthread_sigwait.c \ + uthread_single_np.c \ + uthread_sleep.c \ + uthread_socket.c \ + uthread_socketpair.c \ + uthread_spec.c \ + uthread_spinlock.c \ + uthread_suspend_np.c \ + uthread_switch_np.c \ + uthread_system.c \ + uthread_tcdrain.c \ + uthread_vfork.c \ + uthread_wait.c \ + uthread_wait4.c \ + uthread_waitpid.c \ + uthread_write.c \ + uthread_writev.c \ + uthread_yield.c diff --git a/lib/libpthread/thread/thr_aio_suspend.c b/lib/libpthread/thread/thr_aio_suspend.c new file mode 100644 index 0000000..1253f20 --- /dev/null +++ b/lib/libpthread/thread/thr_aio_suspend.c @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2000 Jason Evans <jasone@freebsd.org>. + * 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(s), this list of conditions and the following disclaimer as + * the first lines of this file unmodified other than the possible + * addition of one or more copyright notices. + * 2. Redistributions in binary form must reproduce the above copyright + * notice(s), this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``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 COPYRIGHT HOLDER(S) 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. + * + * $FreeBSD$ + */ + +#include <aio.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +int +_aio_suspend(const struct aiocb * const iocbs[], int niocb, const struct + timespec *timeout) +{ + int ret; + + _thread_enter_cancellation_point(); + ret = _aio_suspend(iocbs, niocb, timeout); + _thread_leave_cancellation_point(); + + return ret; +} + +__strong_reference(_aio_suspend, aio_suspend); +#endif diff --git a/lib/libpthread/thread/thr_attr_destroy.c b/lib/libpthread/thread/thr_attr_destroy.c new file mode 100644 index 0000000..dfe668e --- /dev/null +++ b/lib/libpthread/thread/thr_attr_destroy.c @@ -0,0 +1,61 @@ +/* + * Copyright (c) 1996 John Birrell <jb@cimlogic.com.au>. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by John Birrell. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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. + * + * $FreeBSD$ + */ +#include <stdlib.h> +#include <errno.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +int pthread_attr_destroy(pthread_attr_t *attr) +{ + int ret; + + /* Check for invalid arguments: */ + if (attr == NULL || *attr == NULL) + /* Invalid argument: */ + ret = EINVAL; + else { + /* Free the memory allocated to the attribute object: */ + free(*attr); + + /* + * Leave the attribute pointer NULL now that the memory + * has been freed: + */ + *attr = NULL; + ret = 0; + } + return(ret); +} +#endif diff --git a/lib/libpthread/thread/thr_attr_getdetachstate.c b/lib/libpthread/thread/thr_attr_getdetachstate.c new file mode 100644 index 0000000..d120553 --- /dev/null +++ b/lib/libpthread/thread/thr_attr_getdetachstate.c @@ -0,0 +1,59 @@ +/* + * Copyright (c) 1997 John Birrell <jb@cimlogic.com.au>. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by John Birrell. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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. + * + * $FreeBSD$ + */ +#include <errno.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +int +pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate) +{ + int ret; + + /* Check for invalid arguments: */ + if (attr == NULL || *attr == NULL || detachstate == NULL) + ret = EINVAL; + else { + /* Check if the detached flag is set: */ + if ((*attr)->flags & PTHREAD_DETACHED) + /* Return detached: */ + *detachstate = PTHREAD_CREATE_DETACHED; + else + /* Return joinable: */ + *detachstate = PTHREAD_CREATE_JOINABLE; + ret = 0; + } + return(ret); +} +#endif diff --git a/lib/libpthread/thread/thr_attr_getinheritsched.c b/lib/libpthread/thread/thr_attr_getinheritsched.c new file mode 100644 index 0000000..7e243ed --- /dev/null +++ b/lib/libpthread/thread/thr_attr_getinheritsched.c @@ -0,0 +1,51 @@ +/* + * Copyright (c) 1998 Daniel Eischen <eischen@vigrid.com>. + * 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 Daniel Eischen. + * 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 DANIEL EISCHEN 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <errno.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +int +pthread_attr_getinheritsched(const pthread_attr_t *attr, int *sched_inherit) +{ + int ret = 0; + + if ((attr == NULL) || (*attr == NULL)) + ret = EINVAL; + else + *sched_inherit = (*attr)->sched_inherit; + + return(ret); +} +#endif diff --git a/lib/libpthread/thread/thr_attr_getschedparam.c b/lib/libpthread/thread/thr_attr_getschedparam.c new file mode 100644 index 0000000..46586ff --- /dev/null +++ b/lib/libpthread/thread/thr_attr_getschedparam.c @@ -0,0 +1,51 @@ +/* + * Copyright (c) 1998 Daniel Eischen <eischen@vigrid.com>. + * 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 Daniel Eischen. + * 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 DANIEL EISCHEN 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <errno.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +int +pthread_attr_getschedparam(const pthread_attr_t *attr, struct sched_param *param) +{ + int ret = 0; + + if ((attr == NULL) || (*attr == NULL) || (param == NULL)) + ret = EINVAL; + else + param->sched_priority = (*attr)->prio; + + return(ret); +} +#endif diff --git a/lib/libpthread/thread/thr_attr_getschedpolicy.c b/lib/libpthread/thread/thr_attr_getschedpolicy.c new file mode 100644 index 0000000..19f835c --- /dev/null +++ b/lib/libpthread/thread/thr_attr_getschedpolicy.c @@ -0,0 +1,51 @@ +/* + * Copyright (c) 1998 Daniel Eischen <eischen@vigrid.com>. + * 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 Daniel Eischen. + * 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 DANIEL EISCHEN 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <errno.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +int +pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy) +{ + int ret = 0; + + if ((attr == NULL) || (*attr == NULL) || (policy == NULL)) + ret = EINVAL; + else + *policy = (*attr)->sched_policy; + + return(ret); +} +#endif diff --git a/lib/libpthread/thread/thr_attr_getscope.c b/lib/libpthread/thread/thr_attr_getscope.c new file mode 100644 index 0000000..176f01b --- /dev/null +++ b/lib/libpthread/thread/thr_attr_getscope.c @@ -0,0 +1,54 @@ +/* + * Copyright (c) 1998 Daniel Eischen <eischen@vigrid.com>. + * 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 Daniel Eischen. + * 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 DANIEL EISCHEN 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <errno.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +int +pthread_attr_getscope(const pthread_attr_t *attr, int *contentionscope) +{ + int ret = 0; + + if ((attr == NULL) || (*attr == NULL) || (contentionscope == NULL)) + /* Return an invalid argument: */ + ret = EINVAL; + + else + *contentionscope = (*attr)->flags & PTHREAD_SCOPE_SYSTEM ? + PTHREAD_SCOPE_SYSTEM : PTHREAD_SCOPE_PROCESS; + + return(ret); +} +#endif diff --git a/lib/libpthread/thread/thr_attr_getstackaddr.c b/lib/libpthread/thread/thr_attr_getstackaddr.c new file mode 100644 index 0000000..442dcc2 --- /dev/null +++ b/lib/libpthread/thread/thr_attr_getstackaddr.c @@ -0,0 +1,54 @@ +/* + * Copyright (c) 1997 John Birrell <jb@cimlogic.com.au>. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by John Birrell. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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. + * + * $FreeBSD$ + */ +#include <errno.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +int +pthread_attr_getstackaddr(const pthread_attr_t *attr, void **stackaddr) +{ + int ret; + + /* Check for invalid arguments: */ + if (attr == NULL || *attr == NULL || stackaddr == NULL) + ret = EINVAL; + else { + /* Return the stack address: */ + *stackaddr = (*attr)->stackaddr_attr; + ret = 0; + } + return(ret); +} +#endif diff --git a/lib/libpthread/thread/thr_attr_getstacksize.c b/lib/libpthread/thread/thr_attr_getstacksize.c new file mode 100644 index 0000000..d9aaca4 --- /dev/null +++ b/lib/libpthread/thread/thr_attr_getstacksize.c @@ -0,0 +1,54 @@ +/* + * Copyright (c) 1997 John Birrell <jb@cimlogic.com.au>. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by John Birrell. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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. + * + * $FreeBSD$ + */ +#include <errno.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +int +pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *stacksize) +{ + int ret; + + /* Check for invalid arguments: */ + if (attr == NULL || *attr == NULL || stacksize == NULL) + ret = EINVAL; + else { + /* Return the stack size: */ + *stacksize = (*attr)->stacksize_attr; + ret = 0; + } + return(ret); +} +#endif diff --git a/lib/libpthread/thread/thr_attr_init.c b/lib/libpthread/thread/thr_attr_init.c new file mode 100644 index 0000000..dbe3091 --- /dev/null +++ b/lib/libpthread/thread/thr_attr_init.c @@ -0,0 +1,60 @@ +/* + * Copyright (c) 1996 John Birrell <jb@cimlogic.com.au>. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by John Birrell. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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. + * + * $FreeBSD$ + */ +#include <string.h> +#include <stdlib.h> +#include <errno.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +int pthread_attr_init(pthread_attr_t *attr) +{ + int ret; + pthread_attr_t pattr; + + /* Allocate memory for the attribute object: */ + if ((pattr = (pthread_attr_t) malloc(sizeof(struct pthread_attr))) == NULL) + /* Insufficient memory: */ + ret = ENOMEM; + else { + /* Initialise the attribute object with the defaults: */ + memcpy(pattr, &pthread_attr_default, sizeof(struct pthread_attr)); + + /* Return a pointer to the attribute object: */ + *attr = pattr; + ret = 0; + } + return(ret); +} +#endif diff --git a/lib/libpthread/thread/thr_attr_setcreatesuspend_np.c b/lib/libpthread/thread/thr_attr_setcreatesuspend_np.c new file mode 100644 index 0000000..d230397 --- /dev/null +++ b/lib/libpthread/thread/thr_attr_setcreatesuspend_np.c @@ -0,0 +1,52 @@ +/* + * 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <errno.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +int +pthread_attr_setcreatesuspend_np(pthread_attr_t *attr) +{ + int ret; + if (attr == NULL || *attr == NULL) { + errno = EINVAL; + ret = -1; + } else { + (*attr)->suspend = PTHREAD_CREATE_SUSPENDED; + ret = 0; + } + return(ret); +} +#endif diff --git a/lib/libpthread/thread/thr_attr_setdetachstate.c b/lib/libpthread/thread/thr_attr_setdetachstate.c new file mode 100644 index 0000000..6be3e4e --- /dev/null +++ b/lib/libpthread/thread/thr_attr_setdetachstate.c @@ -0,0 +1,61 @@ +/* + * Copyright (c) 1997 John Birrell <jb@cimlogic.com.au>. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by John Birrell. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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. + * + * $FreeBSD$ + */ +#include <errno.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +int +pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate) +{ + int ret; + + /* Check for invalid arguments: */ + if (attr == NULL || *attr == NULL || + (detachstate != PTHREAD_CREATE_DETACHED && + detachstate != PTHREAD_CREATE_JOINABLE)) + ret = EINVAL; + else { + /* Check if detached state: */ + if (detachstate == PTHREAD_CREATE_DETACHED) + /* Set the detached flag: */ + (*attr)->flags |= PTHREAD_DETACHED; + else + /* Reset the detached flag: */ + (*attr)->flags &= ~PTHREAD_DETACHED; + ret = 0; + } + return(ret); +} +#endif diff --git a/lib/libpthread/thread/thr_attr_setinheritsched.c b/lib/libpthread/thread/thr_attr_setinheritsched.c new file mode 100644 index 0000000..eb2384b --- /dev/null +++ b/lib/libpthread/thread/thr_attr_setinheritsched.c @@ -0,0 +1,51 @@ +/* + * Copyright (c) 1998 Daniel Eischen <eischen@vigrid.com>. + * 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 Daniel Eischen. + * 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 DANIEL EISCHEN 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <errno.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +int +pthread_attr_setinheritsched(pthread_attr_t *attr, int sched_inherit) +{ + int ret = 0; + + if ((attr == NULL) || (*attr == NULL)) + ret = EINVAL; + else + (*attr)->sched_inherit = sched_inherit; + + return(ret); +} +#endif diff --git a/lib/libpthread/thread/thr_attr_setschedparam.c b/lib/libpthread/thread/thr_attr_setschedparam.c new file mode 100644 index 0000000..6c4166b --- /dev/null +++ b/lib/libpthread/thread/thr_attr_setschedparam.c @@ -0,0 +1,53 @@ +/* + * Copyright (c) 1998 Daniel Eischen <eischen@vigrid.com>. + * 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 Daniel Eischen. + * 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 DANIEL EISCHEN 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <errno.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +int +pthread_attr_setschedparam(pthread_attr_t *attr, const struct sched_param *param) +{ + int ret = 0; + + if ((attr == NULL) || (*attr == NULL)) + ret = EINVAL; + else if (param == NULL) { + ret = ENOTSUP; + } else + (*attr)->prio = param->sched_priority; + + return(ret); +} +#endif diff --git a/lib/libpthread/thread/thr_attr_setschedpolicy.c b/lib/libpthread/thread/thr_attr_setschedpolicy.c new file mode 100644 index 0000000..2788deb --- /dev/null +++ b/lib/libpthread/thread/thr_attr_setschedpolicy.c @@ -0,0 +1,53 @@ +/* + * Copyright (c) 1998 Daniel Eischen <eischen@vigrid.com>. + * 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 Daniel Eischen. + * 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 DANIEL EISCHEN 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <errno.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +int +pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy) +{ + int ret = 0; + + if ((attr == NULL) || (*attr == NULL)) + ret = EINVAL; + else if ((policy < SCHED_FIFO) || (policy > SCHED_RR)) { + ret = ENOTSUP; + } else + (*attr)->sched_policy = policy; + + return(ret); +} +#endif diff --git a/lib/libpthread/thread/thr_attr_setscope.c b/lib/libpthread/thread/thr_attr_setscope.c new file mode 100644 index 0000000..de2fe8e --- /dev/null +++ b/lib/libpthread/thread/thr_attr_setscope.c @@ -0,0 +1,56 @@ +/* + * Copyright (c) 1998 Daniel Eischen <eischen@vigrid.com>. + * 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 Daniel Eischen. + * 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 DANIEL EISCHEN 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <errno.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +int +pthread_attr_setscope(pthread_attr_t *attr, int contentionscope) +{ + int ret = 0; + + if ((attr == NULL) || (*attr == NULL)) { + /* Return an invalid argument: */ + ret = EINVAL; + } else if ((contentionscope != PTHREAD_SCOPE_PROCESS) || + (contentionscope != PTHREAD_SCOPE_SYSTEM)) { + /* We don't support PTHREAD_SCOPE_SYSTEM. */ + ret = ENOTSUP; + } else + (*attr)->flags |= contentionscope; + + return(ret); +} +#endif diff --git a/lib/libpthread/thread/thr_attr_setstackaddr.c b/lib/libpthread/thread/thr_attr_setstackaddr.c new file mode 100644 index 0000000..46469e4 --- /dev/null +++ b/lib/libpthread/thread/thr_attr_setstackaddr.c @@ -0,0 +1,54 @@ +/* + * Copyright (c) 1997 John Birrell <jb@cimlogic.com.au>. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by John Birrell. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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. + * + * $FreeBSD$ + */ +#include <errno.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +int +pthread_attr_setstackaddr(pthread_attr_t *attr, void *stackaddr) +{ + int ret; + + /* Check for invalid arguments: */ + if (attr == NULL || *attr == NULL || stackaddr == NULL) + ret = EINVAL; + else { + /* Save the stack address: */ + (*attr)->stackaddr_attr = stackaddr; + ret = 0; + } + return(ret); +} +#endif diff --git a/lib/libpthread/thread/thr_attr_setstacksize.c b/lib/libpthread/thread/thr_attr_setstacksize.c new file mode 100644 index 0000000..3897811 --- /dev/null +++ b/lib/libpthread/thread/thr_attr_setstacksize.c @@ -0,0 +1,54 @@ +/* + * Copyright (c) 1996 John Birrell <jb@cimlogic.com.au>. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by John Birrell. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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. + * + * $FreeBSD$ + */ +#include <errno.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +int +pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize) +{ + int ret; + + /* Check for invalid arguments: */ + if (attr == NULL || *attr == NULL || stacksize < PTHREAD_STACK_MIN) + ret = EINVAL; + else { + /* Save the stack size: */ + (*attr)->stacksize_attr = stacksize; + ret = 0; + } + return(ret); +} +#endif diff --git a/lib/libpthread/thread/thr_cancel.c b/lib/libpthread/thread/thr_cancel.c new file mode 100644 index 0000000..c6df52e --- /dev/null +++ b/lib/libpthread/thread/thr_cancel.c @@ -0,0 +1,215 @@ +/* + * David Leonard <d@openbsd.org>, 1999. Public domain. + * $FreeBSD$ + */ +#include <sys/errno.h> +#include <pthread.h> +#include "pthread_private.h" + +static void finish_cancellation(void *arg); + +int +pthread_cancel(pthread_t pthread) +{ + int ret; + + if ((ret = _find_thread(pthread)) != 0) { + /* NOTHING */ + } else if (pthread->state == PS_DEAD || pthread->state == PS_DEADLOCK) { + ret = 0; + } else { + /* Protect the scheduling queues: */ + _thread_kern_sig_defer(); + + if (((pthread->cancelflags & PTHREAD_CANCEL_DISABLE) != 0) || + (((pthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS) == 0) && + ((pthread->cancelflags & PTHREAD_AT_CANCEL_POINT) == 0))) + /* Just mark it for cancellation: */ + pthread->cancelflags |= PTHREAD_CANCELLING; + else { + /* + * Check if we need to kick it back into the + * run queue: + */ + switch (pthread->state) { + case PS_RUNNING: + /* No need to resume: */ + pthread->cancelflags |= PTHREAD_CANCELLING; + break; + + case PS_SPINBLOCK: + case PS_FDR_WAIT: + case PS_FDW_WAIT: + case PS_POLL_WAIT: + case PS_SELECT_WAIT: + /* Remove these threads from the work queue: */ + if ((pthread->flags & PTHREAD_FLAGS_IN_WORKQ) + != 0) + PTHREAD_WORKQ_REMOVE(pthread); + /* Fall through: */ + case PS_SIGTHREAD: + case PS_SLEEP_WAIT: + case PS_WAIT_WAIT: + case PS_SIGSUSPEND: + case PS_SIGWAIT: + /* Interrupt and resume: */ + pthread->interrupted = 1; + pthread->cancelflags |= PTHREAD_CANCELLING; + PTHREAD_NEW_STATE(pthread,PS_RUNNING); + break; + + case PS_SUSPENDED: + if (pthread->suspended == SUSP_NO || + pthread->suspended == SUSP_YES || + pthread->suspended == SUSP_NOWAIT) { + /* + * This thread isn't in any scheduling + * queues; just change it's state: + */ + pthread->cancelflags |= + PTHREAD_CANCELLING; + PTHREAD_SET_STATE(pthread, PS_RUNNING); + break; + } + /* FALLTHROUGH */ + case PS_MUTEX_WAIT: + case PS_COND_WAIT: + case PS_FDLR_WAIT: + case PS_FDLW_WAIT: + case PS_FILE_WAIT: + case PS_JOIN: + /* + * Threads in these states may be in queues. + * In order to preserve queue integrity, the + * cancelled thread must remove itself from the + * queue. Mark the thread as interrupted and + * needing cancellation, and set the state to + * running. When the thread resumes, it will + * remove itself from the queue and call the + * cancellation completion routine. + */ + pthread->interrupted = 1; + pthread->cancelflags |= PTHREAD_CANCEL_NEEDED; + PTHREAD_NEW_STATE(pthread,PS_RUNNING); + pthread->continuation = finish_cancellation; + break; + + case PS_DEAD: + case PS_DEADLOCK: + case PS_STATE_MAX: + /* Ignore - only here to silence -Wall: */ + break; + } + } + + /* Unprotect the scheduling queues: */ + _thread_kern_sig_undefer(); + + ret = 0; + } + return (ret); +} + +int +pthread_setcancelstate(int state, int *oldstate) +{ + int ostate; + int ret; + + ostate = _thread_run->cancelflags & PTHREAD_CANCEL_DISABLE; + + switch (state) { + case PTHREAD_CANCEL_ENABLE: + if (oldstate != NULL) + *oldstate = ostate; + _thread_run->cancelflags &= ~PTHREAD_CANCEL_DISABLE; + if ((_thread_run->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS) != 0) + pthread_testcancel(); + ret = 0; + break; + case PTHREAD_CANCEL_DISABLE: + if (oldstate != NULL) + *oldstate = ostate; + _thread_run->cancelflags |= PTHREAD_CANCEL_DISABLE; + ret = 0; + break; + default: + ret = EINVAL; + } + + return (ret); +} + +int +pthread_setcanceltype(int type, int *oldtype) +{ + int otype; + int ret; + + otype = _thread_run->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS; + switch (type) { + case PTHREAD_CANCEL_ASYNCHRONOUS: + if (oldtype != NULL) + *oldtype = otype; + _thread_run->cancelflags |= PTHREAD_CANCEL_ASYNCHRONOUS; + pthread_testcancel(); + ret = 0; + break; + case PTHREAD_CANCEL_DEFERRED: + if (oldtype != NULL) + *oldtype = otype; + _thread_run->cancelflags &= ~PTHREAD_CANCEL_ASYNCHRONOUS; + ret = 0; + break; + default: + ret = EINVAL; + } + + return (ret); +} + +void +pthread_testcancel(void) +{ + if (((_thread_run->cancelflags & PTHREAD_CANCEL_DISABLE) == 0) && + ((_thread_run->cancelflags & PTHREAD_CANCELLING) != 0)) { + /* + * It is possible for this thread to be swapped out + * while performing cancellation; do not allow it + * to be cancelled again. + */ + _thread_run->cancelflags &= ~PTHREAD_CANCELLING; + _thread_exit_cleanup(); + pthread_exit(PTHREAD_CANCELED); + PANIC("cancel"); + } +} + +void +_thread_enter_cancellation_point(void) +{ + /* Look for a cancellation before we block: */ + pthread_testcancel(); + _thread_run->cancelflags |= PTHREAD_AT_CANCEL_POINT; +} + +void +_thread_leave_cancellation_point(void) +{ + _thread_run->cancelflags &= ~PTHREAD_AT_CANCEL_POINT; + /* Look for a cancellation after we unblock: */ + pthread_testcancel(); +} + +static void +finish_cancellation(void *arg) +{ + _thread_run->continuation = NULL; + _thread_run->interrupted = 0; + + if ((_thread_run->cancelflags & PTHREAD_CANCEL_NEEDED) != 0) { + _thread_run->cancelflags &= ~PTHREAD_CANCEL_NEEDED; + _thread_exit_cleanup(); + pthread_exit(PTHREAD_CANCELED); + } +} diff --git a/lib/libpthread/thread/thr_clean.c b/lib/libpthread/thread/thr_clean.c new file mode 100644 index 0000000..bba5500 --- /dev/null +++ b/lib/libpthread/thread/thr_clean.c @@ -0,0 +1,69 @@ +/* + * 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <signal.h> +#include <errno.h> +#include <stdlib.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +void +pthread_cleanup_push(void (*routine) (void *), void *routine_arg) +{ + struct pthread_cleanup *new; + + 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; + } +} + +void +pthread_cleanup_pop(int execute) +{ + struct pthread_cleanup *old; + + if ((old = _thread_run->cleanup) != NULL) { + _thread_run->cleanup = old->next; + if (execute) { + old->routine(old->routine_arg); + } + free(old); + } +} + +#endif diff --git a/lib/libpthread/thread/thr_close.c b/lib/libpthread/thread/thr_close.c new file mode 100644 index 0000000..9dee2bc --- /dev/null +++ b/lib/libpthread/thread/thr_close.c @@ -0,0 +1,114 @@ +/* + * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by John Birrell. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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. + * + * $FreeBSD$ + */ +#include <errno.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/stat.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +int +_close(int fd) +{ + int flags; + int ret; + struct stat sb; + struct fd_table_entry *entry; + + if ((fd == _thread_kern_pipe[0]) || (fd == _thread_kern_pipe[1])) { + /* + * Don't allow silly programs to close the kernel pipe. + */ + errno = EBADF; + ret = -1; + } + /* + * Lock the file descriptor while the file is closed and get + * the file descriptor status: + */ + else if (((ret = _FD_LOCK(fd, FD_RDWR, NULL)) == 0) && + ((ret = _thread_sys_fstat(fd, &sb)) == 0)) { + /* + * 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); + } + + /* XXX: Assumes well behaved threads. */ + /* XXX: Defer real close to avoid race condition */ + entry = _thread_fd_table[fd]; + _thread_fd_table[fd] = NULL; + free(entry); + + /* Close the file descriptor: */ + ret = _thread_sys_close(fd); + } + return (ret); +} + +int +close(int fd) +{ + int ret; + + _thread_enter_cancellation_point(); + ret = _close(fd); + _thread_leave_cancellation_point(); + + return ret; +} +#endif diff --git a/lib/libpthread/thread/thr_cond.c b/lib/libpthread/thread/thr_cond.c new file mode 100644 index 0000000..0a5298b --- /dev/null +++ b/lib/libpthread/thread/thr_cond.c @@ -0,0 +1,660 @@ +/* + * 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <stdlib.h> +#include <errno.h> +#include <string.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +/* + * Prototypes + */ +static inline pthread_t cond_queue_deq(pthread_cond_t); +static inline void cond_queue_remove(pthread_cond_t, pthread_t); +static inline void cond_queue_enq(pthread_cond_t, pthread_t); + +/* Reinitialize a condition variable to defaults. */ +int +_cond_reinit(pthread_cond_t * cond) +{ + int ret = 0; + + if (cond == NULL) + ret = EINVAL; + else if (*cond == NULL) + ret = pthread_cond_init(cond, NULL); + else { + /* + * Initialize the condition variable structure: + */ + TAILQ_INIT(&(*cond)->c_queue); + (*cond)->c_flags = COND_FLAGS_INITED; + (*cond)->c_type = COND_TYPE_FAST; + (*cond)->c_mutex = NULL; + memset(&(*cond)->lock, 0, sizeof((*cond)->lock)); + } + return (ret); +} + +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; + + if (cond == NULL) + rval = EINVAL; + else { + /* + * 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; + } + + /* 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: */ + rval = EINVAL; + break; + } + + /* Check for no errors: */ + if (rval == 0) { + if ((pcond = (pthread_cond_t) + malloc(sizeof(struct pthread_cond))) == NULL) { + rval = ENOMEM; + } else { + /* + * Initialise the condition variable + * structure: + */ + TAILQ_INIT(&pcond->c_queue); + pcond->c_flags |= COND_FLAGS_INITED; + pcond->c_type = type; + pcond->c_mutex = NULL; + memset(&pcond->lock,0,sizeof(pcond->lock)); + *cond = pcond; + } + } + } + /* Return the completion status: */ + return (rval); +} + +int +pthread_cond_destroy(pthread_cond_t * cond) +{ + int rval = 0; + + if (cond == NULL || *cond == NULL) + rval = EINVAL; + else { + /* Lock the condition variable structure: */ + _SPINLOCK(&(*cond)->lock); + + /* + * Free the memory allocated for the condition + * variable structure: + */ + free(*cond); + + /* + * NULL the caller's pointer now that the condition + * variable has been destroyed: + */ + *cond = NULL; + } + /* Return the completion status: */ + return (rval); +} + +int +pthread_cond_wait(pthread_cond_t * cond, pthread_mutex_t * mutex) +{ + int rval = 0; + int interrupted = 0; + + _thread_enter_cancellation_point(); + + if (cond == NULL) + rval = EINVAL; + + /* + * If the condition variable is statically initialized, + * perform the dynamic initialization: + */ + else if (*cond != NULL || + (rval = pthread_cond_init(cond,NULL)) == 0) { + + _thread_enter_cancellation_point(); + + /* Lock the condition variable structure: */ + _SPINLOCK(&(*cond)->lock); + + /* + * If the condvar was statically allocated, properly + * initialize the tail queue. + */ + if (((*cond)->c_flags & COND_FLAGS_INITED) == 0) { + TAILQ_INIT(&(*cond)->c_queue); + (*cond)->c_flags |= COND_FLAGS_INITED; + } + + /* Process according to condition variable type: */ + switch ((*cond)->c_type) { + /* Fast condition variable: */ + case COND_TYPE_FAST: + if ((mutex == NULL) || (((*cond)->c_mutex != NULL) && + ((*cond)->c_mutex != *mutex))) { + /* Unlock the condition variable structure: */ + _SPINUNLOCK(&(*cond)->lock); + + /* Return invalid argument error: */ + rval = EINVAL; + } else { + /* Reset the timeout and interrupted flags: */ + _thread_run->timeout = 0; + _thread_run->interrupted = 0; + + /* + * Queue the running thread for the condition + * variable: + */ + cond_queue_enq(*cond, _thread_run); + + /* Remember the mutex that is being used: */ + (*cond)->c_mutex = *mutex; + + /* Wait forever: */ + _thread_run->wakeup_time.tv_sec = -1; + + /* Unlock the mutex: */ + if ((rval = _mutex_cv_unlock(mutex)) != 0) { + /* + * Cannot unlock the mutex, so remove + * the running thread from the condition + * variable queue: + */ + cond_queue_remove(*cond, _thread_run); + + /* Check for no more waiters: */ + if (TAILQ_FIRST(&(*cond)->c_queue) == + NULL) + (*cond)->c_mutex = NULL; + + /* Unlock the condition variable structure: */ + _SPINUNLOCK(&(*cond)->lock); + } + else { + /* + * Schedule the next thread and unlock + * the condition variable structure: + */ + _thread_kern_sched_state_unlock(PS_COND_WAIT, + &(*cond)->lock, __FILE__, __LINE__); + + if (_thread_run->interrupted != 0) { + /* + * Remember that this thread + * was interrupted: + */ + interrupted = 1; + + /* + * Lock the condition variable + * while removing the thread. + */ + _SPINLOCK(&(*cond)->lock); + + cond_queue_remove(*cond, + _thread_run); + + /* Check for no more waiters: */ + if (TAILQ_FIRST(&(*cond)->c_queue) == NULL) + (*cond)->c_mutex = NULL; + + _SPINUNLOCK(&(*cond)->lock); + } + + /* + * Note that even though this thread may have + * been canceled, POSIX requires that the mutex + * be reaquired prior to cancellation. + */ + rval = _mutex_cv_lock(mutex); + } + } + break; + + /* Trap invalid condition variable types: */ + default: + /* Unlock the condition variable structure: */ + _SPINUNLOCK(&(*cond)->lock); + + /* Return an invalid argument error: */ + rval = EINVAL; + break; + } + + if (interrupted != 0) { + if (_thread_run->continuation != NULL) + _thread_run->continuation((void *) _thread_run); + } + + _thread_leave_cancellation_point(); + } + + _thread_leave_cancellation_point(); + + /* 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 interrupted = 0; + + _thread_enter_cancellation_point(); + + if (abstime == NULL || abstime->tv_sec < 0 || abstime->tv_nsec < 0 || + abstime->tv_nsec >= 1000000000) + rval = EINVAL; + /* + * If the condition variable is statically initialized, perform dynamic + * initialization. + */ + else if (*cond != NULL || (rval = pthread_cond_init(cond, NULL)) == 0) { + _thread_enter_cancellation_point(); + + /* Lock the condition variable structure: */ + _SPINLOCK(&(*cond)->lock); + + /* + * If the condvar was statically allocated, properly + * initialize the tail queue. + */ + if (((*cond)->c_flags & COND_FLAGS_INITED) == 0) { + TAILQ_INIT(&(*cond)->c_queue); + (*cond)->c_flags |= COND_FLAGS_INITED; + } + + /* Process according to condition variable type: */ + switch ((*cond)->c_type) { + /* Fast condition variable: */ + case COND_TYPE_FAST: + if ((mutex == NULL) || (((*cond)->c_mutex != NULL) && + ((*cond)->c_mutex != *mutex))) { + /* Return invalid argument error: */ + rval = EINVAL; + + /* Unlock the condition variable structure: */ + _SPINUNLOCK(&(*cond)->lock); + } else { + /* Set the wakeup time: */ + _thread_run->wakeup_time.tv_sec = + abstime->tv_sec; + _thread_run->wakeup_time.tv_nsec = + abstime->tv_nsec; + + /* Reset the timeout and interrupted flags: */ + _thread_run->timeout = 0; + _thread_run->interrupted = 0; + + /* + * Queue the running thread for the condition + * variable: + */ + cond_queue_enq(*cond, _thread_run); + + /* Remember the mutex that is being used: */ + (*cond)->c_mutex = *mutex; + + /* Unlock the mutex: */ + if ((rval = _mutex_cv_unlock(mutex)) != 0) { + /* + * Cannot unlock the mutex, so remove + * the running thread from the condition + * variable queue: + */ + cond_queue_remove(*cond, _thread_run); + + /* Check for no more waiters: */ + if (TAILQ_FIRST(&(*cond)->c_queue) == NULL) + (*cond)->c_mutex = NULL; + + /* Unlock the condition variable structure: */ + _SPINUNLOCK(&(*cond)->lock); + } else { + /* + * Schedule the next thread and unlock + * the condition variable structure: + */ + _thread_kern_sched_state_unlock(PS_COND_WAIT, + &(*cond)->lock, __FILE__, __LINE__); + + /* + * Check if the wait timedout or was + * interrupted (canceled): + */ + if ((_thread_run->timeout == 0) && + (_thread_run->interrupted == 0)) { + /* Lock the mutex: */ + rval = _mutex_cv_lock(mutex); + + } else { + /* + * Remember if this thread was + * interrupted: + */ + interrupted = _thread_run->interrupted; + + /* Lock the condition variable structure: */ + _SPINLOCK(&(*cond)->lock); + + /* + * The wait timed out; remove + * the thread from the condition + * variable queue: + */ + cond_queue_remove(*cond, + _thread_run); + + /* Check for no more waiters: */ + if (TAILQ_FIRST(&(*cond)->c_queue) == NULL) + (*cond)->c_mutex = NULL; + + /* Unock the condition variable structure: */ + _SPINUNLOCK(&(*cond)->lock); + + /* Return a timeout error: */ + rval = ETIMEDOUT; + + /* + * Lock the mutex and ignore any + * errors. Note that even though + * this thread may have been + * canceled, POSIX requires that + * the mutex be reaquired prior + * to cancellation. + */ + (void)_mutex_cv_lock(mutex); + } + } + } + break; + + /* Trap invalid condition variable types: */ + default: + /* Unlock the condition variable structure: */ + _SPINUNLOCK(&(*cond)->lock); + + /* Return an invalid argument error: */ + rval = EINVAL; + break; + } + + if (interrupted != 0) { + if (_thread_run->continuation != NULL) + _thread_run->continuation((void *) _thread_run); + } + + _thread_leave_cancellation_point(); + } + + _thread_leave_cancellation_point(); + + /* Return the completion status: */ + return (rval); +} + +int +pthread_cond_signal(pthread_cond_t * cond) +{ + int rval = 0; + pthread_t pthread; + + if (cond == NULL) + rval = EINVAL; + /* + * If the condition variable is statically initialized, perform dynamic + * initialization. + */ + else if (*cond != NULL || (rval = pthread_cond_init(cond, NULL) == 0)) { + /* + * Defer signals to protect the scheduling queues + * from access by the signal handler: + */ + _thread_kern_sig_defer(); + + /* Lock the condition variable structure: */ + _SPINLOCK(&(*cond)->lock); + + /* Process according to condition variable type: */ + switch ((*cond)->c_type) { + /* Fast condition variable: */ + case COND_TYPE_FAST: + if ((pthread = cond_queue_deq(*cond)) != NULL) { + /* + * Unless the thread is currently suspended, + * allow it to run. If the thread is suspended, + * make a note that the thread isn't in a wait + * queue any more. + */ + if (pthread->state != PS_SUSPENDED) + PTHREAD_NEW_STATE(pthread,PS_RUNNING); + else + pthread->suspended = SUSP_NOWAIT; + } + + /* Check for no more waiters: */ + if (TAILQ_FIRST(&(*cond)->c_queue) == NULL) + (*cond)->c_mutex = NULL; + break; + + /* Trap invalid condition variable types: */ + default: + /* Return an invalid argument error: */ + rval = EINVAL; + break; + } + + /* Unlock the condition variable structure: */ + _SPINUNLOCK(&(*cond)->lock); + + /* + * Undefer and handle pending signals, yielding if + * necessary: + */ + _thread_kern_sig_undefer(); + } + + /* Return the completion status: */ + return (rval); +} + +int +pthread_cond_broadcast(pthread_cond_t * cond) +{ + int rval = 0; + pthread_t pthread; + + if (cond == NULL) + rval = EINVAL; + /* + * If the condition variable is statically initialized, perform dynamic + * initialization. + */ + else if (*cond != NULL || (rval = pthread_cond_init(cond, NULL) == 0)) { + /* + * Defer signals to protect the scheduling queues + * from access by the signal handler: + */ + _thread_kern_sig_defer(); + + /* Lock the condition variable structure: */ + _SPINLOCK(&(*cond)->lock); + + /* Process according to condition variable type: */ + switch ((*cond)->c_type) { + /* Fast condition variable: */ + case COND_TYPE_FAST: + /* + * Enter a loop to bring all threads off the + * condition queue: + */ + while ((pthread = cond_queue_deq(*cond)) != NULL) { + /* + * Unless the thread is currently suspended, + * allow it to run. If the thread is suspended, + * make a note that the thread isn't in a wait + * queue any more. + */ + if (pthread->state != PS_SUSPENDED) + PTHREAD_NEW_STATE(pthread,PS_RUNNING); + else + pthread->suspended = SUSP_NOWAIT; + } + + /* There are no more waiting threads: */ + (*cond)->c_mutex = NULL; + break; + + /* Trap invalid condition variable types: */ + default: + /* Return an invalid argument error: */ + rval = EINVAL; + break; + } + + /* Unlock the condition variable structure: */ + _SPINUNLOCK(&(*cond)->lock); + + /* + * Undefer and handle pending signals, yielding if + * necessary: + */ + _thread_kern_sig_undefer(); + } + + /* Return the completion status: */ + return (rval); +} + +/* + * Dequeue a waiting thread from the head of a condition queue in + * descending priority order. + */ +static inline pthread_t +cond_queue_deq(pthread_cond_t cond) +{ + pthread_t pthread; + + while ((pthread = TAILQ_FIRST(&cond->c_queue)) != NULL) { + TAILQ_REMOVE(&cond->c_queue, pthread, qe); + pthread->flags &= ~PTHREAD_FLAGS_IN_CONDQ; + if ((pthread->timeout == 0) && (pthread->interrupted == 0)) + /* + * Only exit the loop when we find a thread + * that hasn't timed out or been canceled; + * those threads are already running and don't + * need their run state changed. + */ + break; + } + + return(pthread); +} + +/* + * Remove a waiting thread from a condition queue in descending priority + * order. + */ +static inline void +cond_queue_remove(pthread_cond_t cond, pthread_t pthread) +{ + /* + * Because pthread_cond_timedwait() can timeout as well + * as be signaled by another thread, it is necessary to + * guard against removing the thread from the queue if + * it isn't in the queue. + */ + if (pthread->flags & PTHREAD_FLAGS_IN_CONDQ) { + TAILQ_REMOVE(&cond->c_queue, pthread, qe); + pthread->flags &= ~PTHREAD_FLAGS_IN_CONDQ; + } +} + +/* + * Enqueue a waiting thread to a condition queue in descending priority + * order. + */ +static inline void +cond_queue_enq(pthread_cond_t cond, pthread_t pthread) +{ + pthread_t tid = TAILQ_LAST(&cond->c_queue, cond_head); + + /* + * For the common case of all threads having equal priority, + * we perform a quick check against the priority of the thread + * at the tail of the queue. + */ + if ((tid == NULL) || (pthread->active_priority <= tid->active_priority)) + TAILQ_INSERT_TAIL(&cond->c_queue, pthread, qe); + else { + tid = TAILQ_FIRST(&cond->c_queue); + while (pthread->active_priority <= tid->active_priority) + tid = TAILQ_NEXT(tid, qe); + TAILQ_INSERT_BEFORE(tid, pthread, qe); + } + pthread->flags |= PTHREAD_FLAGS_IN_CONDQ; +} +#endif diff --git a/lib/libpthread/thread/thr_condattr_destroy.c b/lib/libpthread/thread/thr_condattr_destroy.c new file mode 100644 index 0000000..ad91228 --- /dev/null +++ b/lib/libpthread/thread/thr_condattr_destroy.c @@ -0,0 +1,52 @@ +/* + * Copyright (c) 1997 John Birrell <jb@cimlogic.com.au>. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by John Birrell. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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. + * + * $FreeBSD$ + */ +#include <stdlib.h> +#include <errno.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +int pthread_condattr_destroy(pthread_condattr_t *attr) +{ + int ret; + if (attr == NULL || *attr == NULL) { + ret = EINVAL; + } else { + free(*attr); + *attr = NULL; + ret = 0; + } + return(ret); +} +#endif diff --git a/lib/libpthread/thread/thr_condattr_init.c b/lib/libpthread/thread/thr_condattr_init.c new file mode 100644 index 0000000..3379898 --- /dev/null +++ b/lib/libpthread/thread/thr_condattr_init.c @@ -0,0 +1,58 @@ +/* + * Copyright (c) 1997 John Birrell <jb@cimlogic.com.au> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by John Birrell. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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. + * + * $FreeBSD$ + */ +#include <string.h> +#include <stdlib.h> +#include <errno.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +int +pthread_condattr_init(pthread_condattr_t *attr) +{ + int ret; + pthread_condattr_t pattr; + + if ((pattr = (pthread_condattr_t) + malloc(sizeof(struct pthread_cond_attr))) == NULL) { + ret = ENOMEM; + } else { + memcpy(pattr, &pthread_condattr_default, + sizeof(struct pthread_cond_attr)); + *attr = pattr; + ret = 0; + } + return(ret); +} +#endif diff --git a/lib/libpthread/thread/thr_creat.c b/lib/libpthread/thread/thr_creat.c new file mode 100644 index 0000000..1b51fec --- /dev/null +++ b/lib/libpthread/thread/thr_creat.c @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2000 Jason Evans <jasone@freebsd.org>. + * 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(s), this list of conditions and the following disclaimer as + * the first lines of this file unmodified other than the possible + * addition of one or more copyright notices. + * 2. Redistributions in binary form must reproduce the above copyright + * notice(s), this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``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 COPYRIGHT HOLDER(S) 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. + * + * $FreeBSD$ + */ + +#include <fcntl.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +int +creat(const char *path, mode_t mode) +{ + int ret; + + _thread_enter_cancellation_point(); + ret = __creat(path, mode); + _thread_leave_cancellation_point(); + + return ret; +} +#endif diff --git a/lib/libpthread/thread/thr_create.c b/lib/libpthread/thread/thr_create.c new file mode 100644 index 0000000..3a80611 --- /dev/null +++ b/lib/libpthread/thread/thr_create.c @@ -0,0 +1,347 @@ +/* + * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by John Birrell. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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. + * + * $FreeBSD$ + */ +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include <fcntl.h> +#include <unistd.h> +#include <stddef.h> +#include <sys/time.h> +#include <sys/param.h> +#include <sys/mman.h> +#ifdef _THREAD_SAFE +#include <machine/reg.h> +#include <pthread.h> +#include "pthread_private.h" +#include "libc_private.h" + +static u_int64_t next_uniqueid = 1; + +#define OFF(f) offsetof(struct pthread, f) +int _thread_next_offset = OFF(tle.tqe_next); +int _thread_uniqueid_offset = OFF(uniqueid); +int _thread_state_offset = OFF(state); +int _thread_name_offset = OFF(name); +int _thread_sig_saved_offset = OFF(sig_saved); +int _thread_saved_sigcontext_offset = OFF(saved_sigcontext); +int _thread_saved_jmp_buf_offset = OFF(saved_jmp_buf); +#undef OFF + +int _thread_PS_RUNNING_value = PS_RUNNING; +int _thread_PS_DEAD_value = PS_DEAD; + +int +pthread_create(pthread_t * thread, const pthread_attr_t * attr, + void *(*start_routine) (void *), void *arg) +{ + int f_gc = 0; + int ret = 0; + pthread_t gc_thread; + pthread_t new_thread; + pthread_attr_t pattr; + void *stack; + + /* + * Locking functions in libc are required when there are + * threads other than the initial thread. + */ + __isthreaded = 1; + + /* Allocate memory for the thread structure: */ + if ((new_thread = (pthread_t) malloc(sizeof(struct pthread))) == NULL) { + /* Insufficient memory to create a thread: */ + ret = EAGAIN; + } else { + /* Check if default thread attributes are required: */ + if (attr == NULL || *attr == NULL) { + /* Use the default thread attributes: */ + pattr = &pthread_attr_default; + } else { + pattr = *attr; + } + /* Check if a stack was specified in the thread attributes: */ + if ((stack = pattr->stackaddr_attr) != NULL) { + } + /* Allocate memory for a default-size stack: */ + else if (pattr->stacksize_attr == PTHREAD_STACK_DEFAULT) { + struct stack *spare_stack; + + /* Allocate or re-use a default-size stack. */ + + /* + * Use the garbage collector mutex for synchronization + * of the spare stack list. + */ + if (pthread_mutex_lock(&_gc_mutex) != 0) + PANIC("Cannot lock gc mutex"); + + if ((spare_stack = SLIST_FIRST(&_stackq)) != NULL) { + /* Use the spare stack. */ + SLIST_REMOVE_HEAD(&_stackq, qe); + + /* Unlock the garbage collector mutex. */ + if (pthread_mutex_unlock(&_gc_mutex) != 0) + PANIC("Cannot unlock gc mutex"); + + stack = sizeof(struct stack) + + (void *) spare_stack + - PTHREAD_STACK_DEFAULT; + } else { + /* Allocate a new stack. */ + stack = _next_stack + PTHREAD_STACK_GUARD; + + /* + * Even if stack allocation fails, we don't want + * to try to use this location again, so + * unconditionally decrement _next_stack. Under + * normal operating conditions, the most likely + * reason for an mmap() error is a stack + * overflow of the adjacent thread stack. + */ + _next_stack -= (PTHREAD_STACK_DEFAULT + + PTHREAD_STACK_GUARD); + + /* Unlock the garbage collector mutex. */ + if (pthread_mutex_unlock(&_gc_mutex) != 0) + PANIC("Cannot unlock gc mutex"); + + /* Stack: */ + if (mmap(stack, PTHREAD_STACK_DEFAULT, + PROT_READ | PROT_WRITE, MAP_STACK, + -1, 0) == MAP_FAILED) { + ret = EAGAIN; + free(new_thread); + } + } + } + /* + * The user wants a stack of a particular size. Lets hope they + * really know what they want, and simply malloc the stack. + */ + else if ((stack = (void *) malloc(pattr->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; + + new_thread->cancelflags = PTHREAD_CANCEL_ENABLE | + PTHREAD_CANCEL_DEFERRED; + + /* + * Write a magic value to the thread structure + * to help identify valid ones: + */ + new_thread->magic = PTHREAD_MAGIC; + + /* Initialise the thread for signals: */ + new_thread->sigmask = _thread_run->sigmask; + + /* Initialise the jump buffer: */ + 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(). + */ +#if defined(__FreeBSD__) +#if defined(__alpha__) + new_thread->saved_jmp_buf[0]._jb[2] = + (long)_thread_start; + new_thread->saved_jmp_buf[0]._jb[4 + R_RA] = + 0; + new_thread->saved_jmp_buf[0]._jb[4 + R_T12] = + (long)_thread_start; +#else + new_thread->saved_jmp_buf[0]._jb[0] = + (long)_thread_start; +#endif +#elif defined(__NetBSD__) +#if defined(__alpha__) + new_thread->saved_jmp_buf[2] = (long)_thread_start; + new_thread->saved_jmp_buf[4 + R_RA] = 0; + new_thread->saved_jmp_buf[4 + R_T12] = + (long)_thread_start; +#else + new_thread->saved_jmp_buf[0] = (long)_thread_start; +#endif +#else +#error "Don't recognize this operating system!" +#endif + + /* The stack starts high and builds down: */ +#if defined(__FreeBSD__) +#if defined(__alpha__) + new_thread->saved_jmp_buf[0]._jb[4 + R_SP] = + (long)new_thread->stack + pattr->stacksize_attr + - sizeof(double); +#else + new_thread->saved_jmp_buf[0]._jb[2] = + (int)(new_thread->stack + pattr->stacksize_attr - + sizeof(double)); +#endif +#elif defined(__NetBSD__) +#if defined(__alpha__) + 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 + + pattr->stacksize_attr - sizeof(double); +#endif +#else +#error "Don't recognize this operating system!" +#endif + + /* Copy the thread attributes: */ + memcpy(&new_thread->attr, pattr, sizeof(struct pthread_attr)); + + /* + * 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->base_priority + = _thread_run->base_priority; + new_thread->attr.prio + = _thread_run->base_priority; + new_thread->attr.sched_policy + = _thread_run->attr.sched_policy; + } else { + /* + * Use just the thread priority, leaving the + * other scheduling attributes as their + * default values: + */ + new_thread->base_priority + = new_thread->attr.prio; + } + new_thread->active_priority = new_thread->base_priority; + new_thread->inherited_priority = 0; + + /* Initialise the join queue for the new thread: */ + TAILQ_INIT(&(new_thread->join_queue)); + + /* Initialize the mutex queue: */ + TAILQ_INIT(&new_thread->mutexq); + + /* Initialise hooks in the thread structure: */ + new_thread->specific_data = NULL; + new_thread->cleanup = NULL; + new_thread->flags = 0; + new_thread->poll_data.nfds = 0; + new_thread->poll_data.fds = NULL; + new_thread->jmpflags = 0; + new_thread->continuation = NULL; + + /* + * Defer signals to protect the scheduling queues + * from access by the signal handler: + */ + _thread_kern_sig_defer(); + + /* + * Initialise the unique id which GDB uses to + * track threads. + */ + new_thread->uniqueid = next_uniqueid++; + + /* + * Check if the garbage collector thread + * needs to be started. + */ + f_gc = (TAILQ_FIRST(&_thread_list) == _thread_initial); + + /* Add the thread to the linked list of all threads: */ + TAILQ_INSERT_HEAD(&_thread_list, new_thread, tle); + + if (pattr->suspend == PTHREAD_CREATE_SUSPENDED) + new_thread->state = PS_SUSPENDED; + else { + new_thread->state = PS_RUNNING; + PTHREAD_PRIOQ_INSERT_TAIL(new_thread); + } + + /* + * Undefer and handle pending signals, yielding + * if necessary. + */ + _thread_kern_sig_undefer(); + + /* Return a pointer to the thread structure: */ + (*thread) = new_thread; + + /* Schedule the new user thread: */ + _thread_kern_sched(NULL); + + /* + * Start a garbage collector thread + * if necessary. + */ + if (f_gc && pthread_create(&gc_thread,NULL, + _thread_gc,NULL) != 0) + PANIC("Can't create gc thread"); + } + } + + /* Return the status: */ + return (ret); +} + +void +_thread_start(void) +{ + /* We just left the scheduler via longjmp: */ + _thread_kern_in_sched = 0; + + /* 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"); +} +#endif diff --git a/lib/libpthread/thread/thr_detach.c b/lib/libpthread/thread/thr_detach.c new file mode 100644 index 0000000..89cc667 --- /dev/null +++ b/lib/libpthread/thread/thr_detach.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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <errno.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +int +pthread_detach(pthread_t pthread) +{ + int rval = 0; + pthread_t next_thread; + + /* Check for invalid calling parameters: */ + if (pthread == NULL || pthread->magic != PTHREAD_MAGIC) + /* Return an invalid argument error: */ + rval = EINVAL; + + /* Check if the thread has not been detached: */ + else if ((pthread->attr.flags & PTHREAD_DETACHED) == 0) { + /* Flag the thread as detached: */ + pthread->attr.flags |= PTHREAD_DETACHED; + + /* + * Defer signals to protect the scheduling queues from + * access by the signal handler: + */ + _thread_kern_sig_defer(); + + /* Enter a loop to bring all threads off the join queue: */ + while ((next_thread = TAILQ_FIRST(&pthread->join_queue)) != NULL) { + /* Remove the thread from the queue: */ + TAILQ_REMOVE(&pthread->join_queue, next_thread, qe); + + /* Make the thread run: */ + PTHREAD_NEW_STATE(next_thread,PS_RUNNING); + } + + /* + * Undefer and handle pending signals, yielding if a + * scheduling signal occurred while in the critical region. + */ + _thread_kern_sig_undefer(); + } else + /* Return an error: */ + rval = EINVAL; + + /* Return the completion status: */ + return (rval); +} +#endif diff --git a/lib/libpthread/thread/thr_equal.c b/lib/libpthread/thread/thr_equal.c new file mode 100644 index 0000000..e03ba4a --- /dev/null +++ b/lib/libpthread/thread/thr_equal.c @@ -0,0 +1,44 @@ +/* + * 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +int +pthread_equal(pthread_t t1, pthread_t t2) +{ + /* Compare the two thread pointers: */ + return (t1 == t2); +} +#endif diff --git a/lib/libpthread/thread/thr_exit.c b/lib/libpthread/thread/thr_exit.c new file mode 100644 index 0000000..0d22638 --- /dev/null +++ b/lib/libpthread/thread/thr_exit.c @@ -0,0 +1,242 @@ +/* + * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by John Birrell. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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. + * + * $FreeBSD$ + */ +#include <errno.h> +#include <unistd.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +void __exit(int status) +{ + int flags; + int i; + struct itimerval itimer; + + /* Disable the interval timer: */ + itimer.it_interval.tv_sec = 0; + itimer.it_interval.tv_usec = 0; + itimer.it_value.tv_sec = 0; + itimer.it_value.tv_usec = 0; + setitimer(_ITIMER_SCHED_TIMER, &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); +} + +__strong_reference(__exit, _exit); + +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: */ + /* XXX - Do we want abort to be conditional on _PTHREADS_INVARIANTS? */ +#if defined(_PTHREADS_INVARIANTS) + abort(); +#else + _exit(1); +#endif +} + +/* + * Only called when a thread is cancelled. It may be more useful + * to call it from pthread_exit() if other ways of asynchronous or + * abnormal thread termination can be found. + */ +void +_thread_exit_cleanup(void) +{ + /* + * POSIX states that cancellation/termination of a thread should + * not release any visible resources (such as mutexes) and that + * it is the applications responsibility. Resources that are + * internal to the threads library, including file and fd locks, + * are not visible to the application and need to be released. + */ + /* Unlock all owned fd locks: */ + _thread_fd_unlock_owned(_thread_run); + + /* Unlock all owned file locks: */ + _funlock_owned(_thread_run); + + /* Unlock all private mutexes: */ + _mutex_unlock_private(_thread_run); + + /* + * This still isn't quite correct because we don't account + * for held spinlocks (see libc/stdlib/malloc.c). + */ +} + +void +pthread_exit(void *status) +{ + pthread_t pthread; + + /* Check if this thread is already in the process of exiting: */ + if ((_thread_run->flags & PTHREAD_EXITING) != 0) { + char msg[128]; + snprintf(msg, sizeof(msg), "Thread %p has called pthread_exit() from a destructor. POSIX 1003.1 1996 s16.2.5.2 does not allow this!",_thread_run); + PANIC(msg); + } + + /* Flag this thread as exiting: */ + _thread_run->flags |= PTHREAD_EXITING; + + /* Save the return value: */ + _thread_run->ret = status; + + while (_thread_run->cleanup != NULL) { + pthread_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(); + } + + /* Free thread-specific poll_data structure, if allocated: */ + if (_thread_run->poll_data.fds != NULL) { + free(_thread_run->poll_data.fds); + _thread_run->poll_data.fds = NULL; + } + + /* + * Defer signals to protect the scheduling queues from access + * by the signal handler: + */ + _thread_kern_sig_defer(); + + /* Check if there are any threads joined to this one: */ + while ((pthread = TAILQ_FIRST(&(_thread_run->join_queue))) != NULL) { + /* Remove the thread from the queue: */ + TAILQ_REMOVE(&_thread_run->join_queue, pthread, qe); + + /* Wake the joined thread and let it detach this thread: */ + PTHREAD_NEW_STATE(pthread,PS_RUNNING); + } + + /* + * Undefer and handle pending signals, yielding if necessary: + */ + _thread_kern_sig_undefer(); + + /* + * Lock the garbage collector mutex to ensure that the garbage + * collector is not using the dead thread list. + */ + if (pthread_mutex_lock(&_gc_mutex) != 0) + PANIC("Cannot lock gc mutex"); + + /* Add this thread to the list of dead threads. */ + TAILQ_INSERT_HEAD(&_dead_list, _thread_run, dle); + + /* + * Defer signals to protect the scheduling queues from access + * by the signal handler: + */ + _thread_kern_sig_defer(); + + /* Remove this thread from the thread list: */ + TAILQ_REMOVE(&_thread_list, _thread_run, tle); + + /* + * Undefer and handle pending signals, yielding if necessary: + */ + _thread_kern_sig_undefer(); + + /* + * Signal the garbage collector thread that there is something + * to clean up. + */ + if (pthread_cond_signal(&_gc_cond) != 0) + PANIC("Cannot signal gc cond"); + + /* + * Mark the thread as dead so it will not return if it + * gets context switched out when the mutex is unlocked. + */ + PTHREAD_SET_STATE(_thread_run, PS_DEAD); + + /* Unlock the garbage collector mutex: */ + if (pthread_mutex_unlock(&_gc_mutex) != 0) + PANIC("Cannot lock gc mutex"); + + /* This this thread will never be re-scheduled. */ + _thread_kern_sched(NULL); + + /* This point should not be reached. */ + PANIC("Dead thread has resumed"); +} +#endif diff --git a/lib/libpthread/thread/thr_fcntl.c b/lib/libpthread/thread/thr_fcntl.c new file mode 100644 index 0000000..f5dd064 --- /dev/null +++ b/lib/libpthread/thread/thr_fcntl.c @@ -0,0 +1,170 @@ +/* + * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by John Birrell. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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. + * + * $FreeBSD$ + */ +#include <stdarg.h> +#include <unistd.h> +#include <fcntl.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +int +_fcntl(int fd, int cmd,...) +{ + int flags = 0; + int nonblock; + int oldfd; + int ret; + va_list ap; + + /* Lock the file descriptor: */ + if ((ret = _FD_LOCK(fd, FD_RDWR, NULL)) == 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: + flags = va_arg(ap, int); + ret = _thread_sys_fcntl(fd, cmd, flags); + break; + case F_GETFD: + ret = _thread_sys_fcntl(fd, cmd, 0); + break; + case F_GETFL: + ret = _thread_fd_table[fd]->flags; + break; + case F_SETFL: + /* + * Get the file descriptor flags passed by the + * caller: + */ + flags = va_arg(ap, int); + + /* + * Check if the user wants a non-blocking file + * descriptor: + */ + nonblock = flags & O_NONBLOCK; + + /* Set the file descriptor flags: */ + if ((ret = _thread_sys_fcntl(fd, cmd, flags | O_NONBLOCK)) != 0) { + + /* Get the flags so that we behave like the kernel: */ + } else if ((flags = _thread_sys_fcntl(fd, + F_GETFL, 0)) == -1) { + /* Error getting flags: */ + ret = -1; + + /* + * Check if the file descriptor is non-blocking + * with respect to the user: + */ + } else if (nonblock) + /* A non-blocking descriptor: */ + _thread_fd_table[fd]->flags = flags | O_NONBLOCK; + else + /* Save the flags: */ + _thread_fd_table[fd]->flags = flags & ~O_NONBLOCK; + 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: */ + _FD_UNLOCK(fd, FD_RDWR); + } + /* Return the completion status: */ + return (ret); +} + +int +fcntl(int fd, int cmd,...) +{ + int ret; + va_list ap; + + _thread_enter_cancellation_point(); + + va_start(ap, cmd); + switch (cmd) { + case F_DUPFD: + case F_SETFD: + case F_SETFL: + ret = _fcntl(fd, cmd, va_arg(ap, int)); + break; + case F_GETFD: + case F_GETFL: + ret = _fcntl(fd, cmd); + break; + default: + ret = _fcntl(fd, cmd, va_arg(ap, void *)); + } + va_end(ap); + + _thread_leave_cancellation_point(); + + return ret; +} +#endif diff --git a/lib/libpthread/thread/thr_find_thread.c b/lib/libpthread/thread/thr_find_thread.c new file mode 100644 index 0000000..d4a3bbd --- /dev/null +++ b/lib/libpthread/thread/thr_find_thread.c @@ -0,0 +1,100 @@ +/* + * Copyright (c) 1998 John Birrell <jb@cimlogic.com.au>. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by John Birrell. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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. + * + * $FreeBSD$ + */ +#include <errno.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +/* Find a thread in the linked list of active threads: */ +int +_find_thread(pthread_t pthread) +{ + pthread_t pthread1; + + /* Check if the caller has specified an invalid thread: */ + if (pthread == NULL || pthread->magic != PTHREAD_MAGIC) + /* Invalid thread: */ + return(EINVAL); + + /* + * Defer signals to protect the thread list from access + * by the signal handler: + */ + _thread_kern_sig_defer(); + + /* Search for the specified thread: */ + TAILQ_FOREACH(pthread1, &_thread_list, tle) { + if (pthread == pthread1) + break; + } + + /* Undefer and handle pending signals, yielding if necessary: */ + _thread_kern_sig_undefer(); + + /* Return zero if the thread exists: */ + return ((pthread1 != NULL) ? 0:ESRCH); +} + +/* Find a thread in the linked list of dead threads: */ +int +_find_dead_thread(pthread_t pthread) +{ + pthread_t pthread1; + + /* Check if the caller has specified an invalid thread: */ + if (pthread == NULL || pthread->magic != PTHREAD_MAGIC) + /* Invalid thread: */ + return(EINVAL); + + /* + * Lock the garbage collector mutex to ensure that the garbage + * collector is not using the dead thread list. + */ + if (pthread_mutex_lock(&_gc_mutex) != 0) + PANIC("Cannot lock gc mutex"); + + /* Search for the specified thread: */ + TAILQ_FOREACH(pthread1, &_dead_list, dle) { + if (pthread1 == pthread) + break; + } + + /* Unlock the garbage collector mutex: */ + if (pthread_mutex_unlock(&_gc_mutex) != 0) + PANIC("Cannot lock gc mutex"); + + /* Return zero if the thread exists: */ + return ((pthread1 != NULL) ? 0:ESRCH); +} +#endif diff --git a/lib/libpthread/thread/thr_fork.c b/lib/libpthread/thread/thr_fork.c new file mode 100644 index 0000000..a8e85d8 --- /dev/null +++ b/lib/libpthread/thread/thr_fork.c @@ -0,0 +1,225 @@ +/* + * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by John Birrell. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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. + * + * $FreeBSD$ + */ +#include <errno.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +pid_t +_fork(void) +{ + int i, flags; + pid_t ret; + pthread_t pthread; + pthread_t pthread_save; + + /* + * Defer signals to protect the scheduling queues from access + * by the signal handler: + */ + _thread_kern_sig_defer(); + + /* 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: */ + sigemptyset(&_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(); + } + /* Reinitialize the GC mutex: */ + else if (_mutex_reinit(&_gc_mutex) != 0) { + /* Abort this application: */ + PANIC("Cannot initialize GC mutex for forked process"); + } + /* Reinitialize the GC condition variable: */ + else if (_cond_reinit(&_gc_cond) != 0) { + /* Abort this application: */ + PANIC("Cannot initialize GC condvar for forked process"); + } + /* Initialize the ready queue: */ + else if (_pq_init(&_readyq) != 0) { + /* Abort this application: */ + PANIC("Cannot initialize priority ready queue."); + } else { + /* + * Enter a loop to remove all threads other than + * the running thread from the thread list: + */ + pthread = TAILQ_FIRST(&_thread_list); + while (pthread != NULL) { + /* Save the thread to be freed: */ + pthread_save = pthread; + + /* + * Advance to the next thread before + * destroying the current thread: + */ + pthread = TAILQ_NEXT(pthread, dle); + + /* Make sure this isn't the running thread: */ + if (pthread_save != _thread_run) { + /* Remove this thread from the list: */ + TAILQ_REMOVE(&_thread_list, + pthread_save, tle); + + if (pthread_save->attr.stackaddr_attr == + NULL && pthread_save->stack != NULL) { + if (pthread_save->attr.stacksize_attr + == PTHREAD_STACK_DEFAULT) { + /* + * Default-size stack. + * Cache it: + */ + struct stack *spare_stack; + + spare_stack + = (pthread_save->stack + + PTHREAD_STACK_DEFAULT + - sizeof(struct stack)); + SLIST_INSERT_HEAD(&_stackq, + spare_stack, qe); + } else + /* + * Free the stack of + * the dead thread: + */ + free(pthread_save->stack); + } + + if (pthread_save->specific_data != NULL) + free(pthread_save->specific_data); + + if (pthread_save->poll_data.fds != NULL) + free(pthread_save->poll_data.fds); + + free(pthread_save); + } + } + + /* Treat the current thread as the initial thread: */ + _thread_initial = _thread_run; + + /* Re-init the dead thread list: */ + TAILQ_INIT(&_dead_list); + + /* Re-init the waiting and work queues. */ + TAILQ_INIT(&_waitingq); + TAILQ_INIT(&_workq); + + /* Re-init the threads mutex queue: */ + TAILQ_INIT(&_thread_run->mutexq); + + /* No spinlocks yet: */ + _spinblock_count = 0; + + /* Don't queue signals yet: */ + _queue_signals = 0; + + /* Initialize signal handling: */ + _thread_sig_init(); + + /* Initialize the scheduling switch hook routine: */ + _sched_switch_hook = NULL; + + /* Clear out any locks in the file descriptor table: */ + for (i = 0; i < _thread_dtablesize; i++) { + if (_thread_fd_table[i] != NULL) { + /* Initialise the file locks: */ + memset(&_thread_fd_table[i]->lock, 0, + sizeof(_thread_fd_table[i]->lock)); + _thread_fd_table[i]->r_owner = NULL; + _thread_fd_table[i]->w_owner = NULL; + _thread_fd_table[i]->r_fname = NULL; + _thread_fd_table[i]->w_fname = NULL; + _thread_fd_table[i]->r_lineno = 0;; + _thread_fd_table[i]->w_lineno = 0;; + _thread_fd_table[i]->r_lockcount = 0;; + _thread_fd_table[i]->w_lockcount = 0;; + + /* Initialise the read/write queues: */ + TAILQ_INIT(&_thread_fd_table[i]->r_queue); + TAILQ_INIT(&_thread_fd_table[i]->w_queue); + } + } + } + } + + /* + * Undefer and handle pending signals, yielding if necessary: + */ + _thread_kern_sig_undefer(); + + /* Return the process ID: */ + return (ret); +} + +__strong_reference(_fork, fork); +#endif diff --git a/lib/libpthread/thread/thr_fsync.c b/lib/libpthread/thread/thr_fsync.c new file mode 100644 index 0000000..0d88320 --- /dev/null +++ b/lib/libpthread/thread/thr_fsync.c @@ -0,0 +1,62 @@ +/* + * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by John Birrell. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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. + * + * $FreeBSD$ + */ +#include <unistd.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +int +_fsync(int fd) +{ + int ret; + + if ((ret = _FD_LOCK(fd, FD_RDWR, NULL)) == 0) { + ret = _thread_sys_fsync(fd); + _FD_UNLOCK(fd, FD_RDWR); + } + return (ret); +} + +int +fsync(int fd) +{ + int ret; + + _thread_enter_cancellation_point(); + ret = _fsync(fd); + _thread_leave_cancellation_point(); + + return ret; +} +#endif diff --git a/lib/libpthread/thread/thr_gc.c b/lib/libpthread/thread/thr_gc.c new file mode 100644 index 0000000..cd1f838 --- /dev/null +++ b/lib/libpthread/thread/thr_gc.c @@ -0,0 +1,256 @@ +/* + * Copyright (c) 1998 John Birrell <jb@cimlogic.com.au> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by John Birrell. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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. + * + * $FreeBSD$ + * + * Garbage collector thread. Frees memory allocated for dead threads. + * + */ +#include <errno.h> +#include <time.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/types.h> +#include <sys/mman.h> +#include <pthread.h> +#include "pthread_private.h" + +pthread_addr_t +_thread_gc(pthread_addr_t arg) +{ + int f_debug; + int f_done = 0; + int ret; + sigset_t mask; + pthread_t pthread; + pthread_t pthread_cln; + struct timespec abstime; + void *p_stack; + + /* Block all signals */ + sigfillset (&mask); + sigprocmask (SIG_BLOCK, &mask, NULL); + + /* Mark this thread as a library thread (not a user thread). */ + _thread_run->flags |= PTHREAD_FLAGS_PRIVATE; + + /* Set a debug flag based on an environment variable. */ + f_debug = (getenv("LIBC_R_DEBUG") != NULL); + + /* Set the name of this thread. */ + pthread_set_name_np(_thread_run,"GC"); + + while (!f_done) { + /* Check if debugging this application. */ + if (f_debug) + /* Dump thread info to file. */ + _thread_dump_info(); + + /* + * Defer signals to protect the scheduling queues from + * access by the signal handler: + */ + _thread_kern_sig_defer(); + + /* Check if this is the last running thread: */ + if (TAILQ_FIRST(&_thread_list) == _thread_run && + TAILQ_NEXT(_thread_run, tle) == NULL) + /* + * This is the last thread, so it can exit + * now. + */ + f_done = 1; + + /* + * Undefer and handle pending signals, yielding if + * necessary: + */ + _thread_kern_sig_undefer(); + + /* + * Lock the garbage collector mutex which ensures that + * this thread sees another thread exit: + */ + if (pthread_mutex_lock(&_gc_mutex) != 0) + PANIC("Cannot lock gc mutex"); + + /* No stack of thread structure to free yet: */ + p_stack = NULL; + pthread_cln = NULL; + + /* + * Enter a loop to search for the first dead thread that + * has memory to free. + */ + for (pthread = TAILQ_FIRST(&_dead_list); + p_stack == NULL && pthread_cln == NULL && pthread != NULL; + pthread = TAILQ_NEXT(pthread, dle)) { + /* Check if the initial thread: */ + if (pthread == _thread_initial) { + /* Don't destroy the initial thread. */ + } + /* + * Check if this thread has detached: + */ + else if ((pthread->attr.flags & + PTHREAD_DETACHED) != 0) { + /* Remove this thread from the dead list: */ + TAILQ_REMOVE(&_dead_list, pthread, dle); + + /* + * 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) { + if (pthread->attr.stacksize_attr + == PTHREAD_STACK_DEFAULT) { + /* + * Default-size stack. Cache + * it: + */ + struct stack *spare_stack; + + spare_stack + = (pthread->stack + + PTHREAD_STACK_DEFAULT + - sizeof(struct stack)); + SLIST_INSERT_HEAD(&_stackq, + spare_stack, + qe); + } else { + /* + * Non-standard stack size. + * free() it outside the locks. + */ + p_stack = pthread->stack; + } + } + + /* + * Point to the thread structure that must + * be freed outside the locks: + */ + pthread_cln = pthread; + + } else { + /* + * This thread has not detached, so do + * not destroy it. + * + * 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) { + if (pthread->attr.stacksize_attr + == PTHREAD_STACK_DEFAULT) { + /* + * Default-size stack. Cache + * it: + */ + struct stack *spare_stack; + + spare_stack + = (pthread->stack + + PTHREAD_STACK_DEFAULT + - sizeof(struct stack)); + SLIST_INSERT_HEAD(&_stackq, + spare_stack, + qe); + } else { + /* + * Non-standard stack size. + * free() it outside the locks: + */ + p_stack = pthread->stack; + } + + /* + * NULL the stack pointer now + * that the memory has been freed: + */ + pthread->stack = NULL; + } + } + } + + /* + * Check if this is not the last thread and there is no + * memory to free this time around. + */ + if (!f_done && p_stack == NULL && pthread_cln == NULL) { + /* Get the current time. */ + if (clock_gettime(CLOCK_REALTIME,&abstime) != 0) + PANIC("gc cannot get time"); + + /* + * Do a backup poll in 10 seconds if no threads + * die before then. + */ + abstime.tv_sec += 10; + + /* + * Wait for a signal from a dying thread or a + * timeout (for a backup poll). + */ + if ((ret = pthread_cond_timedwait(&_gc_cond, + &_gc_mutex, &abstime)) != 0 && ret != ETIMEDOUT) + PANIC("gc cannot wait for a signal"); + } + + /* Unlock the garbage collector mutex: */ + if (pthread_mutex_unlock(&_gc_mutex) != 0) + PANIC("Cannot unlock gc mutex"); + + /* + * If there is memory to free, do it now. The call to + * free() might block, so this must be done outside the + * locks. + */ + if (p_stack != NULL) + free(p_stack); + if (pthread_cln != NULL) + if (pthread_cln->name != NULL) { + /* Free the thread name string. */ + free(pthread_cln->name); + } + /* + * Free the memory allocated for the thread + * structure. + */ + free(pthread_cln); + } + return (NULL); +} diff --git a/lib/libpthread/thread/thr_getprio.c b/lib/libpthread/thread/thr_getprio.c new file mode 100644 index 0000000..2f94b86 --- /dev/null +++ b/lib/libpthread/thread/thr_getprio.c @@ -0,0 +1,56 @@ +/* + * 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <errno.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +int +pthread_getprio(pthread_t pthread) +{ + int policy, ret; + struct sched_param param; + + if ((ret = pthread_getschedparam(pthread, &policy, ¶m)) == 0) + ret = param.sched_priority; + else { + /* Invalid thread: */ + errno = ret; + ret = -1; + } + + /* Return the thread priority or an error status: */ + return (ret); +} +#endif diff --git a/lib/libpthread/thread/thr_getschedparam.c b/lib/libpthread/thread/thr_getschedparam.c new file mode 100644 index 0000000..09d8c1b --- /dev/null +++ b/lib/libpthread/thread/thr_getschedparam.c @@ -0,0 +1,58 @@ +/* + * Copyright (c) 1998 Daniel Eischen <eischen@vigrid.com>. + * 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 Daniel Eischen. + * 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 DANIEL EISCHEN 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <errno.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +int +pthread_getschedparam(pthread_t pthread, int *policy, + struct sched_param *param) +{ + int ret; + + if ((param == NULL) || (policy == NULL)) + /* Return an invalid argument error: */ + ret = EINVAL; + + /* Find the thread in the list of active threads: */ + else if ((ret = _find_thread(pthread)) == 0) { + /* Return the threads base priority and scheduling policy: */ + param->sched_priority = pthread->base_priority; + *policy = pthread->attr.sched_policy; + } + + return(ret); +} +#endif diff --git a/lib/libpthread/thread/thr_info.c b/lib/libpthread/thread/thr_info.c new file mode 100644 index 0000000..d091ec1 --- /dev/null +++ b/lib/libpthread/thread/thr_info.c @@ -0,0 +1,315 @@ +/* + * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by John Birrell. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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. + * + * $FreeBSD$ + */ +#include <stdio.h> +#include <fcntl.h> +#include <string.h> +#include <unistd.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include <errno.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 , "Waiting for write"}, + {PS_FILE_WAIT , "Waiting for FILE lock"}, + {PS_POLL_WAIT , "Waiting on poll"}, + {PS_SELECT_WAIT , "Waiting on select"}, + {PS_SLEEP_WAIT , "Sleeping"}, + {PS_WAIT_WAIT , "Waiting process"}, + {PS_SIGSUSPEND , "Suspended, waiting for a signal"}, + {PS_SIGWAIT , "Waiting for a signal"}, + {PS_SPINBLOCK , "Waiting for a spinlock"}, + {PS_JOIN , "Waiting to join"}, + {PS_SUSPENDED , "Suspended"}, + {PS_DEAD , "Dead"}, + {PS_DEADLOCK , "Deadlocked"}, + {PS_STATE_MAX , "Not a real state!"} +}; + +void +_thread_dump_info(void) +{ + char s[512]; + int fd; + int i; + int j; + pthread_t pthread; + char tmpfile[128]; + pq_list_t *pq_list; + + for (i = 0; i < 100000; i++) { + snprintf(tmpfile, sizeof(tmpfile), "/tmp/uthread.dump.%u.%i", + getpid(), i); + /* Open the dump file for append and create it if necessary: */ + if ((fd = _thread_sys_open(tmpfile, O_RDWR | O_CREAT | O_EXCL, + 0666)) < 0) { + /* Can't open the dump file. */ + if (errno == EEXIST) + continue; + /* + * We only need to continue in case of + * EEXIT error. Most other error + * codes means that we will fail all + * the times. + */ + return; + } else { + break; + } + } + if (i==100000) { + /* all 100000 possibilities are in use :( */ + return; + } 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: */ + TAILQ_FOREACH(pthread, &_thread_list, tle) { + /* 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: */ + snprintf(s, sizeof(s), + "--------------------\nThread %p (%s) prio %3d state %s [%s:%d]\n", + pthread, (pthread->name == NULL) ? + "":pthread->name, pthread->base_priority, + thread_info[j].name, + pthread->fname,pthread->lineno); + _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: + case PS_FDLW_WAIT: + case PS_FDR_WAIT: + case PS_FDW_WAIT: + /* Write the lock details: */ + snprintf(s, sizeof(s), "fd %d[%s:%d]", + pthread->data.fd.fd, + pthread->data.fd.fname, + pthread->data.fd.branch); + _thread_sys_write(fd, s, strlen(s)); + snprintf(s, sizeof(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; + case PS_SIGWAIT: + snprintf(s, sizeof(s), "sigmask (hi)"); + _thread_sys_write(fd, s, strlen(s)); + for (i = _SIG_WORDS - 1; i >= 0; i--) { + snprintf(s, sizeof(s), "%08x\n", + pthread->sigmask.__bits[i]); + _thread_sys_write(fd, s, strlen(s)); + } + snprintf(s, sizeof(s), "(lo)\n"); + _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; + } + } + + /* Output a header for ready threads: */ + strcpy(s, "\n\n=============\nREADY THREADS\n\n"); + _thread_sys_write(fd, s, strlen(s)); + + /* Enter a loop to report each thread in the ready queue: */ + TAILQ_FOREACH (pq_list, &_readyq.pq_queue, pl_link) { + TAILQ_FOREACH(pthread, &pq_list->pl_head, pqe) { + /* 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: */ + snprintf(s, sizeof(s), + "--------------------\nThread %p (%s) prio %3d state %s [%s:%d]\n", + pthread, (pthread->name == NULL) ? + "":pthread->name, pthread->base_priority, + thread_info[j].name, + pthread->fname,pthread->lineno); + _thread_sys_write(fd, s, strlen(s)); + } + } + + /* Output a header for waiting threads: */ + strcpy(s, "\n\n=============\nWAITING THREADS\n\n"); + _thread_sys_write(fd, s, strlen(s)); + + /* Enter a loop to report each thread in the waiting queue: */ + TAILQ_FOREACH (pthread, &_waitingq, pqe) { + /* 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: */ + snprintf(s, sizeof(s), + "--------------------\nThread %p (%s) prio %3d state %s [%s:%d]\n", + pthread, (pthread->name == NULL) ? + "":pthread->name, pthread->base_priority, + thread_info[j].name, + pthread->fname,pthread->lineno); + _thread_sys_write(fd, s, strlen(s)); + } + + /* Output a header for threads in the work queue: */ + strcpy(s, "\n\n=============\nTHREADS IN WORKQ\n\n"); + _thread_sys_write(fd, s, strlen(s)); + + /* Enter a loop to report each thread in the waiting queue: */ + TAILQ_FOREACH (pthread, &_workq, qe) { + /* 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: */ + snprintf(s, sizeof(s), + "--------------------\nThread %p (%s) prio %3d state %s [%s:%d]\n", + pthread, (pthread->name == NULL) ? + "":pthread->name, pthread->base_priority, + thread_info[j].name, + pthread->fname,pthread->lineno); + _thread_sys_write(fd, s, strlen(s)); + } + + /* Check if there are no dead threads: */ + if (TAILQ_FIRST(&_dead_list) == 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: + */ + TAILQ_FOREACH(pthread, &_dead_list, dle) { + /* Output a record for the current thread: */ + snprintf(s, sizeof(s), + "Thread %p prio %3d [%s:%d]\n", + pthread, pthread->base_priority, + pthread->fname,pthread->lineno); + _thread_sys_write(fd, s, strlen(s)); + } + } + + /* Output a header for file descriptors: */ + snprintf(s, sizeof(s), "\n\n=============\nFILE DESCRIPTOR TABLE (table size %d)\n\n",_thread_dtablesize); + _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: */ + snprintf(s, sizeof(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; +} + +/* Set the thread name for debug: */ +void +pthread_set_name_np(pthread_t thread, char *name) +{ + /* Check if the caller has specified a valid thread: */ + if (thread != NULL && thread->magic == PTHREAD_MAGIC) { + if (thread->name != NULL) { + /* Free space for previous name. */ + free(thread->name); + } + thread->name = strdup(name); + } +} +#endif diff --git a/lib/libpthread/thread/thr_init.c b/lib/libpthread/thread/thr_init.c new file mode 100644 index 0000000..8e13f90 --- /dev/null +++ b/lib/libpthread/thread/thr_init.c @@ -0,0 +1,393 @@ +/* + * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by John Birrell. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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. + * + * $FreeBSD$ + */ + +/* Allocate space for global thread variables here: */ +#define GLOBAL_PTHREAD_PRIVATE + +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include <fcntl.h> +#include <paths.h> +#include <poll.h> +#include <unistd.h> +#include <sys/ioctl.h> +#include <sys/sysctl.h> +#include <sys/time.h> +#include <sys/ttycom.h> +#include <sys/param.h> +#include <sys/user.h> +#include <sys/mman.h> +#ifdef _THREAD_SAFE +#include <machine/reg.h> +#include <pthread.h> +#include "pthread_private.h" + +#ifdef GCC_2_8_MADE_THREAD_AWARE +typedef void *** (*dynamic_handler_allocator)(); +extern void __set_dynamic_handler_allocator(dynamic_handler_allocator); + +static pthread_key_t except_head_key; + +typedef struct { + void **__dynamic_handler_chain; + void *top_elt[2]; +} except_struct; + +static void ***dynamic_allocator_handler_fn() +{ + except_struct *dh = (except_struct *)pthread_getspecific(except_head_key); + + if(dh == NULL) { + dh = (except_struct *)malloc( sizeof(except_struct) ); + memset(dh, '\0', sizeof(except_struct)); + dh->__dynamic_handler_chain= dh->top_elt; + pthread_setspecific(except_head_key, (void *)dh); + } + return &dh->__dynamic_handler_chain; +} +#endif /* GCC_2_8_MADE_THREAD_AWARE */ + +/* + * Threaded process initialization + */ +void +_thread_init(void) +{ + int fd; + int flags; + int i; + size_t len; + int mib[2]; + struct timeval tv; + struct clockinfo clockinfo; + struct sigaction act; + + /* Check if this function has already been called: */ + if (_thread_initial) + /* Only initialise the threaded application once. */ + return; + + /* + * Check for the special case of this process running as + * or in place of init as pid = 1: + */ + if (getpid() == 1) { + /* + * Setup a new session for this process which is + * assumed to be running as root. + */ + if (setsid() == -1) + PANIC("Can't set session ID"); + if (revoke(_PATH_CONSOLE) != 0) + PANIC("Can't revoke console"); + if ((fd = _thread_sys_open(_PATH_CONSOLE, O_RDWR)) < 0) + PANIC("Can't open console"); + if (setlogin("root") == -1) + PANIC("Can't set login to root"); + if (_thread_sys_ioctl(fd,TIOCSCTTY, (char *) NULL) == -1) + PANIC("Can't set controlling terminal"); + if (_thread_sys_dup2(fd,0) == -1 || + _thread_sys_dup2(fd,1) == -1 || + _thread_sys_dup2(fd,2) == -1) + PANIC("Can't dup2"); + } + + /* Get the standard I/O flags before messing with them : */ + for (i = 0; i < 3; i++) + if (((_pthread_stdio_flags[i] = + _thread_sys_fcntl(i,F_GETFL, NULL)) == -1) && + (errno != EBADF)) + PANIC("Cannot get stdio flags"); + + /* + * Create a pipe that is written to by the signal handler to prevent + * signals being missed in calls to _select: + */ + 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 and initialize the ready queue: */ + else if (_pq_alloc(&_readyq, PTHREAD_MIN_PRIORITY, PTHREAD_MAX_PRIORITY) != 0) { + /* Abort this application: */ + PANIC("Cannot allocate priority ready queue."); + } + /* 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)); + _thread_kern_thread.flags = PTHREAD_FLAGS_PRIVATE; + memset(_thread_initial, 0, sizeof(struct pthread)); + + /* Initialize the waiting and work queues: */ + TAILQ_INIT(&_waitingq); + TAILQ_INIT(&_workq); + + /* Initialize the scheduling switch hook routine: */ + _sched_switch_hook = NULL; + + /* Give this thread default attributes: */ + memcpy((void *) &_thread_initial->attr, &pthread_attr_default, + sizeof(struct pthread_attr)); + + /* Initialize the thread stack cache: */ + SLIST_INIT(&_stackq); + + /* + * Create a red zone below the main stack. All other stacks are + * constrained to a maximum size by the paramters passed to + * mmap(), but this stack is only limited by resource limits, so + * this stack needs an explicitly mapped red zone to protect the + * thread stack that is just beyond. + */ + if (mmap((void *) USRSTACK - PTHREAD_STACK_INITIAL - + PTHREAD_STACK_GUARD, PTHREAD_STACK_GUARD, 0, MAP_ANON, + -1, 0) == MAP_FAILED) + PANIC("Cannot allocate red zone for initial thread"); + + /* Set the main thread stack pointer. */ + _thread_initial->stack = (void *) USRSTACK - + PTHREAD_STACK_INITIAL; + + /* Set the stack attributes: */ + _thread_initial->attr.stackaddr_attr = _thread_initial->stack; + _thread_initial->attr.stacksize_attr = PTHREAD_STACK_INITIAL; + + /* + * Write a magic value to the thread structure + * to help identify valid ones: + */ + _thread_initial->magic = PTHREAD_MAGIC; + + /* Set the initial cancel state */ + _thread_initial->cancelflags = PTHREAD_CANCEL_ENABLE | + PTHREAD_CANCEL_DEFERRED; + + /* Default the priority of the initial thread: */ + _thread_initial->base_priority = PTHREAD_DEFAULT_PRIORITY; + _thread_initial->active_priority = PTHREAD_DEFAULT_PRIORITY; + _thread_initial->inherited_priority = 0; + + /* Initialise the state of the initial thread: */ + _thread_initial->state = PS_RUNNING; + + /* Initialise the queue: */ + TAILQ_INIT(&(_thread_initial->join_queue)); + + /* Initialize the owned mutex queue and count: */ + TAILQ_INIT(&(_thread_initial->mutexq)); + _thread_initial->priority_mutex_count = 0; + + /* Initialize last active time to now: */ + gettimeofday(&tv, NULL); + _thread_initial->last_active.tv_sec = tv.tv_sec; + _thread_initial->last_active.tv_usec = tv.tv_usec; + + /* Initialise the rest of the fields: */ + _thread_initial->poll_data.nfds = 0; + _thread_initial->poll_data.fds = NULL; + _thread_initial->sig_defer_count = 0; + _thread_initial->yield_on_sig_undefer = 0; + _thread_initial->specific_data = NULL; + _thread_initial->cleanup = NULL; + _thread_initial->flags = 0; + _thread_initial->error = 0; + TAILQ_INIT(&_thread_list); + TAILQ_INSERT_HEAD(&_thread_list, _thread_initial, tle); + _thread_run = _thread_initial; + + /* Initialise the global signal action structure: */ + sigfillset(&act.sa_mask); + act.sa_handler = (void (*) ()) _thread_sig_handler; + act.sa_flags = 0; + + /* Initialize signal handling: */ + _thread_sig_init(); + + /* 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, + &_thread_sigact[i - 1]) != 0) { + /* + * Abort this process if signal + * initialisation fails: + */ + PANIC("Cannot read signal handler info"); + } + + /* Initialize the SIG_DFL dummy handler count. */ + _thread_dfl_count[i] = 0; + } + + /* + * Install the signal handler for the most important + * signals that the user-thread kernel needs. Actually + * SIGINFO isn't really needed, but it is nice to have. + */ + if (_thread_sys_sigaction(_SCHED_SIGNAL, &act, NULL) != 0 || + _thread_sys_sigaction(SIGINFO, &act, NULL) != 0 || + _thread_sys_sigaction(SIGCHLD, &act, NULL) != 0) { + /* + * Abort this process if signal initialisation fails: + */ + PANIC("Cannot initialise signal handler"); + } + + /* Get the kernel clockrate: */ + mib[0] = CTL_KERN; + mib[1] = KERN_CLOCKRATE; + len = sizeof (struct clockinfo); + if (sysctl(mib, 2, &clockinfo, &len, NULL, 0) == 0) + _clock_res_nsec = clockinfo.tick * 1000; + + /* 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) { + /* Avoid accesses to file descriptor table on exit: */ + _thread_dtablesize = 0; + + /* + * Cannot allocate memory for the file descriptor + * table, so abort this process. + */ + PANIC("Cannot allocate memory for file descriptor table"); + } + /* Allocate memory for the pollfd table: */ + if ((_thread_pfd_table = (struct pollfd *) malloc(sizeof(struct pollfd) * _thread_dtablesize)) == NULL) { + /* + * Cannot allocate memory for the file descriptor + * table, so abort this process. + */ + PANIC("Cannot allocate memory for pollfd 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; + } + + /* Initialize stdio file descriptor table entries: */ + for (i = 0; i < 3; i++) { + if ((_thread_fd_table_init(i) != 0) && + (errno != EBADF)) + PANIC("Cannot initialize stdio file " + "descriptor table entry"); + } + } + } + +#ifdef GCC_2_8_MADE_THREAD_AWARE + /* Create the thread-specific data for the exception linked list. */ + if(pthread_key_create(&except_head_key, NULL) != 0) + PANIC("Failed to create thread specific execption head"); + + /* Setup the gcc exception handler per thread. */ + __set_dynamic_handler_allocator( dynamic_allocator_handler_fn ); +#endif /* GCC_2_8_MADE_THREAD_AWARE */ + + /* Initialise the garbage collector mutex and condition variable. */ + if (pthread_mutex_init(&_gc_mutex,NULL) != 0 || + pthread_cond_init(&_gc_cond,NULL) != 0) + PANIC("Failed to initialise garbage collector mutex or condvar"); + + gettimeofday(&kern_inc_prio_time, NULL); + + return; +} + +/* + * Special start up code for NetBSD/Alpha + */ +#if defined(__NetBSD__) && defined(__alpha__) +int +main(int argc, char *argv[], char *env); + +int +_thread_main(int argc, char *argv[], char *env) +{ + _thread_init(); + return (main(argc, argv, env)); +} +#endif +#else +/* + * A stub for non-threaded programs. + */ +void +_thread_init(void) +{ +} +#endif diff --git a/lib/libpthread/thread/thr_join.c b/lib/libpthread/thread/thr_join.c new file mode 100644 index 0000000..1cffc96 --- /dev/null +++ b/lib/libpthread/thread/thr_join.c @@ -0,0 +1,125 @@ +/* + * 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <errno.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +int +pthread_join(pthread_t pthread, void **thread_return) +{ + int ret = 0; + pthread_t pthread1 = NULL; + + _thread_enter_cancellation_point(); + + /* Check if the caller has specified an invalid thread: */ + if (pthread == NULL || pthread->magic != PTHREAD_MAGIC) { + /* Invalid thread: */ + _thread_leave_cancellation_point(); + return(EINVAL); + } + + /* Check if the caller has specified itself: */ + if (pthread == _thread_run) { + /* Avoid a deadlock condition: */ + _thread_leave_cancellation_point(); + return(EDEADLK); + } + + /* + * Find the thread in the list of active threads or in the + * list of dead threads: + */ + if (_find_thread(pthread) == 0 || + _find_dead_thread(pthread) == 0) + pthread1 = pthread; + + if (pthread1 == NULL) + /* Return an error: */ + ret = ESRCH; + + /* Check if this thread has been detached: */ + else if ((pthread->attr.flags & PTHREAD_DETACHED) != 0) + /* Return an error: */ + ret = ESRCH; + + /* Check if the thread is not dead: */ + else if (pthread->state != PS_DEAD) { + /* Clear the interrupted flag: */ + _thread_run->interrupted = 0; + + /* + * Protect against being context switched out while + * adding this thread to the join queue. + */ + _thread_kern_sig_defer(); + + /* Add the running thread to the join queue: */ + TAILQ_INSERT_TAIL(&(pthread->join_queue), _thread_run, qe); + + /* Schedule the next thread: */ + _thread_kern_sched_state(PS_JOIN, __FILE__, __LINE__); + + if (_thread_run->interrupted != 0) + TAILQ_REMOVE(&(pthread->join_queue), _thread_run, qe); + + _thread_kern_sig_undefer(); + + if (_thread_run->interrupted != 0 && + _thread_run->continuation != NULL) + _thread_run->continuation(_thread_run); + + /* 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: */ + ret = ESRCH; + + /* Check if the return value is required: */ + } else if (thread_return != NULL) + /* Return the thread's return value: */ + *thread_return = pthread->ret; + + _thread_leave_cancellation_point(); + + /* Return the completion status: */ + return (ret); +} +#endif diff --git a/lib/libpthread/thread/thr_kern.c b/lib/libpthread/thread/thr_kern.c new file mode 100644 index 0000000..96a11da --- /dev/null +++ b/lib/libpthread/thread/thr_kern.c @@ -0,0 +1,1174 @@ +/* + * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by John Birrell. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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. + * + * $FreeBSD$ + * + */ +#include <errno.h> +#include <poll.h> +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <unistd.h> +#include <setjmp.h> +#include <sys/param.h> +#include <sys/types.h> +#include <sys/signalvar.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 function prototype definitions: */ +static void +_thread_kern_poll(int wait_reqd); + +static void +dequeue_signals(void); + +static inline void +thread_run_switch_hook(pthread_t thread_out, pthread_t thread_in); + +void +_thread_kern_sched(ucontext_t * scp) +{ +#ifndef __alpha__ + char *fdata; +#endif + pthread_t pthread, pthread_h = NULL; + struct itimerval itimer; + struct timespec ts, ts1; + struct timeval tv, tv1; + int set_timer = 0; + + /* + * Flag the pthread kernel as executing scheduler code + * to avoid a scheduler signal from interrupting this + * execution and calling the scheduler again. + */ + _thread_kern_in_sched = 1; + + /* Check if this function was called from the signal handler: */ + if (scp != NULL) { + /* + * 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 (setjmp(_thread_run->saved_jmp_buf) != 0) { + /* + * This point is reached when a longjmp() is called to + * restore the state of a thread. + * + * This is the normal way out of the scheduler. + */ + _thread_kern_in_sched = 0; + + if (((_thread_run->cancelflags & PTHREAD_AT_CANCEL_POINT) == 0) && + ((_thread_run->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS) != 0)) { + /* + * Cancellations override signals. + * + * Stick a cancellation point at the start of + * each async-cancellable thread's resumption. + * + * We allow threads woken at cancel points to do their + * own checks. + */ + pthread_testcancel(); + } + + /* + * Check for undispatched signals due to calls to + * pthread_kill(). + */ + if (SIGNOTEMPTY(_thread_run->sigpend)) + _dispatch_signals(); + + if (_sched_switch_hook != NULL) { + /* Run the installed switch hook: */ + thread_run_switch_hook(_last_user_thread, _thread_run); + } + + return; + } else + /* Flag the jump buffer was the last state saved: */ + _thread_run->sig_saved = 0; + + /* If the currently running thread is a user thread, save it: */ + if ((_thread_run->flags & PTHREAD_FLAGS_PRIVATE) == 0) + _last_user_thread = _thread_run; + + /* + * Enter a 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 (!(TAILQ_EMPTY(&_thread_list))) { + /* Get the current time of day: */ + gettimeofday(&tv, NULL); + TIMEVAL_TO_TIMESPEC(&tv, &ts); + + /* + * Protect the scheduling queues from access by the signal + * handler. + */ + _queue_signals = 1; + + if (_thread_run != &_thread_kern_thread) { + + /* + * This thread no longer needs to yield the CPU. + */ + _thread_run->yield_on_sig_undefer = 0; + + /* + * 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; + + /* + * Place the currently running thread into the + * appropriate queue(s). + */ + switch (_thread_run->state) { + case PS_DEAD: + case PS_STATE_MAX: /* to silence -Wall */ + case PS_SUSPENDED: + /* + * Dead and suspended threads are not placed + * in any queue: + */ + break; + + case PS_RUNNING: + /* + * Runnable threads can't be placed in the + * priority queue until after waiting threads + * are polled (to preserve round-robin + * scheduling). + */ + if ((_thread_run->slice_usec != -1) && + (_thread_run->attr.sched_policy != SCHED_FIFO)) { + /* + * 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 for time quantum exceeded: */ + if (_thread_run->slice_usec > TIMESLICE_USEC) + _thread_run->slice_usec = -1; + } + break; + + /* + * States which do not depend on file descriptor I/O + * operations or timeouts: + */ + case PS_DEADLOCK: + case PS_FDLR_WAIT: + case PS_FDLW_WAIT: + case PS_FILE_WAIT: + case PS_JOIN: + case PS_MUTEX_WAIT: + case PS_SIGSUSPEND: + case PS_SIGTHREAD: + case PS_SIGWAIT: + case PS_WAIT_WAIT: + /* No timeouts for these states: */ + _thread_run->wakeup_time.tv_sec = -1; + _thread_run->wakeup_time.tv_nsec = -1; + + /* Restart the time slice: */ + _thread_run->slice_usec = -1; + + /* Insert into the waiting queue: */ + PTHREAD_WAITQ_INSERT(_thread_run); + break; + + /* States which can timeout: */ + case PS_COND_WAIT: + case PS_SLEEP_WAIT: + /* Restart the time slice: */ + _thread_run->slice_usec = -1; + + /* Insert into the waiting queue: */ + PTHREAD_WAITQ_INSERT(_thread_run); + break; + + /* States that require periodic work: */ + case PS_SPINBLOCK: + /* No timeouts for this state: */ + _thread_run->wakeup_time.tv_sec = -1; + _thread_run->wakeup_time.tv_nsec = -1; + + /* Increment spinblock count: */ + _spinblock_count++; + + /* fall through */ + case PS_FDR_WAIT: + case PS_FDW_WAIT: + case PS_POLL_WAIT: + case PS_SELECT_WAIT: + /* Restart the time slice: */ + _thread_run->slice_usec = -1; + + /* Insert into the waiting queue: */ + PTHREAD_WAITQ_INSERT(_thread_run); + + /* Insert into the work queue: */ + PTHREAD_WORKQ_INSERT(_thread_run); + break; + } + } + + /* Unprotect the scheduling queues: */ + _queue_signals = 0; + + /* + * Poll file descriptors to update the state of threads + * waiting on file I/O where data may be available: + */ + _thread_kern_poll(0); + + /* Protect the scheduling queues: */ + _queue_signals = 1; + + /* + * Wake up threads that have timedout. This has to be + * done after polling in case a thread does a poll or + * select with zero time. + */ + PTHREAD_WAITQ_SETACTIVE(); + while (((pthread = TAILQ_FIRST(&_waitingq)) != NULL) && + (pthread->wakeup_time.tv_sec != -1) && + (((pthread->wakeup_time.tv_sec == 0) && + (pthread->wakeup_time.tv_nsec == 0)) || + (pthread->wakeup_time.tv_sec < ts.tv_sec) || + ((pthread->wakeup_time.tv_sec == ts.tv_sec) && + (pthread->wakeup_time.tv_nsec <= ts.tv_nsec)))) { + switch (pthread->state) { + case PS_POLL_WAIT: + case PS_SELECT_WAIT: + /* Return zero file descriptors ready: */ + pthread->data.poll_data->nfds = 0; + /* fall through */ + default: + /* + * Remove this thread from the waiting queue + * (and work queue if necessary) and place it + * in the ready queue. + */ + PTHREAD_WAITQ_CLEARACTIVE(); + if (pthread->flags & PTHREAD_FLAGS_IN_WORKQ) + PTHREAD_WORKQ_REMOVE(pthread); + PTHREAD_NEW_STATE(pthread, PS_RUNNING); + PTHREAD_WAITQ_SETACTIVE(); + break; + } + /* + * Flag the timeout in the thread structure: + */ + pthread->timeout = 1; + } + PTHREAD_WAITQ_CLEARACTIVE(); + + /* + * Check if there is a current runnable thread that isn't + * already in the ready queue: + */ + if ((_thread_run != &_thread_kern_thread) && + (_thread_run->state == PS_RUNNING) && + ((_thread_run->flags & PTHREAD_FLAGS_IN_PRIOQ) == 0)) { + if (_thread_run->slice_usec == -1) { + /* + * The thread exceeded its time + * quantum or it yielded the CPU; + * place it at the tail of the + * queue for its priority. + */ + PTHREAD_PRIOQ_INSERT_TAIL(_thread_run); + } else { + /* + * The thread hasn't exceeded its + * interval. Place it at the head + * of the queue for its priority. + */ + PTHREAD_PRIOQ_INSERT_HEAD(_thread_run); + } + } + + /* + * Get the highest priority thread in the ready queue. + */ + pthread_h = PTHREAD_PRIOQ_FIRST(); + + /* Check if there are no threads ready to run: */ + if (pthread_h == 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; + + /* Unprotect the scheduling queues: */ + _queue_signals = 0; + + /* + * There are no threads ready to run, so wait until + * something happens that changes this condition: + */ + _thread_kern_poll(1); + } else { + /* Remove the thread from the ready queue: */ + PTHREAD_PRIOQ_REMOVE(pthread_h); + + /* Get first thread on the waiting list: */ + pthread = TAILQ_FIRST(&_waitingq); + + /* Check to see if there is more than one thread: */ + if (pthread_h != TAILQ_FIRST(&_thread_list) || + TAILQ_NEXT(pthread_h, tle) != NULL) + set_timer = 1; + else + set_timer = 0; + + /* Unprotect the scheduling queues: */ + _queue_signals = 0; + + /* + * Check for signals queued while the scheduling + * queues were protected: + */ + while (_sigq_check_reqd != 0) { + /* Clear before handling queued signals: */ + _sigq_check_reqd = 0; + + /* Protect the scheduling queues again: */ + _queue_signals = 1; + + dequeue_signals(); + + /* + * Check for a higher priority thread that + * became runnable due to signal handling. + */ + if (((pthread = PTHREAD_PRIOQ_FIRST()) != NULL) && + (pthread->active_priority > pthread_h->active_priority)) { + /* + * Insert the lower priority thread + * at the head of its priority list: + */ + PTHREAD_PRIOQ_INSERT_HEAD(pthread_h); + + /* Remove the thread from the ready queue: */ + PTHREAD_PRIOQ_REMOVE(pthread); + + /* There's a new thread in town: */ + pthread_h = pthread; + } + + /* Get first thread on the waiting list: */ + pthread = TAILQ_FIRST(&_waitingq); + + /* + * Check to see if there is more than one + * thread: + */ + if (pthread_h != TAILQ_FIRST(&_thread_list) || + TAILQ_NEXT(pthread_h, tle) != NULL) + set_timer = 1; + else + set_timer = 0; + + /* Unprotect the scheduling queues: */ + _queue_signals = 0; + } + + /* Make the selected thread the current thread: */ + _thread_run = pthread_h; + + /* + * 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; + + /* + * Define the maximum time before a scheduling signal + * 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; + + /* Get first thread on the waiting list: */ + if ((pthread != NULL) && + (pthread->wakeup_time.tv_sec != -1)) { + /* + * Calculate the time until this thread + * is ready, allowing for the clock + * resolution: + */ + 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; + + /* + * Check for underflow of the nanosecond field: + */ + while (ts1.tv_nsec < 0) { + /* + * Allow for the underflow of the + * nanosecond field: + */ + ts1.tv_sec--; + ts1.tv_nsec += 1000000000; + } + /* + * Check for overflow of the nanosecond field: + */ + while (ts1.tv_nsec >= 1000000000) { + /* + * Allow for the overflow of the + * nanosecond field: + */ + ts1.tv_sec++; + ts1.tv_nsec -= 1000000000; + } + /* + * Convert the timespec structure to a + * timeval structure: + */ + TIMESPEC_TO_TIMEVAL(&tv1, &ts1); + + /* + * Check if the thread will be ready + * sooner than the earliest ones found + * so far: + */ + if (timercmp(&tv1, &itimer.it_value, <)) { + /* + * Update the time value: + */ + itimer.it_value.tv_sec = tv1.tv_sec; + itimer.it_value.tv_usec = tv1.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; + } + + /* Check if there is more than one thread: */ + if (set_timer != 0) { + /* + * Start the interval timer for the + * calculated time interval: + */ + if (setitimer(_ITIMER_SCHED_TIMER, &itimer, NULL) != 0) { + /* + * Cannot initialise the timer, so + * abort this process: + */ + PANIC("Cannot set scheduling timer"); + } + } + + /* + * Check if this thread is being continued from a + * longjmp() out of a signal handler: + */ + if ((_thread_run->jmpflags & JMPFLAGS_LONGJMP) != 0) { + _thread_run->jmpflags = 0; + __longjmp(_thread_run->nested_jmp.jmp, + _thread_run->longjmp_val); + } + /* + * Check if this thread is being continued from a + * _longjmp() out of a signal handler: + */ + else if ((_thread_run->jmpflags & JMPFLAGS__LONGJMP) != + 0) { + _thread_run->jmpflags = 0; + ___longjmp(_thread_run->nested_jmp.jmp, + _thread_run->longjmp_val); + } + /* + * Check if this thread is being continued from a + * siglongjmp() out of a signal handler: + */ + else if ((_thread_run->jmpflags & JMPFLAGS_SIGLONGJMP) + != 0) { + _thread_run->jmpflags = 0; + __siglongjmp( + _thread_run->nested_jmp.sigjmp, + _thread_run->longjmp_val); + } + /* Check if a signal context was saved: */ + else 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_kern_in_sched = 0; + + /* + * If we had a context switch, run any + * installed switch hooks. + */ + if ((_sched_switch_hook != NULL) && + (_last_user_thread != _thread_run)) { + thread_run_switch_hook(_last_user_thread, + _thread_run); + } + _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): + */ + __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); +} + +void +_thread_kern_sched_state(enum pthread_state state, char *fname, int lineno) +{ + /* + * Flag the pthread kernel as executing scheduler code + * to avoid a scheduler signal from interrupting this + * execution and calling the scheduler again. + */ + _thread_kern_in_sched = 1; + + /* + * Prevent the signal handler from fiddling with this thread + * before its state is set and is placed into the proper queue. + */ + _queue_signals = 1; + + /* Change the state of the current thread: */ + _thread_run->state = state; + _thread_run->fname = fname; + _thread_run->lineno = lineno; + + /* Schedule the next thread that is ready: */ + _thread_kern_sched(NULL); + return; +} + +void +_thread_kern_sched_state_unlock(enum pthread_state state, + spinlock_t *lock, char *fname, int lineno) +{ + /* + * Flag the pthread kernel as executing scheduler code + * to avoid a scheduler signal from interrupting this + * execution and calling the scheduler again. + */ + _thread_kern_in_sched = 1; + + /* + * Prevent the signal handler from fiddling with this thread + * before its state is set and it is placed into the proper + * queue(s). + */ + _queue_signals = 1; + + /* Change the state of the current thread: */ + _thread_run->state = state; + _thread_run->fname = fname; + _thread_run->lineno = lineno; + + _SPINUNLOCK(lock); + + /* Schedule the next thread that is ready: */ + _thread_kern_sched(NULL); + return; +} + +static void +_thread_kern_poll(int wait_reqd) +{ + int count = 0; + int i, found; + int kern_pipe_added = 0; + int nfds = 0; + int timeout_ms = 0; + struct pthread *pthread; + struct timespec ts; + struct timeval tv; + + /* Check if the caller wants to wait: */ + if (wait_reqd == 0) { + timeout_ms = 0; + } + else { + /* Get the current time of day: */ + gettimeofday(&tv, NULL); + TIMEVAL_TO_TIMESPEC(&tv, &ts); + + _queue_signals = 1; + pthread = TAILQ_FIRST(&_waitingq); + _queue_signals = 0; + + if ((pthread == NULL) || (pthread->wakeup_time.tv_sec == -1)) { + /* + * Either there are no threads in the waiting queue, + * or there are no threads that can timeout. + */ + timeout_ms = INFTIM; + } + else { + /* + * Calculate the time left for the next thread to + * timeout allowing for the clock resolution: + */ + timeout_ms = ((pthread->wakeup_time.tv_sec - ts.tv_sec) * + 1000) + ((pthread->wakeup_time.tv_nsec - ts.tv_nsec + + _clock_res_nsec) / 1000000); + /* + * Don't allow negative timeouts: + */ + if (timeout_ms < 0) + timeout_ms = 0; + } + } + + /* Protect the scheduling queues: */ + _queue_signals = 1; + + /* + * Check to see if the signal queue needs to be walked to look + * for threads awoken by a signal while in the scheduler. + */ + if (_sigq_check_reqd != 0) { + /* Reset flag before handling queued signals: */ + _sigq_check_reqd = 0; + + dequeue_signals(); + } + + /* + * Check for a thread that became runnable due to a signal: + */ + if (PTHREAD_PRIOQ_FIRST() != NULL) { + /* + * Since there is at least one runnable thread, + * disable the wait. + */ + timeout_ms = 0; + } + + /* + * Form the poll table: + */ + nfds = 0; + if (timeout_ms != 0) { + /* Add the kernel pipe to the poll table: */ + _thread_pfd_table[nfds].fd = _thread_kern_pipe[0]; + _thread_pfd_table[nfds].events = POLLRDNORM; + _thread_pfd_table[nfds].revents = 0; + nfds++; + kern_pipe_added = 1; + } + + PTHREAD_WAITQ_SETACTIVE(); + TAILQ_FOREACH(pthread, &_workq, qe) { + switch (pthread->state) { + case PS_SPINBLOCK: + /* + * If the lock is available, let the thread run. + */ + if (pthread->data.spinlock->access_lock == 0) { + PTHREAD_WAITQ_CLEARACTIVE(); + PTHREAD_WORKQ_REMOVE(pthread); + PTHREAD_NEW_STATE(pthread,PS_RUNNING); + PTHREAD_WAITQ_SETACTIVE(); + /* One less thread in a spinblock state: */ + _spinblock_count--; + /* + * Since there is at least one runnable + * thread, disable the wait. + */ + timeout_ms = 0; + } + break; + + /* File descriptor read wait: */ + case PS_FDR_WAIT: + /* Limit number of polled files to table size: */ + if (nfds < _thread_dtablesize) { + _thread_pfd_table[nfds].events = POLLRDNORM; + _thread_pfd_table[nfds].fd = pthread->data.fd.fd; + nfds++; + } + break; + + /* File descriptor write wait: */ + case PS_FDW_WAIT: + /* Limit number of polled files to table size: */ + if (nfds < _thread_dtablesize) { + _thread_pfd_table[nfds].events = POLLWRNORM; + _thread_pfd_table[nfds].fd = pthread->data.fd.fd; + nfds++; + } + break; + + /* File descriptor poll or select wait: */ + case PS_POLL_WAIT: + case PS_SELECT_WAIT: + /* Limit number of polled files to table size: */ + if (pthread->data.poll_data->nfds + nfds < + _thread_dtablesize) { + for (i = 0; i < pthread->data.poll_data->nfds; i++) { + _thread_pfd_table[nfds + i].fd = + pthread->data.poll_data->fds[i].fd; + _thread_pfd_table[nfds + i].events = + pthread->data.poll_data->fds[i].events; + } + nfds += pthread->data.poll_data->nfds; + } + break; + + /* Other states do not depend on file I/O. */ + default: + break; + } + } + PTHREAD_WAITQ_CLEARACTIVE(); + + /* + * Wait for a file descriptor to be ready for read, write, or + * an exception, or a timeout to occur: + */ + count = _thread_sys_poll(_thread_pfd_table, nfds, timeout_ms); + + if (kern_pipe_added != 0) + /* + * Remove the pthread kernel pipe file descriptor + * from the pollfd table: + */ + nfds = 1; + else + nfds = 0; + + /* + * Check if it is possible that there are bytes in the kernel + * read pipe waiting to be read: + */ + if (count < 0 || ((kern_pipe_added != 0) && + (_thread_pfd_table[0].revents & POLLRDNORM))) { + /* + * If the kernel read pipe was included in the + * count: + */ + if (count > 0) { + /* Decrement the count of file descriptors: */ + count--; + } + + if (_sigq_check_reqd != 0) { + /* Reset flag before handling signals: */ + _sigq_check_reqd = 0; + + dequeue_signals(); + } + } + + /* + * Check if any file descriptors are ready: + */ + if (count > 0) { + /* + * Enter a loop to look for threads waiting on file + * descriptors that are flagged as available by the + * _poll syscall: + */ + PTHREAD_WAITQ_SETACTIVE(); + TAILQ_FOREACH(pthread, &_workq, qe) { + switch (pthread->state) { + case PS_SPINBLOCK: + /* + * If the lock is available, let the thread run. + */ + if (pthread->data.spinlock->access_lock == 0) { + PTHREAD_WAITQ_CLEARACTIVE(); + PTHREAD_WORKQ_REMOVE(pthread); + PTHREAD_NEW_STATE(pthread,PS_RUNNING); + PTHREAD_WAITQ_SETACTIVE(); + + /* + * One less thread in a spinblock state: + */ + _spinblock_count--; + } + break; + + /* File descriptor read wait: */ + case PS_FDR_WAIT: + if ((nfds < _thread_dtablesize) && + (_thread_pfd_table[nfds].revents & POLLRDNORM)) { + PTHREAD_WAITQ_CLEARACTIVE(); + PTHREAD_WORKQ_REMOVE(pthread); + PTHREAD_NEW_STATE(pthread,PS_RUNNING); + PTHREAD_WAITQ_SETACTIVE(); + } + nfds++; + break; + + /* File descriptor write wait: */ + case PS_FDW_WAIT: + if ((nfds < _thread_dtablesize) && + (_thread_pfd_table[nfds].revents & POLLWRNORM)) { + PTHREAD_WAITQ_CLEARACTIVE(); + PTHREAD_WORKQ_REMOVE(pthread); + PTHREAD_NEW_STATE(pthread,PS_RUNNING); + PTHREAD_WAITQ_SETACTIVE(); + } + nfds++; + break; + + /* File descriptor poll or select wait: */ + case PS_POLL_WAIT: + case PS_SELECT_WAIT: + if (pthread->data.poll_data->nfds + nfds < + _thread_dtablesize) { + /* + * Enter a loop looking for I/O + * readiness: + */ + found = 0; + for (i = 0; i < pthread->data.poll_data->nfds; i++) { + if (_thread_pfd_table[nfds + i].revents != 0) { + pthread->data.poll_data->fds[i].revents = + _thread_pfd_table[nfds + i].revents; + found++; + } + } + + /* Increment before destroying: */ + nfds += pthread->data.poll_data->nfds; + + if (found != 0) { + pthread->data.poll_data->nfds = found; + PTHREAD_WAITQ_CLEARACTIVE(); + PTHREAD_WORKQ_REMOVE(pthread); + PTHREAD_NEW_STATE(pthread,PS_RUNNING); + PTHREAD_WAITQ_SETACTIVE(); + } + } + else + nfds += pthread->data.poll_data->nfds; + break; + + /* Other states do not depend on file I/O. */ + default: + break; + } + } + PTHREAD_WAITQ_CLEARACTIVE(); + } + else if (_spinblock_count != 0) { + /* + * Enter a loop to look for threads waiting on a spinlock + * that is now available. + */ + PTHREAD_WAITQ_SETACTIVE(); + TAILQ_FOREACH(pthread, &_workq, qe) { + if (pthread->state == PS_SPINBLOCK) { + /* + * If the lock is available, let the thread run. + */ + if (pthread->data.spinlock->access_lock == 0) { + PTHREAD_WAITQ_CLEARACTIVE(); + PTHREAD_WORKQ_REMOVE(pthread); + PTHREAD_NEW_STATE(pthread,PS_RUNNING); + PTHREAD_WAITQ_SETACTIVE(); + + /* + * One less thread in a spinblock state: + */ + _spinblock_count--; + } + } + } + PTHREAD_WAITQ_CLEARACTIVE(); + } + + /* Unprotect the scheduling queues: */ + _queue_signals = 0; + + while (_sigq_check_reqd != 0) { + /* Handle queued signals: */ + _sigq_check_reqd = 0; + + /* Protect the scheduling queues: */ + _queue_signals = 1; + + dequeue_signals(); + + /* Unprotect the scheduling queues: */ + _queue_signals = 0; + } + + /* Nothing to return. */ + return; +} + +void +_thread_kern_set_timeout(const 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.tv_sec = -1; + _thread_run->wakeup_time.tv_nsec = -1; + } + /* Check if no waiting is required: */ + else if (timeout->tv_sec == 0 && timeout->tv_nsec == 0) { + /* Set the wake up time to 'immediately': */ + _thread_run->wakeup_time.tv_sec = 0; + _thread_run->wakeup_time.tv_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.tv_sec = current_time.tv_sec + timeout->tv_sec; + _thread_run->wakeup_time.tv_nsec = current_time.tv_nsec + timeout->tv_nsec; + + /* Check if the nanosecond field needs to wrap: */ + if (_thread_run->wakeup_time.tv_nsec >= 1000000000) { + /* Wrap the nanosecond field: */ + _thread_run->wakeup_time.tv_sec += 1; + _thread_run->wakeup_time.tv_nsec -= 1000000000; + } + } + return; +} + +void +_thread_kern_sig_defer(void) +{ + /* Allow signal deferral to be recursive. */ + _thread_run->sig_defer_count++; +} + +void +_thread_kern_sig_undefer(void) +{ + pthread_t pthread; + int need_resched = 0; + + /* + * Perform checks to yield only if we are about to undefer + * signals. + */ + if (_thread_run->sig_defer_count > 1) { + /* Decrement the signal deferral count. */ + _thread_run->sig_defer_count--; + } + else if (_thread_run->sig_defer_count == 1) { + /* Reenable signals: */ + _thread_run->sig_defer_count = 0; + + /* + * Check if there are queued signals: + */ + while (_sigq_check_reqd != 0) { + /* Defer scheduling while we process queued signals: */ + _thread_run->sig_defer_count = 1; + + /* Clear the flag before checking the signal queue: */ + _sigq_check_reqd = 0; + + /* Dequeue and handle signals: */ + dequeue_signals(); + + /* + * Avoiding an unnecessary check to reschedule, check + * to see if signal handling caused a higher priority + * thread to become ready. + */ + if ((need_resched == 0) && + (((pthread = PTHREAD_PRIOQ_FIRST()) != NULL) && + (pthread->active_priority > _thread_run->active_priority))) { + need_resched = 1; + } + + /* Reenable signals: */ + _thread_run->sig_defer_count = 0; + } + + /* Yield the CPU if necessary: */ + if (need_resched || _thread_run->yield_on_sig_undefer != 0) { + _thread_run->yield_on_sig_undefer = 0; + _thread_kern_sched(NULL); + } + } +} + +static void +dequeue_signals(void) +{ + char bufr[128]; + int i, num; + pthread_t pthread; + + /* + * Enter a loop to read and handle queued signals from the + * pthread kernel pipe: + */ + while (((num = _thread_sys_read(_thread_kern_pipe[0], bufr, + sizeof(bufr))) > 0) || (num == -1 && errno == EINTR)) { + /* + * The buffer read contains one byte per signal and + * each byte is the signal number. + */ + for (i = 0; i < num; i++) { + if ((int) bufr[i] == _SCHED_SIGNAL) { + /* + * Scheduling signals shouldn't ever be + * queued; just ignore it for now. + */ + } + else { + /* Handle this signal: */ + pthread = _thread_sig_handle((int) bufr[i], + NULL); + if (pthread != NULL) + _thread_sig_deliver(pthread, + (int) bufr[i]); + } + } + } + if ((num < 0) && (errno != EAGAIN)) { + /* + * The only error we should expect is if there is + * no data to read. + */ + PANIC("Unable to read from thread kernel pipe"); + } +} + +static inline void +thread_run_switch_hook(pthread_t thread_out, pthread_t thread_in) +{ + pthread_t tid_out = thread_out; + pthread_t tid_in = thread_in; + + if ((tid_out != NULL) && + (tid_out->flags & PTHREAD_FLAGS_PRIVATE) != 0) + tid_out = NULL; + if ((tid_in != NULL) && + (tid_in->flags & PTHREAD_FLAGS_PRIVATE) != 0) + tid_in = NULL; + + if ((_sched_switch_hook != NULL) && (tid_out != tid_in)) { + /* Run the scheduler switch hook: */ + _sched_switch_hook(tid_out, tid_in); + } +} +#endif diff --git a/lib/libpthread/thread/thr_kill.c b/lib/libpthread/thread/thr_kill.c new file mode 100644 index 0000000..4bf1761 --- /dev/null +++ b/lib/libpthread/thread/thr_kill.c @@ -0,0 +1,74 @@ +/* + * Copyright (c) 1997 John Birrell <jb@cimlogic.com.au>. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by John Birrell. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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. + * + * $FreeBSD$ + */ +#include <errno.h> +#include <signal.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +int +pthread_kill(pthread_t pthread, int sig) +{ + int ret; + + /* Check for invalid signal numbers: */ + if (sig < 0 || sig >= NSIG) + /* Invalid signal: */ + ret = EINVAL; + /* + * Ensure the thread is in the list of active threads, and the + * signal is valid (signal 0 specifies error checking only) and + * not being ignored: + */ + else if (((ret = _find_thread(pthread)) == 0) && (sig > 0) && + (_thread_sigact[sig - 1].sa_handler != SIG_IGN)) { + /* + * Defer signals to protect the scheduling queues from + * access by the signal handler: + */ + _thread_kern_sig_defer(); + + _thread_sig_send(pthread, sig); + + /* + * Undefer and handle pending signals, yielding if + * necessary: + */ + _thread_kern_sig_undefer(); + } + + /* Return the completion status: */ + return (ret); +} +#endif diff --git a/lib/libpthread/thread/thr_mattr_init.c b/lib/libpthread/thread/thr_mattr_init.c new file mode 100644 index 0000000..63d4401 --- /dev/null +++ b/lib/libpthread/thread/thr_mattr_init.c @@ -0,0 +1,58 @@ +/* + * Copyright (c) 1996 Jeffrey Hsu <hsu@freebsd.org>. + * 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <string.h> +#include <stdlib.h> +#include <errno.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +int +pthread_mutexattr_init(pthread_mutexattr_t *attr) +{ + int ret; + pthread_mutexattr_t pattr; + + if ((pattr = (pthread_mutexattr_t) + malloc(sizeof(struct pthread_mutex_attr))) == NULL) { + ret = ENOMEM; + } else { + memcpy(pattr, &pthread_mutexattr_default, + sizeof(struct pthread_mutex_attr)); + *attr = pattr; + ret = 0; + } + return(ret); +} +#endif diff --git a/lib/libpthread/thread/thr_mattr_kind_np.c b/lib/libpthread/thread/thr_mattr_kind_np.c new file mode 100644 index 0000000..1a0832f --- /dev/null +++ b/lib/libpthread/thread/thr_mattr_kind_np.c @@ -0,0 +1,94 @@ +/* + * Copyright (c) 1996 Jeffrey Hsu <hsu@freebsd.org>. + * 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <errno.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +int +pthread_mutexattr_setkind_np(pthread_mutexattr_t *attr, int kind) +{ + int ret; + if (attr == NULL || *attr == NULL) { + errno = EINVAL; + ret = -1; + } else { + (*attr)->m_type = kind; + ret = 0; + } + return(ret); +} + +int +pthread_mutexattr_getkind_np(pthread_mutexattr_t attr) +{ + int ret; + if (attr == NULL) { + errno = EINVAL; + ret = -1; + } else { + ret = attr->m_type; + } + return(ret); +} + +int +pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type) +{ + int ret; + if (attr == NULL || *attr == NULL || type >= MUTEX_TYPE_MAX) { + errno = EINVAL; + ret = -1; + } else { + (*attr)->m_type = type; + ret = 0; + } + return(ret); +} + +int +pthread_mutexattr_gettype(pthread_mutexattr_t *attr, int *type) +{ + int ret; + + if (attr == NULL || *attr == NULL || (*attr)->m_type >= + MUTEX_TYPE_MAX) { + ret = EINVAL; + } else { + *type = (*attr)->m_type; + ret = 0; + } + return ret; +} +#endif diff --git a/lib/libpthread/thread/thr_msync.c b/lib/libpthread/thread/thr_msync.c new file mode 100644 index 0000000..2ae6ac7 --- /dev/null +++ b/lib/libpthread/thread/thr_msync.c @@ -0,0 +1,42 @@ +/* + * David Leonard <d@openbsd.org>, 1999. Public Domain. + * + * $OpenBSD: uthread_msync.c,v 1.2 1999/06/09 07:16:17 d Exp $ + * + * $FreeBSD$ + */ + +#include <sys/types.h> +#include <sys/mman.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +int +_msync(void *addr, size_t len, int flags) +{ + int ret; + + ret = _thread_sys_msync(addr, len, flags); + + return (ret); +} + +int +msync(void *addr, size_t len, int flags) +{ + int ret; + + /* + * XXX This is quite pointless unless we know how to get the + * file descriptor associated with the memory, and lock it for + * write. The only real use of this wrapper is to guarantee + * a cancellation point, as per the standard. sigh. + */ + _thread_enter_cancellation_point(); + ret = _msync(addr, len, flags); + _thread_leave_cancellation_point(); + + return ret; +} +#endif diff --git a/lib/libpthread/thread/thr_multi_np.c b/lib/libpthread/thread/thr_multi_np.c new file mode 100644 index 0000000..9a2f7c1 --- /dev/null +++ b/lib/libpthread/thread/thr_multi_np.c @@ -0,0 +1,46 @@ +/* + * Copyright (c) 1996 John Birrell <jb@cimlogic.com.au>. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by John Birrell. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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. + * + * $FreeBSD$ + */ +#include <string.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +int +pthread_multi_np() +{ + /* Return to multi-threaded scheduling mode: */ + _thread_single = NULL; + return(0); +} +#endif diff --git a/lib/libpthread/thread/thr_mutex.c b/lib/libpthread/thread/thr_mutex.c new file mode 100644 index 0000000..b8877f8 --- /dev/null +++ b/lib/libpthread/thread/thr_mutex.c @@ -0,0 +1,1432 @@ +/* + * 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <stdlib.h> +#include <errno.h> +#include <string.h> +#include <sys/param.h> +#include <sys/queue.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +#if defined(_PTHREADS_INVARIANTS) +#define _MUTEX_INIT_LINK(m) do { \ + (m)->m_qe.tqe_prev = NULL; \ + (m)->m_qe.tqe_next = NULL; \ +} while (0) +#define _MUTEX_ASSERT_IS_OWNED(m) do { \ + if ((m)->m_qe.tqe_prev == NULL) \ + PANIC("mutex is not on list"); \ +} while (0) +#define _MUTEX_ASSERT_NOT_OWNED(m) do { \ + if (((m)->m_qe.tqe_prev != NULL) || \ + ((m)->m_qe.tqe_next != NULL)) \ + PANIC("mutex is on list"); \ +} while (0) +#else +#define _MUTEX_INIT_LINK(m) +#define _MUTEX_ASSERT_IS_OWNED(m) +#define _MUTEX_ASSERT_NOT_OWNED(m) +#endif + +/* + * Prototypes + */ +static inline int mutex_self_trylock(pthread_mutex_t); +static inline int mutex_self_lock(pthread_mutex_t); +static inline int mutex_unlock_common(pthread_mutex_t *, int); +static void mutex_priority_adjust(pthread_mutex_t); +static void mutex_rescan_owned (pthread_t, pthread_mutex_t); +static inline pthread_t mutex_queue_deq(pthread_mutex_t); +static inline void mutex_queue_remove(pthread_mutex_t, pthread_t); +static inline void mutex_queue_enq(pthread_mutex_t, pthread_t); + + +static spinlock_t static_init_lock = _SPINLOCK_INITIALIZER; + +/* Reinitialize a mutex to defaults. */ +int +_mutex_reinit(pthread_mutex_t * mutex) +{ + int ret = 0; + + if (mutex == NULL) + ret = EINVAL; + else if (*mutex == NULL) + ret = pthread_mutex_init(mutex, NULL); + else { + /* + * Initialize the mutex structure: + */ + (*mutex)->m_type = PTHREAD_MUTEX_DEFAULT; + (*mutex)->m_protocol = PTHREAD_PRIO_NONE; + TAILQ_INIT(&(*mutex)->m_queue); + (*mutex)->m_owner = NULL; + (*mutex)->m_data.m_count = 0; + (*mutex)->m_flags &= MUTEX_FLAGS_PRIVATE; + (*mutex)->m_flags |= MUTEX_FLAGS_INITED; + (*mutex)->m_refcount = 0; + (*mutex)->m_prio = 0; + (*mutex)->m_saved_prio = 0; + _MUTEX_INIT_LINK(*mutex); + memset(&(*mutex)->lock, 0, sizeof((*mutex)->lock)); + } + return (ret); +} + +int +pthread_mutex_init(pthread_mutex_t * mutex, + const pthread_mutexattr_t * mutex_attr) +{ + enum pthread_mutextype type; + int protocol; + int ceiling; + pthread_mutex_t pmutex; + int ret = 0; + + if (mutex == NULL) + ret = EINVAL; + + /* Check if default mutex attributes: */ + else if (mutex_attr == NULL || *mutex_attr == NULL) { + /* Default to a (error checking) POSIX mutex: */ + type = PTHREAD_MUTEX_ERRORCHECK; + protocol = PTHREAD_PRIO_NONE; + ceiling = PTHREAD_MAX_PRIORITY; + } + + /* Check mutex type: */ + else if (((*mutex_attr)->m_type < PTHREAD_MUTEX_ERRORCHECK) || + ((*mutex_attr)->m_type >= MUTEX_TYPE_MAX)) + /* Return an invalid argument error: */ + ret = EINVAL; + + /* Check mutex protocol: */ + else if (((*mutex_attr)->m_protocol < PTHREAD_PRIO_NONE) || + ((*mutex_attr)->m_protocol > PTHREAD_MUTEX_RECURSIVE)) + /* Return an invalid argument error: */ + ret = EINVAL; + + else { + /* Use the requested mutex type and protocol: */ + type = (*mutex_attr)->m_type; + protocol = (*mutex_attr)->m_protocol; + ceiling = (*mutex_attr)->m_ceiling; + } + + /* Check no errors so far: */ + if (ret == 0) { + if ((pmutex = (pthread_mutex_t) + malloc(sizeof(struct pthread_mutex))) == NULL) + ret = ENOMEM; + else { + /* Reset the mutex flags: */ + pmutex->m_flags = 0; + + /* Process according to mutex type: */ + switch (type) { + /* case PTHREAD_MUTEX_DEFAULT: */ + case PTHREAD_MUTEX_ERRORCHECK: + case PTHREAD_MUTEX_NORMAL: + /* Nothing to do here. */ + break; + + /* Single UNIX Spec 2 recursive mutex: */ + case PTHREAD_MUTEX_RECURSIVE: + /* Reset the mutex count: */ + pmutex->m_data.m_count = 0; + break; + + /* Trap invalid mutex types: */ + default: + /* Return an invalid argument error: */ + ret = EINVAL; + break; + } + if (ret == 0) { + /* Initialise the rest of the mutex: */ + TAILQ_INIT(&pmutex->m_queue); + pmutex->m_flags |= MUTEX_FLAGS_INITED; + pmutex->m_owner = NULL; + pmutex->m_type = type; + pmutex->m_protocol = protocol; + pmutex->m_refcount = 0; + if (protocol == PTHREAD_PRIO_PROTECT) + pmutex->m_prio = ceiling; + else + pmutex->m_prio = 0; + pmutex->m_saved_prio = 0; + _MUTEX_INIT_LINK(pmutex); + memset(&pmutex->lock, 0, sizeof(pmutex->lock)); + *mutex = pmutex; + } else { + free(pmutex); + *mutex = NULL; + } + } + } + /* Return the completion status: */ + return(ret); +} + +int +pthread_mutex_destroy(pthread_mutex_t * mutex) +{ + int ret = 0; + + if (mutex == NULL || *mutex == NULL) + ret = EINVAL; + else { + /* Lock the mutex structure: */ + _SPINLOCK(&(*mutex)->lock); + + /* + * Check to see if this mutex is in use: + */ + if (((*mutex)->m_owner != NULL) || + (TAILQ_FIRST(&(*mutex)->m_queue) != NULL) || + ((*mutex)->m_refcount != 0)) { + ret = EBUSY; + + /* Unlock the mutex structure: */ + _SPINUNLOCK(&(*mutex)->lock); + } + else { + /* + * Free the memory allocated for the mutex + * structure: + */ + _MUTEX_ASSERT_NOT_OWNED(*mutex); + free(*mutex); + + /* + * Leave the caller's pointer NULL now that + * the mutex has been destroyed: + */ + *mutex = NULL; + } + } + + /* Return the completion status: */ + return (ret); +} + +static int +init_static(pthread_mutex_t *mutex) +{ + int ret; + + _SPINLOCK(&static_init_lock); + + if (*mutex == NULL) + ret = pthread_mutex_init(mutex, NULL); + else + ret = 0; + + _SPINUNLOCK(&static_init_lock); + + return(ret); +} + +int +pthread_mutex_trylock(pthread_mutex_t * mutex) +{ + int ret = 0; + + if (mutex == NULL) + ret = EINVAL; + + /* + * If the mutex is statically initialized, perform the dynamic + * initialization: + */ + else if (*mutex != NULL || (ret = init_static(mutex)) == 0) { + /* + * Defer signals to protect the scheduling queues from + * access by the signal handler: + */ + _thread_kern_sig_defer(); + + /* Lock the mutex structure: */ + _SPINLOCK(&(*mutex)->lock); + + /* + * If the mutex was statically allocated, properly + * initialize the tail queue. + */ + if (((*mutex)->m_flags & MUTEX_FLAGS_INITED) == 0) { + TAILQ_INIT(&(*mutex)->m_queue); + _MUTEX_INIT_LINK(*mutex); + (*mutex)->m_flags |= MUTEX_FLAGS_INITED; + } + + /* Process according to mutex type: */ + switch ((*mutex)->m_protocol) { + /* Default POSIX mutex: */ + case PTHREAD_PRIO_NONE: + /* Check if this mutex is not locked: */ + if ((*mutex)->m_owner == NULL) { + /* Lock the mutex for the running thread: */ + (*mutex)->m_owner = _thread_run; + + /* Add to the list of owned mutexes: */ + _MUTEX_ASSERT_NOT_OWNED(*mutex); + TAILQ_INSERT_TAIL(&_thread_run->mutexq, + (*mutex), m_qe); + } else if ((*mutex)->m_owner == _thread_run) + ret = mutex_self_trylock(*mutex); + else + /* Return a busy error: */ + ret = EBUSY; + break; + + /* POSIX priority inheritence mutex: */ + case PTHREAD_PRIO_INHERIT: + /* Check if this mutex is not locked: */ + if ((*mutex)->m_owner == NULL) { + /* Lock the mutex for the running thread: */ + (*mutex)->m_owner = _thread_run; + + /* Track number of priority mutexes owned: */ + _thread_run->priority_mutex_count++; + + /* + * The mutex takes on the attributes of the + * running thread when there are no waiters. + */ + (*mutex)->m_prio = _thread_run->active_priority; + (*mutex)->m_saved_prio = + _thread_run->inherited_priority; + + /* Add to the list of owned mutexes: */ + _MUTEX_ASSERT_NOT_OWNED(*mutex); + TAILQ_INSERT_TAIL(&_thread_run->mutexq, + (*mutex), m_qe); + } else if ((*mutex)->m_owner == _thread_run) + ret = mutex_self_trylock(*mutex); + else + /* Return a busy error: */ + ret = EBUSY; + break; + + /* POSIX priority protection mutex: */ + case PTHREAD_PRIO_PROTECT: + /* Check for a priority ceiling violation: */ + if (_thread_run->active_priority > (*mutex)->m_prio) + ret = EINVAL; + + /* Check if this mutex is not locked: */ + else if ((*mutex)->m_owner == NULL) { + /* Lock the mutex for the running thread: */ + (*mutex)->m_owner = _thread_run; + + /* Track number of priority mutexes owned: */ + _thread_run->priority_mutex_count++; + + /* + * The running thread inherits the ceiling + * priority of the mutex and executes at that + * priority. + */ + _thread_run->active_priority = (*mutex)->m_prio; + (*mutex)->m_saved_prio = + _thread_run->inherited_priority; + _thread_run->inherited_priority = + (*mutex)->m_prio; + + /* Add to the list of owned mutexes: */ + _MUTEX_ASSERT_NOT_OWNED(*mutex); + TAILQ_INSERT_TAIL(&_thread_run->mutexq, + (*mutex), m_qe); + } else if ((*mutex)->m_owner == _thread_run) + ret = mutex_self_trylock(*mutex); + else + /* Return a busy error: */ + ret = EBUSY; + break; + + /* Trap invalid mutex types: */ + default: + /* Return an invalid argument error: */ + ret = EINVAL; + break; + } + + /* Unlock the mutex structure: */ + _SPINUNLOCK(&(*mutex)->lock); + + /* + * Undefer and handle pending signals, yielding if + * necessary: + */ + _thread_kern_sig_undefer(); + } + + /* Return the completion status: */ + return (ret); +} + +int +pthread_mutex_lock(pthread_mutex_t * mutex) +{ + int ret = 0; + + if (mutex == NULL) + ret = EINVAL; + + /* + * If the mutex is statically initialized, perform the dynamic + * initialization: + */ + else if (*mutex != NULL || (ret = init_static(mutex)) == 0) { + /* + * Defer signals to protect the scheduling queues from + * access by the signal handler: + */ + _thread_kern_sig_defer(); + + /* Lock the mutex structure: */ + _SPINLOCK(&(*mutex)->lock); + + /* + * If the mutex was statically allocated, properly + * initialize the tail queue. + */ + if (((*mutex)->m_flags & MUTEX_FLAGS_INITED) == 0) { + TAILQ_INIT(&(*mutex)->m_queue); + (*mutex)->m_flags |= MUTEX_FLAGS_INITED; + _MUTEX_INIT_LINK(*mutex); + } + + /* Reset the interrupted flag: */ + _thread_run->interrupted = 0; + + /* Process according to mutex type: */ + switch ((*mutex)->m_protocol) { + /* Default POSIX mutex: */ + case PTHREAD_PRIO_NONE: + if ((*mutex)->m_owner == NULL) { + /* Lock the mutex for this thread: */ + (*mutex)->m_owner = _thread_run; + + /* Add to the list of owned mutexes: */ + _MUTEX_ASSERT_NOT_OWNED(*mutex); + TAILQ_INSERT_TAIL(&_thread_run->mutexq, + (*mutex), m_qe); + + } else if ((*mutex)->m_owner == _thread_run) + ret = mutex_self_lock(*mutex); + else { + /* + * Join the queue of threads waiting to lock + * the mutex: + */ + mutex_queue_enq(*mutex, _thread_run); + + /* + * Keep a pointer to the mutex this thread + * is waiting on: + */ + _thread_run->data.mutex = *mutex; + + /* + * Unlock the mutex structure and schedule the + * next thread: + */ + _thread_kern_sched_state_unlock(PS_MUTEX_WAIT, + &(*mutex)->lock, __FILE__, __LINE__); + + /* Lock the mutex structure again: */ + _SPINLOCK(&(*mutex)->lock); + } + break; + + /* POSIX priority inheritence mutex: */ + case PTHREAD_PRIO_INHERIT: + /* Check if this mutex is not locked: */ + if ((*mutex)->m_owner == NULL) { + /* Lock the mutex for this thread: */ + (*mutex)->m_owner = _thread_run; + + /* Track number of priority mutexes owned: */ + _thread_run->priority_mutex_count++; + + /* + * The mutex takes on attributes of the + * running thread when there are no waiters. + */ + (*mutex)->m_prio = _thread_run->active_priority; + (*mutex)->m_saved_prio = + _thread_run->inherited_priority; + _thread_run->inherited_priority = + (*mutex)->m_prio; + + /* Add to the list of owned mutexes: */ + _MUTEX_ASSERT_NOT_OWNED(*mutex); + TAILQ_INSERT_TAIL(&_thread_run->mutexq, + (*mutex), m_qe); + + } else if ((*mutex)->m_owner == _thread_run) + ret = mutex_self_lock(*mutex); + else { + /* + * Join the queue of threads waiting to lock + * the mutex: + */ + mutex_queue_enq(*mutex, _thread_run); + + /* + * Keep a pointer to the mutex this thread + * is waiting on: + */ + _thread_run->data.mutex = *mutex; + + if (_thread_run->active_priority > + (*mutex)->m_prio) + /* Adjust priorities: */ + mutex_priority_adjust(*mutex); + + /* + * Unlock the mutex structure and schedule the + * next thread: + */ + _thread_kern_sched_state_unlock(PS_MUTEX_WAIT, + &(*mutex)->lock, __FILE__, __LINE__); + + /* Lock the mutex structure again: */ + _SPINLOCK(&(*mutex)->lock); + } + break; + + /* POSIX priority protection mutex: */ + case PTHREAD_PRIO_PROTECT: + /* Check for a priority ceiling violation: */ + if (_thread_run->active_priority > (*mutex)->m_prio) + ret = EINVAL; + + /* Check if this mutex is not locked: */ + else if ((*mutex)->m_owner == NULL) { + /* + * Lock the mutex for the running + * thread: + */ + (*mutex)->m_owner = _thread_run; + + /* Track number of priority mutexes owned: */ + _thread_run->priority_mutex_count++; + + /* + * The running thread inherits the ceiling + * priority of the mutex and executes at that + * priority: + */ + _thread_run->active_priority = (*mutex)->m_prio; + (*mutex)->m_saved_prio = + _thread_run->inherited_priority; + _thread_run->inherited_priority = + (*mutex)->m_prio; + + /* Add to the list of owned mutexes: */ + _MUTEX_ASSERT_NOT_OWNED(*mutex); + TAILQ_INSERT_TAIL(&_thread_run->mutexq, + (*mutex), m_qe); + } else if ((*mutex)->m_owner == _thread_run) + ret = mutex_self_lock(*mutex); + else { + /* + * Join the queue of threads waiting to lock + * the mutex: + */ + mutex_queue_enq(*mutex, _thread_run); + + /* + * Keep a pointer to the mutex this thread + * is waiting on: + */ + _thread_run->data.mutex = *mutex; + + /* Clear any previous error: */ + _thread_run->error = 0; + + /* + * Unlock the mutex structure and schedule the + * next thread: + */ + _thread_kern_sched_state_unlock(PS_MUTEX_WAIT, + &(*mutex)->lock, __FILE__, __LINE__); + + /* Lock the mutex structure again: */ + _SPINLOCK(&(*mutex)->lock); + + /* + * The threads priority may have changed while + * waiting for the mutex causing a ceiling + * violation. + */ + ret = _thread_run->error; + _thread_run->error = 0; + } + break; + + /* Trap invalid mutex types: */ + default: + /* Return an invalid argument error: */ + ret = EINVAL; + break; + } + + /* + * Check to see if this thread was interrupted and + * is still in the mutex queue of waiting threads: + */ + if (_thread_run->interrupted != 0) { + mutex_queue_remove(*mutex, _thread_run); + } + + /* Unlock the mutex structure: */ + _SPINUNLOCK(&(*mutex)->lock); + + /* + * Undefer and handle pending signals, yielding if + * necessary: + */ + _thread_kern_sig_undefer(); + + if (_thread_run->interrupted != 0 && + _thread_run->continuation != NULL) + _thread_run->continuation((void *) _thread_run); + } + + /* Return the completion status: */ + return (ret); +} + +int +pthread_mutex_unlock(pthread_mutex_t * mutex) +{ + return (mutex_unlock_common(mutex, /* add reference */ 0)); +} + +int +_mutex_cv_unlock(pthread_mutex_t * mutex) +{ + return (mutex_unlock_common(mutex, /* add reference */ 1)); +} + +int +_mutex_cv_lock(pthread_mutex_t * mutex) +{ + int ret; + if ((ret = pthread_mutex_lock(mutex)) == 0) + (*mutex)->m_refcount--; + return (ret); +} + +static inline int +mutex_self_trylock(pthread_mutex_t mutex) +{ + int ret = 0; + + switch (mutex->m_type) { + + /* case PTHREAD_MUTEX_DEFAULT: */ + case PTHREAD_MUTEX_ERRORCHECK: + case PTHREAD_MUTEX_NORMAL: + /* + * POSIX specifies that mutexes should return EDEADLK if a + * recursive lock is detected. + */ + ret = EBUSY; + break; + + case PTHREAD_MUTEX_RECURSIVE: + /* Increment the lock count: */ + mutex->m_data.m_count++; + break; + + default: + /* Trap invalid mutex types; */ + ret = EINVAL; + } + + return(ret); +} + +static inline int +mutex_self_lock(pthread_mutex_t mutex) +{ + int ret = 0; + + switch (mutex->m_type) { + /* case PTHREAD_MUTEX_DEFAULT: */ + case PTHREAD_MUTEX_ERRORCHECK: + /* + * POSIX specifies that mutexes should return EDEADLK if a + * recursive lock is detected. + */ + ret = EDEADLK; + break; + + case PTHREAD_MUTEX_NORMAL: + /* + * What SS2 define as a 'normal' mutex. Intentionally + * deadlock on attempts to get a lock you already own. + */ + _thread_kern_sched_state_unlock(PS_DEADLOCK, + &mutex->lock, __FILE__, __LINE__); + break; + + case PTHREAD_MUTEX_RECURSIVE: + /* Increment the lock count: */ + mutex->m_data.m_count++; + break; + + default: + /* Trap invalid mutex types; */ + ret = EINVAL; + } + + return(ret); +} + +static inline int +mutex_unlock_common(pthread_mutex_t * mutex, int add_reference) +{ + int ret = 0; + + if (mutex == NULL || *mutex == NULL) { + ret = EINVAL; + } else { + /* + * Defer signals to protect the scheduling queues from + * access by the signal handler: + */ + _thread_kern_sig_defer(); + + /* Lock the mutex structure: */ + _SPINLOCK(&(*mutex)->lock); + + /* Process according to mutex type: */ + switch ((*mutex)->m_protocol) { + /* Default POSIX mutex: */ + case PTHREAD_PRIO_NONE: + /* + * Check if the running thread is not the owner of the + * mutex: + */ + if ((*mutex)->m_owner != _thread_run) { + /* + * Return an invalid argument error for no + * owner and a permission error otherwise: + */ + ret = (*mutex)->m_owner == NULL ? EINVAL : EPERM; + } + else if (((*mutex)->m_type == PTHREAD_MUTEX_RECURSIVE) && + ((*mutex)->m_data.m_count > 0)) { + /* Decrement the count: */ + (*mutex)->m_data.m_count--; + } else { + /* + * Clear the count in case this is recursive + * mutex. + */ + (*mutex)->m_data.m_count = 0; + + /* Remove the mutex from the threads queue. */ + _MUTEX_ASSERT_IS_OWNED(*mutex); + TAILQ_REMOVE(&(*mutex)->m_owner->mutexq, + (*mutex), m_qe); + _MUTEX_INIT_LINK(*mutex); + + /* + * Get the next thread from the queue of + * threads waiting on the mutex: + */ + if (((*mutex)->m_owner = + mutex_queue_deq(*mutex)) != NULL) { + /* + * Unless the new owner of the mutex is + * currently suspended, allow the owner + * to run. If the thread is suspended, + * make a note that the thread isn't in + * a wait queue any more. + */ + if (((*mutex)->m_owner->state != + PS_SUSPENDED)) { + PTHREAD_NEW_STATE((*mutex)->m_owner, + PS_RUNNING); + } else { + (*mutex)->m_owner->suspended = + SUSP_NOWAIT; + } + + /* + * Add the mutex to the threads list of + * owned mutexes: + */ + TAILQ_INSERT_TAIL(&(*mutex)->m_owner->mutexq, + (*mutex), m_qe); + + /* + * The owner is no longer waiting for + * this mutex: + */ + (*mutex)->m_owner->data.mutex = NULL; + } + } + break; + + /* POSIX priority inheritence mutex: */ + case PTHREAD_PRIO_INHERIT: + /* + * Check if the running thread is not the owner of the + * mutex: + */ + if ((*mutex)->m_owner != _thread_run) { + /* + * Return an invalid argument error for no + * owner and a permission error otherwise: + */ + ret = (*mutex)->m_owner == NULL ? EINVAL : EPERM; + } + else if (((*mutex)->m_type == PTHREAD_MUTEX_RECURSIVE) && + ((*mutex)->m_data.m_count > 0)) { + /* Decrement the count: */ + (*mutex)->m_data.m_count--; + } else { + /* + * Clear the count in case this is recursive + * mutex. + */ + (*mutex)->m_data.m_count = 0; + + /* + * Restore the threads inherited priority and + * recompute the active priority (being careful + * not to override changes in the threads base + * priority subsequent to locking the mutex). + */ + _thread_run->inherited_priority = + (*mutex)->m_saved_prio; + _thread_run->active_priority = + MAX(_thread_run->inherited_priority, + _thread_run->base_priority); + + /* + * This thread now owns one less priority mutex. + */ + _thread_run->priority_mutex_count--; + + /* Remove the mutex from the threads queue. */ + _MUTEX_ASSERT_IS_OWNED(*mutex); + TAILQ_REMOVE(&(*mutex)->m_owner->mutexq, + (*mutex), m_qe); + _MUTEX_INIT_LINK(*mutex); + + /* + * Get the next thread from the queue of threads + * waiting on the mutex: + */ + if (((*mutex)->m_owner = + mutex_queue_deq(*mutex)) == NULL) + /* This mutex has no priority. */ + (*mutex)->m_prio = 0; + else { + /* + * Track number of priority mutexes owned: + */ + (*mutex)->m_owner->priority_mutex_count++; + + /* + * Add the mutex to the threads list + * of owned mutexes: + */ + TAILQ_INSERT_TAIL(&(*mutex)->m_owner->mutexq, + (*mutex), m_qe); + + /* + * The owner is no longer waiting for + * this mutex: + */ + (*mutex)->m_owner->data.mutex = NULL; + + /* + * Set the priority of the mutex. Since + * our waiting threads are in descending + * priority order, the priority of the + * mutex becomes the active priority of + * the thread we just dequeued. + */ + (*mutex)->m_prio = + (*mutex)->m_owner->active_priority; + + /* + * Save the owning threads inherited + * priority: + */ + (*mutex)->m_saved_prio = + (*mutex)->m_owner->inherited_priority; + + /* + * The owning threads inherited priority + * now becomes his active priority (the + * priority of the mutex). + */ + (*mutex)->m_owner->inherited_priority = + (*mutex)->m_prio; + + /* + * Unless the new owner of the mutex is + * currently suspended, allow the owner + * to run. If the thread is suspended, + * make a note that the thread isn't in + * a wait queue any more. + */ + if (((*mutex)->m_owner->state != + PS_SUSPENDED)) { + PTHREAD_NEW_STATE((*mutex)->m_owner, + PS_RUNNING); + } else { + (*mutex)->m_owner->suspended = + SUSP_NOWAIT; + } + } + } + break; + + /* POSIX priority ceiling mutex: */ + case PTHREAD_PRIO_PROTECT: + /* + * Check if the running thread is not the owner of the + * mutex: + */ + if ((*mutex)->m_owner != _thread_run) { + /* + * Return an invalid argument error for no + * owner and a permission error otherwise: + */ + ret = (*mutex)->m_owner == NULL ? EINVAL : EPERM; + } + else if (((*mutex)->m_type == PTHREAD_MUTEX_RECURSIVE) && + ((*mutex)->m_data.m_count > 0)) { + /* Decrement the count: */ + (*mutex)->m_data.m_count--; + } else { + /* + * Clear the count in case this is recursive + * mutex. + */ + (*mutex)->m_data.m_count = 0; + + /* + * Restore the threads inherited priority and + * recompute the active priority (being careful + * not to override changes in the threads base + * priority subsequent to locking the mutex). + */ + _thread_run->inherited_priority = + (*mutex)->m_saved_prio; + _thread_run->active_priority = + MAX(_thread_run->inherited_priority, + _thread_run->base_priority); + + /* + * This thread now owns one less priority mutex. + */ + _thread_run->priority_mutex_count--; + + /* Remove the mutex from the threads queue. */ + _MUTEX_ASSERT_IS_OWNED(*mutex); + TAILQ_REMOVE(&(*mutex)->m_owner->mutexq, + (*mutex), m_qe); + _MUTEX_INIT_LINK(*mutex); + + /* + * Enter a loop to find a waiting thread whose + * active priority will not cause a ceiling + * violation: + */ + while ((((*mutex)->m_owner = + mutex_queue_deq(*mutex)) != NULL) && + ((*mutex)->m_owner->active_priority > + (*mutex)->m_prio)) { + /* + * Either the mutex ceiling priority + * been lowered and/or this threads + * priority has been raised subsequent + * to this thread being queued on the + * waiting list. + */ + (*mutex)->m_owner->error = EINVAL; + PTHREAD_NEW_STATE((*mutex)->m_owner, + PS_RUNNING); + /* + * The thread is no longer waiting for + * this mutex: + */ + (*mutex)->m_owner->data.mutex = NULL; + } + + /* Check for a new owner: */ + if ((*mutex)->m_owner != NULL) { + /* + * Track number of priority mutexes owned: + */ + (*mutex)->m_owner->priority_mutex_count++; + + /* + * Add the mutex to the threads list + * of owned mutexes: + */ + TAILQ_INSERT_TAIL(&(*mutex)->m_owner->mutexq, + (*mutex), m_qe); + + /* + * The owner is no longer waiting for + * this mutex: + */ + (*mutex)->m_owner->data.mutex = NULL; + + /* + * Save the owning threads inherited + * priority: + */ + (*mutex)->m_saved_prio = + (*mutex)->m_owner->inherited_priority; + + /* + * The owning thread inherits the + * ceiling priority of the mutex and + * executes at that priority: + */ + (*mutex)->m_owner->inherited_priority = + (*mutex)->m_prio; + (*mutex)->m_owner->active_priority = + (*mutex)->m_prio; + + /* + * Unless the new owner of the mutex is + * currently suspended, allow the owner + * to run. If the thread is suspended, + * make a note that the thread isn't in + * a wait queue any more. + */ + if (((*mutex)->m_owner->state != + PS_SUSPENDED)) { + PTHREAD_NEW_STATE((*mutex)->m_owner, + PS_RUNNING); + } else { + (*mutex)->m_owner->suspended = + SUSP_NOWAIT; + } + } + } + break; + + /* Trap invalid mutex types: */ + default: + /* Return an invalid argument error: */ + ret = EINVAL; + break; + } + + if ((ret == 0) && (add_reference != 0)) { + /* Increment the reference count: */ + (*mutex)->m_refcount++; + } + + /* Unlock the mutex structure: */ + _SPINUNLOCK(&(*mutex)->lock); + + /* + * Undefer and handle pending signals, yielding if + * necessary: + */ + _thread_kern_sig_undefer(); + } + + /* Return the completion status: */ + return (ret); +} + + +/* + * This function is called when a change in base priority occurs for + * a thread that is holding or waiting for a priority protection or + * inheritence mutex. A change in a threads base priority can effect + * changes to active priorities of other threads and to the ordering + * of mutex locking by waiting threads. + * + * This must be called while thread scheduling is deferred. + */ +void +_mutex_notify_priochange(pthread_t pthread) +{ + /* Adjust the priorites of any owned priority mutexes: */ + if (pthread->priority_mutex_count > 0) { + /* + * Rescan the mutexes owned by this thread and correct + * their priorities to account for this threads change + * in priority. This has the side effect of changing + * the threads active priority. + */ + mutex_rescan_owned(pthread, /* rescan all owned */ NULL); + } + + /* + * If this thread is waiting on a priority inheritence mutex, + * check for priority adjustments. A change in priority can + * also effect a ceiling violation(*) for a thread waiting on + * a priority protection mutex; we don't perform the check here + * as it is done in pthread_mutex_unlock. + * + * (*) It should be noted that a priority change to a thread + * _after_ taking and owning a priority ceiling mutex + * does not affect ownership of that mutex; the ceiling + * priority is only checked before mutex ownership occurs. + */ + if (pthread->state == PS_MUTEX_WAIT) { + /* Lock the mutex structure: */ + _SPINLOCK(&pthread->data.mutex->lock); + + /* + * Check to make sure this thread is still in the same state + * (the spinlock above can yield the CPU to another thread): + */ + if (pthread->state == PS_MUTEX_WAIT) { + /* + * Remove and reinsert this thread into the list of + * waiting threads to preserve decreasing priority + * order. + */ + mutex_queue_remove(pthread->data.mutex, pthread); + mutex_queue_enq(pthread->data.mutex, pthread); + + if (pthread->data.mutex->m_protocol == + PTHREAD_PRIO_INHERIT) { + /* Adjust priorities: */ + mutex_priority_adjust(pthread->data.mutex); + } + } + + /* Unlock the mutex structure: */ + _SPINUNLOCK(&pthread->data.mutex->lock); + } +} + +/* + * Called when a new thread is added to the mutex waiting queue or + * when a threads priority changes that is already in the mutex + * waiting queue. + */ +static void +mutex_priority_adjust(pthread_mutex_t mutex) +{ + pthread_t pthread_next, pthread = mutex->m_owner; + int temp_prio; + pthread_mutex_t m = mutex; + + /* + * Calculate the mutex priority as the maximum of the highest + * active priority of any waiting threads and the owning threads + * active priority(*). + * + * (*) Because the owning threads current active priority may + * reflect priority inherited from this mutex (and the mutex + * priority may have changed) we must recalculate the active + * priority based on the threads saved inherited priority + * and its base priority. + */ + pthread_next = TAILQ_FIRST(&m->m_queue); /* should never be NULL */ + temp_prio = MAX(pthread_next->active_priority, + MAX(m->m_saved_prio, pthread->base_priority)); + + /* See if this mutex really needs adjusting: */ + if (temp_prio == m->m_prio) + /* No need to propagate the priority: */ + return; + + /* Set new priority of the mutex: */ + m->m_prio = temp_prio; + + while (m != NULL) { + /* + * Save the threads priority before rescanning the + * owned mutexes: + */ + temp_prio = pthread->active_priority; + + /* + * Fix the priorities for all the mutexes this thread has + * locked since taking this mutex. This also has a + * potential side-effect of changing the threads priority. + */ + mutex_rescan_owned(pthread, m); + + /* + * If the thread is currently waiting on a mutex, check + * to see if the threads new priority has affected the + * priority of the mutex. + */ + if ((temp_prio != pthread->active_priority) && + (pthread->state == PS_MUTEX_WAIT) && + (pthread->data.mutex->m_protocol == PTHREAD_PRIO_INHERIT)) { + /* Grab the mutex this thread is waiting on: */ + m = pthread->data.mutex; + + /* + * The priority for this thread has changed. Remove + * and reinsert this thread into the list of waiting + * threads to preserve decreasing priority order. + */ + mutex_queue_remove(m, pthread); + mutex_queue_enq(m, pthread); + + /* Grab the waiting thread with highest priority: */ + pthread_next = TAILQ_FIRST(&m->m_queue); + + /* + * Calculate the mutex priority as the maximum of the + * highest active priority of any waiting threads and + * the owning threads active priority. + */ + temp_prio = MAX(pthread_next->active_priority, + MAX(m->m_saved_prio, m->m_owner->base_priority)); + + if (temp_prio != m->m_prio) { + /* + * The priority needs to be propagated to the + * mutex this thread is waiting on and up to + * the owner of that mutex. + */ + m->m_prio = temp_prio; + pthread = m->m_owner; + } + else + /* We're done: */ + m = NULL; + + } + else + /* We're done: */ + m = NULL; + } +} + +static void +mutex_rescan_owned(pthread_t pthread, pthread_mutex_t mutex) +{ + int active_prio, inherited_prio; + pthread_mutex_t m; + pthread_t pthread_next; + + /* + * Start walking the mutexes the thread has taken since + * taking this mutex. + */ + if (mutex == NULL) { + /* + * A null mutex means start at the beginning of the owned + * mutex list. + */ + m = TAILQ_FIRST(&pthread->mutexq); + + /* There is no inherited priority yet. */ + inherited_prio = 0; + } + else { + /* + * The caller wants to start after a specific mutex. It + * is assumed that this mutex is a priority inheritence + * mutex and that its priority has been correctly + * calculated. + */ + m = TAILQ_NEXT(mutex, m_qe); + + /* Start inheriting priority from the specified mutex. */ + inherited_prio = mutex->m_prio; + } + active_prio = MAX(inherited_prio, pthread->base_priority); + + while (m != NULL) { + /* + * We only want to deal with priority inheritence + * mutexes. This might be optimized by only placing + * priority inheritence mutexes into the owned mutex + * list, but it may prove to be useful having all + * owned mutexes in this list. Consider a thread + * exiting while holding mutexes... + */ + if (m->m_protocol == PTHREAD_PRIO_INHERIT) { + /* + * Fix the owners saved (inherited) priority to + * reflect the priority of the previous mutex. + */ + m->m_saved_prio = inherited_prio; + + if ((pthread_next = TAILQ_FIRST(&m->m_queue)) != NULL) + /* Recalculate the priority of the mutex: */ + m->m_prio = MAX(active_prio, + pthread_next->active_priority); + else + m->m_prio = active_prio; + + /* Recalculate new inherited and active priorities: */ + inherited_prio = m->m_prio; + active_prio = MAX(m->m_prio, pthread->base_priority); + } + + /* Advance to the next mutex owned by this thread: */ + m = TAILQ_NEXT(m, m_qe); + } + + /* + * Fix the threads inherited priority and recalculate its + * active priority. + */ + pthread->inherited_priority = inherited_prio; + active_prio = MAX(inherited_prio, pthread->base_priority); + + if (active_prio != pthread->active_priority) { + /* + * If this thread is in the priority queue, it must be + * removed and reinserted for its new priority. + */ + if (pthread->flags & PTHREAD_FLAGS_IN_PRIOQ) { + /* + * Remove the thread from the priority queue + * before changing its priority: + */ + PTHREAD_PRIOQ_REMOVE(pthread); + + /* + * POSIX states that if the priority is being + * lowered, the thread must be inserted at the + * head of the queue for its priority if it owns + * any priority protection or inheritence mutexes. + */ + if ((active_prio < pthread->active_priority) && + (pthread->priority_mutex_count > 0)) { + /* Set the new active priority. */ + pthread->active_priority = active_prio; + + PTHREAD_PRIOQ_INSERT_HEAD(pthread); + } + else { + /* Set the new active priority. */ + pthread->active_priority = active_prio; + + PTHREAD_PRIOQ_INSERT_TAIL(pthread); + } + } + else { + /* Set the new active priority. */ + pthread->active_priority = active_prio; + } + } +} + +void +_mutex_unlock_private(pthread_t pthread) +{ + struct pthread_mutex *m, *m_next; + + for (m = TAILQ_FIRST(&pthread->mutexq); m != NULL; m = m_next) { + m_next = TAILQ_NEXT(m, m_qe); + if ((m->m_flags & MUTEX_FLAGS_PRIVATE) != 0) + pthread_mutex_unlock(&m); + } +} + +/* + * Dequeue a waiting thread from the head of a mutex queue in descending + * priority order. + */ +static inline pthread_t +mutex_queue_deq(pthread_mutex_t mutex) +{ + pthread_t pthread; + + while ((pthread = TAILQ_FIRST(&mutex->m_queue)) != NULL) { + TAILQ_REMOVE(&mutex->m_queue, pthread, qe); + pthread->flags &= ~PTHREAD_FLAGS_IN_MUTEXQ; + + /* + * Only exit the loop if the thread hasn't been + * cancelled. + */ + if (pthread->interrupted == 0) + break; + } + + return(pthread); +} + +/* + * Remove a waiting thread from a mutex queue in descending priority order. + */ +static inline void +mutex_queue_remove(pthread_mutex_t mutex, pthread_t pthread) +{ + if ((pthread->flags & PTHREAD_FLAGS_IN_MUTEXQ) != 0) { + TAILQ_REMOVE(&mutex->m_queue, pthread, qe); + pthread->flags &= ~PTHREAD_FLAGS_IN_MUTEXQ; + } +} + +/* + * Enqueue a waiting thread to a queue in descending priority order. + */ +static inline void +mutex_queue_enq(pthread_mutex_t mutex, pthread_t pthread) +{ + pthread_t tid = TAILQ_LAST(&mutex->m_queue, mutex_head); + + /* + * For the common case of all threads having equal priority, + * we perform a quick check against the priority of the thread + * at the tail of the queue. + */ + if ((tid == NULL) || (pthread->active_priority <= tid->active_priority)) + TAILQ_INSERT_TAIL(&mutex->m_queue, pthread, qe); + else { + tid = TAILQ_FIRST(&mutex->m_queue); + while (pthread->active_priority <= tid->active_priority) + tid = TAILQ_NEXT(tid, qe); + TAILQ_INSERT_BEFORE(tid, pthread, qe); + } + pthread->flags |= PTHREAD_FLAGS_IN_MUTEXQ; +} + +#endif diff --git a/lib/libpthread/thread/thr_mutex_prioceiling.c b/lib/libpthread/thread/thr_mutex_prioceiling.c new file mode 100644 index 0000000..c193c82 --- /dev/null +++ b/lib/libpthread/thread/thr_mutex_prioceiling.c @@ -0,0 +1,110 @@ +/* + * Copyright (c) 1998 Daniel Eischen <eischen@vigrid.com>. + * 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 Daniel Eischen. + * 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 DANIEL EISCHEN 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <string.h> +#include <stdlib.h> +#include <errno.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +int +pthread_mutexattr_getprioceiling(pthread_mutexattr_t *mattr, int *prioceiling) +{ + int ret = 0; + + if ((mattr == NULL) || (*mattr == NULL)) + ret = EINVAL; + else if ((*mattr)->m_protocol != PTHREAD_PRIO_PROTECT) + ret = EINVAL; + else + *prioceiling = (*mattr)->m_ceiling; + + return(ret); +} + +int +pthread_mutexattr_setprioceiling(pthread_mutexattr_t *mattr, int prioceiling) +{ + int ret = 0; + + if ((mattr == NULL) || (*mattr == NULL)) + ret = EINVAL; + else if ((*mattr)->m_protocol != PTHREAD_PRIO_PROTECT) + ret = EINVAL; + else + (*mattr)->m_ceiling = prioceiling; + + return(ret); +} + +int +pthread_mutex_getprioceiling(pthread_mutex_t *mutex, + int *prioceiling) +{ + int ret; + + if ((mutex == NULL) || (*mutex == NULL)) + ret = EINVAL; + else if ((*mutex)->m_protocol != PTHREAD_PRIO_PROTECT) + ret = EINVAL; + else + ret = (*mutex)->m_prio; + + return(ret); +} + +int +pthread_mutex_setprioceiling(pthread_mutex_t *mutex, + int prioceiling, int *old_ceiling) +{ + int ret = 0; + + if ((mutex == NULL) || (*mutex == NULL)) + ret = EINVAL; + else if ((*mutex)->m_protocol != PTHREAD_PRIO_PROTECT) + ret = EINVAL; + else { + /* Lock the mutex: */ + if ((ret = pthread_mutex_lock(mutex)) == 0) { + /* Return the old ceiling and set the new ceiling: */ + *old_ceiling = (*mutex)->m_prio; + (*mutex)->m_prio = prioceiling; + + /* Unlock the mutex: */ + ret = pthread_mutex_unlock(mutex); + } + } + return(ret); +} +#endif diff --git a/lib/libpthread/thread/thr_mutex_protocol.c b/lib/libpthread/thread/thr_mutex_protocol.c new file mode 100644 index 0000000..9847ae5 --- /dev/null +++ b/lib/libpthread/thread/thr_mutex_protocol.c @@ -0,0 +1,69 @@ +/* + * Copyright (c) 1998 Daniel Eischen <eischen@vigrid.com>. + * 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 Daniel Eischen. + * 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 DANIEL EISCHEN 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <string.h> +#include <stdlib.h> +#include <errno.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +int +pthread_mutexattr_getprotocol(pthread_mutexattr_t *mattr, int *protocol) +{ + int ret = 0; + + if ((mattr == NULL) || (*mattr == NULL)) + ret = EINVAL; + else + *protocol = (*mattr)->m_protocol; + + return(ret); +} + +int +pthread_mutexattr_setprotocol(pthread_mutexattr_t *mattr, int protocol) +{ + int ret = 0; + + if ((mattr == NULL) || (*mattr == NULL) || + (protocol < PTHREAD_PRIO_NONE) || (protocol > PTHREAD_PRIO_PROTECT)) + ret = EINVAL; + else { + (*mattr)->m_protocol = protocol; + (*mattr)->m_ceiling = PTHREAD_MAX_PRIORITY; + } + return(ret); +} + +#endif diff --git a/lib/libpthread/thread/thr_mutexattr_destroy.c b/lib/libpthread/thread/thr_mutexattr_destroy.c new file mode 100644 index 0000000..6eed2a2 --- /dev/null +++ b/lib/libpthread/thread/thr_mutexattr_destroy.c @@ -0,0 +1,53 @@ +/* + * Copyright (c) 1997 John Birrell <jb@cimlogic.com.au>. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by John Birrell. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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. + * + * $FreeBSD$ + */ +#include <stdlib.h> +#include <errno.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +int +pthread_mutexattr_destroy(pthread_mutexattr_t *attr) +{ + int ret; + if (attr == NULL || *attr == NULL) { + ret = EINVAL; + } else { + free(*attr); + *attr = NULL; + ret = 0; + } + return(ret); +} +#endif diff --git a/lib/libpthread/thread/thr_nanosleep.c b/lib/libpthread/thread/thr_nanosleep.c new file mode 100644 index 0000000..3bbc9a6 --- /dev/null +++ b/lib/libpthread/thread/thr_nanosleep.c @@ -0,0 +1,134 @@ +/* + * 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <stdio.h> +#include <errno.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +int +_nanosleep(const 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; + + /* Check if the time to sleep is legal: */ + if (time_to_sleep == NULL || time_to_sleep->tv_sec < 0 || + time_to_sleep->tv_nsec < 0 || time_to_sleep->tv_nsec >= 1000000000) { + /* 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.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; + + /* Check if the nanosecond field has overflowed: */ + if (_thread_run->wakeup_time.tv_nsec >= 1000000000) { + /* Wrap the nanosecond field: */ + _thread_run->wakeup_time.tv_sec += 1; + _thread_run->wakeup_time.tv_nsec -= 1000000000; + } + _thread_run->interrupted = 0; + + /* Reschedule the current thread to sleep: */ + _thread_kern_sched_state(PS_SLEEP_WAIT, __FILE__, __LINE__); + + /* Get the current time: */ + gettimeofday(&tv, NULL); + TIMEVAL_TO_TIMESPEC(&tv, ¤t_time1); + + /* Calculate the remaining time to sleep: */ + 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; + + /* Check if the nanosecond field has underflowed: */ + if (remaining_time.tv_nsec < 0) { + /* Handle the underflow: */ + remaining_time.tv_sec -= 1; + remaining_time.tv_nsec += 1000000000; + } + + /* Check if the nanosecond field has overflowed: */ + if (remaining_time.tv_nsec >= 1000000000) { + /* Handle the overflow: */ + remaining_time.tv_sec += 1; + remaining_time.tv_nsec -= 1000000000; + } + + /* Check if the sleep was longer than the required time: */ + if (remaining_time.tv_sec < 0) { + /* Reset the time left: */ + remaining_time.tv_sec = 0; + remaining_time.tv_nsec = 0; + } + + /* Check if the time remaining is to be returned: */ + if (time_remaining != NULL) { + /* Return the actual time slept: */ + time_remaining->tv_sec = remaining_time.tv_sec; + time_remaining->tv_nsec = remaining_time.tv_nsec; + } + + /* Check if the sleep was interrupted: */ + if (_thread_run->interrupted) { + /* Return an EINTR error : */ + errno = EINTR; + ret = -1; + } + } + return (ret); +} + +int +nanosleep(const struct timespec * time_to_sleep, struct timespec * + time_remaining) +{ + int ret; + + _thread_enter_cancellation_point(); + ret = _nanosleep(time_to_sleep, time_remaining); + _thread_leave_cancellation_point(); + + return ret; +} +#endif diff --git a/lib/libpthread/thread/thr_once.c b/lib/libpthread/thread/thr_once.c new file mode 100644 index 0000000..d7bb494 --- /dev/null +++ b/lib/libpthread/thread/thr_once.c @@ -0,0 +1,53 @@ +/* + * 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#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) { + if (_thread_initial == NULL) + _thread_init(); + pthread_mutex_lock(&(once_control->mutex)); + if (once_control->state == PTHREAD_NEEDS_INIT) { + init_routine(); + once_control->state = PTHREAD_DONE_INIT; + } + pthread_mutex_unlock(&(once_control->mutex)); + } + return (0); +} +#endif diff --git a/lib/libpthread/thread/thr_open.c b/lib/libpthread/thread/thr_open.c new file mode 100644 index 0000000..e7fef91 --- /dev/null +++ b/lib/libpthread/thread/thr_open.c @@ -0,0 +1,96 @@ +/* + * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by John Birrell. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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. + * + * $FreeBSD$ + * + */ +#include <stdarg.h> +#include <unistd.h> +#include <fcntl.h> +#include <dirent.h> +#include <errno.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +int +_open(const char *path, int flags,...) +{ + int fd; + int mode = 0; + va_list ap; + + /* 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: */ + if ((fd = _thread_sys_open(path, flags, 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; + } + + /* Return the file descriptor or -1 on error: */ + return (fd); +} + +int +open(const char *path, int flags,...) +{ + int ret; + int mode = 0; + va_list ap; + + _thread_enter_cancellation_point(); + + /* 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); + } + + ret = _open(path, flags, mode); + _thread_leave_cancellation_point(); + + return ret; +} +#endif diff --git a/lib/libpthread/thread/thr_pause.c b/lib/libpthread/thread/thr_pause.c new file mode 100644 index 0000000..09e4c17 --- /dev/null +++ b/lib/libpthread/thread/thr_pause.c @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2000 Jason Evans <jasone@freebsd.org>. + * 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(s), this list of conditions and the following disclaimer as + * the first lines of this file unmodified other than the possible + * addition of one or more copyright notices. + * 2. Redistributions in binary form must reproduce the above copyright + * notice(s), this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``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 COPYRIGHT HOLDER(S) 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. + * + * $FreeBSD$ + */ + +#include <unistd.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +int +pause(void) +{ + int ret; + + _thread_enter_cancellation_point(); + ret = __pause(); + _thread_leave_cancellation_point(); + + return ret; +} +#endif diff --git a/lib/libpthread/thread/thr_poll.c b/lib/libpthread/thread/thr_poll.c new file mode 100644 index 0000000..3717273 --- /dev/null +++ b/lib/libpthread/thread/thr_poll.c @@ -0,0 +1,101 @@ +/* + * Copyright (c) 1999 Daniel Eischen <eischen@vigrid.com> + * 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 Daniel Eischen. + * 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 DANIEL EISCHEN 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <unistd.h> +#include <errno.h> +#include <string.h> +#include <poll.h> +#include <sys/types.h> +#include <sys/time.h> +#include <sys/fcntl.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + + +int +_poll(struct pollfd *fds, unsigned int nfds, int timeout) +{ + struct timespec ts; + int numfds = nfds; + int i, ret = 0; + struct pthread_poll_data data; + + if (numfds > _thread_dtablesize) { + numfds = _thread_dtablesize; + } + /* Check if a timeout was specified: */ + if (timeout == INFTIM) { + /* Wait for ever: */ + _thread_kern_set_timeout(NULL); + } else if (timeout > 0) { + /* Convert the timeout in msec to a timespec: */ + ts.tv_sec = timeout / 1000; + ts.tv_nsec = (timeout % 1000) * 1000000; + + /* Set the wake up time: */ + _thread_kern_set_timeout(&ts); + } else if (timeout < 0) { + /* a timeout less than zero but not == INFTIM is invalid */ + errno = EINVAL; + return (-1); + } + + if (((ret = _thread_sys_poll(fds, numfds, 0)) == 0) && (timeout != 0)) { + data.nfds = numfds; + data.fds = fds; + + /* + * Clear revents in case of a timeout which leaves fds + * unchanged: + */ + for (i = 0; i < numfds; i++) { + fds[i].revents = 0; + } + + _thread_run->data.poll_data = &data; + _thread_run->interrupted = 0; + _thread_kern_sched_state(PS_POLL_WAIT, __FILE__, __LINE__); + if (_thread_run->interrupted) { + errno = EINTR; + ret = -1; + } else { + ret = data.nfds; + } + } + + return (ret); +} + +__strong_reference(_poll, poll); +#endif diff --git a/lib/libpthread/thread/thr_priority_queue.c b/lib/libpthread/thread/thr_priority_queue.c new file mode 100644 index 0000000..1b9fcba --- /dev/null +++ b/lib/libpthread/thread/thr_priority_queue.c @@ -0,0 +1,335 @@ +/* + * Copyright (c) 1998 Daniel Eischen <eischen@vigrid.com>. + * 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 Daniel Eischen. + * 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 DANIEL EISCHEN 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <stdlib.h> +#include <sys/queue.h> +#include <string.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +/* Prototypes: */ +static void pq_insert_prio_list(pq_queue_t *pq, int prio); + +#if defined(_PTHREADS_INVARIANTS) + +static int _pq_active = 0; + +#define _PQ_IN_SCHEDQ (PTHREAD_FLAGS_IN_PRIOQ | PTHREAD_FLAGS_IN_WAITQ | PTHREAD_FLAGS_IN_WORKQ) + +#define _PQ_SET_ACTIVE() _pq_active = 1 +#define _PQ_CLEAR_ACTIVE() _pq_active = 0 +#define _PQ_ASSERT_ACTIVE(msg) do { \ + if (_pq_active == 0) \ + PANIC(msg); \ +} while (0) +#define _PQ_ASSERT_INACTIVE(msg) do { \ + if (_pq_active != 0) \ + PANIC(msg); \ +} while (0) +#define _PQ_ASSERT_IN_WAITQ(thrd, msg) do { \ + if (((thrd)->flags & PTHREAD_FLAGS_IN_WAITQ) == 0) \ + PANIC(msg); \ +} while (0) +#define _PQ_ASSERT_IN_PRIOQ(thrd, msg) do { \ + if (((thrd)->flags & PTHREAD_FLAGS_IN_PRIOQ) == 0) \ + PANIC(msg); \ +} while (0) +#define _PQ_ASSERT_NOT_QUEUED(thrd, msg) do { \ + if ((thrd)->flags & _PQ_IN_SCHEDQ) \ + PANIC(msg); \ +} while (0) + +#else + +#define _PQ_SET_ACTIVE() +#define _PQ_CLEAR_ACTIVE() +#define _PQ_ASSERT_ACTIVE(msg) +#define _PQ_ASSERT_INACTIVE(msg) +#define _PQ_ASSERT_IN_WAITQ(thrd, msg) +#define _PQ_ASSERT_IN_PRIOQ(thrd, msg) +#define _PQ_ASSERT_NOT_QUEUED(thrd, msg) +#define _PQ_CHECK_PRIO() + +#endif + + +int +_pq_alloc(pq_queue_t *pq, int minprio, int maxprio) +{ + int ret = 0; + int prioslots = maxprio - minprio + 1; + + if (pq == NULL) + ret = -1; + + /* Create the priority queue with (maxprio - minprio + 1) slots: */ + else if ((pq->pq_lists = + (pq_list_t *) malloc(sizeof(pq_list_t) * prioslots)) == NULL) + ret = -1; + + else { + /* Remember the queue size: */ + pq->pq_size = prioslots; + + ret = _pq_init(pq); + + } + return (ret); +} + +int +_pq_init(pq_queue_t *pq) +{ + int i, ret = 0; + + if ((pq == NULL) || (pq->pq_lists == NULL)) + ret = -1; + + else { + /* Initialize the queue for each priority slot: */ + for (i = 0; i < pq->pq_size; i++) { + TAILQ_INIT(&pq->pq_lists[i].pl_head); + pq->pq_lists[i].pl_prio = i; + pq->pq_lists[i].pl_queued = 0; + } + + /* Initialize the priority queue: */ + TAILQ_INIT(&pq->pq_queue); + _PQ_CLEAR_ACTIVE(); + } + return (ret); +} + +void +_pq_remove(pq_queue_t *pq, pthread_t pthread) +{ + int prio = pthread->active_priority; + + /* + * Make some assertions when debugging is enabled: + */ + _PQ_ASSERT_INACTIVE("_pq_remove: pq_active"); + _PQ_SET_ACTIVE(); + _PQ_ASSERT_IN_PRIOQ(pthread, "_pq_remove: Not in priority queue"); + + /* + * Remove this thread from priority list. Note that if + * the priority list becomes empty, it is not removed + * from the priority queue because another thread may be + * added to the priority list (resulting in a needless + * removal/insertion). Priority lists are only removed + * from the priority queue when _pq_first is called. + */ + TAILQ_REMOVE(&pq->pq_lists[prio].pl_head, pthread, pqe); + + /* This thread is now longer in the priority queue. */ + pthread->flags &= ~PTHREAD_FLAGS_IN_PRIOQ; + + _PQ_CLEAR_ACTIVE(); +} + + +void +_pq_insert_head(pq_queue_t *pq, pthread_t pthread) +{ + int prio = pthread->active_priority; + + /* + * Make some assertions when debugging is enabled: + */ + _PQ_ASSERT_INACTIVE("_pq_insert_head: pq_active"); + _PQ_SET_ACTIVE(); + _PQ_ASSERT_NOT_QUEUED(pthread, + "_pq_insert_head: Already in priority queue"); + + TAILQ_INSERT_HEAD(&pq->pq_lists[prio].pl_head, pthread, pqe); + if (pq->pq_lists[prio].pl_queued == 0) + /* Insert the list into the priority queue: */ + pq_insert_prio_list(pq, prio); + + /* Mark this thread as being in the priority queue. */ + pthread->flags |= PTHREAD_FLAGS_IN_PRIOQ; + + _PQ_CLEAR_ACTIVE(); +} + + +void +_pq_insert_tail(pq_queue_t *pq, pthread_t pthread) +{ + int prio = pthread->active_priority; + + /* + * Make some assertions when debugging is enabled: + */ + _PQ_ASSERT_INACTIVE("_pq_insert_tail: pq_active"); + _PQ_SET_ACTIVE(); + _PQ_ASSERT_NOT_QUEUED(pthread, + "_pq_insert_tail: Already in priority queue"); + + TAILQ_INSERT_TAIL(&pq->pq_lists[prio].pl_head, pthread, pqe); + if (pq->pq_lists[prio].pl_queued == 0) + /* Insert the list into the priority queue: */ + pq_insert_prio_list(pq, prio); + + /* Mark this thread as being in the priority queue. */ + pthread->flags |= PTHREAD_FLAGS_IN_PRIOQ; + + _PQ_CLEAR_ACTIVE(); +} + + +pthread_t +_pq_first(pq_queue_t *pq) +{ + pq_list_t *pql; + pthread_t pthread = NULL; + + /* + * Make some assertions when debugging is enabled: + */ + _PQ_ASSERT_INACTIVE("_pq_first: pq_active"); + _PQ_SET_ACTIVE(); + + while (((pql = TAILQ_FIRST(&pq->pq_queue)) != NULL) && + (pthread == NULL)) { + if ((pthread = TAILQ_FIRST(&pql->pl_head)) == NULL) { + /* + * The priority list is empty; remove the list + * from the queue. + */ + TAILQ_REMOVE(&pq->pq_queue, pql, pl_link); + + /* Mark the list as not being in the queue: */ + pql->pl_queued = 0; + } + } + + _PQ_CLEAR_ACTIVE(); + return (pthread); +} + + +static void +pq_insert_prio_list(pq_queue_t *pq, int prio) +{ + pq_list_t *pql; + + /* + * Make some assertions when debugging is enabled: + */ + _PQ_ASSERT_ACTIVE("pq_insert_prio_list: pq_active"); + + /* + * The priority queue is in descending priority order. Start at + * the beginning of the queue and find the list before which the + * new list should be inserted. + */ + pql = TAILQ_FIRST(&pq->pq_queue); + while ((pql != NULL) && (pql->pl_prio > prio)) + pql = TAILQ_NEXT(pql, pl_link); + + /* Insert the list: */ + if (pql == NULL) + TAILQ_INSERT_TAIL(&pq->pq_queue, &pq->pq_lists[prio], pl_link); + else + TAILQ_INSERT_BEFORE(pql, &pq->pq_lists[prio], pl_link); + + /* Mark this list as being in the queue: */ + pq->pq_lists[prio].pl_queued = 1; +} + +#if defined(_PTHREADS_INVARIANTS) +void +_waitq_insert(pthread_t pthread) +{ + pthread_t tid; + + /* + * Make some assertions when debugging is enabled: + */ + _PQ_ASSERT_INACTIVE("_waitq_insert: pq_active"); + _PQ_SET_ACTIVE(); + _PQ_ASSERT_NOT_QUEUED(pthread, "_waitq_insert: Already in queue"); + + if (pthread->wakeup_time.tv_sec == -1) + TAILQ_INSERT_TAIL(&_waitingq, pthread, pqe); + else { + tid = TAILQ_FIRST(&_waitingq); + while ((tid != NULL) && (tid->wakeup_time.tv_sec != -1) && + ((tid->wakeup_time.tv_sec < pthread->wakeup_time.tv_sec) || + ((tid->wakeup_time.tv_sec == pthread->wakeup_time.tv_sec) && + (tid->wakeup_time.tv_nsec <= pthread->wakeup_time.tv_nsec)))) + tid = TAILQ_NEXT(tid, pqe); + if (tid == NULL) + TAILQ_INSERT_TAIL(&_waitingq, pthread, pqe); + else + TAILQ_INSERT_BEFORE(tid, pthread, pqe); + } + pthread->flags |= PTHREAD_FLAGS_IN_WAITQ; + + _PQ_CLEAR_ACTIVE(); +} + +void +_waitq_remove(pthread_t pthread) +{ + /* + * Make some assertions when debugging is enabled: + */ + _PQ_ASSERT_INACTIVE("_waitq_remove: pq_active"); + _PQ_SET_ACTIVE(); + _PQ_ASSERT_IN_WAITQ(pthread, "_waitq_remove: Not in queue"); + + TAILQ_REMOVE(&_waitingq, pthread, pqe); + pthread->flags &= ~PTHREAD_FLAGS_IN_WAITQ; + + _PQ_CLEAR_ACTIVE(); +} + +void +_waitq_setactive(void) +{ + _PQ_ASSERT_INACTIVE("_waitq_setactive: pq_active"); + _PQ_SET_ACTIVE(); +} + +void +_waitq_clearactive(void) +{ + _PQ_ASSERT_ACTIVE("_waitq_clearactive: ! pq_active"); + _PQ_CLEAR_ACTIVE(); +} +#endif +#endif diff --git a/lib/libpthread/thread/thr_private.h b/lib/libpthread/thread/thr_private.h new file mode 100644 index 0000000..9d76747 --- /dev/null +++ b/lib/libpthread/thread/thr_private.h @@ -0,0 +1,1276 @@ +/* + * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by John Birrell. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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. + * + * $FreeBSD$ + */ + +#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/queue.h> +#include <sys/types.h> +#include <sys/time.h> +#include <sys/cdefs.h> +#include <sched.h> +#include <spinlock.h> +#include <pthread_np.h> + +/* + * Kernel fatal error handler macro. + */ +#define PANIC(string) _thread_exit(__FILE__,__LINE__,string) + +/* Output debug messages like this: */ +#define stdout_debug(_x) _thread_sys_write(1,_x,strlen(_x)); +#define stderr_debug(_x) _thread_sys_write(2,_x,strlen(_x)); + + +/* + * Priority queue manipulation macros (using pqe link): + */ +#define PTHREAD_PRIOQ_INSERT_HEAD(thrd) _pq_insert_head(&_readyq,thrd) +#define PTHREAD_PRIOQ_INSERT_TAIL(thrd) _pq_insert_tail(&_readyq,thrd) +#define PTHREAD_PRIOQ_REMOVE(thrd) _pq_remove(&_readyq,thrd) +#define PTHREAD_PRIOQ_FIRST() _pq_first(&_readyq) + +/* + * Waiting queue manipulation macros (using pqe link): + */ +#if defined(_PTHREADS_INVARIANTS) +#define PTHREAD_WAITQ_REMOVE(thrd) _waitq_remove(thrd) +#define PTHREAD_WAITQ_INSERT(thrd) _waitq_insert(thrd) +#define PTHREAD_WAITQ_CLEARACTIVE() _waitq_clearactive() +#define PTHREAD_WAITQ_SETACTIVE() _waitq_setactive() +#else +#define PTHREAD_WAITQ_REMOVE(thrd) do { \ + TAILQ_REMOVE(&_waitingq,thrd,pqe); \ + (thrd)->flags &= ~PTHREAD_FLAGS_IN_WAITQ; \ +} while (0) + +#define PTHREAD_WAITQ_INSERT(thrd) do { \ + if ((thrd)->wakeup_time.tv_sec == -1) \ + TAILQ_INSERT_TAIL(&_waitingq,thrd,pqe); \ + else { \ + pthread_t tid = TAILQ_FIRST(&_waitingq); \ + while ((tid != NULL) && (tid->wakeup_time.tv_sec != -1) && \ + ((tid->wakeup_time.tv_sec < (thrd)->wakeup_time.tv_sec) || \ + ((tid->wakeup_time.tv_sec == (thrd)->wakeup_time.tv_sec) && \ + (tid->wakeup_time.tv_nsec <= (thrd)->wakeup_time.tv_nsec)))) \ + tid = TAILQ_NEXT(tid, pqe); \ + if (tid == NULL) \ + TAILQ_INSERT_TAIL(&_waitingq,thrd,pqe); \ + else \ + TAILQ_INSERT_BEFORE(tid,thrd,pqe); \ + } \ + (thrd)->flags |= PTHREAD_FLAGS_IN_WAITQ; \ +} while (0) +#define PTHREAD_WAITQ_CLEARACTIVE() +#define PTHREAD_WAITQ_SETACTIVE() +#endif + +/* + * Work queue manipulation macros (using qe link): + */ +#define PTHREAD_WORKQ_INSERT(thrd) do { \ + TAILQ_INSERT_TAIL(&_workq,thrd,qe); \ + (thrd)->flags |= PTHREAD_FLAGS_IN_WORKQ; \ +} while (0) +#define PTHREAD_WORKQ_REMOVE(thrd) do { \ + TAILQ_REMOVE(&_workq,thrd,qe); \ + (thrd)->flags &= ~PTHREAD_FLAGS_IN_WORKQ; \ +} while (0) + + +/* + * State change macro without scheduling queue change: + */ +#define PTHREAD_SET_STATE(thrd, newstate) do { \ + (thrd)->state = newstate; \ + (thrd)->fname = __FILE__; \ + (thrd)->lineno = __LINE__; \ +} while (0) + +/* + * State change macro with scheduling queue change - This must be + * called with preemption deferred (see thread_kern_sched_[un]defer). + */ +#if defined(_PTHREADS_INVARIANTS) +#define PTHREAD_NEW_STATE(thrd, newstate) do { \ + if (_thread_kern_new_state != 0) \ + PANIC("Recursive PTHREAD_NEW_STATE"); \ + _thread_kern_new_state = 1; \ + if ((thrd)->state != newstate) { \ + if ((thrd)->state == PS_RUNNING) { \ + PTHREAD_PRIOQ_REMOVE(thrd); \ + PTHREAD_WAITQ_INSERT(thrd); \ + } else if (newstate == PS_RUNNING) { \ + PTHREAD_WAITQ_REMOVE(thrd); \ + PTHREAD_PRIOQ_INSERT_TAIL(thrd); \ + } \ + } \ + _thread_kern_new_state = 0; \ + PTHREAD_SET_STATE(thrd, newstate); \ +} while (0) +#else +#define PTHREAD_NEW_STATE(thrd, newstate) do { \ + if ((thrd)->state != newstate) { \ + if ((thrd)->state == PS_RUNNING) { \ + PTHREAD_PRIOQ_REMOVE(thrd); \ + PTHREAD_WAITQ_INSERT(thrd); \ + } else if (newstate == PS_RUNNING) { \ + PTHREAD_WAITQ_REMOVE(thrd); \ + PTHREAD_PRIOQ_INSERT_TAIL(thrd); \ + } \ + } \ + PTHREAD_SET_STATE(thrd, newstate); \ +} while (0) +#endif + +/* + * Define the signals to be used for scheduling. + */ +#if defined(_PTHREADS_COMPAT_SCHED) +#define _ITIMER_SCHED_TIMER ITIMER_VIRTUAL +#define _SCHED_SIGNAL SIGVTALRM +#else +#define _ITIMER_SCHED_TIMER ITIMER_PROF +#define _SCHED_SIGNAL SIGPROF +#endif + +/* + * Priority queues. + * + * XXX It'd be nice if these were contained in uthread_priority_queue.[ch]. + */ +typedef struct pq_list { + TAILQ_HEAD(, pthread) pl_head; /* list of threads at this priority */ + TAILQ_ENTRY(pq_list) pl_link; /* link for queue of priority lists */ + int pl_prio; /* the priority of this list */ + int pl_queued; /* is this in the priority queue */ +} pq_list_t; + +typedef struct pq_queue { + TAILQ_HEAD(, pq_list) pq_queue; /* queue of priority lists */ + pq_list_t *pq_lists; /* array of all priority lists */ + int pq_size; /* number of priority lists */ +} pq_queue_t; + + +/* + * TailQ initialization values. + */ +#define TAILQ_INITIALIZER { NULL, NULL } + +/* + * Mutex definitions. + */ +union pthread_mutex_data { + void *m_ptr; + int m_count; +}; + +struct pthread_mutex { + enum pthread_mutextype m_type; + int m_protocol; + TAILQ_HEAD(mutex_head, pthread) m_queue; + struct pthread *m_owner; + union pthread_mutex_data m_data; + long m_flags; + int m_refcount; + + /* + * Used for priority inheritence and protection. + * + * m_prio - For priority inheritence, the highest active + * priority (threads locking the mutex inherit + * this priority). For priority protection, the + * ceiling priority of this mutex. + * m_saved_prio - mutex owners inherited priority before + * taking the mutex, restored when the owner + * unlocks the mutex. + */ + int m_prio; + int m_saved_prio; + + /* + * Link for list of all mutexes a thread currently owns. + */ + TAILQ_ENTRY(pthread_mutex) m_qe; + + /* + * Lock for accesses to this structure. + */ + spinlock_t lock; +}; + +/* + * 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_STATIC_INITIALIZER \ + { PTHREAD_MUTEX_DEFAULT, PTHREAD_PRIO_NONE, TAILQ_INITIALIZER, \ + NULL, { NULL }, MUTEX_FLAGS_PRIVATE, 0, 0, 0, TAILQ_INITIALIZER, \ + _SPINLOCK_INITIALIZER } + +struct pthread_mutex_attr { + enum pthread_mutextype m_type; + int m_protocol; + int m_ceiling; + 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; + TAILQ_HEAD(cond_head, pthread) c_queue; + pthread_mutex_t c_mutex; + void *c_data; + long c_flags; + + /* + * Lock for accesses to this structure. + */ + spinlock_t lock; +}; + +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_STATIC_INITIALIZER \ + { COND_TYPE_FAST, TAILQ_INITIALIZER, NULL, NULL, \ + 0, _SPINLOCK_INITIALIZER } + +/* + * Semaphore definitions. + */ +struct sem { +#define SEM_MAGIC ((u_int32_t) 0x09fa4012) + u_int32_t magic; + pthread_mutex_t lock; + pthread_cond_t gtzero; + u_int32_t count; + u_int32_t nwaiters; +}; + +/* + * Cleanup definitions. + */ +struct pthread_cleanup { + struct pthread_cleanup *next; + void (*routine) (); + void *routine_arg; +}; + +struct pthread_attr { + int sched_policy; + int sched_inherit; + int sched_interval; + int prio; + int suspend; + int flags; + void *arg_attr; + void (*cleanup_attr) (); + void *stackaddr_attr; + size_t stacksize_attr; +}; + +/* + * Thread creation state attributes. + */ +#define PTHREAD_CREATE_RUNNING 0 +#define PTHREAD_CREATE_SUSPENDED 1 + +/* + * Additional state for a thread suspended with pthread_suspend_np(). + */ +enum pthread_susp { + SUSP_NO, /* Not suspended. */ + SUSP_YES, /* Suspended. */ + SUSP_NOWAIT, /* Suspended, was in a mutex or condition queue. */ + SUSP_MUTEX_WAIT,/* Suspended, still in a mutex queue. */ + SUSP_COND_WAIT /* Suspended, still in a condition queue. */ +}; + +/* + * Miscellaneous definitions. + */ +#define PTHREAD_STACK_DEFAULT 65536 +/* + * Size of red zone at the end of each stack. In actuality, this "red zone" is + * merely an unmapped region, except in the case of the initial stack. Since + * mmap() makes it possible to specify the maximum growth of a MAP_STACK region, + * an unmapped gap between thread stacks achieves the same effect as explicitly + * mapped red zones. + */ +#define PTHREAD_STACK_GUARD PAGE_SIZE + +/* + * Maximum size of initial thread's stack. This perhaps deserves to be larger + * than the stacks of other threads, since many applications are likely to run + * almost entirely on this stack. + */ +#define PTHREAD_STACK_INITIAL 0x100000 +/* Address immediately beyond the beginning of the initial thread stack. */ +#define PTHREAD_DEFAULT_PRIORITY 64 +#define PTHREAD_MAX_PRIORITY 126 +#define PTHREAD_MIN_PRIORITY 0 +#define _POSIX_THREAD_ATTR_STACKSIZE + +/* + * Clock resolution in nanoseconds. + */ +#define CLOCK_RES_NSEC 10000000 + +/* + * Time slice period in microseconds. + */ +#define TIMESLICE_USEC 100000 + +struct pthread_key { + spinlock_t lock; + volatile int allocated; + volatile int count; + void (*destructor) (); +}; + +struct pthread_rwlockattr { + int pshared; +}; + +struct pthread_rwlock { + pthread_mutex_t lock; /* monitor lock */ + int state; /* 0 = idle >0 = # of readers -1 = writer */ + pthread_cond_t read_signal; + pthread_cond_t write_signal; + int blocked_writers; +}; + +/* + * 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_FILE_WAIT, + PS_POLL_WAIT, + PS_SELECT_WAIT, + PS_SLEEP_WAIT, + PS_WAIT_WAIT, + PS_SIGSUSPEND, + PS_SIGWAIT, + PS_SPINBLOCK, + PS_JOIN, + PS_SUSPENDED, + PS_DEAD, + PS_DEADLOCK, + 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 { + /* + * Lock for accesses to this file descriptor table + * entry. This is passed to _spinlock() to provide atomic + * access to this structure. It does *not* represent the + * state of the lock on the file descriptor. + */ + spinlock_t lock; + TAILQ_HEAD(, pthread) r_queue; /* Read queue. */ + TAILQ_HEAD(, pthread) 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_poll_data { + int nfds; + struct pollfd *fds; +}; + +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_poll_data * poll_data; + spinlock_t *spinlock; +}; + +/* + * Define a continuation routine that can be used to perform a + * transfer of control: + */ +typedef void (*thread_continuation_t) (void *); + +/* + * Thread structure. + */ +struct pthread { + /* + * Magic value to help recognize a valid thread structure + * from an invalid one: + */ +#define PTHREAD_MAGIC ((u_int32_t) 0xd09ba115) + u_int32_t magic; + char *name; + u_int64_t uniqueid; /* for gdb */ + + /* + * Lock for accesses to this thread structure. + */ + spinlock_t lock; + + /* Queue entry for list of all threads: */ + TAILQ_ENTRY(pthread) tle; + + /* Queue entry for list of dead threads: */ + TAILQ_ENTRY(pthread) dle; + + /* + * Thread start routine, argument, stack pointer and thread + * attributes. + */ + void *(*start_routine)(void *); + void *arg; + void *stack; + struct pthread_attr attr; + +#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. + */ + ucontext_t saved_sigcontext; + + /* + * Saved jump buffer used in call to longjmp by _thread_kern_sched + * if sig_saved is FALSE. + */ + jmp_buf saved_jmp_buf; + jmp_buf *sighandler_jmp_buf; + + /* + * Saved jump buffers for use when doing nested [sig|_]longjmp()s, as + * when doing signal delivery. + */ + union { + jmp_buf jmp; + sigjmp_buf sigjmp; + } nested_jmp; + int longjmp_val; + +#define JMPFLAGS_NONE 0x00 +#define JMPFLAGS_LONGJMP 0x01 +#define JMPFLAGS__LONGJMP 0x02 +#define JMPFLAGS_SIGLONGJMP 0x04 +#define JMPFLAGS_DEFERRED 0x08 + int jmpflags; + + /* + * TRUE if the last state saved was a signal context. FALSE if the + * last state saved was a jump buffer. + */ + int sig_saved; + + /* + * Used for tracking delivery of nested signal handlers. + */ + int signal_nest_level; + + /* + * Cancelability flags - the lower 2 bits are used by cancel + * definitions in pthread.h + */ +#define PTHREAD_AT_CANCEL_POINT 0x0004 +#define PTHREAD_CANCELLING 0x0008 +#define PTHREAD_CANCEL_NEEDED 0x0010 + int cancelflags; + + enum pthread_susp suspended; + + thread_continuation_t continuation; + + /* + * Current signal mask and pending signals. + */ + sigset_t sigmask; + sigset_t sigpend; + + /* Thread state: */ + enum pthread_state state; + enum pthread_state oldstate; + + /* 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 head and link for waiting threads: */ + TAILQ_HEAD(join_head, pthread) join_queue; + + /* + * The current thread can belong to only one scheduling queue at + * a time (ready or waiting queue). It can also belong to (only) + * one of: + * + * o A queue of threads waiting for a mutex + * o A queue of threads waiting for a condition variable + * o A queue of threads waiting for another thread to terminate + * (the join queue above) + * o A queue of threads waiting for a file descriptor lock + * o A queue of threads needing work done by the kernel thread + * (waiting for a spinlock or file I/O) + * + * Use pqe for the scheduling queue link (both ready and waiting), + * and qe for other links. + */ + + /* Priority queue entry for this thread: */ + TAILQ_ENTRY(pthread) pqe; + + /* Queue entry for this thread: */ + TAILQ_ENTRY(pthread) qe; + + /* Wait data. */ + union pthread_wait_data data; + + /* + * Allocated for converting select into poll. + */ + struct pthread_poll_data poll_data; + + /* + * Set to TRUE if a blocking operation was + * interrupted by a signal: + */ + int interrupted; + + /* Signal number when in state PS_SIGWAIT: */ + int signo; + + /* + * Set to non-zero when this thread has deferred signals. + * We allow for recursive deferral. + */ + int sig_defer_count; + + /* + * Set to TRUE if this thread should yield after undeferring + * signals. + */ + int yield_on_sig_undefer; + + /* Miscellaneous flags; only set with signals deferred. */ + int flags; +#define PTHREAD_FLAGS_PRIVATE 0x0001 +#define PTHREAD_EXITING 0x0002 +#define PTHREAD_FLAGS_IN_CONDQ 0x0004 /* in condition queue using qe link*/ +#define PTHREAD_FLAGS_IN_WORKQ 0x0008 /* in work queue using qe link */ +#define PTHREAD_FLAGS_IN_WAITQ 0x0010 /* in waiting queue using pqe link */ +#define PTHREAD_FLAGS_IN_PRIOQ 0x0020 /* in priority queue using pqe link */ +#define PTHREAD_FLAGS_IN_MUTEXQ 0x0040 /* in mutex queue using qe link */ +#define PTHREAD_FLAGS_IN_FILEQ 0x0080 /* in file lock queue using qe link */ +#define PTHREAD_FLAGS_IN_FDQ 0x0100 /* in fd lock queue using qe link */ +#define PTHREAD_FLAGS_TRACE 0x0200 /* for debugging purposes */ + + /* + * Base priority is the user setable and retrievable priority + * of the thread. It is only affected by explicit calls to + * set thread priority and upon thread creation via a thread + * attribute or default priority. + */ + char base_priority; + + /* + * Inherited priority is the priority a thread inherits by + * taking a priority inheritence or protection mutex. It + * is not affected by base priority changes. Inherited + * priority defaults to and remains 0 until a mutex is taken + * that is being waited on by any other thread whose priority + * is non-zero. + */ + char inherited_priority; + + /* + * Active priority is always the maximum of the threads base + * priority and inherited priority. When there is a change + * in either the base or inherited priority, the active + * priority must be recalculated. + */ + char active_priority; + + /* Number of priority ceiling or protection mutexes owned. */ + int priority_mutex_count; + + /* + * Queue of currently owned mutexes. + */ + TAILQ_HEAD(, pthread_mutex) mutexq; + + void *ret; + const void **specific_data; + int specific_data_count; + + /* Cleanup handlers Link List */ + struct pthread_cleanup *cleanup; + char *fname; /* Ptr to source file name */ + int lineno; /* Source line number. */ +}; + +/* Spare thread stack. */ +struct stack { + SLIST_ENTRY(stack) qe; /* Queue entry for this stack. */ +}; + +/* + * 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 * volatile _thread_run +#ifdef GLOBAL_PTHREAD_PRIVATE += &_thread_kern_thread; +#else +; +#endif + +/* Ptr to the thread structure for the last user thread to run: */ +SCLASS struct pthread * volatile _last_user_thread +#ifdef GLOBAL_PTHREAD_PRIVATE += &_thread_kern_thread; +#else +; +#endif + +/* + * Ptr to the thread running in single-threaded mode or NULL if + * running multi-threaded (default POSIX behaviour). + */ +SCLASS struct pthread * volatile _thread_single +#ifdef GLOBAL_PTHREAD_PRIVATE += NULL; +#else +; +#endif + +/* List of all threads: */ +SCLASS TAILQ_HEAD(, pthread) _thread_list +#ifdef GLOBAL_PTHREAD_PRIVATE += TAILQ_HEAD_INITIALIZER(_thread_list); +#else +; +#endif + +/* + * Array of kernel pipe file descriptors that are used to ensure that + * no signals are missed in calls to _select. + */ +SCLASS int _thread_kern_pipe[2] +#ifdef GLOBAL_PTHREAD_PRIVATE += { + -1, + -1 +}; +#else +; +#endif +SCLASS int volatile _queue_signals +#ifdef GLOBAL_PTHREAD_PRIVATE += 0; +#else +; +#endif +SCLASS int _thread_kern_in_sched +#ifdef GLOBAL_PTHREAD_PRIVATE += 0; +#else +; +#endif + +/* Last time that an incremental priority update was performed: */ +SCLASS struct timeval kern_inc_prio_time +#ifdef GLOBAL_PTHREAD_PRIVATE += { 0, 0 }; +#else +; +#endif + +/* Dead threads: */ +SCLASS TAILQ_HEAD(, pthread) _dead_list +#ifdef GLOBAL_PTHREAD_PRIVATE += TAILQ_HEAD_INITIALIZER(_dead_list); +#else +; +#endif + +/* Initial thread: */ +SCLASS struct pthread *_thread_initial +#ifdef GLOBAL_PTHREAD_PRIVATE += NULL; +#else +; +#endif + +/* Default thread attributes: */ +SCLASS struct pthread_attr pthread_attr_default +#ifdef GLOBAL_PTHREAD_PRIVATE += { SCHED_RR, 0, TIMESLICE_USEC, PTHREAD_DEFAULT_PRIORITY, PTHREAD_CREATE_RUNNING, + PTHREAD_CREATE_JOINABLE, NULL, NULL, NULL, PTHREAD_STACK_DEFAULT }; +#else +; +#endif + +/* Default mutex attributes: */ +SCLASS struct pthread_mutex_attr pthread_mutexattr_default +#ifdef GLOBAL_PTHREAD_PRIVATE += { PTHREAD_MUTEX_DEFAULT, PTHREAD_PRIO_NONE, 0, 0 }; +#else +; +#endif + +/* Default condition variable attributes: */ +SCLASS struct pthread_cond_attr pthread_condattr_default +#ifdef GLOBAL_PTHREAD_PRIVATE += { COND_TYPE_FAST, 0 }; +#else +; +#endif + +/* + * Standard I/O file descriptors need special flag treatment since + * setting one to non-blocking does all on *BSD. Sigh. This array + * is used to store the initial flag settings. + */ +SCLASS int _pthread_stdio_flags[3]; + +/* File table information: */ +SCLASS struct fd_table_entry **_thread_fd_table +#ifdef GLOBAL_PTHREAD_PRIVATE += NULL; +#else +; +#endif + +/* Table for polling file descriptors: */ +SCLASS struct pollfd *_thread_pfd_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 += 0; +#else +; +#endif + +SCLASS int _clock_res_nsec /* Clock resolution in nsec. */ +#ifdef GLOBAL_PTHREAD_PRIVATE += CLOCK_RES_NSEC; +#else +; +#endif + +/* Garbage collector mutex and condition variable. */ +SCLASS pthread_mutex_t _gc_mutex +#ifdef GLOBAL_PTHREAD_PRIVATE += NULL +#endif +; +SCLASS pthread_cond_t _gc_cond +#ifdef GLOBAL_PTHREAD_PRIVATE += NULL +#endif +; + +/* + * Array of signal actions for this process. + */ +SCLASS struct sigaction _thread_sigact[NSIG]; + +/* + * Array of counts of dummy handlers for SIG_DFL signals. This is used to + * assure that there is always a dummy signal handler installed while there is a + * thread sigwait()ing on the corresponding signal. + */ +SCLASS int _thread_dfl_count[NSIG]; + +/* + * Pending signals for this process. + */ +SCLASS sigset_t _process_sigpending; + +/* + * Scheduling queues: + */ +SCLASS pq_queue_t _readyq; +SCLASS TAILQ_HEAD(, pthread) _waitingq; + +/* + * Work queue: + */ +SCLASS TAILQ_HEAD(, pthread) _workq; + +/* Tracks the number of threads blocked while waiting for a spinlock. */ +SCLASS volatile int _spinblock_count +#ifdef GLOBAL_PTHREAD_PRIVATE += 0 +#endif +; + +/* Indicates that the signal queue needs to be checked. */ +SCLASS volatile int _sigq_check_reqd +#ifdef GLOBAL_PTHREAD_PRIVATE += 0 +#endif +; + +/* Thread switch hook. */ +SCLASS pthread_switch_routine_t _sched_switch_hook +#ifdef GLOBAL_PTHREAD_PRIVATE += NULL +#endif +; + +/* + * Spare stack queue. Stacks of default size are cached in order to reduce + * thread creation time. Spare stacks are used in LIFO order to increase cache + * locality. + */ +SCLASS SLIST_HEAD(, stack) _stackq; + +/* + * Base address of next unallocated default-size {stack, red zone}. Stacks are + * allocated contiguously, starting below the bottom of the main stack. When a + * new stack is created, a red zone is created (actually, the red zone is simply + * left unmapped) below the bottom of the stack, such that the stack will not be + * able to grow all the way to the top of the next stack. This isn't + * fool-proof. It is possible for a stack to grow by a large amount, such that + * it grows into the next stack, and as long as the memory within the red zone + * is never accessed, nothing will prevent one thread stack from trouncing all + * over the next. + */ +SCLASS void * _next_stack +#ifdef GLOBAL_PTHREAD_PRIVATE +/* main stack top - main stack size - stack size - (red zone + main stack red zone) */ += (void *) USRSTACK - PTHREAD_STACK_INITIAL - PTHREAD_STACK_DEFAULT - (2 * PTHREAD_STACK_GUARD) +#endif +; + +/* Used for _PTHREADS_INVARIANTS checking. */ +SCLASS int _thread_kern_new_state +#ifdef GLOBAL_PTHREAD_PRIVATE += 0 +#endif +; + +/* Undefine the storage class specifier: */ +#undef SCLASS + +#ifdef _LOCK_DEBUG +#define _FD_LOCK(_fd,_type,_ts) _thread_fd_lock_debug(_fd, _type, \ + _ts, __FILE__, __LINE__) +#define _FD_UNLOCK(_fd,_type) _thread_fd_unlock_debug(_fd, _type, \ + __FILE__, __LINE__) +#else +#define _FD_LOCK(_fd,_type,_ts) _thread_fd_lock(_fd, _type, _ts) +#define _FD_UNLOCK(_fd,_type) _thread_fd_unlock(_fd, _type) +#endif + +/* + * 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 _find_dead_thread(pthread_t); +int _find_thread(pthread_t); +void _funlock_owned(pthread_t); +int _thread_create(pthread_t *,const pthread_attr_t *,void *(*start_routine)(void *),void *,pthread_t); +int _thread_fd_lock(int, int, struct timespec *); +int _thread_fd_lock_debug(int, int, struct timespec *,char *fname,int lineno); +void _dispatch_signals(void); +int _mutex_cv_lock(pthread_mutex_t *); +int _mutex_cv_unlock(pthread_mutex_t *); +void _mutex_notify_priochange(pthread_t); +int _mutex_reinit(pthread_mutex_t *); +void _mutex_unlock_private(pthread_t); +int _cond_reinit(pthread_cond_t *); +int _pq_alloc(struct pq_queue *, int, int); +int _pq_init(struct pq_queue *); +void _pq_remove(struct pq_queue *pq, struct pthread *); +void _pq_insert_head(struct pq_queue *pq, struct pthread *); +void _pq_insert_tail(struct pq_queue *pq, struct pthread *); +struct pthread *_pq_first(struct pq_queue *pq); +#if defined(_PTHREADS_INVARIANTS) +void _waitq_insert(pthread_t pthread); +void _waitq_remove(pthread_t pthread); +void _waitq_setactive(void); +void _waitq_clearactive(void); +#endif +void _thread_exit(char *, int, char *); +void _thread_exit_cleanup(void); +void _thread_fd_unlock(int, int); +void _thread_fd_unlock_debug(int, int, char *, int); +void _thread_fd_unlock_owned(pthread_t); +void *_thread_cleanup(pthread_t); +void _thread_cleanupspecific(void); +void _thread_dump_info(void); +void _thread_init(void); +void _thread_kern_sched(ucontext_t *); +void _thread_kern_sched_state(enum pthread_state,char *fname,int lineno); +void _thread_kern_sched_state_unlock(enum pthread_state state, + spinlock_t *lock, char *fname, int lineno); +void _thread_kern_set_timeout(const struct timespec *); +void _thread_kern_sig_defer(void); +void _thread_kern_sig_undefer(void); +void _thread_sig_handler(int, int, ucontext_t *); +pthread_t _thread_sig_handle(int, ucontext_t *); +void _thread_sig_init(void); +void _thread_sig_send(pthread_t pthread, int sig); +void _thread_sig_deliver(pthread_t pthread, int sig); +void _thread_start(void); +void _thread_start_sig_handler(void); +void _thread_seterrno(pthread_t,int); +int _thread_fd_table_init(int fd); +pthread_addr_t _thread_gc(pthread_addr_t); +void _thread_enter_cancellation_point(void); +void _thread_leave_cancellation_point(void); +void _thread_cancellation_point(void); + +/* #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_siginterrupt(int, int); +int _thread_sys_sigpause(int); +int _thread_sys_sigreturn(ucontext_t *); +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_ +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 *); +long _thread_sys_fpathconf(int, int); +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); +void _thread_sys__exit(int); +#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 <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 + +/* #include <poll.h> */ +#ifdef _SYS_POLL_H_ +int _thread_sys_poll(struct pollfd *, unsigned, int); +#endif + +/* #include <sys/mman.h> */ +#ifdef _SYS_MMAN_H_ +int _thread_sys_msync(void *, size_t, int); +#endif + +/* #include <setjmp.h> */ +#ifdef _SETJMP_H_ +extern void __siglongjmp(sigjmp_buf, int) __dead2; +extern void __longjmp(jmp_buf, int) __dead2; +extern void ___longjmp(jmp_buf, int) __dead2; +#endif +__END_DECLS + +#endif /* !_PTHREAD_PRIVATE_H */ diff --git a/lib/libpthread/thread/thr_read.c b/lib/libpthread/thread/thr_read.c new file mode 100644 index 0000000..b4d9694 --- /dev/null +++ b/lib/libpthread/thread/thr_read.c @@ -0,0 +1,110 @@ +/* + * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by John Birrell. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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. + * + * $FreeBSD$ + * + */ +#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 ret; + int type; + + /* POSIX says to do just this: */ + if (nbytes == 0) { + return (0); + } + + /* Lock the file descriptor for read: */ + if ((ret = _FD_LOCK(fd, FD_READ, NULL)) == 0) { + /* Get the read/write mode type: */ + type = _thread_fd_table[fd]->flags & O_ACCMODE; + + /* Check if the file is not open for read: */ + if (type != O_RDONLY && type != O_RDWR) { + /* File is not open for read: */ + errno = EBADF; + _FD_UNLOCK(fd, FD_READ); + return (-1); + } + + /* Perform a non-blocking read syscall: */ + while ((ret = _thread_sys_read(fd, buf, nbytes)) < 0) { + if ((_thread_fd_table[fd]->flags & O_NONBLOCK) == 0 && + (errno == EWOULDBLOCK || errno == EAGAIN)) { + _thread_run->data.fd.fd = fd; + _thread_kern_set_timeout(NULL); + + /* Reset the interrupted operation flag: */ + _thread_run->interrupted = 0; + + _thread_kern_sched_state(PS_FDR_WAIT, + __FILE__, __LINE__); + + /* + * Check if the operation was + * interrupted by a signal + */ + if (_thread_run->interrupted) { + errno = EINTR; + ret = -1; + break; + } + } else { + break; + } + } + _FD_UNLOCK(fd, FD_READ); + } + return (ret); +} + +ssize_t +read(int fd, void *buf, size_t nbytes) +{ + ssize_t ret; + + _thread_enter_cancellation_point(); + ret = _read(fd, buf, nbytes); + _thread_leave_cancellation_point(); + + return ret; +} +#endif diff --git a/lib/libpthread/thread/thr_readv.c b/lib/libpthread/thread/thr_readv.c new file mode 100644 index 0000000..d8e02c0 --- /dev/null +++ b/lib/libpthread/thread/thr_readv.c @@ -0,0 +1,95 @@ +/* + * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by John Birrell. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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. + * + * $FreeBSD$ + * + */ +#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 ret; + int type; + + /* Lock the file descriptor for read: */ + if ((ret = _FD_LOCK(fd, FD_READ, NULL)) == 0) { + /* Get the read/write mode type: */ + type = _thread_fd_table[fd]->flags & O_ACCMODE; + + /* Check if the file is not open for read: */ + if (type != O_RDONLY && type != O_RDWR) { + /* File is not open for read: */ + errno = EBADF; + _FD_UNLOCK(fd, FD_READ); + return (-1); + } + + /* Perform a non-blocking readv syscall: */ + while ((ret = _thread_sys_readv(fd, iov, iovcnt)) < 0) { + if ((_thread_fd_table[fd]->flags & O_NONBLOCK) == 0 && + (errno == EWOULDBLOCK || errno == EAGAIN)) { + _thread_run->data.fd.fd = fd; + _thread_kern_set_timeout(NULL); + + /* Reset the interrupted operation flag: */ + _thread_run->interrupted = 0; + + _thread_kern_sched_state(PS_FDR_WAIT, + __FILE__, __LINE__); + + /* + * Check if the operation was + * interrupted by a signal + */ + if (_thread_run->interrupted) { + errno = EINTR; + ret = -1; + break; + } + } else { + break; + } + } + _FD_UNLOCK(fd, FD_READ); + } + return (ret); +} + +__strong_reference(_readv, readv); +#endif diff --git a/lib/libpthread/thread/thr_resume_np.c b/lib/libpthread/thread/thr_resume_np.c new file mode 100644 index 0000000..32b3d05 --- /dev/null +++ b/lib/libpthread/thread/thr_resume_np.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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <errno.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +/* Resume a thread: */ +int +pthread_resume_np(pthread_t thread) +{ + int ret; + enum pthread_susp old_suspended; + + /* Find the thread in the list of active threads: */ + if ((ret = _find_thread(thread)) == 0) { + /* Cancel any pending suspensions: */ + old_suspended = thread->suspended; + thread->suspended = SUSP_NO; + + /* Is it currently suspended? */ + if (thread->state == PS_SUSPENDED) { + /* + * Defer signals to protect the scheduling queues + * from access by the signal handler: + */ + _thread_kern_sig_defer(); + + switch (old_suspended) { + case SUSP_MUTEX_WAIT: + /* Set the thread's state back. */ + PTHREAD_SET_STATE(thread,PS_MUTEX_WAIT); + break; + case SUSP_COND_WAIT: + /* Set the thread's state back. */ + PTHREAD_SET_STATE(thread,PS_COND_WAIT); + break; + case SUSP_NOWAIT: + /* Allow the thread to run. */ + PTHREAD_SET_STATE(thread,PS_RUNNING); + PTHREAD_WAITQ_REMOVE(thread); + PTHREAD_PRIOQ_INSERT_TAIL(thread); + break; + case SUSP_NO: + case SUSP_YES: + /* Allow the thread to run. */ + PTHREAD_SET_STATE(thread,PS_RUNNING); + PTHREAD_PRIOQ_INSERT_TAIL(thread); + break; + } + + /* + * Undefer and handle pending signals, yielding if + * necessary: + */ + _thread_kern_sig_undefer(); + } + } + return(ret); +} +#endif diff --git a/lib/libpthread/thread/thr_rwlock.c b/lib/libpthread/thread/thr_rwlock.c new file mode 100644 index 0000000..648e8a3 --- /dev/null +++ b/lib/libpthread/thread/thr_rwlock.c @@ -0,0 +1,335 @@ +/*- + * Copyright (c) 1998 Alex Nash + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + * $FreeBSD$ + */ + +#ifdef _THREAD_SAFE +#include <errno.h> +#include <limits.h> +#include <stdlib.h> + +#include <pthread.h> +#include "pthread_private.h" + +/* maximum number of times a read lock may be obtained */ +#define MAX_READ_LOCKS (INT_MAX - 1) + +static int init_static (pthread_rwlock_t *rwlock); + +static spinlock_t static_init_lock = _SPINLOCK_INITIALIZER; + +static int +init_static (pthread_rwlock_t *rwlock) +{ + int ret; + + _SPINLOCK(&static_init_lock); + + if (*rwlock == NULL) + ret = pthread_rwlock_init(rwlock, NULL); + else + ret = 0; + + _SPINUNLOCK(&static_init_lock); + + return(ret); +} + +int +pthread_rwlock_destroy (pthread_rwlock_t *rwlock) +{ + int ret; + + if (rwlock == NULL) + ret = EINVAL; + else { + pthread_rwlock_t prwlock; + + prwlock = *rwlock; + + pthread_mutex_destroy(&prwlock->lock); + pthread_cond_destroy(&prwlock->read_signal); + pthread_cond_destroy(&prwlock->write_signal); + free(prwlock); + + *rwlock = NULL; + + ret = 0; + } + + return(ret); +} + +int +pthread_rwlock_init (pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr) +{ + pthread_rwlock_t prwlock; + int ret; + + /* allocate rwlock object */ + prwlock = (pthread_rwlock_t)malloc(sizeof(struct pthread_rwlock)); + + if (prwlock == NULL) + return(ENOMEM); + + /* initialize the lock */ + if ((ret = pthread_mutex_init(&prwlock->lock, NULL)) != 0) + free(prwlock); + else { + /* initialize the read condition signal */ + ret = pthread_cond_init(&prwlock->read_signal, NULL); + + if (ret != 0) { + pthread_mutex_destroy(&prwlock->lock); + free(prwlock); + } else { + /* initialize the write condition signal */ + ret = pthread_cond_init(&prwlock->write_signal, NULL); + + if (ret != 0) { + pthread_cond_destroy(&prwlock->read_signal); + pthread_mutex_destroy(&prwlock->lock); + free(prwlock); + } else { + /* success */ + prwlock->state = 0; + prwlock->blocked_writers = 0; + + *rwlock = prwlock; + } + } + } + + return(ret); +} + +int +pthread_rwlock_rdlock (pthread_rwlock_t *rwlock) +{ + pthread_rwlock_t prwlock; + int ret; + + if (rwlock == NULL) + return(EINVAL); + + prwlock = *rwlock; + + /* check for static initialization */ + if (prwlock == NULL) { + if ((ret = init_static(rwlock)) != 0) + return(ret); + + prwlock = *rwlock; + } + + /* grab the monitor lock */ + if ((ret = pthread_mutex_lock(&prwlock->lock)) != 0) + return(ret); + + /* give writers priority over readers */ + while (prwlock->blocked_writers || prwlock->state < 0) { + ret = pthread_cond_wait(&prwlock->read_signal, &prwlock->lock); + + if (ret != 0) { + /* can't do a whole lot if this fails */ + pthread_mutex_unlock(&prwlock->lock); + return(ret); + } + } + + /* check lock count */ + if (prwlock->state == MAX_READ_LOCKS) + ret = EAGAIN; + else + ++prwlock->state; /* indicate we are locked for reading */ + + /* + * Something is really wrong if this call fails. Returning + * error won't do because we've already obtained the read + * lock. Decrementing 'state' is no good because we probably + * don't have the monitor lock. + */ + pthread_mutex_unlock(&prwlock->lock); + + return(ret); +} + +int +pthread_rwlock_tryrdlock (pthread_rwlock_t *rwlock) +{ + pthread_rwlock_t prwlock; + int ret; + + if (rwlock == NULL) + return(EINVAL); + + prwlock = *rwlock; + + /* check for static initialization */ + if (prwlock == NULL) { + if ((ret = init_static(rwlock)) != 0) + return(ret); + + prwlock = *rwlock; + } + + /* grab the monitor lock */ + if ((ret = pthread_mutex_lock(&prwlock->lock)) != 0) + return(ret); + + /* give writers priority over readers */ + if (prwlock->blocked_writers || prwlock->state < 0) + ret = EWOULDBLOCK; + else if (prwlock->state == MAX_READ_LOCKS) + ret = EAGAIN; /* too many read locks acquired */ + else + ++prwlock->state; /* indicate we are locked for reading */ + + /* see the comment on this in pthread_rwlock_rdlock */ + pthread_mutex_unlock(&prwlock->lock); + + return(ret); +} + +int +pthread_rwlock_trywrlock (pthread_rwlock_t *rwlock) +{ + pthread_rwlock_t prwlock; + int ret; + + if (rwlock == NULL) + return(EINVAL); + + prwlock = *rwlock; + + /* check for static initialization */ + if (prwlock == NULL) { + if ((ret = init_static(rwlock)) != 0) + return(ret); + + prwlock = *rwlock; + } + + /* grab the monitor lock */ + if ((ret = pthread_mutex_lock(&prwlock->lock)) != 0) + return(ret); + + if (prwlock->state != 0) + ret = EWOULDBLOCK; + else + /* indicate we are locked for writing */ + prwlock->state = -1; + + /* see the comment on this in pthread_rwlock_rdlock */ + pthread_mutex_unlock(&prwlock->lock); + + return(ret); +} + +int +pthread_rwlock_unlock (pthread_rwlock_t *rwlock) +{ + pthread_rwlock_t prwlock; + int ret; + + if (rwlock == NULL) + return(EINVAL); + + prwlock = *rwlock; + + if (prwlock == NULL) + return(EINVAL); + + /* grab the monitor lock */ + if ((ret = pthread_mutex_lock(&prwlock->lock)) != 0) + return(ret); + + if (prwlock->state > 0) { + if (--prwlock->state == 0 && prwlock->blocked_writers) + ret = pthread_cond_signal(&prwlock->write_signal); + } else if (prwlock->state < 0) { + prwlock->state = 0; + + if (prwlock->blocked_writers) + ret = pthread_cond_signal(&prwlock->write_signal); + else + ret = pthread_cond_broadcast(&prwlock->read_signal); + } else + ret = EINVAL; + + /* see the comment on this in pthread_rwlock_rdlock */ + pthread_mutex_unlock(&prwlock->lock); + + return(ret); +} + +int +pthread_rwlock_wrlock (pthread_rwlock_t *rwlock) +{ + pthread_rwlock_t prwlock; + int ret; + + if (rwlock == NULL) + return(EINVAL); + + prwlock = *rwlock; + + /* check for static initialization */ + if (prwlock == NULL) { + if ((ret = init_static(rwlock)) != 0) + return(ret); + + prwlock = *rwlock; + } + + /* grab the monitor lock */ + if ((ret = pthread_mutex_lock(&prwlock->lock)) != 0) + return(ret); + + while (prwlock->state != 0) { + ++prwlock->blocked_writers; + + ret = pthread_cond_wait(&prwlock->write_signal, &prwlock->lock); + + if (ret != 0) { + --prwlock->blocked_writers; + pthread_mutex_unlock(&prwlock->lock); + return(ret); + } + + --prwlock->blocked_writers; + } + + /* indicate we are locked for writing */ + prwlock->state = -1; + + /* see the comment on this in pthread_rwlock_rdlock */ + pthread_mutex_unlock(&prwlock->lock); + + return(ret); +} + +#endif /* _THREAD_SAFE */ diff --git a/lib/libpthread/thread/thr_rwlockattr.c b/lib/libpthread/thread/thr_rwlockattr.c new file mode 100644 index 0000000..37eb3ea --- /dev/null +++ b/lib/libpthread/thread/thr_rwlockattr.c @@ -0,0 +1,95 @@ +/*- + * Copyright (c) 1998 Alex Nash + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + * $FreeBSD$ + */ + +#ifdef _THREAD_SAFE +#include <errno.h> +#include <stdlib.h> + +#include <pthread.h> +#include "pthread_private.h" + +int +pthread_rwlockattr_destroy(pthread_rwlockattr_t *rwlockattr) +{ + pthread_rwlockattr_t prwlockattr; + + if (rwlockattr == NULL) + return(EINVAL); + + prwlockattr = *rwlockattr; + + if (prwlockattr == NULL) + return(EINVAL); + + free(prwlockattr); + + return(0); +} + +int +pthread_rwlockattr_getpshared(const pthread_rwlockattr_t *rwlockattr, + int *pshared) +{ + *pshared = (*rwlockattr)->pshared; + + return(0); +} + +int +pthread_rwlockattr_init(pthread_rwlockattr_t *rwlockattr) +{ + pthread_rwlockattr_t prwlockattr; + + if (rwlockattr == NULL) + return(EINVAL); + + prwlockattr = (pthread_rwlockattr_t) + malloc(sizeof(struct pthread_rwlockattr)); + + if (prwlockattr == NULL) + return(ENOMEM); + + prwlockattr->pshared = PTHREAD_PROCESS_PRIVATE; + *rwlockattr = prwlockattr; + + return(0); +} + +int +pthread_rwlockattr_setpshared(pthread_rwlockattr_t *rwlockattr, int pshared) +{ + /* Only PTHREAD_PROCESS_PRIVATE is supported. */ + if (pshared != PTHREAD_PROCESS_PRIVATE) + return(EINVAL); + + (*rwlockattr)->pshared = pshared; + + return(0); +} + +#endif /* _THREAD_SAFE */ diff --git a/lib/libpthread/thread/thr_select.c b/lib/libpthread/thread/thr_select.c new file mode 100644 index 0000000..0a7c0d4 --- /dev/null +++ b/lib/libpthread/thread/thr_select.c @@ -0,0 +1,208 @@ +/* + * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by John Birrell. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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. + * + * $FreeBSD$ + */ +#include <unistd.h> +#include <errno.h> +#include <poll.h> +#include <stdlib.h> +#include <string.h> +#include <sys/param.h> +#include <sys/types.h> +#include <sys/time.h> +#include <sys/fcntl.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) +{ + struct timespec ts; + int i, ret = 0, f_wait = 1; + int pfd_index, got_one = 0, fd_count = 0; + struct pthread_poll_data data; + + if (numfds > _thread_dtablesize) { + numfds = _thread_dtablesize; + } + /* Check if a timeout was specified: */ + if (timeout) { + if (timeout->tv_sec < 0 || + timeout->tv_usec < 0 || timeout->tv_usec >= 1000000) { + errno = EINVAL; + return (-1); + } + + /* Convert the timeval to a timespec: */ + TIMEVAL_TO_TIMESPEC(timeout, &ts); + + /* Set the wake up time: */ + _thread_kern_set_timeout(&ts); + if (ts.tv_sec == 0 && ts.tv_nsec == 0) + f_wait = 0; + } else { + /* Wait for ever: */ + _thread_kern_set_timeout(NULL); + } + + /* Count the number of file descriptors to be polled: */ + if (readfds || writefds || exceptfds) { + for (i = 0; i < numfds; i++) { + if ((readfds && FD_ISSET(i, readfds)) || + (exceptfds && FD_ISSET(i, exceptfds)) || + (writefds && FD_ISSET(i, writefds))) { + fd_count++; + } + } + } + + /* + * Allocate memory for poll data if it hasn't already been + * allocated or if previously allocated memory is insufficient. + */ + if ((_thread_run->poll_data.fds == NULL) || + (_thread_run->poll_data.nfds < fd_count)) { + data.fds = (struct pollfd *) realloc(_thread_run->poll_data.fds, + sizeof(struct pollfd) * MAX(128, fd_count)); + if (data.fds == NULL) { + errno = ENOMEM; + ret = -1; + } + else { + /* + * Note that the threads poll data always + * indicates what is allocated, not what is + * currently being polled. + */ + _thread_run->poll_data.fds = data.fds; + _thread_run->poll_data.nfds = MAX(128, fd_count); + } + } + if (ret == 0) { + /* Setup the wait data. */ + data.fds = _thread_run->poll_data.fds; + data.nfds = fd_count; + + /* + * Setup the array of pollfds. Optimize this by + * running the loop in reverse and stopping when + * the number of selected file descriptors is reached. + */ + for (i = numfds - 1, pfd_index = fd_count - 1; + (i >= 0) && (pfd_index >= 0); i--) { + data.fds[pfd_index].events = 0; + if (readfds && FD_ISSET(i, readfds)) { + data.fds[pfd_index].events = POLLRDNORM; + } + if (exceptfds && FD_ISSET(i, exceptfds)) { + data.fds[pfd_index].events |= POLLRDBAND; + } + if (writefds && FD_ISSET(i, writefds)) { + data.fds[pfd_index].events |= POLLWRNORM; + } + if (data.fds[pfd_index].events != 0) { + /* + * Set the file descriptor to be polled and + * clear revents in case of a timeout which + * leaves fds unchanged: + */ + data.fds[pfd_index].fd = i; + data.fds[pfd_index].revents = 0; + pfd_index--; + } + } + if (((ret = _thread_sys_poll(data.fds, data.nfds, 0)) == 0) && + (f_wait != 0)) { + _thread_run->data.poll_data = &data; + _thread_run->interrupted = 0; + _thread_kern_sched_state(PS_SELECT_WAIT, __FILE__, __LINE__); + if (_thread_run->interrupted) { + errno = EINTR; + data.nfds = 0; + ret = -1; + } else + ret = data.nfds; + } + } + + if (ret >= 0) { + numfds = 0; + for (i = 0; i < fd_count; i++) { + /* + * Check the results of the poll and clear + * this file descriptor from the fdset if + * the requested event wasn't ready. + */ + got_one = 0; + if (readfds != NULL) { + if (FD_ISSET(data.fds[i].fd, readfds)) { + if (data.fds[i].revents & (POLLIN | + POLLRDNORM)) + got_one = 1; + else + FD_CLR(data.fds[i].fd, readfds); + } + } + if (writefds != NULL) { + if (FD_ISSET(data.fds[i].fd, writefds)) { + if (data.fds[i].revents & (POLLOUT | + POLLWRNORM | POLLWRBAND)) + got_one = 1; + else + FD_CLR(data.fds[i].fd, + writefds); + } + } + if (exceptfds != NULL) { + if (FD_ISSET(data.fds[i].fd, exceptfds)) { + if (data.fds[i].revents & (POLLRDBAND | + POLLPRI | POLLHUP | POLLERR | + POLLNVAL)) + got_one = 1; + else + FD_CLR(data.fds[i].fd, + exceptfds); + } + } + if (got_one) + numfds++; + } + ret = numfds; + } + + return (ret); +} + +__strong_reference(_select, select); +#endif diff --git a/lib/libpthread/thread/thr_self.c b/lib/libpthread/thread/thr_self.c new file mode 100644 index 0000000..81ec427 --- /dev/null +++ b/lib/libpthread/thread/thr_self.c @@ -0,0 +1,44 @@ +/* + * 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +pthread_t +pthread_self(void) +{ + /* Return the running thread pointer: */ + return (_thread_run); +} +#endif diff --git a/lib/libpthread/thread/thr_sem.c b/lib/libpthread/thread/thr_sem.c new file mode 100644 index 0000000..2dcf722 --- /dev/null +++ b/lib/libpthread/thread/thr_sem.c @@ -0,0 +1,251 @@ +/* + * Copyright (C) 2000 Jason Evans <jasone@freebsd.org>. + * 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(s), this list of conditions and the following disclaimer as + * the first lines of this file unmodified other than the possible + * addition of one or more copyright notices. + * 2. Redistributions in binary form must reproduce the above copyright + * notice(s), this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``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 COPYRIGHT HOLDER(S) 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. + * + * $FreeBSD$ + */ + +#include <errno.h> +#ifdef _THREAD_SAFE +#include <semaphore.h> +#include <pthread.h> +#include "pthread_private.h" + +#define _SEM_CHECK_VALIDITY(sem) \ + if ((*(sem))->magic != SEM_MAGIC) { \ + errno = EINVAL; \ + retval = -1; \ + goto RETURN; \ + } + +int +sem_init(sem_t *sem, int pshared, unsigned int value) +{ + int retval; + + /* + * Range check the arguments. + */ + if (pshared != 0) { + /* + * The user wants a semaphore that can be shared among + * processes, which this implementation can't do. Sounds like a + * permissions problem to me (yeah right). + */ + errno = EPERM; + retval = -1; + goto RETURN; + } + + if (value > SEM_VALUE_MAX) { + errno = EINVAL; + retval = -1; + goto RETURN; + } + + *sem = (sem_t)malloc(sizeof(struct sem)); + if (*sem == NULL) { + errno = ENOSPC; + retval = -1; + goto RETURN; + } + + /* + * Initialize the semaphore. + */ + if (pthread_mutex_init(&(*sem)->lock, NULL) != 0) { + free(*sem); + errno = ENOSPC; + retval = -1; + goto RETURN; + } + + if (pthread_cond_init(&(*sem)->gtzero, NULL) != 0) { + pthread_mutex_destroy(&(*sem)->lock); + free(*sem); + errno = ENOSPC; + retval = -1; + goto RETURN; + } + + (*sem)->count = (u_int32_t)value; + (*sem)->nwaiters = 0; + (*sem)->magic = SEM_MAGIC; + + retval = 0; + RETURN: + return retval; +} + +int +sem_destroy(sem_t *sem) +{ + int retval; + + _SEM_CHECK_VALIDITY(sem); + + /* Make sure there are no waiters. */ + pthread_mutex_lock(&(*sem)->lock); + if ((*sem)->nwaiters > 0) { + pthread_mutex_unlock(&(*sem)->lock); + errno = EBUSY; + retval = -1; + goto RETURN; + } + pthread_mutex_unlock(&(*sem)->lock); + + pthread_mutex_destroy(&(*sem)->lock); + pthread_cond_destroy(&(*sem)->gtzero); + (*sem)->magic = 0; + + free(*sem); + + retval = 0; + RETURN: + return retval; +} + +sem_t * +sem_open(const char *name, int oflag, ...) +{ + errno = ENOSYS; + return SEM_FAILED; +} + +int +sem_close(sem_t *sem) +{ + errno = ENOSYS; + return -1; +} + +int +sem_unlink(const char *name) +{ + errno = ENOSYS; + return -1; +} + +int +sem_wait(sem_t *sem) +{ + int retval; + + _thread_enter_cancellation_point(); + + _SEM_CHECK_VALIDITY(sem); + + pthread_mutex_lock(&(*sem)->lock); + + while ((*sem)->count == 0) { + (*sem)->nwaiters++; + pthread_cond_wait(&(*sem)->gtzero, &(*sem)->lock); + (*sem)->nwaiters--; + } + (*sem)->count--; + + pthread_mutex_unlock(&(*sem)->lock); + + retval = 0; + RETURN: + _thread_leave_cancellation_point(); + return retval; +} + +int +sem_trywait(sem_t *sem) +{ + int retval; + + _SEM_CHECK_VALIDITY(sem); + + pthread_mutex_lock(&(*sem)->lock); + + if ((*sem)->count > 0) { + (*sem)->count--; + retval = 0; + } else { + errno = EAGAIN; + retval = -1; + } + + pthread_mutex_unlock(&(*sem)->lock); + + RETURN: + return retval; +} + +int +sem_post(sem_t *sem) +{ + int retval; + + _SEM_CHECK_VALIDITY(sem); + + /* + * sem_post() is required to be safe to call from within signal + * handlers. Thus, we must defer signals. + */ + _thread_kern_sig_defer(); + + pthread_mutex_lock(&(*sem)->lock); + + (*sem)->count++; + if ((*sem)->nwaiters > 0) { + /* + * We must use pthread_cond_broadcast() rather than + * pthread_cond_signal() in order to assure that the highest + * priority thread is run by the scheduler, since + * pthread_cond_signal() signals waiting threads in FIFO order. + */ + pthread_cond_broadcast(&(*sem)->gtzero); + } + + pthread_mutex_unlock(&(*sem)->lock); + + _thread_kern_sig_undefer(); + retval = 0; + RETURN: + return retval; +} + +int +sem_getvalue(sem_t *sem, int *sval) +{ + int retval; + + _SEM_CHECK_VALIDITY(sem); + + pthread_mutex_lock(&(*sem)->lock); + *sval = (int)(*sem)->count; + pthread_mutex_unlock(&(*sem)->lock); + + retval = 0; + RETURN: + return retval; +} +#endif diff --git a/lib/libpthread/thread/thr_seterrno.c b/lib/libpthread/thread/thr_seterrno.c new file mode 100644 index 0000000..1934aac --- /dev/null +++ b/lib/libpthread/thread/thr_seterrno.c @@ -0,0 +1,61 @@ +/* + * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by John Birrell. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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. + * + * $FreeBSD$ + */ +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +/* + * This function needs to reference the global error variable which is + * normally hidden from the user. + */ +#ifdef errno +#undef errno; +#endif +extern int errno; + +void +_thread_seterrno(pthread_t thread, int error) +{ + /* Check for the initial thread: */ + if (thread == _thread_initial) + /* The initial thread always uses the global error variable: */ + errno = error; + else + /* + * Threads other than the initial thread always use the error + * field in the thread structureL + */ + thread->error = error; +} +#endif diff --git a/lib/libpthread/thread/thr_setprio.c b/lib/libpthread/thread/thr_setprio.c new file mode 100644 index 0000000..c630db5 --- /dev/null +++ b/lib/libpthread/thread/thr_setprio.c @@ -0,0 +1,52 @@ +/* + * 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +int +pthread_setprio(pthread_t pthread, int prio) +{ + int ret, policy; + struct sched_param param; + + if ((ret = pthread_getschedparam(pthread, &policy, ¶m)) == 0) { + param.sched_priority = prio; + ret = pthread_setschedparam(pthread, policy, ¶m); + } + + /* Return the error status: */ + return (ret); +} +#endif diff --git a/lib/libpthread/thread/thr_setschedparam.c b/lib/libpthread/thread/thr_setschedparam.c new file mode 100644 index 0000000..bce965f --- /dev/null +++ b/lib/libpthread/thread/thr_setschedparam.c @@ -0,0 +1,116 @@ +/* + * Copyright (c) 1998 Daniel Eischen <eischen@vigrid.com>. + * 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 Daniel Eischen. + * 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 DANIEL EISCHEN 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <errno.h> +#include <sys/param.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +int +pthread_setschedparam(pthread_t pthread, int policy, + const struct sched_param *param) +{ + int old_prio, in_readyq = 0, ret = 0; + + if ((param == NULL) || (policy < SCHED_FIFO) || (policy > SCHED_RR)) { + /* Return an invalid argument error: */ + ret = EINVAL; + } else if ((param->sched_priority < PTHREAD_MIN_PRIORITY) || + (param->sched_priority > PTHREAD_MAX_PRIORITY)) { + /* Return an unsupported value error. */ + ret = ENOTSUP; + + /* Find the thread in the list of active threads: */ + } else if ((ret = _find_thread(pthread)) == 0) { + /* + * Defer signals to protect the scheduling queues from + * access by the signal handler: + */ + _thread_kern_sig_defer(); + + if (param->sched_priority != pthread->base_priority) { + /* + * Remove the thread from its current priority + * queue before any adjustments are made to its + * active priority: + */ + old_prio = pthread->active_priority; + if ((pthread->flags & PTHREAD_FLAGS_IN_PRIOQ) != 0) { + in_readyq = 1; + PTHREAD_PRIOQ_REMOVE(pthread); + } + + /* Set the thread base priority: */ + pthread->base_priority = param->sched_priority; + + /* Recalculate the active priority: */ + pthread->active_priority = MAX(pthread->base_priority, + pthread->inherited_priority); + + if (in_readyq) { + if ((pthread->priority_mutex_count > 0) && + (old_prio > pthread->active_priority)) { + /* + * POSIX states that if the priority is + * being lowered, the thread must be + * inserted at the head of the queue for + * its priority if it owns any priority + * protection or inheritence mutexes. + */ + PTHREAD_PRIOQ_INSERT_HEAD(pthread); + } + else + PTHREAD_PRIOQ_INSERT_TAIL(pthread); + } + + /* + * Check for any mutex priority adjustments. This + * includes checking for a priority mutex on which + * this thread is waiting. + */ + _mutex_notify_priochange(pthread); + } + + /* Set the scheduling policy: */ + pthread->attr.sched_policy = policy; + + /* + * Undefer and handle pending signals, yielding if + * necessary: + */ + _thread_kern_sig_undefer(); + } + return(ret); +} +#endif diff --git a/lib/libpthread/thread/thr_sig.c b/lib/libpthread/thread/thr_sig.c new file mode 100644 index 0000000..86ded7f --- /dev/null +++ b/lib/libpthread/thread/thr_sig.c @@ -0,0 +1,761 @@ +/* + * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by John Birrell. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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. + * + * $FreeBSD$ + */ +#include <sys/param.h> +#include <sys/types.h> +#include <sys/signalvar.h> +#include <signal.h> +#include <fcntl.h> +#include <unistd.h> +#include <setjmp.h> +#include <errno.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +/* Prototypes: */ +static void thread_sig_check_state(pthread_t pthread, int sig); +static void thread_sig_finish_longjmp(void *arg); +static void handle_state_change(pthread_t pthread); + + +/* Static variables: */ +static spinlock_t signal_lock = _SPINLOCK_INITIALIZER; +static unsigned int pending_sigs[NSIG]; +static unsigned int handled_sigs[NSIG]; +static int volatile check_pending = 0; +static int volatile check_waiting = 0; + +/* Initialize signal handling facility: */ +void +_thread_sig_init(void) +{ + int i; + + /* Clear pending and handled signal counts: */ + for (i = 1; i < NSIG; i++) { + pending_sigs[i - 1] = 0; + handled_sigs[i - 1] = 0; + } + + /* Clear the lock: */ + signal_lock.access_lock = 0; + + /* Clear the process pending signals: */ + sigemptyset(&_process_sigpending); +} + +void +_thread_sig_handler(int sig, int code, ucontext_t * scp) +{ + pthread_t pthread, pthread_next; + int i; + char c; + + /* Check if an interval timer signal: */ + if (sig == _SCHED_SIGNAL) { + if (_thread_kern_in_sched != 0) { + /* + * The scheduler is already running; ignore this + * signal. + */ + } + /* + * Check if the scheduler interrupt has come when + * the currently running thread has deferred thread + * signals. + */ + else if (_thread_run->sig_defer_count > 0) + _thread_run->yield_on_sig_undefer = 1; + + else { + /* + * 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"); + } + } + /* + * Check if the kernel has been interrupted while the scheduler + * is accessing the scheduling queues or if there is a currently + * running thread that has deferred signals. + */ + else if ((_queue_signals != 0) || ((_thread_kern_in_sched == 0) && + (_thread_run->sig_defer_count > 0))) { + /* 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. + */ + _thread_sys_write(_thread_kern_pipe[1], &c, 1); + + /* Indicate that there are queued signals in the pipe. */ + _sigq_check_reqd = 1; + } else { + if (_atomic_lock(&signal_lock.access_lock)) { + /* There is another signal handler running: */ + pending_sigs[sig - 1]++; + check_pending = 1; + } + else { + /* It's safe to handle the signal now. */ + pthread = _thread_sig_handle(sig, scp); + + /* Reset the pending and handled count back to 0: */ + pending_sigs[sig - 1] = 0; + handled_sigs[sig - 1] = 0; + + if (pthread == NULL) + signal_lock.access_lock = 0; + else { + sigaddset(&pthread->sigmask, sig); + + /* + * Make sure not to deliver the same signal to + * the thread twice. sigpend is potentially + * modified by the call chain + * _thread_sig_handle() --> + * thread_sig_check_state(), which can happen + * just above. + */ + if (sigismember(&pthread->sigpend, sig)) + sigdelset(&pthread->sigpend, sig); + + signal_lock.access_lock = 0; + _thread_sig_deliver(pthread, sig); + sigdelset(&pthread->sigmask, sig); + } + } + + /* Enter a loop to process pending signals: */ + while ((check_pending != 0) && + (_atomic_lock(&signal_lock.access_lock) == 0)) { + check_pending = 0; + for (i = 1; i < NSIG; i++) { + if (pending_sigs[i - 1] > handled_sigs[i - 1]) { + pending_sigs[i - 1] = handled_sigs[i - 1]; + pthread = _thread_sig_handle(i, scp); + if (pthread != NULL) { + sigaddset(&pthread->sigmask, i); + /* Save the old state: */ + pthread->oldstate = pthread->state; + signal_lock.access_lock = 0; + _thread_sig_deliver(pthread, i); + sigdelset(&pthread->sigmask, i); + if (_atomic_lock(&signal_lock.access_lock)) { + check_pending = 1; + /* + * Have the lock holder take care + * of any state changes: + */ + if (pthread->state != pthread->oldstate) + check_waiting = 1; + return; + } + if (pthread->state != pthread->oldstate) + handle_state_change(pthread); + } + } + } + while (check_waiting != 0) { + check_waiting = 0; + /* + * Enter a loop to wake up all threads waiting + * for a process to complete: + */ + for (pthread = TAILQ_FIRST(&_waitingq); + pthread != NULL; pthread = pthread_next) { + pthread_next = TAILQ_NEXT(pthread, pqe); + if (pthread->state == PS_RUNNING) + handle_state_change(pthread); + } + } + /* Release the lock: */ + signal_lock.access_lock = 0; + } + + /* + * Check to see if the current thread performed a + * [sig|_]longjmp() out of a signal handler. + */ + if ((_thread_run->jmpflags & (JMPFLAGS_LONGJMP | + JMPFLAGS__LONGJMP)) != 0) { + _thread_run->jmpflags = JMPFLAGS_NONE; + __longjmp(_thread_run->nested_jmp.jmp, + _thread_run->longjmp_val); + } else if ((_thread_run->jmpflags & JMPFLAGS_SIGLONGJMP) != 0) { + _thread_run->jmpflags = JMPFLAGS_NONE; + __siglongjmp(_thread_run->nested_jmp.sigjmp, + _thread_run->longjmp_val); + } + } +} + +pthread_t +_thread_sig_handle(int sig, ucontext_t * scp) +{ + int i, handler_installed; + pthread_t pthread, pthread_next; + pthread_t suspended_thread, signaled_thread; + + /* Check if the signal requires a dump of thread information: */ + if (sig == SIGINFO) + /* Dump thread information to file: */ + _thread_dump_info(); + + /* Check if an interval timer signal: */ + else if (sig == _SCHED_SIGNAL) { + /* + * This shouldn't ever occur (should this panic?). + */ + } else { + /* Check if a child has terminated: */ + if (sig == SIGCHLD) { + /* + * Go through the file list and set all files + * to non-blocking again in case the child + * set some of them to block. Sigh. + */ + 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); + } + } + /* + * Enter a loop to wake up all threads waiting + * for a process to complete: + */ + for (pthread = TAILQ_FIRST(&_waitingq); + pthread != NULL; pthread = pthread_next) { + /* + * Grab the next thread before possibly + * destroying the link entry: + */ + pthread_next = TAILQ_NEXT(pthread, pqe); + + /* + * If this thread is waiting for a child + * process to complete, wake it up: + */ + if (pthread->state == PS_WAIT_WAIT) { + /* Make the thread runnable: */ + PTHREAD_NEW_STATE(pthread,PS_RUNNING); + + /* Return the signal number: */ + pthread->signo = sig; + } + } + } + + /* + * POSIX says that pending SIGCONT signals are + * discarded when one of these signals occurs. + */ + if (sig == SIGTSTP || sig == SIGTTIN || sig == SIGTTOU) { + /* + * Enter a loop to discard pending SIGCONT + * signals: + */ + TAILQ_FOREACH(pthread, &_thread_list, tle) { + sigdelset(&pthread->sigpend,SIGCONT); + } + } + + /* + * Enter a loop to look for threads that have the signal + * unmasked. POSIX specifies that a thread in a sigwait + * will get the signal over any other threads. Second + * preference will be threads in in a sigsuspend. If + * none of the above, then the signal is delivered to the + * first thread we find. Note that if a custom handler + * is not installed, the signal only affects threads in + * sigwait. + */ + suspended_thread = NULL; + signaled_thread = NULL; + if ((_thread_sigact[sig - 1].sa_handler == SIG_IGN) || + (_thread_sigact[sig - 1].sa_handler == SIG_DFL)) + handler_installed = 0; + else + handler_installed = 1; + + for (pthread = TAILQ_FIRST(&_waitingq); + pthread != NULL; pthread = pthread_next) { + /* + * Grab the next thread before possibly destroying + * the link entry. + */ + pthread_next = TAILQ_NEXT(pthread, pqe); + + if ((pthread->state == PS_SIGWAIT) && + sigismember(pthread->data.sigwait, sig)) { + /* Change the state of the thread to run: */ + PTHREAD_NEW_STATE(pthread,PS_RUNNING); + + /* Return the signal number: */ + pthread->signo = sig; + + /* + * POSIX doesn't doesn't specify which thread + * will get the signal if there are multiple + * waiters, so we give it to the first thread + * we find. + * + * Do not attempt to deliver this signal + * to other threads. + */ + return (NULL); + } + else if ((handler_installed != 0) && + !sigismember(&pthread->sigmask, sig)) { + if (pthread->state == PS_SIGSUSPEND) { + if (suspended_thread == NULL) + suspended_thread = pthread; + } else if (signaled_thread == NULL) + signaled_thread = pthread; + } + } + + /* + * Only perform wakeups and signal delivery if there is a + * custom handler installed: + */ + if (handler_installed != 0) { + /* + * If we didn't find a thread in the waiting queue, + * check the all threads queue: + */ + if (suspended_thread == NULL && + signaled_thread == NULL) { + /* + * Enter a loop to look for other threads + * capable of receiving the signal: + */ + TAILQ_FOREACH(pthread, &_thread_list, tle) { + if (!sigismember(&pthread->sigmask, + sig)) { + signaled_thread = pthread; + break; + } + } + } + + if (suspended_thread == NULL && + signaled_thread == NULL) + /* + * Add it to the set of signals pending + * on the process: + */ + sigaddset(&_process_sigpending, sig); + else { + /* + * We only deliver the signal to one thread; + * give preference to the suspended thread: + */ + if (suspended_thread != NULL) + pthread = suspended_thread; + else + pthread = signaled_thread; + + /* + * Perform any state changes due to signal + * arrival: + */ + thread_sig_check_state(pthread, sig); + return (pthread); + } + } + } + + /* Returns nothing. */ + return (NULL); +} + +static void +thread_sig_finish_longjmp(void *arg) +{ + /* + * Check to see if the current thread performed a [_]longjmp() out of a + * signal handler. + */ + if ((_thread_run->jmpflags & (JMPFLAGS_LONGJMP | JMPFLAGS__LONGJMP)) + != 0) { + _thread_run->jmpflags = JMPFLAGS_NONE; + _thread_run->continuation = NULL; + __longjmp(_thread_run->nested_jmp.jmp, + _thread_run->longjmp_val); + } + /* + * Check to see if the current thread performed a siglongjmp + * out of a signal handler: + */ + else if ((_thread_run->jmpflags & JMPFLAGS_SIGLONGJMP) != 0) { + _thread_run->jmpflags = JMPFLAGS_NONE; + _thread_run->continuation = NULL; + __siglongjmp(_thread_run->nested_jmp.sigjmp, + _thread_run->longjmp_val); + } +} + +static void +handle_state_change(pthread_t pthread) +{ + /* + * We should only need to handle threads whose state was + * changed to running: + */ + if (pthread->state == PS_RUNNING) { + switch (pthread->oldstate) { + /* + * States which do not change when a signal is trapped: + */ + case PS_DEAD: + case PS_DEADLOCK: + case PS_RUNNING: + case PS_SIGTHREAD: + case PS_STATE_MAX: + case PS_SUSPENDED: + break; + + /* + * States which need to return to critical sections + * before they can switch contexts: + */ + case PS_COND_WAIT: + case PS_FDLR_WAIT: + case PS_FDLW_WAIT: + case PS_FILE_WAIT: + case PS_JOIN: + case PS_MUTEX_WAIT: + /* Indicate that the thread was interrupted: */ + pthread->interrupted = 1; + /* + * Defer the [sig|_]longjmp until leaving the critical + * region: + */ + pthread->jmpflags |= JMPFLAGS_DEFERRED; + + /* Set the continuation routine: */ + pthread->continuation = thread_sig_finish_longjmp; + /* FALLTHROUGH */ + case PS_FDR_WAIT: + case PS_FDW_WAIT: + case PS_POLL_WAIT: + case PS_SELECT_WAIT: + case PS_SIGSUSPEND: + case PS_SIGWAIT: + case PS_SLEEP_WAIT: + case PS_SPINBLOCK: + case PS_WAIT_WAIT: + if ((pthread->flags & PTHREAD_FLAGS_IN_WAITQ) != 0) { + PTHREAD_WAITQ_REMOVE(pthread); + if (pthread->flags & PTHREAD_FLAGS_IN_WORKQ) + PTHREAD_WORKQ_REMOVE(pthread); + } + break; + } + + if ((pthread->flags & PTHREAD_FLAGS_IN_PRIOQ) == 0) + PTHREAD_PRIOQ_INSERT_TAIL(pthread); + } +} + + +/* Perform thread specific actions in response to a signal: */ +static void +thread_sig_check_state(pthread_t pthread, int sig) +{ + /* + * 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_DEADLOCK: + case PS_FILE_WAIT: + case PS_JOIN: + case PS_MUTEX_WAIT: + case PS_RUNNING: + case PS_STATE_MAX: + case PS_SIGTHREAD: + case PS_SPINBLOCK: + case PS_SUSPENDED: + /* Increment the pending signal count. */ + sigaddset(&pthread->sigpend,sig); + break; + + case PS_SIGWAIT: + /* Wake up the thread if the signal is blocked. */ + if (sigismember(pthread->data.sigwait, sig)) { + /* Change the state of the thread to run: */ + PTHREAD_NEW_STATE(pthread,PS_RUNNING); + + /* Return the signal number: */ + pthread->signo = sig; + } else + /* Increment the pending signal count. */ + sigaddset(&pthread->sigpend,sig); + break; + + /* + * The wait state is a special case due to the handling of + * SIGCHLD signals. + */ + case PS_WAIT_WAIT: + /* + * Check for signals other than the death of a child + * process: + */ + if (sig != SIGCHLD) + /* Flag the operation as interrupted: */ + pthread->interrupted = 1; + + /* Change the state of the thread to run: */ + PTHREAD_NEW_STATE(pthread,PS_RUNNING); + + /* Return the signal number: */ + pthread->signo = sig; + break; + + /* + * States that are interrupted by the occurrence of a signal + * other than the scheduling alarm: + */ + case PS_FDLR_WAIT: + case PS_FDLW_WAIT: + case PS_FDR_WAIT: + case PS_FDW_WAIT: + case PS_POLL_WAIT: + case PS_SLEEP_WAIT: + case PS_SELECT_WAIT: + if ((_thread_sigact[sig - 1].sa_flags & SA_RESTART) == 0) { + /* Flag the operation as interrupted: */ + pthread->interrupted = 1; + + if (pthread->flags & PTHREAD_FLAGS_IN_WORKQ) + PTHREAD_WORKQ_REMOVE(pthread); + + /* Change the state of the thread to run: */ + PTHREAD_NEW_STATE(pthread,PS_RUNNING); + + /* Return the signal number: */ + pthread->signo = sig; + } + break; + + case PS_SIGSUSPEND: + /* + * Only wake up the thread if there is a handler installed + * for the signal. + */ + if (_thread_sigact[sig - 1].sa_handler != SIG_DFL) { + /* Change the state of the thread to run: */ + PTHREAD_NEW_STATE(pthread,PS_RUNNING); + + /* Return the signal number: */ + pthread->signo = sig; + } + break; + } +} + +/* Send a signal to a specific thread (ala pthread_kill): */ +void +_thread_sig_send(pthread_t pthread, int sig) +{ + /* + * Check that the signal is not being ignored: + */ + if (_thread_sigact[sig - 1].sa_handler != SIG_IGN) { + if (pthread->state == PS_SIGWAIT && + sigismember(pthread->data.sigwait, sig)) { + /* Change the state of the thread to run: */ + PTHREAD_NEW_STATE(pthread,PS_RUNNING); + + /* Return the signal number: */ + pthread->signo = sig; + } else if (pthread->state != PS_SIGWAIT && + !sigismember(&pthread->sigmask, sig)) { + /* Perform any state changes due to signal arrival: */ + thread_sig_check_state(pthread, sig); + /* Increment the pending signal count. */ + sigaddset(&pthread->sigpend,sig); + } else { + /* Increment the pending signal count. */ + sigaddset(&pthread->sigpend,sig); + } + } +} + +/* Dispatch pending signals to the running thread: */ +void +_dispatch_signals() +{ + sigset_t sigset; + int i; + + /* + * Check if there are pending signals for the running + * thread or process that aren't blocked: + */ + sigset = _thread_run->sigpend; + SIGSETOR(sigset, _process_sigpending); + SIGSETNAND(sigset, _thread_run->sigmask); + if (SIGNOTEMPTY(sigset)) { + /* + * Enter a loop to calculate deliverable pending signals + * before actually delivering them. The pending signals + * must be removed from the pending signal sets before + * calling the signal handler because the handler may + * call library routines that again check for and deliver + * pending signals. + */ + for (i = 1; i < NSIG; i++) { + /* + * Check that a custom handler is installed + * and if the signal is not blocked: + */ + if (_thread_sigact[i - 1].sa_handler != SIG_DFL && + _thread_sigact[i - 1].sa_handler != SIG_IGN && + sigismember(&sigset, i)) { + if (sigismember(&_thread_run->sigpend,i)) + /* Clear the thread pending signal: */ + sigdelset(&_thread_run->sigpend,i); + else + /* Clear the process pending signal: */ + sigdelset(&_process_sigpending,i); + } + else + /* Remove the signal if it can't be handled: */ + sigdelset(&sigset, i); + } + + /* Now deliver the signals: */ + for (i = 1; i < NSIG; i++) { + if (sigismember(&sigset, i)) + /* Deliver the signal to the running thread: */ + _thread_sig_deliver(_thread_run, i); + } + } +} + +/* Deliver a signal to a thread: */ +void +_thread_sig_deliver(pthread_t pthread, int sig) +{ + sigset_t mask; + pthread_t pthread_saved; + jmp_buf jb, *saved_sighandler_jmp_buf; + + /* + * Check that a custom handler is installed + * and if the signal is not blocked: + */ + if (_thread_sigact[sig - 1].sa_handler != SIG_DFL && + _thread_sigact[sig - 1].sa_handler != SIG_IGN) { + /* Save the current thread: */ + pthread_saved = _thread_run; + + /* Save the threads signal mask: */ + mask = pthread->sigmask; + + /* + * Add the current signal and signal handler + * mask to the thread's current signal mask: + */ + SIGSETOR(pthread->sigmask, _thread_sigact[sig - 1].sa_mask); + sigaddset(&pthread->sigmask, sig); + + /* Current thread inside critical region? */ + if (_thread_run->sig_defer_count > 0) + pthread->sig_defer_count++; + + /* Increment the number of nested signals being handled. */ + pthread->signal_nest_level++; + + /* + * The jump buffer is allocated off the stack and the current + * jump buffer is saved. If the signal handler tries to + * [sig|_]longjmp(), our version of [sig|_]longjmp() will copy + * the user supplied jump buffer into + * _thread_run->nested_jmp.[sig]jmp and _longjmp() back to here. + */ + saved_sighandler_jmp_buf = pthread->sighandler_jmp_buf; + pthread->sighandler_jmp_buf = &jb; + + _thread_run = pthread; + + if (_setjmp(jb) == 0) { + /* + * Dispatch the signal via the custom signal + * handler: + */ + (*(_thread_sigact[sig - 1].sa_handler))(sig); + } + + _thread_run = pthread_saved; + + pthread->sighandler_jmp_buf = saved_sighandler_jmp_buf; + + /* Decrement the signal nest level. */ + pthread->signal_nest_level--; + + /* Current thread inside critical region? */ + if (_thread_run->sig_defer_count > 0) + pthread->sig_defer_count--; + + /* Restore the threads signal mask: */ + pthread->sigmask = mask; + } +} +#endif diff --git a/lib/libpthread/thread/thr_sigaction.c b/lib/libpthread/thread/thr_sigaction.c new file mode 100644 index 0000000..319999b --- /dev/null +++ b/lib/libpthread/thread/thr_sigaction.c @@ -0,0 +1,110 @@ +/* + * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by John Birrell. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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. + * + * $FreeBSD$ + */ +#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; + struct sigaction gact; + + /* Check if the signal number is out of range: */ + if (sig < 1 || sig > NSIG) { + /* Return an invalid argument: */ + errno = 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_sigact[sig - 1].sa_handler; + oact->sa_mask = _thread_sigact[sig - 1].sa_mask; + oact->sa_flags = _thread_sigact[sig - 1].sa_flags; + } + + /* Check if a signal action was supplied: */ + if (act != NULL) { + /* Set the new signal handler: */ + _thread_sigact[sig - 1].sa_mask = act->sa_mask; + _thread_sigact[sig - 1].sa_flags = act->sa_flags; + _thread_sigact[sig - 1].sa_handler = act->sa_handler; + } + + /* + * Check if the kernel needs to be advised of a change + * in signal action: + */ + if (act != NULL && sig != _SCHED_SIGNAL && sig != SIGCHLD && + sig != SIGINFO) { + /* Initialise the global signal action structure: */ + gact.sa_mask = act->sa_mask; + gact.sa_flags = 0; + + /* Ensure the scheduling signal is masked: */ + sigaddset(&gact.sa_mask, _SCHED_SIGNAL); + + /* + * Check if the signal handler is being set to + * the default or ignore handlers: + */ + if (act->sa_handler == SIG_DFL || + act->sa_handler == SIG_IGN) + /* Specify the built in handler: */ + gact.sa_handler = act->sa_handler; + else + /* + * Specify the thread kernel signal + * handler: + */ + gact.sa_handler = (void (*) ()) _thread_sig_handler; + + /* Change the signal action in the kernel: */ + if (_thread_sys_sigaction(sig,&gact,NULL) != 0) + ret = -1; + } + } + + /* Return the completion status: */ + return (ret); +} + +__strong_reference(_sigaction, sigaction); +#endif diff --git a/lib/libpthread/thread/thr_sigmask.c b/lib/libpthread/thread/thr_sigmask.c new file mode 100644 index 0000000..b880d9c --- /dev/null +++ b/lib/libpthread/thread/thr_sigmask.c @@ -0,0 +1,93 @@ +/* + * Copyright (c) 1997 John Birrell <jb@cimlogic.com.au>. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by John Birrell. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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. + * + * $FreeBSD$ + */ +#include <sys/param.h> +#include <sys/types.h> +#include <sys/signalvar.h> +#include <errno.h> +#include <signal.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +int +pthread_sigmask(int how, const sigset_t *set, sigset_t *oset) +{ + int ret = 0; + + /* 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) { + /* Process according to what to do: */ + switch (how) { + /* Block signals: */ + case SIG_BLOCK: + /* Add signals to the existing mask: */ + SIGSETOR(_thread_run->sigmask, *set); + break; + + /* Unblock signals: */ + case SIG_UNBLOCK: + /* Clear signals from the existing mask: */ + SIGSETNAND(_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: */ + errno = EINVAL; + ret = -1; + break; + } + + /* + * Dispatch signals to the running thread that are pending + * and now unblocked: + */ + _dispatch_signals(); + } + + /* Return the completion status: */ + return (ret); +} +#endif diff --git a/lib/libpthread/thread/thr_sigpending.c b/lib/libpthread/thread/thr_sigpending.c new file mode 100644 index 0000000..a118347 --- /dev/null +++ b/lib/libpthread/thread/thr_sigpending.c @@ -0,0 +1,58 @@ +/* + * Copyright (c) 1999 Daniel Eischen <eischen@vigrid.com>. + * 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 DANIEL EISCHEN 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <signal.h> +#include <errno.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +int +_sigpending(sigset_t * set) +{ + int ret = 0; + + /* Check for a null signal set pointer: */ + if (set == NULL) { + /* Return an invalid argument: */ + ret = EINVAL; + } + else { + *set = _thread_run->sigpend; + } + /* Return the completion status: */ + return (ret); +} + +__strong_reference(_sigpending, sigpending); +#endif diff --git a/lib/libpthread/thread/thr_sigprocmask.c b/lib/libpthread/thread/thr_sigprocmask.c new file mode 100644 index 0000000..6addb4a --- /dev/null +++ b/lib/libpthread/thread/thr_sigprocmask.c @@ -0,0 +1,94 @@ +/* + * 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <sys/param.h> +#include <sys/types.h> +#include <sys/signalvar.h> +#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; + + /* 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) { + /* Process according to what to do: */ + switch (how) { + /* Block signals: */ + case SIG_BLOCK: + /* Add signals to the existing mask: */ + SIGSETOR(_thread_run->sigmask, *set); + break; + + /* Unblock signals: */ + case SIG_UNBLOCK: + /* Clear signals from the existing mask: */ + SIGSETNAND(_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: */ + errno = EINVAL; + ret = -1; + break; + } + + /* + * Dispatch signals to the running thread that are pending + * and now unblocked: + */ + _dispatch_signals(); + } + /* Return the completion status: */ + return (ret); +} + +__strong_reference(_sigprocmask, sigprocmask); +#endif diff --git a/lib/libpthread/thread/thr_sigsuspend.c b/lib/libpthread/thread/thr_sigsuspend.c new file mode 100644 index 0000000..28959c8 --- /dev/null +++ b/lib/libpthread/thread/thr_sigsuspend.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 AUTHOR 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. + * + * $FreeBSD$ + */ +#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 signal mask: */ + oset = _thread_run->sigmask; + + /* Change the caller's mask: */ + _thread_run->sigmask = *set; + + /* Wait for a signal: */ + _thread_kern_sched_state(PS_SIGSUSPEND, __FILE__, __LINE__); + + /* Always return an interrupted error: */ + errno = EINTR; + + /* Restore the signal mask: */ + _thread_run->sigmask = oset; + } else { + /* Return an invalid argument error: */ + errno = EINVAL; + } + + /* Return the completion status: */ + return (ret); +} + +int +sigsuspend(const sigset_t * set) +{ + int ret; + + _thread_enter_cancellation_point(); + ret = _sigsuspend(set); + _thread_leave_cancellation_point(); + + return ret; +} +#endif diff --git a/lib/libpthread/thread/thr_sigwait.c b/lib/libpthread/thread/thr_sigwait.c new file mode 100644 index 0000000..b12c028 --- /dev/null +++ b/lib/libpthread/thread/thr_sigwait.c @@ -0,0 +1,173 @@ +/* + * Copyright (c) 1997 John Birrell <jb@cimlogic.com.au>. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by John Birrell. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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. + * + * $FreeBSD$ + */ +#include <signal.h> +#include <sys/param.h> +#include <sys/signalvar.h> +#include <errno.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +int +sigwait(const sigset_t * set, int *sig) +{ + int ret = 0; + int i; + sigset_t tempset, waitset; + struct sigaction act; + + _thread_enter_cancellation_point(); + /* + * Specify the thread kernel signal handler. + */ + act.sa_handler = (void (*) ()) _thread_sig_handler; + act.sa_flags = SA_RESTART; + act.sa_mask = *set; + + /* Ensure the scheduling signal is masked: */ + sigaddset(&act.sa_mask, _SCHED_SIGNAL); + + /* + * Initialize the set of signals that will be waited on: + */ + waitset = *set; + + /* These signals can't be waited on. */ + sigdelset(&waitset, SIGKILL); + sigdelset(&waitset, SIGSTOP); + sigdelset(&waitset, _SCHED_SIGNAL); + sigdelset(&waitset, SIGCHLD); + sigdelset(&waitset, SIGINFO); + + /* Check to see if a pending signal is in the wait mask. */ + tempset = _thread_run->sigpend; + SIGSETOR(tempset, _process_sigpending); + SIGSETAND(tempset, waitset); + if (SIGNOTEMPTY(tempset)) { + /* Enter a loop to find a pending signal: */ + for (i = 1; i < NSIG; i++) { + if (sigismember (&tempset, i)) + break; + } + + /* Clear the pending signal: */ + if (sigismember(&_thread_run->sigpend,i)) + sigdelset(&_thread_run->sigpend,i); + else + sigdelset(&_process_sigpending,i); + + /* Return the signal number to the caller: */ + *sig = i; + + _thread_leave_cancellation_point(); + return (0); + } + + /* + * Access the _thread_dfl_count array under the protection of signal + * deferral. + */ + _thread_kern_sig_defer(); + + /* + * Enter a loop to find the signals that are SIG_DFL. For + * these signals we must install a dummy signal handler in + * order for the kernel to pass them in to us. POSIX says + * that the _application_ must explicitly install a dummy + * handler for signals that are SIG_IGN in order to sigwait + * on them. Note that SIG_IGN signals are left in the + * mask because a subsequent sigaction could enable an + * ignored signal. + */ + for (i = 1; i < NSIG; i++) { + if (sigismember(&waitset, i) && + (_thread_sigact[i - 1].sa_handler == SIG_DFL)) { + _thread_dfl_count[i]++; + if (_thread_dfl_count[i] == 1) { + if (_thread_sys_sigaction(i,&act,NULL) != 0) + ret = -1; + } + } + } + /* Done accessing _thread_dfl_count for now. */ + _thread_kern_sig_undefer(); + + if (ret == 0) { + /* + * Save the wait signal mask. The wait signal + * mask is independent of the threads signal mask + * and requires separate storage. + */ + _thread_run->data.sigwait = &waitset; + + /* Wait for a signal: */ + _thread_kern_sched_state(PS_SIGWAIT, __FILE__, __LINE__); + + /* Return the signal number to the caller: */ + *sig = _thread_run->signo; + + /* + * Probably unnecessary, but since it's in a union struct + * we don't know how it could be used in the future. + */ + _thread_run->data.sigwait = NULL; + } + + /* + * Access the _thread_dfl_count array under the protection of signal + * deferral. + */ + _thread_kern_sig_defer(); + + /* Restore the sigactions: */ + act.sa_handler = SIG_DFL; + for (i = 1; i < NSIG; i++) { + if (sigismember(&waitset, i) && + (_thread_sigact[i - 1].sa_handler == SIG_DFL)) { + _thread_dfl_count[i]--; + if (_thread_dfl_count == 0) { + if (_thread_sys_sigaction(i,&act,NULL) != 0) + ret = -1; + } + } + } + /* Done accessing _thread_dfl_count. */ + _thread_kern_sig_undefer(); + + _thread_leave_cancellation_point(); + + /* Return the completion status: */ + return (ret); +} +#endif diff --git a/lib/libpthread/thread/thr_single_np.c b/lib/libpthread/thread/thr_single_np.c new file mode 100644 index 0000000..d6ecb48 --- /dev/null +++ b/lib/libpthread/thread/thr_single_np.c @@ -0,0 +1,45 @@ +/* + * Copyright (c) 1996 John Birrell <jb@cimlogic.com.au>. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by John Birrell. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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. + * + * $FreeBSD$ + */ +#include <string.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +int pthread_single_np() +{ + /* Enter single-threaded (non-POSIX) scheduling mode: */ + _thread_single = _thread_run; + return(0); +} +#endif diff --git a/lib/libpthread/thread/thr_sleep.c b/lib/libpthread/thread/thr_sleep.c new file mode 100644 index 0000000..fdfeeec --- /dev/null +++ b/lib/libpthread/thread/thr_sleep.c @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2000 Jason Evans <jasone@freebsd.org>. + * 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(s), this list of conditions and the following disclaimer as + * the first lines of this file unmodified other than the possible + * addition of one or more copyright notices. + * 2. Redistributions in binary form must reproduce the above copyright + * notice(s), this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``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 COPYRIGHT HOLDER(S) 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. + * + * $FreeBSD$ + */ + +#include <unistd.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +unsigned int +sleep(unsigned int seconds) +{ + unsigned int ret; + + _thread_enter_cancellation_point(); + ret = __sleep(seconds); + _thread_leave_cancellation_point(); + + return ret; +} +#endif diff --git a/lib/libpthread/thread/thr_spec.c b/lib/libpthread/thread/thr_spec.c new file mode 100644 index 0000000..1485cbb --- /dev/null +++ b/lib/libpthread/thread/thr_spec.c @@ -0,0 +1,200 @@ +/* + * 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#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_KEYS_MAX]; + +int +pthread_key_create(pthread_key_t * key, void (*destructor) (void *)) +{ + for ((*key) = 0; (*key) < PTHREAD_KEYS_MAX; (*key)++) { + /* Lock the key table entry: */ + _SPINLOCK(&key_table[*key].lock); + + if (key_table[(*key)].allocated == 0) { + key_table[(*key)].allocated = 1; + key_table[(*key)].destructor = destructor; + + /* Unlock the key table entry: */ + _SPINUNLOCK(&key_table[*key].lock); + return (0); + } + + /* Unlock the key table entry: */ + _SPINUNLOCK(&key_table[*key].lock); + } + return (EAGAIN); +} + +int +pthread_key_delete(pthread_key_t key) +{ + int ret = 0; + + if (key < PTHREAD_KEYS_MAX) { + /* Lock the key table entry: */ + _SPINLOCK(&key_table[key].lock); + + if (key_table[key].allocated) + key_table[key].allocated = 0; + else + ret = EINVAL; + + /* Unlock the key table entry: */ + _SPINUNLOCK(&key_table[key].lock); + } else + ret = EINVAL; + return (ret); +} + +void +_thread_cleanupspecific(void) +{ + void *data = NULL; + int key; + int itr; + void (*destructor)( void *); + + for (itr = 0; itr < PTHREAD_DESTRUCTOR_ITERATIONS; itr++) { + for (key = 0; key < PTHREAD_KEYS_MAX; key++) { + if (_thread_run->specific_data_count) { + /* Lock the key table entry: */ + _SPINLOCK(&key_table[key].lock); + destructor = NULL; + + if (key_table[key].allocated) { + if (_thread_run->specific_data[key]) { + data = (void *) _thread_run->specific_data[key]; + _thread_run->specific_data[key] = NULL; + _thread_run->specific_data_count--; + destructor = key_table[key].destructor; + } + } + + /* Unlock the key table entry: */ + _SPINUNLOCK(&key_table[key].lock); + + /* + * If there is a destructore, call it + * with the key table entry unlocked: + */ + if (destructor) + destructor(data); + } else { + free(_thread_run->specific_data); + _thread_run->specific_data = NULL; + return; + } + } + } + free(_thread_run->specific_data); + _thread_run->specific_data = NULL; +} + +static inline const void ** +pthread_key_allocate_data(void) +{ + const void **new_data; + 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); +} + +int +pthread_setspecific(pthread_key_t key, const void *value) +{ + pthread_t pthread; + int ret = 0; + + /* Point to the running thread: */ + pthread = _thread_run; + + if ((pthread->specific_data) || + (pthread->specific_data = pthread_key_allocate_data())) { + if (key < PTHREAD_KEYS_MAX) { + if (key_table[key].allocated) { + if (pthread->specific_data[key] == NULL) { + if (value != NULL) + pthread->specific_data_count++; + } else { + if (value == NULL) + pthread->specific_data_count--; + } + pthread->specific_data[key] = value; + ret = 0; + } else + ret = EINVAL; + } else + ret = EINVAL; + } else + ret = ENOMEM; + return (ret); +} + +void * +pthread_getspecific(pthread_key_t key) +{ + pthread_t pthread; + void *data; + + /* Point to the running thread: */ + pthread = _thread_run; + + /* Check if there is specific data: */ + if (pthread->specific_data != NULL && key < PTHREAD_KEYS_MAX) { + /* Check if this key has been used before: */ + if (key_table[key].allocated) { + /* Return the value: */ + data = (void *) pthread->specific_data[key]; + } else { + /* + * This key has not been used before, so return NULL + * instead: + */ + data = NULL; + } + } else + /* No specific data has been created, so just return NULL: */ + data = NULL; + return (data); +} +#endif diff --git a/lib/libpthread/thread/thr_spinlock.c b/lib/libpthread/thread/thr_spinlock.c new file mode 100644 index 0000000..e797f90 --- /dev/null +++ b/lib/libpthread/thread/thr_spinlock.c @@ -0,0 +1,106 @@ +/* + * Copyright (c) 1997 John Birrell <jb@cimlogic.com.au>. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by John Birrell. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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. + * + * $FreeBSD$ + * + */ + +#include <stdio.h> +#include <sched.h> +#include <unistd.h> +#include <pthread.h> +#include <string.h> +#include "pthread_private.h" + +extern char *__progname; + +/* + * Lock a location for the running thread. Yield to allow other + * threads to run if this thread is blocked because the lock is + * not available. Note that this function does not sleep. It + * assumes that the lock will be available very soon. + */ +void +_spinlock(spinlock_t *lck) +{ + /* + * Try to grab the lock and loop if another thread grabs + * it before we do. + */ + while(_atomic_lock(&lck->access_lock)) { + /* Block the thread until the lock. */ + _thread_run->data.spinlock = lck; + _thread_kern_sched_state(PS_SPINBLOCK, __FILE__, __LINE__); + } + + /* The running thread now owns the lock: */ + lck->lock_owner = (long) _thread_run; +} + +/* + * Lock a location for the running thread. Yield to allow other + * threads to run if this thread is blocked because the lock is + * not available. Note that this function does not sleep. It + * assumes that the lock will be available very soon. + * + * This function checks if the running thread has already locked the + * location, warns if this occurs and creates a thread dump before + * returning. + */ +void +_spinlock_debug(spinlock_t *lck, char *fname, int lineno) +{ + int cnt = 0; + + /* + * Try to grab the lock and loop if another thread grabs + * it before we do. + */ + while(_atomic_lock(&lck->access_lock)) { + cnt++; + if (cnt > 100) { + char str[256]; + snprintf(str, sizeof(str), "%s - Warning: Thread %p attempted to lock %p from %s (%d) was left locked from %s (%d)\n", __progname, _thread_run, lck, fname, lineno, lck->fname, lck->lineno); + _thread_sys_write(2,str,strlen(str)); + __sleep(1); + cnt = 0; + } + + /* Block the thread until the lock. */ + _thread_run->data.spinlock = lck; + _thread_kern_sched_state(PS_SPINBLOCK, fname, lineno); + } + + /* The running thread now owns the lock: */ + lck->lock_owner = (long) _thread_run; + lck->fname = fname; + lck->lineno = lineno; +} diff --git a/lib/libpthread/thread/thr_suspend_np.c b/lib/libpthread/thread/thr_suspend_np.c new file mode 100644 index 0000000..083f552 --- /dev/null +++ b/lib/libpthread/thread/thr_suspend_np.c @@ -0,0 +1,152 @@ +/* + * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by John Birrell. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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. + * + * $FreeBSD$ + */ +#include <errno.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +static void finish_suspension(void *arg); + +/* Suspend a thread: */ +int +pthread_suspend_np(pthread_t thread) +{ + int ret; + + /* Find the thread in the list of active threads: */ + if ((ret = _find_thread(thread)) == 0) { + /* + * Defer signals to protect the scheduling queues from + * access by the signal handler: + */ + _thread_kern_sig_defer(); + + switch (thread->state) { + case PS_RUNNING: + /* + * Remove the thread from the priority queue and + * set the state to suspended: + */ + PTHREAD_PRIOQ_REMOVE(thread); + PTHREAD_SET_STATE(thread, PS_SUSPENDED); + break; + + case PS_SPINBLOCK: + case PS_FDR_WAIT: + case PS_FDW_WAIT: + case PS_POLL_WAIT: + case PS_SELECT_WAIT: + /* + * Remove these threads from the work queue + * and mark the operation as interrupted: + */ + if ((thread->flags & PTHREAD_FLAGS_IN_WORKQ) != 0) + PTHREAD_WORKQ_REMOVE(thread); + _thread_seterrno(thread,EINTR); + thread->interrupted = 1; + + /* FALLTHROUGH */ + case PS_SIGTHREAD: + case PS_SLEEP_WAIT: + case PS_WAIT_WAIT: + case PS_SIGSUSPEND: + case PS_SIGWAIT: + /* + * Remove these threads from the waiting queue and + * set their state to suspended: + */ + PTHREAD_WAITQ_REMOVE(thread); + PTHREAD_SET_STATE(thread, PS_SUSPENDED); + break; + + case PS_MUTEX_WAIT: + /* Mark the thread as suspended and still in a queue. */ + thread->suspended = SUSP_MUTEX_WAIT; + + PTHREAD_SET_STATE(thread, PS_SUSPENDED); + break; + case PS_COND_WAIT: + /* Mark the thread as suspended and still in a queue. */ + thread->suspended = SUSP_COND_WAIT; + + PTHREAD_SET_STATE(thread, PS_SUSPENDED); + break; + case PS_FDLR_WAIT: + case PS_FDLW_WAIT: + case PS_FILE_WAIT: + case PS_JOIN: + /* Mark the thread as suspended: */ + thread->suspended = SUSP_YES; + + /* + * Threads in these states may be in queues. + * In order to preserve queue integrity, the + * cancelled thread must remove itself from the + * queue. Mark the thread as interrupted and + * set the state to running. When the thread + * resumes, it will remove itself from the queue + * and call the suspension completion routine. + */ + thread->interrupted = 1; + _thread_seterrno(thread, EINTR); + PTHREAD_NEW_STATE(thread, PS_RUNNING); + thread->continuation = finish_suspension; + break; + + case PS_DEAD: + case PS_DEADLOCK: + case PS_STATE_MAX: + case PS_SUSPENDED: + /* Nothing needs to be done: */ + break; + } + + /* + * Undefer and handle pending signals, yielding if + * necessary: + */ + _thread_kern_sig_undefer(); + } + return(ret); +} + +static void +finish_suspension(void *arg) +{ + if (_thread_run->suspended != SUSP_NO) + _thread_kern_sched_state(PS_SUSPENDED, __FILE__, __LINE__); +} + + +#endif diff --git a/lib/libpthread/thread/thr_switch_np.c b/lib/libpthread/thread/thr_switch_np.c new file mode 100644 index 0000000..9b83545 --- /dev/null +++ b/lib/libpthread/thread/thr_switch_np.c @@ -0,0 +1,70 @@ +/* + * Copyright (c) 1998 Daniel Eischen <eischen@vigrid.com>. + * 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 Daniel Eischen. + * 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 DANIEL EISCHEN 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <errno.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include <pthread_np.h> +#include "pthread_private.h" + + +int +pthread_switch_add_np(pthread_switch_routine_t routine) +{ + int ret = 0; + + if (routine == NULL) + /* Return an invalid argument error: */ + ret = EINVAL; + else + /* Shouldn't need a lock to protect this assigment. */ + _sched_switch_hook = routine; + + return(ret); +} + +int +pthread_switch_delete_np(pthread_switch_routine_t routine) +{ + int ret = 0; + + if (routine != _sched_switch_hook) + /* Return an invalid argument error: */ + ret = EINVAL; + else + /* Shouldn't need a lock to protect this assigment. */ + _sched_switch_hook = NULL; + + return(ret); +} +#endif diff --git a/lib/libpthread/thread/thr_system.c b/lib/libpthread/thread/thr_system.c new file mode 100644 index 0000000..47a572d --- /dev/null +++ b/lib/libpthread/thread/thr_system.c @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2000 Jason Evans <jasone@freebsd.org>. + * 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(s), this list of conditions and the following disclaimer as + * the first lines of this file unmodified other than the possible + * addition of one or more copyright notices. + * 2. Redistributions in binary form must reproduce the above copyright + * notice(s), this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``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 COPYRIGHT HOLDER(S) 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. + * + * $FreeBSD$ + */ + +#include <stdlib.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +int +system(const char *string) +{ + int ret; + + _thread_enter_cancellation_point(); + ret = __system(string); + _thread_leave_cancellation_point(); + + return ret; +} +#endif diff --git a/lib/libpthread/thread/thr_tcdrain.c b/lib/libpthread/thread/thr_tcdrain.c new file mode 100644 index 0000000..6470882 --- /dev/null +++ b/lib/libpthread/thread/thr_tcdrain.c @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2000 Jason Evans <jasone@freebsd.org>. + * 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(s), this list of conditions and the following disclaimer as + * the first lines of this file unmodified other than the possible + * addition of one or more copyright notices. + * 2. Redistributions in binary form must reproduce the above copyright + * notice(s), this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``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 COPYRIGHT HOLDER(S) 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. + * + * $FreeBSD$ + */ + +#include <termios.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +int +tcdrain(int fd) +{ + int ret; + + _thread_enter_cancellation_point(); + ret = __tcdrain(fd); + _thread_leave_cancellation_point(); + + return ret; +} +#endif diff --git a/lib/libpthread/thread/thr_vfork.c b/lib/libpthread/thread/thr_vfork.c new file mode 100644 index 0000000..bbfcf00 --- /dev/null +++ b/lib/libpthread/thread/thr_vfork.c @@ -0,0 +1,9 @@ +#include <unistd.h> +#ifdef _THREAD_SAFE + +int +vfork(void) +{ + return (fork()); +} +#endif diff --git a/lib/libpthread/thread/thr_wait.c b/lib/libpthread/thread/thr_wait.c new file mode 100644 index 0000000..c34d997 --- /dev/null +++ b/lib/libpthread/thread/thr_wait.c @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2000 Jason Evans <jasone@freebsd.org>. + * 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(s), this list of conditions and the following disclaimer as + * the first lines of this file unmodified other than the possible + * addition of one or more copyright notices. + * 2. Redistributions in binary form must reproduce the above copyright + * notice(s), this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``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 COPYRIGHT HOLDER(S) 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. + * + * $FreeBSD$ + */ + +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +pid_t +wait(int *istat) +{ + pid_t ret; + + _thread_enter_cancellation_point(); + ret = __wait(istat); + _thread_leave_cancellation_point(); + + return ret; +} +#endif diff --git a/lib/libpthread/thread/thr_wait4.c b/lib/libpthread/thread/thr_wait4.c new file mode 100644 index 0000000..083c230 --- /dev/null +++ b/lib/libpthread/thread/thr_wait4.c @@ -0,0 +1,69 @@ +/* + * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by John Birrell. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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. + * + * $FreeBSD$ + */ +#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) +{ + pid_t ret; + + _thread_kern_sig_defer(); + + /* Perform a non-blocking wait4 syscall: */ + while ((ret = _thread_sys_wait4(pid, istat, options | WNOHANG, rusage)) == 0 && (options & WNOHANG) == 0) { + /* Reset the interrupted operation flag: */ + _thread_run->interrupted = 0; + + /* Schedule the next thread while this one waits: */ + _thread_kern_sched_state(PS_WAIT_WAIT, __FILE__, __LINE__); + + /* Check if this call was interrupted by a signal: */ + if (_thread_run->interrupted) { + errno = EINTR; + ret = -1; + break; + } + } + + _thread_kern_sig_undefer(); + + return (ret); +} + +__strong_reference(_wait4, wait4); +#endif diff --git a/lib/libpthread/thread/thr_waitpid.c b/lib/libpthread/thread/thr_waitpid.c new file mode 100644 index 0000000..28fcd78 --- /dev/null +++ b/lib/libpthread/thread/thr_waitpid.c @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2000 Jason Evans <jasone@freebsd.org>. + * 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(s), this list of conditions and the following disclaimer as + * the first lines of this file unmodified other than the possible + * addition of one or more copyright notices. + * 2. Redistributions in binary form must reproduce the above copyright + * notice(s), this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``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 COPYRIGHT HOLDER(S) 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. + * + * $FreeBSD$ + */ + +#include <sys/types.h> +#include <sys/wait.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +pid_t +waitpid(pid_t wpid, int *status, int options) +{ + pid_t ret; + + _thread_enter_cancellation_point(); + ret = __waitpid(wpid, status, options); + _thread_leave_cancellation_point(); + + return ret; +} +#endif diff --git a/lib/libpthread/thread/thr_write.c b/lib/libpthread/thread/thr_write.c new file mode 100644 index 0000000..6408a64 --- /dev/null +++ b/lib/libpthread/thread/thr_write.c @@ -0,0 +1,146 @@ +/* + * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by John Birrell. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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. + * + * $FreeBSD$ + * + */ +#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 blocking; + int type; + ssize_t n; + ssize_t num = 0; + ssize_t ret; + + /* POSIX says to do just this: */ + if (nbytes == 0) + return (0); + + /* Lock the file descriptor for write: */ + if ((ret = _FD_LOCK(fd, FD_WRITE, NULL)) == 0) { + /* Get the read/write mode type: */ + type = _thread_fd_table[fd]->flags & O_ACCMODE; + + /* Check if the file is not open for write: */ + if (type != O_WRONLY && type != O_RDWR) { + /* File is not open for write: */ + errno = EBADF; + _FD_UNLOCK(fd, FD_WRITE); + return (-1); + } + + /* Check if file operations are to block */ + blocking = ((_thread_fd_table[fd]->flags & O_NONBLOCK) == 0); + + /* + * Loop while no error occurs and until the expected number + * of bytes are written if performing a blocking write: + */ + while (ret == 0) { + /* Perform a non-blocking write syscall: */ + n = _thread_sys_write(fd, buf + num, nbytes - num); + + /* Check if one or more bytes were written: */ + if (n > 0) + /* + * Keep a count of the number of bytes + * written: + */ + num += n; + + /* + * If performing a blocking write, check if the + * write would have blocked or if some bytes + * were written but there are still more to + * write: + */ + if (blocking && ((n < 0 && (errno == EWOULDBLOCK || + errno == EAGAIN)) || (n >= 0 && num < nbytes))) { + _thread_run->data.fd.fd = fd; + _thread_kern_set_timeout(NULL); + + /* Reset the interrupted operation flag: */ + _thread_run->interrupted = 0; + + _thread_kern_sched_state(PS_FDW_WAIT, + __FILE__, __LINE__); + + /* + * Check if the operation was + * interrupted by a signal + */ + if (_thread_run->interrupted) { + /* Return an error: */ + ret = -1; + } + + /* + * If performing a non-blocking write or if an + * error occurred, just return whatever the write + * syscall did: + */ + } else if (!blocking || n < 0) { + /* A non-blocking call might return zero: */ + ret = n; + break; + + /* Check if the write has completed: */ + } else if (num >= nbytes) + /* Return the number of bytes written: */ + ret = num; + } + _FD_UNLOCK(fd, FD_RDWR); + } + return (ret); +} + +ssize_t +write(int fd, const void *buf, size_t nbytes) +{ + ssize_t ret; + + _thread_enter_cancellation_point(); + ret = _write(fd, buf, nbytes); + _thread_leave_cancellation_point(); + + return ret; +} +#endif diff --git a/lib/libpthread/thread/thr_writev.c b/lib/libpthread/thread/thr_writev.c new file mode 100644 index 0000000..5f31468 --- /dev/null +++ b/lib/libpthread/thread/thr_writev.c @@ -0,0 +1,205 @@ +/* + * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by John Birrell. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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. + * + * $FreeBSD$ + * + */ +#include <sys/types.h> +#include <sys/fcntl.h> +#include <sys/uio.h> +#include <errno.h> +#include <stdlib.h> +#include <string.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 blocking; + int idx = 0; + int type; + ssize_t cnt; + ssize_t n; + ssize_t num = 0; + ssize_t ret; + struct iovec liov[20]; + struct iovec *p_iov = liov; + + /* Check if the array size exceeds to compiled in size: */ + if (iovcnt > (sizeof(liov) / sizeof(struct iovec))) { + /* Allocate memory for the local array: */ + if ((p_iov = (struct iovec *) + malloc(iovcnt * sizeof(struct iovec))) == NULL) { + /* Insufficient memory: */ + errno = ENOMEM; + return (-1); + } + } + + /* Copy the caller's array so that it can be modified locally: */ + memcpy(p_iov,iov,iovcnt * sizeof(struct iovec)); + + /* Lock the file descriptor for write: */ + if ((ret = _FD_LOCK(fd, FD_WRITE, NULL)) == 0) { + /* Get the read/write mode type: */ + type = _thread_fd_table[fd]->flags & O_ACCMODE; + + /* Check if the file is not open for write: */ + if (type != O_WRONLY && type != O_RDWR) { + /* File is not open for write: */ + errno = EBADF; + _FD_UNLOCK(fd, FD_WRITE); + return (-1); + } + + /* Check if file operations are to block */ + blocking = ((_thread_fd_table[fd]->flags & O_NONBLOCK) == 0); + + /* + * Loop while no error occurs and until the expected number + * of bytes are written if performing a blocking write: + */ + while (ret == 0) { + /* Perform a non-blocking write syscall: */ + n = _thread_sys_writev(fd, &p_iov[idx], iovcnt - idx); + + /* Check if one or more bytes were written: */ + if (n > 0) { + /* + * Keep a count of the number of bytes + * written: + */ + num += n; + + /* + * Enter a loop to check if a short write + * occurred and move the index to the + * array entry where the short write + * ended: + */ + cnt = n; + while (cnt > 0 && idx < iovcnt) { + /* + * If the residual count exceeds + * the size of this vector, then + * it was completely written: + */ + if (cnt >= p_iov[idx].iov_len) + /* + * Decrement the residual + * count and increment the + * index to the next array + * entry: + */ + cnt -= p_iov[idx++].iov_len; + else { + /* + * This entry was only + * partially written, so + * adjust it's length + * and base pointer ready + * for the next write: + */ + p_iov[idx].iov_len -= cnt; + p_iov[idx].iov_base += cnt; + cnt = 0; + } + } + } else if (n == 0) { + /* + * Avoid an infinite loop if the last iov_len is + * 0. + */ + while (idx < iovcnt && p_iov[idx].iov_len == 0) + idx++; + + if (idx == iovcnt) { + ret = num; + break; + } + } + + /* + * If performing a blocking write, check if the + * write would have blocked or if some bytes + * were written but there are still more to + * write: + */ + if (blocking && ((n < 0 && (errno == EWOULDBLOCK || + errno == EAGAIN)) || (n >= 0 && idx < iovcnt))) { + _thread_run->data.fd.fd = fd; + _thread_kern_set_timeout(NULL); + + /* Reset the interrupted operation flag: */ + _thread_run->interrupted = 0; + + _thread_kern_sched_state(PS_FDW_WAIT, + __FILE__, __LINE__); + + /* + * Check if the operation was + * interrupted by a signal + */ + if (_thread_run->interrupted) { + /* Return an error: */ + ret = -1; + } + + /* + * If performing a non-blocking write or if an + * error occurred, just return whatever the write + * syscall did: + */ + } else if (!blocking || n < 0) { + /* A non-blocking call might return zero: */ + ret = n; + break; + + /* Check if the write has completed: */ + } else if (idx == iovcnt) + /* Return the number of bytes written: */ + ret = num; + } + _FD_UNLOCK(fd, FD_RDWR); + } + + /* If memory was allocated for the array, free it: */ + if (p_iov != liov) + free(p_iov); + + return (ret); +} + +__strong_reference(_writev, writev); +#endif diff --git a/lib/libpthread/thread/thr_yield.c b/lib/libpthread/thread/thr_yield.c new file mode 100644 index 0000000..064dd82 --- /dev/null +++ b/lib/libpthread/thread/thr_yield.c @@ -0,0 +1,64 @@ +/* + * 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +int +sched_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); + + /* Always return no error. */ + return(0); +} + +/* Draft 4 yield */ +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 |