summaryrefslogtreecommitdiffstats
path: root/lib/libpthread
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libpthread')
-rw-r--r--lib/libpthread/Makefile29
-rw-r--r--lib/libpthread/arch/alpha/alpha/_atomic_lock.S45
-rw-r--r--lib/libpthread/arch/i386/i386/_atomic_lock.S42
-rw-r--r--lib/libpthread/man/Makefile.inc96
-rw-r--r--lib/libpthread/man/pthread_attr.3219
-rw-r--r--lib/libpthread/man/pthread_cancel.379
-rw-r--r--lib/libpthread/man/pthread_cleanup_pop.364
-rw-r--r--lib/libpthread/man/pthread_cleanup_push.366
-rw-r--r--lib/libpthread/man/pthread_cond_broadcast.370
-rw-r--r--lib/libpthread/man/pthread_cond_destroy.374
-rw-r--r--lib/libpthread/man/pthread_cond_init.380
-rw-r--r--lib/libpthread/man/pthread_cond_signal.370
-rw-r--r--lib/libpthread/man/pthread_cond_timedwait.389
-rw-r--r--lib/libpthread/man/pthread_cond_wait.383
-rw-r--r--lib/libpthread/man/pthread_condattr.385
-rw-r--r--lib/libpthread/man/pthread_create.3123
-rw-r--r--lib/libpthread/man/pthread_detach.389
-rw-r--r--lib/libpthread/man/pthread_equal.368
-rw-r--r--lib/libpthread/man/pthread_exit.3104
-rw-r--r--lib/libpthread/man/pthread_getspecific.383
-rw-r--r--lib/libpthread/man/pthread_join.3104
-rw-r--r--lib/libpthread/man/pthread_key_create.3107
-rw-r--r--lib/libpthread/man/pthread_key_delete.398
-rw-r--r--lib/libpthread/man/pthread_kill.375
-rw-r--r--lib/libpthread/man/pthread_mutex_destroy.372
-rw-r--r--lib/libpthread/man/pthread_mutex_init.377
-rw-r--r--lib/libpthread/man/pthread_mutex_lock.374
-rw-r--r--lib/libpthread/man/pthread_mutex_trylock.375
-rw-r--r--lib/libpthread/man/pthread_mutex_unlock.374
-rw-r--r--lib/libpthread/man/pthread_mutexattr.3177
-rw-r--r--lib/libpthread/man/pthread_once.3105
-rw-r--r--lib/libpthread/man/pthread_rwlock_destroy.382
-rw-r--r--lib/libpthread/man/pthread_rwlock_init.3101
-rw-r--r--lib/libpthread/man/pthread_rwlock_rdlock.3124
-rw-r--r--lib/libpthread/man/pthread_rwlock_unlock.381
-rw-r--r--lib/libpthread/man/pthread_rwlock_wrlock.3104
-rw-r--r--lib/libpthread/man/pthread_rwlockattr_destroy.370
-rw-r--r--lib/libpthread/man/pthread_rwlockattr_getpshared.382
-rw-r--r--lib/libpthread/man/pthread_rwlockattr_init.369
-rw-r--r--lib/libpthread/man/pthread_rwlockattr_setpshared.390
-rw-r--r--lib/libpthread/man/pthread_schedparam.390
-rw-r--r--lib/libpthread/man/pthread_self.361
-rw-r--r--lib/libpthread/man/pthread_setspecific.395
-rw-r--r--lib/libpthread/man/pthread_sigmask.396
-rw-r--r--lib/libpthread/man/pthread_testcancel.3209
-rw-r--r--lib/libpthread/man/sem_destroy.381
-rw-r--r--lib/libpthread/man/sem_getvalue.373
-rw-r--r--lib/libpthread/man/sem_init.398
-rw-r--r--lib/libpthread/man/sem_open.381
-rw-r--r--lib/libpthread/man/sem_post.370
-rw-r--r--lib/libpthread/man/sem_wait.386
-rw-r--r--lib/libpthread/man/sigwait.384
-rw-r--r--lib/libpthread/sys/Makefile.inc6
-rw-r--r--lib/libpthread/sys/thr_error.c51
-rw-r--r--lib/libpthread/test/Makefile115
-rw-r--r--lib/libpthread/test/README28
-rw-r--r--lib/libpthread/test/guard_b.c150
-rw-r--r--lib/libpthread/test/guard_b.exp3
-rwxr-xr-xlib/libpthread/test/guard_s.pl69
-rw-r--r--lib/libpthread/test/hello_b.c13
-rw-r--r--lib/libpthread/test/hello_d.c38
-rw-r--r--lib/libpthread/test/hello_d.exp1
-rw-r--r--lib/libpthread/test/hello_s.c47
-rw-r--r--lib/libpthread/test/join_leak_d.c108
-rw-r--r--lib/libpthread/test/join_leak_d.exp2
-rw-r--r--lib/libpthread/test/mutex_d.c1552
-rw-r--r--lib/libpthread/test/mutex_d.exp290
-rwxr-xr-xlib/libpthread/test/propagate_s.pl74
-rw-r--r--lib/libpthread/test/sem_d.c133
-rw-r--r--lib/libpthread/test/sem_d.exp22
-rw-r--r--lib/libpthread/test/sigsuspend_d.c288
-rw-r--r--lib/libpthread/test/sigsuspend_d.exp8
-rw-r--r--lib/libpthread/test/sigwait_d.c304
-rw-r--r--lib/libpthread/test/sigwait_d.exp10
-rwxr-xr-xlib/libpthread/test/verify474
-rw-r--r--lib/libpthread/thread/Makefile.inc138
-rw-r--r--lib/libpthread/thread/thr_acl_aclcheck_fd.c47
-rw-r--r--lib/libpthread/thread/thr_aio_suspend.c50
-rw-r--r--lib/libpthread/thread/thr_attr_destroy.c62
-rw-r--r--lib/libpthread/thread/thr_attr_getdetachstate.c59
-rw-r--r--lib/libpthread/thread/thr_attr_getguardsize.c52
-rw-r--r--lib/libpthread/thread/thr_attr_getinheritsched.c51
-rw-r--r--lib/libpthread/thread/thr_attr_getschedparam.c51
-rw-r--r--lib/libpthread/thread/thr_attr_getschedpolicy.c51
-rw-r--r--lib/libpthread/thread/thr_attr_getscope.c54
-rw-r--r--lib/libpthread/thread/thr_attr_getstackaddr.c54
-rw-r--r--lib/libpthread/thread/thr_attr_getstacksize.c54
-rw-r--r--lib/libpthread/thread/thr_attr_init.c61
-rw-r--r--lib/libpthread/thread/thr_attr_setcreatesuspend_np.c52
-rw-r--r--lib/libpthread/thread/thr_attr_setdetachstate.c61
-rw-r--r--lib/libpthread/thread/thr_attr_setguardsize.c57
-rw-r--r--lib/libpthread/thread/thr_attr_setinheritsched.c51
-rw-r--r--lib/libpthread/thread/thr_attr_setschedparam.c57
-rw-r--r--lib/libpthread/thread/thr_attr_setschedpolicy.c53
-rw-r--r--lib/libpthread/thread/thr_attr_setscope.c56
-rw-r--r--lib/libpthread/thread/thr_attr_setstackaddr.c54
-rw-r--r--lib/libpthread/thread/thr_attr_setstacksize.c54
-rw-r--r--lib/libpthread/thread/thr_cancel.c243
-rw-r--r--lib/libpthread/thread/thr_clean.c72
-rw-r--r--lib/libpthread/thread/thr_close.c114
-rw-r--r--lib/libpthread/thread/thr_cond.c747
-rw-r--r--lib/libpthread/thread/thr_condattr_destroy.c53
-rw-r--r--lib/libpthread/thread/thr_condattr_init.c58
-rw-r--r--lib/libpthread/thread/thr_creat.c48
-rw-r--r--lib/libpthread/thread/thr_create.c267
-rw-r--r--lib/libpthread/thread/thr_detach.c90
-rw-r--r--lib/libpthread/thread/thr_equal.c44
-rw-r--r--lib/libpthread/thread/thr_exit.c241
-rw-r--r--lib/libpthread/thread/thr_fcntl.c170
-rw-r--r--lib/libpthread/thread/thr_find_thread.c66
-rw-r--r--lib/libpthread/thread/thr_fork.c243
-rw-r--r--lib/libpthread/thread/thr_fsync.c62
-rw-r--r--lib/libpthread/thread/thr_gc.c219
-rw-r--r--lib/libpthread/thread/thr_getprio.c56
-rw-r--r--lib/libpthread/thread/thr_getschedparam.c59
-rw-r--r--lib/libpthread/thread/thr_info.c290
-rw-r--r--lib/libpthread/thread/thr_init.c475
-rw-r--r--lib/libpthread/thread/thr_join.c162
-rw-r--r--lib/libpthread/thread/thr_kern.c1139
-rw-r--r--lib/libpthread/thread/thr_kill.c74
-rw-r--r--lib/libpthread/thread/thr_main_np.c46
-rw-r--r--lib/libpthread/thread/thr_mattr_init.c58
-rw-r--r--lib/libpthread/thread/thr_mattr_kind_np.c97
-rw-r--r--lib/libpthread/thread/thr_msync.c42
-rw-r--r--lib/libpthread/thread/thr_multi_np.c46
-rw-r--r--lib/libpthread/thread/thr_mutex.c1576
-rw-r--r--lib/libpthread/thread/thr_mutex_prioceiling.c113
-rw-r--r--lib/libpthread/thread/thr_mutex_protocol.c70
-rw-r--r--lib/libpthread/thread/thr_mutexattr_destroy.c53
-rw-r--r--lib/libpthread/thread/thr_nanosleep.c143
-rw-r--r--lib/libpthread/thread/thr_once.c53
-rw-r--r--lib/libpthread/thread/thr_open.c96
-rw-r--r--lib/libpthread/thread/thr_pause.c48
-rw-r--r--lib/libpthread/thread/thr_poll.c99
-rw-r--r--lib/libpthread/thread/thr_priority_queue.c337
-rw-r--r--lib/libpthread/thread/thr_private.h1362
-rw-r--r--lib/libpthread/thread/thr_read.c111
-rw-r--r--lib/libpthread/thread/thr_readv.c94
-rw-r--r--lib/libpthread/thread/thr_resume_np.c96
-rw-r--r--lib/libpthread/thread/thr_rwlock.c341
-rw-r--r--lib/libpthread/thread/thr_rwlockattr.c98
-rw-r--r--lib/libpthread/thread/thr_select.c207
-rw-r--r--lib/libpthread/thread/thr_self.c44
-rw-r--r--lib/libpthread/thread/thr_sem.c254
-rw-r--r--lib/libpthread/thread/thr_seterrno.c59
-rw-r--r--lib/libpthread/thread/thr_setprio.c52
-rw-r--r--lib/libpthread/thread/thr_setschedparam.c119
-rw-r--r--lib/libpthread/thread/thr_sig.c1117
-rw-r--r--lib/libpthread/thread/thr_sigaction.c112
-rw-r--r--lib/libpthread/thread/thr_sigmask.c106
-rw-r--r--lib/libpthread/thread/thr_sigpending.c57
-rw-r--r--lib/libpthread/thread/thr_sigprocmask.c48
-rw-r--r--lib/libpthread/thread/thr_sigsuspend.c83
-rw-r--r--lib/libpthread/thread/thr_sigwait.c174
-rw-r--r--lib/libpthread/thread/thr_single_np.c47
-rw-r--r--lib/libpthread/thread/thr_sleep.c48
-rw-r--r--lib/libpthread/thread/thr_spec.c225
-rw-r--r--lib/libpthread/thread/thr_spinlock.c111
-rw-r--r--lib/libpthread/thread/thr_stack.c237
-rw-r--r--lib/libpthread/thread/thr_suspend_np.c161
-rw-r--r--lib/libpthread/thread/thr_switch_np.c71
-rw-r--r--lib/libpthread/thread/thr_system.c48
-rw-r--r--lib/libpthread/thread/thr_tcdrain.c48
-rw-r--r--lib/libpthread/thread/thr_vfork.c12
-rw-r--r--lib/libpthread/thread/thr_wait.c47
-rw-r--r--lib/libpthread/thread/thr_wait4.c70
-rw-r--r--lib/libpthread/thread/thr_waitpid.c49
-rw-r--r--lib/libpthread/thread/thr_write.c147
-rw-r--r--lib/libpthread/thread/thr_writev.c204
-rw-r--r--lib/libpthread/thread/thr_yield.c66
170 files changed, 23682 insertions, 0 deletions
diff --git a/lib/libpthread/Makefile b/lib/libpthread/Makefile
new file mode 100644
index 0000000..d7b21bc
--- /dev/null
+++ b/lib/libpthread/Makefile
@@ -0,0 +1,29 @@
+# $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= 5
+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
+
+.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..af49aff
--- /dev/null
+++ b/lib/libpthread/arch/i386/i386/_atomic_lock.S
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+#if defined(LIBC_RCS) && !defined(lint)
+ .text
+ .asciz "$FreeBSD$"
+#endif /* LIBC_RCS and not lint */
+
+#include <machine/asm.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..ed041aa
--- /dev/null
+++ b/lib/libpthread/man/Makefile.inc
@@ -0,0 +1,96 @@
+# $FreeBSD$
+
+# POSIX thread man files
+
+.PATH: ${.CURDIR}/man
+
+MAN+= 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_getguardsize.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_setguardsize.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..ff692e2
--- /dev/null
+++ b/lib/libpthread/man/pthread_attr.3
@@ -0,0 +1,219 @@
+.\" 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_setguardsize ,
+.Nm pthread_attr_getguardsize ,
+.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
+.In 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_setguardsize "pthread_attr_t *attr" "size_t guardsize"
+.Ft int
+.Fn pthread_attr_getguardsize "const pthread_attr_t *attr" "size_t *guardsize"
+.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 -p1003.1-96
+.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..1b998e6
--- /dev/null
+++ b/lib/libpthread/man/pthread_cancel.3
@@ -0,0 +1,79 @@
+.\" $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
+.In 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
+.St -p1003.1-96 .
+.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..5321303
--- /dev/null
+++ b/lib/libpthread/man/pthread_cleanup_pop.3
@@ -0,0 +1,64 @@
+.\" 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
+.Sh NAME
+.Nm pthread_cleanup_pop
+.Nd call the first cleanup routine
+.Sh LIBRARY
+.Lb libc_r
+.Sh SYNOPSIS
+.In 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
+.St -p1003.1-96 .
diff --git a/lib/libpthread/man/pthread_cleanup_push.3 b/lib/libpthread/man/pthread_cleanup_push.3
new file mode 100644
index 0000000..b7d797e
--- /dev/null
+++ b/lib/libpthread/man/pthread_cleanup_push.3
@@ -0,0 +1,66 @@
+.\" 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
+.Sh NAME
+.Nm pthread_cleanup_push
+.Nd add a cleanup function for thread exit
+.Sh LIBRARY
+.Lb libc_r
+.Sh SYNOPSIS
+.In pthread.h
+.Ft void
+.Fn pthread_cleanup_push "void \*[lp]*cleanup_routine\*[rp]\*[lp]void *\*[rp]" "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
+.Fa cleanup_routine
+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
+.St -p1003.1-96 .
diff --git a/lib/libpthread/man/pthread_cond_broadcast.3 b/lib/libpthread/man/pthread_cond_broadcast.3
new file mode 100644
index 0000000..b3947bd
--- /dev/null
+++ b/lib/libpthread/man/pthread_cond_broadcast.3
@@ -0,0 +1,70 @@
+.\" 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
+.Sh NAME
+.Nm pthread_cond_broadcast
+.Nd unblock all threads waiting for a condition variable
+.Sh LIBRARY
+.Lb libc_r
+.Sh SYNOPSIS
+.In 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
+.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
+.St -p1003.1-96 .
diff --git a/lib/libpthread/man/pthread_cond_destroy.3 b/lib/libpthread/man/pthread_cond_destroy.3
new file mode 100644
index 0000000..ab1ea0f
--- /dev/null
+++ b/lib/libpthread/man/pthread_cond_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 28, 1998
+.Dt PTHREAD_COND_DESTROY 3
+.Os
+.Sh NAME
+.Nm pthread_cond_destroy
+.Nd destroy a condition variable
+.Sh LIBRARY
+.Lb libc_r
+.Sh SYNOPSIS
+.In 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
+.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
+.St -p1003.1-96 .
diff --git a/lib/libpthread/man/pthread_cond_init.3 b/lib/libpthread/man/pthread_cond_init.3
new file mode 100644
index 0000000..542110b
--- /dev/null
+++ b/lib/libpthread/man/pthread_cond_init.3
@@ -0,0 +1,80 @@
+.\" 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
+.Sh NAME
+.Nm pthread_cond_init
+.Nd create a condition variable
+.Sh LIBRARY
+.Lb libc_r
+.Sh SYNOPSIS
+.In 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 system temporarily lacks the resources to create another condition
+variable.
+.El
+.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
+.St -p1003.1-96 .
diff --git a/lib/libpthread/man/pthread_cond_signal.3 b/lib/libpthread/man/pthread_cond_signal.3
new file mode 100644
index 0000000..4bb85c9
--- /dev/null
+++ b/lib/libpthread/man/pthread_cond_signal.3
@@ -0,0 +1,70 @@
+.\" 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
+.Sh NAME
+.Nm pthread_cond_signal
+.Nd unblock a thread waiting for a condition variable
+.Sh LIBRARY
+.Lb libc_r
+.Sh SYNOPSIS
+.In 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
+.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
+.St -p1003.1-96 .
diff --git a/lib/libpthread/man/pthread_cond_timedwait.3 b/lib/libpthread/man/pthread_cond_timedwait.3
new file mode 100644
index 0000000..afd16b5
--- /dev/null
+++ b/lib/libpthread/man/pthread_cond_timedwait.3
@@ -0,0 +1,89 @@
+.\" 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
+.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
+.In 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 reacquires 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
+.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
+.St -p1003.1-96 .
diff --git a/lib/libpthread/man/pthread_cond_wait.3 b/lib/libpthread/man/pthread_cond_wait.3
new file mode 100644
index 0000000..e464a1e
--- /dev/null
+++ b/lib/libpthread/man/pthread_cond_wait.3
@@ -0,0 +1,83 @@
+.\" 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
+.Sh NAME
+.Nm pthread_cond_wait
+.Nd wait on a condition variable
+.Sh LIBRARY
+.Lb libc_r
+.Sh SYNOPSIS
+.In 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 reacquires 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
+.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
+.St -p1003.1-96 .
diff --git a/lib/libpthread/man/pthread_condattr.3 b/lib/libpthread/man/pthread_condattr.3
new file mode 100644
index 0000000..478e112
--- /dev/null
+++ b/lib/libpthread/man/pthread_condattr.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 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
+.In 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 .
+.Fx Ns '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 .
+.El
+.Sh SEE ALSO
+.Xr pthread_cond_init 3
+.Sh STANDARDS
+.Fn pthread_condattr_init
+and
+.Fn pthread_condattr_destroy
+conform to
+.St -p1003.1-96
diff --git a/lib/libpthread/man/pthread_create.3 b/lib/libpthread/man/pthread_create.3
new file mode 100644
index 0000000..35f783c
--- /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
+.Sh NAME
+.Nm pthread_create
+.Nd create a new thread
+.Sh LIBRARY
+.Lb libc_r
+.Sh SYNOPSIS
+.In 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
+.Dv 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
+.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
+.St -p1003.1-96 .
diff --git a/lib/libpthread/man/pthread_detach.3 b/lib/libpthread/man/pthread_detach.3
new file mode 100644
index 0000000..15729af
--- /dev/null
+++ b/lib/libpthread/man/pthread_detach.3
@@ -0,0 +1,89 @@
+.\" 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
+.Sh NAME
+.Nm pthread_detach
+.Nd detach a thread
+.Sh LIBRARY
+.Lb libc_r
+.Sh SYNOPSIS
+.In 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
+.Sh SEE ALSO
+.Xr pthread_join 3
+.Sh STANDARDS
+.Fn pthread_detach
+conforms to
+.St -p1003.1-96 .
diff --git a/lib/libpthread/man/pthread_equal.3 b/lib/libpthread/man/pthread_equal.3
new file mode 100644
index 0000000..8b733da
--- /dev/null
+++ b/lib/libpthread/man/pthread_equal.3
@@ -0,0 +1,68 @@
+.\" 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
+.Sh NAME
+.Nm pthread_equal
+.Nd compare thread IDs
+.Sh LIBRARY
+.Lb libc_r
+.Sh SYNOPSIS
+.In 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 return non-zero if the thread IDs
+.Fa t1
+and
+.Fa t2
+correspond to the same thread, otherwise it will return zero.
+.Sh ERRORS
+None.
+.Sh SEE ALSO
+.Xr pthread_create 3 ,
+.Xr pthread_exit 3
+.Sh STANDARDS
+.Fn pthread_equal
+conforms to
+.St -p1003.1-96 .
diff --git a/lib/libpthread/man/pthread_exit.3 b/lib/libpthread/man/pthread_exit.3
new file mode 100644
index 0000000..0bfdad6
--- /dev/null
+++ b/lib/libpthread/man/pthread_exit.3
@@ -0,0 +1,104 @@
+.\" 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
+.Sh NAME
+.Nm pthread_exit
+.Nd terminate the calling thread
+.Sh LIBRARY
+.Lb libc_r
+.Sh SYNOPSIS
+.In 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.
+.Sh RETURN VALUES
+The
+.Fn pthread_exit
+function cannot return to its caller.
+.Sh ERRORS
+None.
+.Sh SEE ALSO
+.Xr _exit 2 ,
+.Xr exit 3 ,
+.Xr pthread_create 3 ,
+.Xr pthread_join 3
+.Sh STANDARDS
+.Fn pthread_exit
+conforms to
+.St -p1003.1-96 .
diff --git a/lib/libpthread/man/pthread_getspecific.3 b/lib/libpthread/man/pthread_getspecific.3
new file mode 100644
index 0000000..c7a04fa
--- /dev/null
+++ b/lib/libpthread/man/pthread_getspecific.3
@@ -0,0 +1,83 @@
+.\" 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
+.Sh NAME
+.Nm pthread_getspecific
+.Nd get a thread-specific data value
+.Sh LIBRARY
+.Lb libc_r
+.Sh SYNOPSIS
+.In 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
+.St -p1003.1-96 .
diff --git a/lib/libpthread/man/pthread_join.3 b/lib/libpthread/man/pthread_join.3
new file mode 100644
index 0000000..98ae70d
--- /dev/null
+++ b/lib/libpthread/man/pthread_join.3
@@ -0,0 +1,104 @@
+.\" 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
+.Sh NAME
+.Nm pthread_join
+.Nd wait for thread termination
+.Sh LIBRARY
+.Lb libc_r
+.Sh SYNOPSIS
+.In 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].
+.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
+.Sh SEE ALSO
+.Xr wait 2 ,
+.Xr pthread_create 3
+.Sh STANDARDS
+.Fn pthread_join
+conforms to
+.St -p1003.1-96 .
diff --git a/lib/libpthread/man/pthread_key_create.3 b/lib/libpthread/man/pthread_key_create.3
new file mode 100644
index 0000000..7075dcc
--- /dev/null
+++ b/lib/libpthread/man/pthread_key_create.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_KEY_CREATE 3
+.Os
+.Sh NAME
+.Nm pthread_key_create
+.Nd thread-specific data key creation
+.Sh LIBRARY
+.Lb libc_r
+.Sh SYNOPSIS
+.In 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
+.Sh SEE ALSO
+.Xr pthread_getspecific 3 ,
+.Xr pthread_key_delete 3 ,
+.Xr pthread_setspecific 3
+.Sh STANDARDS
+.Fn pthread_key_create
+conforms to
+.St -p1003.1-96 .
diff --git a/lib/libpthread/man/pthread_key_delete.3 b/lib/libpthread/man/pthread_key_delete.3
new file mode 100644
index 0000000..bc0cf8a
--- /dev/null
+++ b/lib/libpthread/man/pthread_key_delete.3
@@ -0,0 +1,98 @@
+.\" 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
+.Sh NAME
+.Nm pthread_key_delete
+.Nd delete a thread-specific data key
+.Sh LIBRARY
+.Lb libc_r
+.Sh SYNOPSIS
+.In 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
+.Sh SEE ALSO
+.Xr pthread_getspecific 3 ,
+.Xr pthread_key_create 3 ,
+.Xr pthread_setspecific 3
+.Sh STANDARDS
+.Fn pthread_key_delete
+conforms to
+.St -p1003.1-96 .
diff --git a/lib/libpthread/man/pthread_kill.3 b/lib/libpthread/man/pthread_kill.3
new file mode 100644
index 0000000..e46e2b2
--- /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
+.In pthread.h
+.In 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 -p1003.1-96
diff --git a/lib/libpthread/man/pthread_mutex_destroy.3 b/lib/libpthread/man/pthread_mutex_destroy.3
new file mode 100644
index 0000000..59d2b48
--- /dev/null
+++ b/lib/libpthread/man/pthread_mutex_destroy.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 29, 1998
+.Dt PTHREAD_MUTEX_DESTROY 3
+.Os
+.Sh NAME
+.Nm pthread_mutex_destroy
+.Nd free resources allocated for a mutex
+.Sh LIBRARY
+.Lb libc_r
+.Sh SYNOPSIS
+.In 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
+.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
+.St -p1003.1-96 .
diff --git a/lib/libpthread/man/pthread_mutex_init.3 b/lib/libpthread/man/pthread_mutex_init.3
new file mode 100644
index 0000000..c3fb60c
--- /dev/null
+++ b/lib/libpthread/man/pthread_mutex_init.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 29, 1998
+.Dt PTHREAD_MUTEX_INIT 3
+.Os
+.Sh NAME
+.Nm pthread_mutex_init
+.Nd create a mutex
+.Sh LIBRARY
+.Lb libc_r
+.Sh SYNOPSIS
+.In 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
+.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
+.St -p1003.1-96 .
diff --git a/lib/libpthread/man/pthread_mutex_lock.3 b/lib/libpthread/man/pthread_mutex_lock.3
new file mode 100644
index 0000000..cc35ff2
--- /dev/null
+++ b/lib/libpthread/man/pthread_mutex_lock.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 30, 1998
+.Dt PTHREAD_MUTEX_LOCK 3
+.Os
+.Sh NAME
+.Nm pthread_mutex_lock
+.Nd lock a mutex
+.Sh LIBRARY
+.Lb libc_r
+.Sh SYNOPSIS
+.In 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
+.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
+.St -p1003.1-96 .
diff --git a/lib/libpthread/man/pthread_mutex_trylock.3 b/lib/libpthread/man/pthread_mutex_trylock.3
new file mode 100644
index 0000000..5de24ce
--- /dev/null
+++ b/lib/libpthread/man/pthread_mutex_trylock.3
@@ -0,0 +1,75 @@
+.\" 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
+.Sh NAME
+.Nm pthread_mutex_trylock
+.Nd attempt to lock a mutex without blocking
+.Sh LIBRARY
+.Lb libc_r
+.Sh SYNOPSIS
+.In 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
+.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
+.St -p1003.1-96 .
diff --git a/lib/libpthread/man/pthread_mutex_unlock.3 b/lib/libpthread/man/pthread_mutex_unlock.3
new file mode 100644
index 0000000..d5ae7dc
--- /dev/null
+++ b/lib/libpthread/man/pthread_mutex_unlock.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 30, 1998
+.Dt PTHREAD_MUTEX_UNLOCK 3
+.Os
+.Sh NAME
+.Nm pthread_mutex_unlock
+.Nd unlock a mutex
+.Sh LIBRARY
+.Lb libc_r
+.Sh SYNOPSIS
+.In 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
+.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
+.St -p1003.1-96 .
diff --git a/lib/libpthread/man/pthread_mutexattr.3 b/lib/libpthread/man/pthread_mutexattr.3
new file mode 100644
index 0000000..7476ae1
--- /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
+.In 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 -p1003.1-96
+.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..7ad97fe
--- /dev/null
+++ b/lib/libpthread/man/pthread_once.3
@@ -0,0 +1,105 @@
+.\" 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
+.Sh NAME
+.Nm pthread_once
+.Nd dynamic package initialization
+.Sh LIBRARY
+.Lb libc_r
+.Sh SYNOPSIS
+.In 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 .
+.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.
+.Sh STANDARDS
+.Fn pthread_once
+conforms to
+.St -p1003.1-96 .
diff --git a/lib/libpthread/man/pthread_rwlock_destroy.3 b/lib/libpthread/man/pthread_rwlock_destroy.3
new file mode 100644
index 0000000..b65e065
--- /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
+.In 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..0360987
--- /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
+.In 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_rwlockattr_init 3 ,
+.Xr pthread_rwlockattr_setpshared 3 ,
+.Xr pthread_rwlock_destroy 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..88dbb17
--- /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
+.In 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..9391f75
--- /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
+.In 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..55ab5f9
--- /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
+.In 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..3ba97cf
--- /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
+.In 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..56bda44
--- /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
+.In 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 -tag -width PTHREAD_PROCESS_PRIVATE
+.It Dv 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 Dv 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_rwlockattr_init 3 ,
+.Xr pthread_rwlockattr_setpshared 3 ,
+.Xr pthread_rwlock_init 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..a4aef31
--- /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
+.In 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_rwlockattr_destroy 3 ,
+.Xr pthread_rwlockattr_getpshared 3 ,
+.Xr pthread_rwlockattr_setpshared 3 ,
+.Xr pthread_rwlock_init 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..48b854d
--- /dev/null
+++ b/lib/libpthread/man/pthread_rwlockattr_setpshared.3
@@ -0,0 +1,90 @@
+.\" 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
+.In 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 -tag -width PTHREAD_PROCESS_PRIVATE
+.It Dv 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 Dv 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_rwlockattr_init 3 ,
+.Xr pthread_rwlockattr_setpshared 3 ,
+.Xr pthread_rwlock_init 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
+.Dv 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..c76f4d90
--- /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
+.In 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..899af43
--- /dev/null
+++ b/lib/libpthread/man/pthread_self.3
@@ -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 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
+.Sh NAME
+.Nm pthread_self
+.Nd get the calling thread's ID
+.Sh LIBRARY
+.Lb libc_r
+.Sh SYNOPSIS
+.In 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.
+.Sh SEE ALSO
+.Xr pthread_create 3 ,
+.Xr pthread_equal 3
+.Sh STANDARDS
+.Fn pthread_self
+conforms to
+.St -p1003.1-96 .
diff --git a/lib/libpthread/man/pthread_setspecific.3 b/lib/libpthread/man/pthread_setspecific.3
new file mode 100644
index 0000000..5bc274c
--- /dev/null
+++ b/lib/libpthread/man/pthread_setspecific.3
@@ -0,0 +1,95 @@
+.\" 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
+.Sh NAME
+.Nm pthread_setspecific
+.Nd set a thread-specific data value
+.Sh LIBRARY
+.Lb libc_r
+.Sh SYNOPSIS
+.In 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
+.Sh SEE ALSO
+.Xr pthread_getspecific 3 ,
+.Xr pthread_key_create 3 ,
+.Xr pthread_key_delete 3
+.Sh STANDARDS
+.Fn pthread_setspecific
+conforms to
+.St -p1003.1-96 .
diff --git a/lib/libpthread/man/pthread_sigmask.3 b/lib/libpthread/man/pthread_sigmask.3
new file mode 100644
index 0000000..5efa925
--- /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
+.In pthread.h
+.In 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 sigsuspend 2 ,
+.Xr sigsetops 3
+.Sh STANDARDS
+.Fn pthread_sigmask
+conforms to
+.St -p1003.1-96
diff --git a/lib/libpthread/man/pthread_testcancel.3 b/lib/libpthread/man/pthread_testcancel.3
new file mode 100644
index 0000000..6467ac6
--- /dev/null
+++ b/lib/libpthread/man/pthread_testcancel.3
@@ -0,0 +1,209 @@
+.\" $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
+.In 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, if
+.Fa oldstate
+is not
+.Dv NULL ,
+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, if
+.Fa oldtype
+is not
+.Dv NULL ,
+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
+.St -p1003.1-96 .
+.Sh AUTHORS
+This man page was written by
+.An David Leonard Aq d@openbsd.org
+for the
+.Ox
+implementation of
+.Xr pthread_cancel 3 .
diff --git a/lib/libpthread/man/sem_destroy.3 b/lib/libpthread/man/sem_destroy.3
new file mode 100644
index 0000000..8094a53
--- /dev/null
+++ b/lib/libpthread/man/sem_destroy.3
@@ -0,0 +1,81 @@
+.\" 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
+.In 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
+.Rv -std sem_destroy
+.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
+.St -p1003.1-96 .
+.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
+.Er 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..d1cc3a4
--- /dev/null
+++ b/lib/libpthread/man/sem_getvalue.3
@@ -0,0 +1,73 @@
+.\" 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
+.In 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
+.Rv -std sem_getvalue
+.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
+.St -p1003.1-96 .
+.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..fd517c2
--- /dev/null
+++ b/lib/libpthread/man/sem_init.3
@@ -0,0 +1,98 @@
+.\" 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
+.In 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
+.Rv -std sem_init
+.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
+.St -p1003.1-96 .
+.Pp
+This implementation does not support shared semaphores, and reports this fact
+by setting
+.Va errno
+to
+.Er 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..07c9543
--- /dev/null
+++ b/lib/libpthread/man/sem_open.3
@@ -0,0 +1,81 @@
+.\" 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
+.In 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
+.St -p1003.1-96 .
diff --git a/lib/libpthread/man/sem_post.3 b/lib/libpthread/man/sem_post.3
new file mode 100644
index 0000000..71b9f43
--- /dev/null
+++ b/lib/libpthread/man/sem_post.3
@@ -0,0 +1,70 @@
+.\" 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
+.In 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
+.Rv -std sem_post
+.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
+.St -p1003.1-96 .
diff --git a/lib/libpthread/man/sem_wait.3 b/lib/libpthread/man/sem_wait.3
new file mode 100644
index 0000000..c89ea04
--- /dev/null
+++ b/lib/libpthread/man/sem_wait.3
@@ -0,0 +1,86 @@
+.\" 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
+.In 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
+.Rv -std
+.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
+.St -p1003.1-96 .
diff --git a/lib/libpthread/man/sigwait.3 b/lib/libpthread/man/sigwait.3
new file mode 100644
index 0000000..76376a6
--- /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
+.In 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 -p1003.1-96
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..0eb530c
--- /dev/null
+++ b/lib/libpthread/test/Makefile
@@ -0,0 +1,115 @@
+#
+# $FreeBSD$
+#
+# Automated test suite for libc_r (pthreads).
+#
+
+# File lists.
+
+# Tests written in C.
+CTESTS := hello_d.c hello_s.c join_leak_d.c mutex_d.c sem_d.c sigsuspend_d.c \
+ sigwait_d.c
+
+# C programs that are used internally by the tests. The build system merely
+# compiles these.
+BTESTS := guard_b.c hello_b.c
+
+# Tests written in perl.
+PTESTS := guard_s.pl propagate_s.pl
+
+# Munge the file lists to their final executable names (strip the .c).
+CTESTS := $(CTESTS:R)
+BTESTS := $(BTESTS:R)
+
+CPPFLAGS := -D_LIBC_R_ -D_REENTRANT
+CFLAGS := -Wall -pipe -g3
+LDFLAGS_A := -static
+LDFLAGS_P := -pg
+LDFLAGS_S :=
+LIBS := -lc_r
+
+# 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 $(CTESTS) $(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 $(CTESTS:R:S/$/&_a.d/) $(BTESTS:R:S/$/&_a.d/) \
+ $(CTESTS:R:S/$/&_p.d/) $(BTESTS:R:S/$/&_p.d/) \
+ $(CTESTS:R:S/$/&_s.d/) $(BTESTS:R:S/$/&_s.d/)
+.if exists($(depfile))
+.include "$(depfile)"
+.endif
+.endfor
+
+default : check
+
+tests_a : $(CTESTS:S/$/&_a/) $(BTESTS:S/$/&_a/)
+tests_p : $(CTESTS:S/$/&_p/) $(BTESTS:S/$/&_p/)
+tests_s : $(CTESTS:S/$/&_s/) $(BTESTS:S/$/&_s/)
+
+tests : tests_a tests_p tests_s
+
+check_a : tests_a
+.for bin in $(CTESTS) $(BTESTS)
+ @cp $(bin)_a $(bin)
+.endfor
+ @echo "Test static library:"
+ @./verify $(VFLAGS) $(CTESTS) $(PTESTS)
+
+check_p : tests_p
+.for bin in $(CTESTS) $(BTESTS)
+ @cp $(bin)_p $(bin)
+.endfor
+ @echo "Test profile library:"
+ @./verify $(VFLAGS) $(CTESTS) $(PTESTS)
+
+check_s : tests_s
+.for bin in $(CTESTS) $(BTESTS)
+ @cp $(bin)_s $(bin)
+.endfor
+ @echo "Test shared library:"
+ @./verify $(VFLAGS) $(CTESTS) $(PTESTS)
+
+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 $(CTESTS) $(BTESTS)
+ rm -f $(CTESTS:S/$/&_a/) $(BTESTS:S/$/&_a/)
+ rm -f $(CTESTS:S/$/&_p/) $(BTESTS:S/$/&_p/)
+ rm -f $(CTESTS: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/guard_b.c b/lib/libpthread/test/guard_b.c
new file mode 100644
index 0000000..e2f1a3a
--- /dev/null
+++ b/lib/libpthread/test/guard_b.c
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2001 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
+ * unmodified other than the allowable 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$
+ *
+ * Test thread stack guard functionality.
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <limits.h>
+#include <pthread.h>
+
+#define FRAME_SIZE 1024
+#define FRAME_OVERHEAD 40
+
+struct args
+{
+ void *top; /* Top of thread's initial stack frame. */
+ int cur; /* Recursion depth. */
+ int max; /* Maximum recursion depth. */
+};
+
+void *
+recurse(void *args)
+{
+ int top;
+ struct args *parms = (struct args *)args;
+ char filler[FRAME_SIZE - FRAME_OVERHEAD];
+
+ /* Touch the memory in this stack frame. */
+ top = 0xa5;
+ memset(filler, 0xa5, sizeof(filler));
+
+ if (parms->top == NULL) {
+ /* Initial stack frame. */
+ parms->top = (void*)&top;
+ }
+
+ /*
+ * Make sure frame size is what we expect. Getting this right involves
+ * hand tweaking, so just print a warning rather than aborting.
+ */
+ if (parms->top - (void *)&top != FRAME_SIZE * parms->cur) {
+ fprintf(stderr, "Stack size (%d) != expected (%d), frame %d\n",
+ parms->top - (void *)&top, FRAME_SIZE * parms->cur,
+ parms->cur);
+ }
+
+ parms->cur++;
+ if (parms->cur < parms->max)
+ recurse(args);
+
+ return NULL;
+}
+
+
+int
+main(int argc, char **argv)
+{
+ size_t def_stacksize, def_guardsize;
+ size_t stacksize, guardsize;
+ pthread_t thread;
+ pthread_attr_t attr;
+ struct args args;
+
+ if (argc != 3) {
+ fprintf(stderr, "Usage: guard_b <stacksize> <guardsize>\n");
+ exit(1);
+ }
+ fprintf(stderr, "Test begin\n");
+
+ stacksize = strtoul(argv[1], NULL, 10);
+ guardsize = strtoul(argv[2], NULL, 10);
+
+ assert(pthread_attr_init(&attr) == 0);
+ /*
+ * Exercise the attribute APIs more thoroughly than is strictly
+ * necessary for the meat of this test program.
+ */
+ assert(pthread_attr_getstacksize(&attr, &def_stacksize) == 0);
+ assert(pthread_attr_getguardsize(&attr, &def_guardsize) == 0);
+ if (def_stacksize != stacksize) {
+ assert(pthread_attr_setstacksize(&attr, stacksize) == 0);
+ assert(pthread_attr_getstacksize(&attr, &def_stacksize) == 0);
+ assert(def_stacksize == stacksize);
+ }
+ if (def_guardsize != guardsize) {
+ assert(pthread_attr_setguardsize(&attr, guardsize) == 0);
+ assert(pthread_attr_getguardsize(&attr, &def_guardsize) == 0);
+ assert(def_guardsize >= guardsize);
+ }
+
+ /*
+ * Create a thread that will come just short of overflowing the thread
+ * stack. We need to leave a bit of breathing room in case the thread
+ * is context switched, and we also have to take care not to call any
+ * functions in the deepest stack frame.
+ */
+ args.top = NULL;
+ args.cur = 0;
+ args.max = (stacksize / FRAME_SIZE) - 1;
+ fprintf(stderr, "No overflow:\n");
+ assert(pthread_create(&thread, &attr, recurse, &args) == 0);
+ assert(pthread_join(thread, NULL) == 0);
+
+ /*
+ * Create a thread that will barely of overflow the thread stack. This
+ * should cause a segfault.
+ */
+ args.top = NULL;
+ args.cur = 0;
+ args.max = (stacksize / FRAME_SIZE) + 1;
+ fprintf(stderr, "Overflow:\n");
+ assert(pthread_create(&thread, &attr, recurse, &args) == 0);
+ assert(pthread_join(thread, NULL) == 0);
+
+ /* Not reached. */
+ fprintf(stderr, "Unexpected success\n");
+ abort();
+
+ return 0;
+}
diff --git a/lib/libpthread/test/guard_b.exp b/lib/libpthread/test/guard_b.exp
new file mode 100644
index 0000000..8e5b9e4
--- /dev/null
+++ b/lib/libpthread/test/guard_b.exp
@@ -0,0 +1,3 @@
+Test begin
+No overflow:
+Overflow:
diff --git a/lib/libpthread/test/guard_s.pl b/lib/libpthread/test/guard_s.pl
new file mode 100755
index 0000000..7802ff3
--- /dev/null
+++ b/lib/libpthread/test/guard_s.pl
@@ -0,0 +1,69 @@
+#!/usr/bin/perl -w
+#
+# Copyright (C) 2001 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
+# unmodified other than the allowable 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$
+#
+# Test thread stack guard functionality. The C test program needs to be driven
+# by this script because it segfaults when the stack guard is hit.
+#
+
+print "1..30\n";
+
+$i = 0;
+# Iterates 10 times.
+for ($stacksize = 65536; $stacksize < 131072; $stacksize += 7168)
+{
+ # Iterates 3 times (1024, 4096, 7168).
+ for ($guardsize = 1024; $guardsize < 8192; $guardsize += 3072)
+ {
+ $i++;
+
+ print "stacksize: $stacksize, guardsize: $guardsize\n";
+
+ `./guard_b $stacksize $guardsize >guard_b.out 2>&1`;
+
+ if (! -f "./guard_b.out")
+ {
+ print "not ok $i\n";
+ }
+ else
+ {
+ `diff guard_b.exp guard_b.out >guard_b.diff 2>&1`;
+ if ($?)
+ {
+ # diff returns non-zero if there is a difference.
+ print "not ok $i\n";
+ }
+ else
+ {
+ print "ok $i\n";
+ }
+ }
+ }
+}
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/join_leak_d.c b/lib/libpthread/test/join_leak_d.c
new file mode 100644
index 0000000..6532ca5
--- /dev/null
+++ b/lib/libpthread/test/join_leak_d.c
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2001 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$
+ *
+ * Test for leaked joined threads.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <errno.h>
+#include <string.h>
+#include <pthread.h>
+
+#define NITERATIONS 16384
+#define MAXGROWTH 16384
+
+void *
+thread_entry(void *a_arg)
+{
+ return NULL;
+}
+
+int
+main(void)
+{
+ pthread_t thread;
+ int i, error;
+ char *brk, *nbrk;
+ unsigned growth;
+
+ fprintf(stderr, "Test begin\n");
+
+ /* Get an initial brk value. */
+ brk = sbrk(0);
+
+ /* Create threads and join them, one at a time. */
+ for (i = 0; i < NITERATIONS; i++) {
+ if ((error = pthread_create(&thread, NULL, thread_entry, NULL))
+ != 0) {
+ fprintf(stderr, "Error in pthread_create(): %s\n",
+ strerror(error));
+ exit(1);
+ }
+ if ((error = pthread_join(thread, NULL)) != 0) {
+ fprintf(stderr, "Error in pthread_join(): %s\n",
+ strerror(error));
+ exit(1);
+ }
+ }
+
+ /* Get a final brk value. */
+ nbrk = sbrk(0);
+
+ /*
+ * Check that the amount of heap space allocated is below an acceptable
+ * threshold. We could just compare brk and nbrk, but the test could
+ * conceivably break if the internals of the threads library changes.
+ */
+ if (nbrk > brk) {
+ /* Heap grows up. */
+ growth = nbrk - brk;
+ } else if (nbrk <= brk) {
+ /* Heap grows down, or no growth. */
+ growth = brk - nbrk;
+ }
+
+ if (growth > MAXGROWTH) {
+ fprintf(stderr, "Heap growth exceeded maximum (%u > %u)\n",
+ growth, MAXGROWTH);
+ }
+#if (0)
+ else {
+ fprintf(stderr, "Heap growth acceptable (%u <= %u)\n",
+ growth, MAXGROWTH);
+ }
+#endif
+
+ fprintf(stderr, "Test end\n");
+ return 0;
+}
diff --git a/lib/libpthread/test/join_leak_d.exp b/lib/libpthread/test/join_leak_d.exp
new file mode 100644
index 0000000..369a88d
--- /dev/null
+++ b/lib/libpthread/test/join_leak_d.exp
@@ -0,0 +1,2 @@
+Test begin
+Test end
diff --git a/lib/libpthread/test/mutex_d.c b/lib/libpthread/test/mutex_d.c
new file mode 100644
index 0000000..21bf848
--- /dev/null
+++ b/lib/libpthread/test/mutex_d.c
@@ -0,0 +1,1552 @@
+/*
+ * 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
+
+static void log_error(const char *, ...) __printflike(1, 2);
+static void log_trace (const char *, ...) __printflike(1, 2);
+static void log (const char *, ...) __printflike(1, 2);
+
+/*------------------------------------------------------------
+ * 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,
+ &param) == 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, &param) == 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, &param) == 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,
+ &param) == 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,
+ &param) == 0);
+ param.sched_priority = states[4].priority;
+ assert (pthread_setschedparam (states[4].tid, SCHED_FIFO,
+ &param) == 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,
+ &param) == 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,
+ &param) == 0);
+ param.sched_priority = states[4].priority;
+ assert (pthread_setschedparam (states[4].tid, SCHED_RR,
+ &param) == 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, &param) == 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,
+ &param) == 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..b834591
--- /dev/null
+++ b/lib/libpthread/test/sem_d.c
@@ -0,0 +1,133 @@
+/****************************************************************************
+ *
+ * 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$
+ *
+ ****************************************************************************/
+
+#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..f3ccd6b
--- /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 SIGUSR1 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..2863e5c
--- /dev/null
+++ b/lib/libpthread/test/verify
@@ -0,0 +1,474 @@
+#!/usr/bin/perl -w
+#-*-mode:perl-*-
+#############################################################################
+#
+# Copyright (C) 1999-2001 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_objdir = ".";
+$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,
+ "o|objdir=s" => \$opt_objdir,
+ "u|ustats" => \$opt_ustats,
+ "z|zero" => \$opt_zero
+ );
+
+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 ($#ARGV + 1 == 0)
+{
+ print STDERR "No tests specified\n";
+ &usage();
+ exit 1;
+}
+
+if ($opt_verbose)
+{
+ print STDERR "Option values: h:$opt_help, v:$opt_verbose, "
+ . "s:\"$opt_srcdir\", o:\"$opt_objdir\" "
+ . "q:$opt_quiet, u:$opt_ustats, z:$opt_zero\n";
+ printf STDERR "Tests (%d total): @ARGV\n", $#ARGV + 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 (@ARGV)
+{
+ # Strip out any whitespace in $test.
+ $test =~ s/^\s*(.*)\s*$/$1/;
+
+ $okay = 1;
+
+ if (-e "$opt_srcdir/$test.exp")
+ {
+ # Diff mode.
+
+ ($okay, $utime, $stime) = &run_test($test);
+
+ if (-e "$opt_objdir/$test.out")
+ {
+ `diff $opt_srcdir/$test.exp $opt_objdir/$test.out > $opt_objdir/$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 output file \"$opt_objdir/$test.out\"\n";
+ }
+ }
+
+ ($hutime, $hstime) = &print_stats($test, $okay, 0, 0, $utime, $stime);
+ }
+ else
+ {
+ # Sequence mode.
+
+ ($okay, $utime, $stime) = &run_test($test);
+
+ if (open (STEST_OUT, "<$opt_objdir/$test.out"))
+ {
+ $num_subtests = 0;
+ $num_failed_subtests = 0;
+
+ while (defined($line = <STEST_OUT>))
+ {
+ if ($line =~ /1\.\.(\d+)/)
+ {
+ $num_subtests = $1;
+ last;
+ }
+ }
+ if ($num_subtests == 0)
+ {
+ $okay = 0;
+ if ($opt_verbose)
+ {
+ print STDERR "Malformed or missing 1..n line\n";
+ }
+ }
+ else
+ {
+ 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 \"$opt_objdir/$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;
+ }
+}
+
+# Print summary stats.
+$tt_str = sprintf ("%d / %d passed (%5.2f%%%%)",
+ ($#ARGV + 1) - ($#FAILED_TESTS + 1),
+ $#ARGV + 1,
+ (($#ARGV + 1) - ($#FAILED_TESTS + 1))
+ / ($#ARGV + 1) * 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";
+ }
+}
+
+if ($#FAILED_TESTS >= 0)
+{
+ # One or more tests failed, so return an error.
+ exit 1;
+}
+# End of main execution.
+
+sub run_test
+{
+ my ($test) = @_;
+ my ($okay) = 1;
+ my ($tutime, $tstime);
+ my ($utime, $stime, $cutime, $cstime);
+ my (@TSTATS, @TPATH);
+ my ($t_str);
+ my ($srcdir, $objdir);
+
+ # Get the path component of $test, if any.
+ @TPATH = split(/\//, $test);
+ pop(@TPATH);
+ $srcdir = join('/', ($opt_srcdir, @TPATH));
+ $objdir = join('/', ($opt_objdir, @TPATH));
+
+ @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;
+ `$opt_objdir/$test $srcdir $objdir > $opt_objdir/$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
+ "\"$opt_objdir/$test > $opt_objdir/$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, "<$opt_objdir/$test.perf"))
+ {
+ print STDERR "Unable to open \"$opt_objdir/$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, ">$opt_objdir/$test.perf"))
+ {
+ if (!$opt_quiet)
+ {
+ print STDERR "Unable to update \"$opt_objdir/$test.perf\"\n";
+ }
+ }
+ else
+ {
+ print TEST_PERF "$utime $stime\n";
+ close TEST_PERF;
+ }
+ }
+
+ return ($hutime, $hstime);
+}
+
+sub usage
+{
+ print <<EOF;
+$0 usage:
+ $0 [<options>] <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 ".").
+ -o --objdir | Path to object tree (default is ".").
+ -u --ustats | Update historical statistics (stored in "<test>.perf".
+ -z --zero | Consider non-zero exit code to be an error.
+ --------------+-------------------------------------------------------------
+
+ If <test>.exp exists, <test>'s output is diff'ed with <test>.exp. Any
+ difference is considered failure.
+
+ If <test>.exp does not exist, 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.
+EOF
+}
diff --git a/lib/libpthread/thread/Makefile.inc b/lib/libpthread/thread/Makefile.inc
new file mode 100644
index 0000000..1ec09c5
--- /dev/null
+++ b/lib/libpthread/thread/Makefile.inc
@@ -0,0 +1,138 @@
+# $FreeBSD$
+
+# uthread sources
+.PATH: ${.CURDIR}/uthread
+
+SRCS+= \
+ uthread_accept.c \
+ uthread_acl_delete_fd.c \
+ uthread_acl_get_fd.c \
+ uthread_acl_set_fd.c \
+ uthread_acl_aclcheck_fd.c \
+ uthread_aio_suspend.c \
+ uthread_attr_destroy.c \
+ uthread_attr_init.c \
+ uthread_attr_getdetachstate.c \
+ uthread_attr_getguardsize.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_setguardsize.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_cap_get_fd.c \
+ uthread_cap_set_fd.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_main_np.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_sigmask.c \
+ uthread_sigpending.c \
+ uthread_sigprocmask.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_stack.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_acl_aclcheck_fd.c b/lib/libpthread/thread/thr_acl_aclcheck_fd.c
new file mode 100644
index 0000000..19e9aaa
--- /dev/null
+++ b/lib/libpthread/thread/thr_acl_aclcheck_fd.c
@@ -0,0 +1,47 @@
+/*-
+ * Copyright (c) 2001 Thomas Moestl
+ * 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$
+ */
+
+#include <sys/types.h>
+#include <sys/acl.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(___acl_aclcheck_fd, __acl_aclcheck_fd);
+
+int
+___acl_aclcheck_fd(int fd, acl_type_t tp, acl_t acl)
+{
+ int error;
+
+ if ((error = _FD_LOCK(fd, FD_READ, NULL)) == 0) {
+ error = __sys___acl_aclcheck_fd(fd, tp, (struct acl *)acl);
+ _FD_UNLOCK(fd, FD_READ);
+ }
+ return (error);
+}
+
diff --git a/lib/libpthread/thread/thr_aio_suspend.c b/lib/libpthread/thread/thr_aio_suspend.c
new file mode 100644
index 0000000..23d34f9
--- /dev/null
+++ b/lib/libpthread/thread/thr_aio_suspend.c
@@ -0,0 +1,50 @@
+/*
+ * 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>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_aio_suspend, aio_suspend);
+
+int
+_aio_suspend(const struct aiocb * const iocbs[], int niocb, const struct
+ timespec *timeout)
+{
+ int ret;
+
+ _thread_enter_cancellation_point();
+ ret = __sys_aio_suspend(iocbs, niocb, timeout);
+ _thread_leave_cancellation_point();
+
+ return ret;
+}
+
diff --git a/lib/libpthread/thread/thr_attr_destroy.c b/lib/libpthread/thread/thr_attr_destroy.c
new file mode 100644
index 0000000..420bd5a
--- /dev/null
+++ b/lib/libpthread/thread/thr_attr_destroy.c
@@ -0,0 +1,62 @@
+/*
+ * 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>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_pthread_attr_destroy, pthread_attr_destroy);
+
+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);
+}
diff --git a/lib/libpthread/thread/thr_attr_getdetachstate.c b/lib/libpthread/thread/thr_attr_getdetachstate.c
new file mode 100644
index 0000000..515248d
--- /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>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_pthread_attr_getdetachstate, pthread_attr_getdetachstate);
+
+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);
+}
diff --git a/lib/libpthread/thread/thr_attr_getguardsize.c b/lib/libpthread/thread/thr_attr_getguardsize.c
new file mode 100644
index 0000000..849bf27
--- /dev/null
+++ b/lib/libpthread/thread/thr_attr_getguardsize.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2001 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
+ * unmodified other than the allowable 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>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_pthread_attr_getguardsize, pthread_attr_getguardsize);
+
+int
+_pthread_attr_getguardsize(const pthread_attr_t *attr, size_t *guardsize)
+{
+ int ret;
+
+ /* Check for invalid arguments: */
+ if (attr == NULL || *attr == NULL || guardsize == NULL)
+ ret = EINVAL;
+ else {
+ /* Return the guard size: */
+ *guardsize = (*attr)->guardsize_attr;
+ ret = 0;
+ }
+ return(ret);
+}
diff --git a/lib/libpthread/thread/thr_attr_getinheritsched.c b/lib/libpthread/thread/thr_attr_getinheritsched.c
new file mode 100644
index 0000000..6d6d324
--- /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>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_pthread_attr_getinheritsched, pthread_attr_getinheritsched);
+
+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);
+}
diff --git a/lib/libpthread/thread/thr_attr_getschedparam.c b/lib/libpthread/thread/thr_attr_getschedparam.c
new file mode 100644
index 0000000..cac86fa
--- /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>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_pthread_attr_getschedparam, pthread_attr_getschedparam);
+
+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);
+}
diff --git a/lib/libpthread/thread/thr_attr_getschedpolicy.c b/lib/libpthread/thread/thr_attr_getschedpolicy.c
new file mode 100644
index 0000000..f2b74fc
--- /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>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_pthread_attr_getschedpolicy, pthread_attr_getschedpolicy);
+
+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);
+}
diff --git a/lib/libpthread/thread/thr_attr_getscope.c b/lib/libpthread/thread/thr_attr_getscope.c
new file mode 100644
index 0000000..8abf418
--- /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>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_pthread_attr_getscope, pthread_attr_getscope);
+
+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);
+}
diff --git a/lib/libpthread/thread/thr_attr_getstackaddr.c b/lib/libpthread/thread/thr_attr_getstackaddr.c
new file mode 100644
index 0000000..0cef0f3
--- /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>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_pthread_attr_getstackaddr, pthread_attr_getstackaddr);
+
+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);
+}
diff --git a/lib/libpthread/thread/thr_attr_getstacksize.c b/lib/libpthread/thread/thr_attr_getstacksize.c
new file mode 100644
index 0000000..091a0c7
--- /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>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_pthread_attr_getstacksize, pthread_attr_getstacksize);
+
+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);
+}
diff --git a/lib/libpthread/thread/thr_attr_init.c b/lib/libpthread/thread/thr_attr_init.c
new file mode 100644
index 0000000..e10d521
--- /dev/null
+++ b/lib/libpthread/thread/thr_attr_init.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 <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_pthread_attr_init, pthread_attr_init);
+
+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);
+}
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..be6f8d7
--- /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>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_pthread_attr_setcreatesuspend_np, pthread_attr_setcreatesuspend_np);
+
+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);
+}
diff --git a/lib/libpthread/thread/thr_attr_setdetachstate.c b/lib/libpthread/thread/thr_attr_setdetachstate.c
new file mode 100644
index 0000000..e0e23c2
--- /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>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_pthread_attr_setdetachstate, pthread_attr_setdetachstate);
+
+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);
+}
diff --git a/lib/libpthread/thread/thr_attr_setguardsize.c b/lib/libpthread/thread/thr_attr_setguardsize.c
new file mode 100644
index 0000000..0c3de14
--- /dev/null
+++ b/lib/libpthread/thread/thr_attr_setguardsize.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2001 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
+ * unmodified other than the allowable 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/param.h>
+#include <errno.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_pthread_attr_setguardsize, pthread_attr_setguardsize);
+
+int
+_pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize)
+{
+ int ret;
+
+ /* Check for invalid arguments. */
+ if (attr == NULL || *attr == NULL)
+ ret = EINVAL;
+ else {
+ /* Round guardsize up to the nearest multiple of PAGE_SIZE. */
+ if (guardsize % PAGE_SIZE != 0)
+ guardsize = ((guardsize / PAGE_SIZE) + 1) * PAGE_SIZE;
+
+ /* Save the stack size. */
+ (*attr)->guardsize_attr = guardsize;
+ ret = 0;
+ }
+ return(ret);
+}
diff --git a/lib/libpthread/thread/thr_attr_setinheritsched.c b/lib/libpthread/thread/thr_attr_setinheritsched.c
new file mode 100644
index 0000000..3538131
--- /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>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_pthread_attr_setinheritsched, pthread_attr_setinheritsched);
+
+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);
+}
diff --git a/lib/libpthread/thread/thr_attr_setschedparam.c b/lib/libpthread/thread/thr_attr_setschedparam.c
new file mode 100644
index 0000000..c42973e
--- /dev/null
+++ b/lib/libpthread/thread/thr_attr_setschedparam.c
@@ -0,0 +1,57 @@
+/*
+ * 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 <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_pthread_attr_setschedparam, pthread_attr_setschedparam);
+
+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 if ((param->sched_priority < PTHREAD_MIN_PRIORITY) ||
+ (param->sched_priority > PTHREAD_MAX_PRIORITY)) {
+ /* Return an unsupported value error. */
+ ret = ENOTSUP;
+ } else
+ (*attr)->prio = param->sched_priority;
+
+ return(ret);
+}
diff --git a/lib/libpthread/thread/thr_attr_setschedpolicy.c b/lib/libpthread/thread/thr_attr_setschedpolicy.c
new file mode 100644
index 0000000..d9c83e6
--- /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>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_pthread_attr_setschedpolicy, pthread_attr_setschedpolicy);
+
+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);
+}
diff --git a/lib/libpthread/thread/thr_attr_setscope.c b/lib/libpthread/thread/thr_attr_setscope.c
new file mode 100644
index 0000000..3614615
--- /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>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_pthread_attr_setscope, pthread_attr_setscope);
+
+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);
+}
diff --git a/lib/libpthread/thread/thr_attr_setstackaddr.c b/lib/libpthread/thread/thr_attr_setstackaddr.c
new file mode 100644
index 0000000..6046932
--- /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>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_pthread_attr_setstackaddr, pthread_attr_setstackaddr);
+
+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);
+}
diff --git a/lib/libpthread/thread/thr_attr_setstacksize.c b/lib/libpthread/thread/thr_attr_setstacksize.c
new file mode 100644
index 0000000..622ba7f
--- /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>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_pthread_attr_setstacksize, pthread_attr_setstacksize);
+
+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);
+}
diff --git a/lib/libpthread/thread/thr_cancel.c b/lib/libpthread/thread/thr_cancel.c
new file mode 100644
index 0000000..cf72d89
--- /dev/null
+++ b/lib/libpthread/thread/thr_cancel.c
@@ -0,0 +1,243 @@
+/*
+ * 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);
+
+__weak_reference(_pthread_cancel, pthread_cancel);
+__weak_reference(_pthread_setcancelstate, pthread_setcancelstate);
+__weak_reference(_pthread_setcanceltype, pthread_setcanceltype);
+__weak_reference(_pthread_testcancel, pthread_testcancel);
+
+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_JOIN:
+ /*
+ * Disconnect the thread from the joinee:
+ */
+ if (pthread->join_status.thread != NULL) {
+ pthread->join_status.thread->joiner
+ = NULL;
+ pthread->join_status.thread = NULL;
+ }
+ 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_JOIN ||
+ 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:
+ /*
+ * 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)
+{
+ struct pthread *curthread = _get_curthread();
+ int ostate;
+ int ret;
+
+ ostate = curthread->cancelflags & PTHREAD_CANCEL_DISABLE;
+
+ switch (state) {
+ case PTHREAD_CANCEL_ENABLE:
+ if (oldstate != NULL)
+ *oldstate = ostate;
+ curthread->cancelflags &= ~PTHREAD_CANCEL_DISABLE;
+ if ((curthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS) != 0)
+ pthread_testcancel();
+ ret = 0;
+ break;
+ case PTHREAD_CANCEL_DISABLE:
+ if (oldstate != NULL)
+ *oldstate = ostate;
+ curthread->cancelflags |= PTHREAD_CANCEL_DISABLE;
+ ret = 0;
+ break;
+ default:
+ ret = EINVAL;
+ }
+
+ return (ret);
+}
+
+int
+_pthread_setcanceltype(int type, int *oldtype)
+{
+ struct pthread *curthread = _get_curthread();
+ int otype;
+ int ret;
+
+ otype = curthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS;
+ switch (type) {
+ case PTHREAD_CANCEL_ASYNCHRONOUS:
+ if (oldtype != NULL)
+ *oldtype = otype;
+ curthread->cancelflags |= PTHREAD_CANCEL_ASYNCHRONOUS;
+ pthread_testcancel();
+ ret = 0;
+ break;
+ case PTHREAD_CANCEL_DEFERRED:
+ if (oldtype != NULL)
+ *oldtype = otype;
+ curthread->cancelflags &= ~PTHREAD_CANCEL_ASYNCHRONOUS;
+ ret = 0;
+ break;
+ default:
+ ret = EINVAL;
+ }
+
+ return (ret);
+}
+
+void
+_pthread_testcancel(void)
+{
+ struct pthread *curthread = _get_curthread();
+
+ if (((curthread->cancelflags & PTHREAD_CANCEL_DISABLE) == 0) &&
+ ((curthread->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.
+ */
+ curthread->cancelflags &= ~PTHREAD_CANCELLING;
+ _thread_exit_cleanup();
+ pthread_exit(PTHREAD_CANCELED);
+ PANIC("cancel");
+ }
+}
+
+void
+_thread_enter_cancellation_point(void)
+{
+ struct pthread *curthread = _get_curthread();
+
+ /* Look for a cancellation before we block: */
+ pthread_testcancel();
+ curthread->cancelflags |= PTHREAD_AT_CANCEL_POINT;
+}
+
+void
+_thread_leave_cancellation_point(void)
+{
+ struct pthread *curthread = _get_curthread();
+
+ curthread->cancelflags &= ~PTHREAD_AT_CANCEL_POINT;
+ /* Look for a cancellation after we unblock: */
+ pthread_testcancel();
+}
+
+static void
+finish_cancellation(void *arg)
+{
+ struct pthread *curthread = _get_curthread();
+
+ curthread->continuation = NULL;
+ curthread->interrupted = 0;
+
+ if ((curthread->cancelflags & PTHREAD_CANCEL_NEEDED) != 0) {
+ curthread->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..6330cb9
--- /dev/null
+++ b/lib/libpthread/thread/thr_clean.c
@@ -0,0 +1,72 @@
+/*
+ * 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>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_pthread_cleanup_push, pthread_cleanup_push);
+__weak_reference(_pthread_cleanup_pop, pthread_cleanup_pop);
+
+void
+_pthread_cleanup_push(void (*routine) (void *), void *routine_arg)
+{
+ struct pthread *curthread = _get_curthread();
+ 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 = curthread->cleanup;
+
+ curthread->cleanup = new;
+ }
+}
+
+void
+_pthread_cleanup_pop(int execute)
+{
+ struct pthread *curthread = _get_curthread();
+ struct pthread_cleanup *old;
+
+ if ((old = curthread->cleanup) != NULL) {
+ curthread->cleanup = old->next;
+ if (execute) {
+ old->routine(old->routine_arg);
+ }
+ free(old);
+ }
+}
+
diff --git a/lib/libpthread/thread/thr_close.c b/lib/libpthread/thread/thr_close.c
new file mode 100644
index 0000000..0a5bd24
--- /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>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(__close, close);
+
+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 = __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 = __sys_fcntl(fd, F_GETFL, NULL);
+ /* Clear the nonblocking file descriptor flag: */
+ __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 = __sys_close(fd);
+ }
+ return (ret);
+}
+
+int
+__close(int fd)
+{
+ int ret;
+
+ _thread_enter_cancellation_point();
+ ret = _close(fd);
+ _thread_leave_cancellation_point();
+
+ return ret;
+}
diff --git a/lib/libpthread/thread/thr_cond.c b/lib/libpthread/thread/thr_cond.c
new file mode 100644
index 0000000..7f3fe7a
--- /dev/null
+++ b/lib/libpthread/thread/thr_cond.c
@@ -0,0 +1,747 @@
+/*
+ * 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 <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);
+
+__weak_reference(_pthread_cond_init, pthread_cond_init);
+__weak_reference(_pthread_cond_destroy, pthread_cond_destroy);
+__weak_reference(_pthread_cond_wait, pthread_cond_wait);
+__weak_reference(_pthread_cond_timedwait, pthread_cond_timedwait);
+__weak_reference(_pthread_cond_signal, pthread_cond_signal);
+__weak_reference(_pthread_cond_broadcast, pthread_cond_broadcast);
+
+
+/* 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;
+ (*cond)->c_seqno = 0;
+ 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;
+ pcond->c_seqno = 0;
+ 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)
+{
+ struct pthread *curthread = _get_curthread();
+ int rval = 0;
+ int done = 0;
+ int interrupted = 0;
+ int seqno;
+
+ _thread_enter_cancellation_point();
+
+ if (cond == NULL)
+ return (EINVAL);
+
+ /*
+ * If the condition variable is statically initialized,
+ * perform the dynamic initialization:
+ */
+ if (*cond == NULL &&
+ (rval = pthread_cond_init(cond, NULL)) != 0)
+ return (rval);
+
+ /*
+ * Enter a loop waiting for a condition signal or broadcast
+ * to wake up this thread. A loop is needed in case the waiting
+ * thread is interrupted by a signal to execute a signal handler.
+ * It is not (currently) possible to remain in the waiting queue
+ * while running a handler. Instead, the thread is interrupted
+ * and backed out of the waiting queue prior to executing the
+ * signal handler.
+ */
+ do {
+ /* 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: */
+ curthread->timeout = 0;
+ curthread->interrupted = 0;
+
+ /*
+ * Queue the running thread for the condition
+ * variable:
+ */
+ cond_queue_enq(*cond, curthread);
+
+ /* Remember the mutex and sequence number: */
+ (*cond)->c_mutex = *mutex;
+ seqno = (*cond)->c_seqno;
+
+ /* Wait forever: */
+ curthread->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, curthread);
+
+ /* 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__);
+
+ done = (seqno != (*cond)->c_seqno);
+
+ interrupted = curthread->interrupted;
+
+ /*
+ * Check if the wait was interrupted
+ * (canceled) or needs to be resumed
+ * after handling a signal.
+ */
+ if (interrupted != 0) {
+ /*
+ * 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);
+ } else {
+ /*
+ * Lock the condition variable
+ * while removing the thread.
+ */
+ _SPINLOCK(&(*cond)->lock);
+
+ cond_queue_remove(*cond,
+ curthread);
+
+ /* Check for no more waiters: */
+ if (TAILQ_FIRST(&(*cond)->c_queue) == NULL)
+ (*cond)->c_mutex = NULL;
+
+ _SPINUNLOCK(&(*cond)->lock);
+
+ /* Lock the mutex: */
+ 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) && (curthread->continuation != NULL))
+ curthread->continuation((void *) curthread);
+ } while ((done == 0) && (rval == 0));
+
+ _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)
+{
+ struct pthread *curthread = _get_curthread();
+ int rval = 0;
+ int done = 0;
+ int interrupted = 0;
+ int seqno;
+
+ _thread_enter_cancellation_point();
+
+ if (abstime == NULL || abstime->tv_sec < 0 || abstime->tv_nsec < 0 ||
+ abstime->tv_nsec >= 1000000000)
+ return (EINVAL);
+ /*
+ * If the condition variable is statically initialized, perform dynamic
+ * initialization.
+ */
+ if (*cond == NULL && (rval = pthread_cond_init(cond, NULL)) != 0)
+ return (rval);
+
+ /*
+ * Enter a loop waiting for a condition signal or broadcast
+ * to wake up this thread. A loop is needed in case the waiting
+ * thread is interrupted by a signal to execute a signal handler.
+ * It is not (currently) possible to remain in the waiting queue
+ * while running a handler. Instead, the thread is interrupted
+ * and backed out of the waiting queue prior to executing the
+ * signal handler.
+ */
+ do {
+ /* 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: */
+ curthread->wakeup_time.tv_sec =
+ abstime->tv_sec;
+ curthread->wakeup_time.tv_nsec =
+ abstime->tv_nsec;
+
+ /* Reset the timeout and interrupted flags: */
+ curthread->timeout = 0;
+ curthread->interrupted = 0;
+
+ /*
+ * Queue the running thread for the condition
+ * variable:
+ */
+ cond_queue_enq(*cond, curthread);
+
+ /* Remember the mutex and sequence number: */
+ (*cond)->c_mutex = *mutex;
+ seqno = (*cond)->c_seqno;
+
+ /* 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, curthread);
+
+ /* 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__);
+
+ done = (seqno != (*cond)->c_seqno);
+
+ interrupted = curthread->interrupted;
+
+ /*
+ * Check if the wait was interrupted
+ * (canceled) or needs to be resumed
+ * after handling a signal.
+ */
+ if (interrupted != 0) {
+ /*
+ * 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);
+ } else {
+ /*
+ * Lock the condition variable
+ * while removing the thread.
+ */
+ _SPINLOCK(&(*cond)->lock);
+
+ cond_queue_remove(*cond,
+ curthread);
+
+ /* Check for no more waiters: */
+ if (TAILQ_FIRST(&(*cond)->c_queue) == NULL)
+ (*cond)->c_mutex = NULL;
+
+ _SPINUNLOCK(&(*cond)->lock);
+
+ /* Lock the mutex: */
+ rval = _mutex_cv_lock(mutex);
+
+ /*
+ * Return ETIMEDOUT if the wait
+ * timed out and there wasn't an
+ * error locking the mutex:
+ */
+ if ((curthread->timeout != 0)
+ && rval == 0)
+ rval = ETIMEDOUT;
+
+ }
+ }
+ }
+ 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) && (curthread->continuation != NULL))
+ curthread->continuation((void *) curthread);
+ } while ((done == 0) && (rval == 0));
+
+ _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:
+ /* Increment the sequence number: */
+ (*cond)->c_seqno++;
+
+ 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:
+ /* Increment the sequence number: */
+ (*cond)->c_seqno++;
+
+ /*
+ * 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);
+}
+
+void
+_cond_wait_backout(pthread_t pthread)
+{
+ pthread_cond_t cond;
+
+ cond = pthread->data.cond;
+ if (cond != NULL) {
+ /*
+ * 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:
+ cond_queue_remove(cond, pthread);
+
+ /* Check for no more waiters: */
+ if (TAILQ_FIRST(&cond->c_queue) == NULL)
+ cond->c_mutex = NULL;
+ break;
+
+ default:
+ break;
+ }
+
+ /* Unlock the condition variable structure: */
+ _SPINUNLOCK(&cond->lock);
+
+ /*
+ * Undefer and handle pending signals, yielding if
+ * necessary:
+ */
+ _thread_kern_sig_undefer();
+ }
+}
+
+/*
+ * 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, sqe);
+ 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, sqe);
+ 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);
+
+ PTHREAD_ASSERT_NOT_IN_SYNCQ(pthread);
+
+ /*
+ * 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, sqe);
+ else {
+ tid = TAILQ_FIRST(&cond->c_queue);
+ while (pthread->active_priority <= tid->active_priority)
+ tid = TAILQ_NEXT(tid, sqe);
+ TAILQ_INSERT_BEFORE(tid, pthread, sqe);
+ }
+ pthread->flags |= PTHREAD_FLAGS_IN_CONDQ;
+ pthread->data.cond = cond;
+}
diff --git a/lib/libpthread/thread/thr_condattr_destroy.c b/lib/libpthread/thread/thr_condattr_destroy.c
new file mode 100644
index 0000000..3a05487
--- /dev/null
+++ b/lib/libpthread/thread/thr_condattr_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>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_pthread_condattr_destroy, pthread_condattr_destroy);
+
+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);
+}
diff --git a/lib/libpthread/thread/thr_condattr_init.c b/lib/libpthread/thread/thr_condattr_init.c
new file mode 100644
index 0000000..cfc1e4a
--- /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>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_pthread_condattr_init, pthread_condattr_init);
+
+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);
+}
diff --git a/lib/libpthread/thread/thr_creat.c b/lib/libpthread/thread/thr_creat.c
new file mode 100644
index 0000000..92da971
--- /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>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(___creat, creat);
+
+int
+___creat(const char *path, mode_t mode)
+{
+ int ret;
+
+ _thread_enter_cancellation_point();
+ ret = __creat(path, mode);
+ _thread_leave_cancellation_point();
+
+ return ret;
+}
diff --git a/lib/libpthread/thread/thr_create.c b/lib/libpthread/thread/thr_create.c
new file mode 100644
index 0000000..f846789
--- /dev/null
+++ b/lib/libpthread/thread/thr_create.c
@@ -0,0 +1,267 @@
+/*
+ * 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 <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_ctx_offset = OFF(ctx);
+#undef OFF
+
+int _thread_PS_RUNNING_value = PS_RUNNING;
+int _thread_PS_DEAD_value = PS_DEAD;
+
+__weak_reference(_pthread_create, pthread_create);
+
+int
+_pthread_create(pthread_t * thread, const pthread_attr_t * attr,
+ void *(*start_routine) (void *), void *arg)
+{
+ struct pthread *curthread = _get_curthread();
+ struct itimerval itimer;
+ 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 a stack: */
+ else {
+ stack = _thread_stack_alloc(pattr->stacksize_attr,
+ pattr->guardsize_attr);
+ if (stack == NULL) {
+ 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->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 = curthread->sigmask;
+ new_thread->sigmask_seqno = 0;
+
+ /* Initialize the signal frame: */
+ new_thread->curframe = NULL;
+
+ /* Initialise the jump buffer: */
+ _setjmp(new_thread->ctx.jb);
+
+ /*
+ * Set up new stack frame so that it looks like it
+ * returned from a longjmp() to the beginning of
+ * _thread_start().
+ */
+ SET_RETURN_ADDR_JB(new_thread->ctx.jb, _thread_start);
+
+ /* The stack starts high and builds down: */
+ SET_STACK_JB(new_thread->ctx.jb,
+ (long)new_thread->stack + pattr->stacksize_attr
+ - sizeof(double));
+
+ /* 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 =
+ curthread->base_priority &
+ ~PTHREAD_SIGNAL_PRIORITY;
+ new_thread->attr.prio =
+ curthread->base_priority &
+ ~PTHREAD_SIGNAL_PRIORITY;
+ new_thread->attr.sched_policy =
+ curthread->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;
+
+ /* Initialize joiner to NULL (no joiner): */
+ new_thread->joiner = NULL;
+
+ /* Initialize the mutex queue: */
+ TAILQ_INIT(&new_thread->mutexq);
+
+ /* Initialise hooks in the thread structure: */
+ new_thread->specific = NULL;
+ new_thread->cleanup = NULL;
+ new_thread->flags = 0;
+ new_thread->poll_data.nfds = 0;
+ new_thread->poll_data.fds = NULL;
+ 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;
+
+ if (f_gc != 0) {
+ /* Install the scheduling timer: */
+ itimer.it_interval.tv_sec = 0;
+ itimer.it_interval.tv_usec = _clock_res_usec;
+ itimer.it_value = itimer.it_interval;
+ if (setitimer(_ITIMER_SCHED_TIMER, &itimer,
+ NULL) != 0)
+ PANIC("Cannot set interval timer");
+ }
+
+ /* 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)
+{
+ struct pthread *curthread = _get_curthread();
+
+ /* We just left the scheduler via longjmp: */
+ _thread_kern_in_sched = 0;
+
+ /* Run the current thread's start routine with argument: */
+ pthread_exit(curthread->start_routine(curthread->arg));
+
+ /* This point should never be reached. */
+ PANIC("Thread has resumed after exit");
+}
diff --git a/lib/libpthread/thread/thr_detach.c b/lib/libpthread/thread/thr_detach.c
new file mode 100644
index 0000000..298fdb4
--- /dev/null
+++ b/lib/libpthread/thread/thr_detach.c
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE 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 <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_pthread_detach, pthread_detach);
+
+int
+_pthread_detach(pthread_t pthread)
+{
+ int rval = 0;
+
+ /* 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();
+
+ /* Check if there is a joiner: */
+ if (pthread->joiner != NULL) {
+ struct pthread *joiner = pthread->joiner;
+
+ /* Make the thread runnable: */
+ PTHREAD_NEW_STATE(joiner, PS_RUNNING);
+
+ /* Set the return value for the woken thread: */
+ joiner->join_status.error = ESRCH;
+ joiner->join_status.ret = NULL;
+ joiner->join_status.thread = NULL;
+
+ /*
+ * Disconnect the joiner from the thread being detached:
+ */
+ pthread->joiner = NULL;
+ }
+
+ /*
+ * 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);
+}
diff --git a/lib/libpthread/thread/thr_equal.c b/lib/libpthread/thread/thr_equal.c
new file mode 100644
index 0000000..0dfb63d
--- /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$
+ */
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_pthread_equal, pthread_equal);
+
+int
+_pthread_equal(pthread_t t1, pthread_t t2)
+{
+ /* Compare the two thread pointers: */
+ return (t1 == t2);
+}
diff --git a/lib/libpthread/thread/thr_exit.c b/lib/libpthread/thread/thr_exit.c
new file mode 100644
index 0000000..c9513cf
--- /dev/null
+++ b/lib/libpthread/thread/thr_exit.c
@@ -0,0 +1,241 @@
+/*
+ * 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>
+#include <pthread.h>
+#include "pthread_private.h"
+
+#define FLAGS_IN_SCHEDQ \
+ (PTHREAD_FLAGS_IN_PRIOQ|PTHREAD_FLAGS_IN_WAITQ|PTHREAD_FLAGS_IN_WORKQ)
+
+__weak_reference(_pthread_exit, pthread_exit);
+
+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: */
+ __sys_close(_thread_kern_pipe[0]);
+ __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 = __sys_fcntl(i, F_GETFL, NULL);
+ /* Clear the nonblocking file descriptor flag: */
+ __sys_fcntl(i, F_SETFL, flags & ~O_NONBLOCK);
+ }
+ }
+
+ /* Call the _exit syscall: */
+ __sys_exit(status);
+}
+
+void
+_thread_exit(char *fname, int lineno, char *string)
+{
+ char s[256];
+
+ /* Prepare an error message string: */
+ snprintf(s, sizeof(s),
+ "Fatal error '%s' at line %d in file %s (errno = %d)\n",
+ string, lineno, fname, errno);
+
+ /* Write the string to the standard error file descriptor: */
+ __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
+ __sys_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)
+{
+ struct pthread *curthread = _get_curthread();
+
+ /*
+ * 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(curthread);
+
+ /* Unlock all private mutexes: */
+ _mutex_unlock_private(curthread);
+
+ /*
+ * This still isn't quite correct because we don't account
+ * for held spinlocks (see libc/stdlib/malloc.c).
+ */
+}
+
+void
+_pthread_exit(void *status)
+{
+ struct pthread *curthread = _get_curthread();
+ pthread_t pthread;
+
+ /* Check if this thread is already in the process of exiting: */
+ if ((curthread->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!",curthread);
+ PANIC(msg);
+ }
+
+ /* Flag this thread as exiting: */
+ curthread->flags |= PTHREAD_EXITING;
+
+ /* Save the return value: */
+ curthread->ret = status;
+
+ while (curthread->cleanup != NULL) {
+ pthread_cleanup_pop(1);
+ }
+ if (curthread->attr.cleanup_attr != NULL) {
+ curthread->attr.cleanup_attr(curthread->attr.arg_attr);
+ }
+ /* Check if there is thread specific data: */
+ if (curthread->specific != NULL) {
+ /* Run the thread-specific data destructors: */
+ _thread_cleanupspecific();
+ }
+
+ /* Free thread-specific poll_data structure, if allocated: */
+ if (curthread->poll_data.fds != NULL) {
+ free(curthread->poll_data.fds);
+ curthread->poll_data.fds = NULL;
+ }
+
+ /*
+ * 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, curthread, dle);
+
+ /*
+ * Signal the garbage collector thread that there is something
+ * to clean up.
+ */
+ if (pthread_cond_signal(&_gc_cond) != 0)
+ PANIC("Cannot signal gc cond");
+
+ /*
+ * Avoid a race condition where a scheduling signal can occur
+ * causing the garbage collector thread to run. If this happens,
+ * the current thread can be cleaned out from under us.
+ */
+ _thread_kern_sig_defer();
+
+ /* Unlock the garbage collector mutex: */
+ if (pthread_mutex_unlock(&_gc_mutex) != 0)
+ PANIC("Cannot unlock gc mutex");
+
+ /* Check if there is a thread joining this one: */
+ if (curthread->joiner != NULL) {
+ pthread = curthread->joiner;
+ curthread->joiner = NULL;
+
+ switch (pthread->suspended) {
+ case SUSP_JOIN:
+ /*
+ * The joining thread is suspended. Change the
+ * suspension state to make the thread runnable when it
+ * is resumed:
+ */
+ pthread->suspended = SUSP_NO;
+ break;
+ case SUSP_NO:
+ /* Make the joining thread runnable: */
+ PTHREAD_NEW_STATE(pthread, PS_RUNNING);
+ break;
+ default:
+ PANIC("Unreachable code reached");
+ }
+
+ /* Set the return value for the joining thread: */
+ pthread->join_status.ret = curthread->ret;
+ pthread->join_status.error = 0;
+ pthread->join_status.thread = NULL;
+
+ /* Make this thread collectable by the garbage collector. */
+ PTHREAD_ASSERT(((curthread->attr.flags & PTHREAD_DETACHED) ==
+ 0), "Cannot join a detached thread");
+ curthread->attr.flags |= PTHREAD_DETACHED;
+ }
+
+ /* Remove this thread from the thread list: */
+ TAILQ_REMOVE(&_thread_list, curthread, tle);
+
+ /* This thread will never be re-scheduled. */
+ _thread_kern_sched_state(PS_DEAD, __FILE__, __LINE__);
+
+ /* This point should not be reached. */
+ PANIC("Dead thread has resumed");
+}
diff --git a/lib/libpthread/thread/thr_fcntl.c b/lib/libpthread/thread/thr_fcntl.c
new file mode 100644
index 0000000..1d12c0e
--- /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>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(__fcntl, fcntl);
+
+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 = __sys_fcntl(fd, cmd, oldfd)) < 0) {
+ }
+ /* Initialise the file descriptor table entry: */
+ else if (_thread_fd_table_init(ret) != 0) {
+ /* Quietly close the file: */
+ __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 = __sys_fcntl(fd, cmd, flags);
+ break;
+ case F_GETFD:
+ ret = __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 = __sys_fcntl(fd, cmd, flags | O_NONBLOCK)) != 0) {
+
+ /* Get the flags so that we behave like the kernel: */
+ } else if ((flags = __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 = __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;
+}
diff --git a/lib/libpthread/thread/thr_find_thread.c b/lib/libpthread/thread/thr_find_thread.c
new file mode 100644
index 0000000..e6e9294
--- /dev/null
+++ b/lib/libpthread/thread/thr_find_thread.c
@@ -0,0 +1,66 @@
+/*
+ * 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>
+#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);
+}
diff --git a/lib/libpthread/thread/thr_fork.c b/lib/libpthread/thread/thr_fork.c
new file mode 100644
index 0000000..dd6d3ff
--- /dev/null
+++ b/lib/libpthread/thread/thr_fork.c
@@ -0,0 +1,243 @@
+/*
+ * 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 <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+static void free_thread_resources(struct pthread *thread);
+
+__weak_reference(_fork, fork);
+
+pid_t
+_fork(void)
+{
+ struct pthread *curthread = _get_curthread();
+ int i, flags, use_deadlist = 0;
+ 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 = __sys_fork()) != 0) {
+ /* Parent process or error. Nothing to do here. */
+ } else {
+ /* Close the pthread kernel pipe: */
+ __sys_close(_thread_kern_pipe[0]);
+ __sys_close(_thread_kern_pipe[1]);
+
+ /* Reset signals pending for the running thread: */
+ sigemptyset(&curthread->sigpend);
+
+ /*
+ * Create a pipe that is written to by the signal handler to
+ * prevent signals being missed in calls to
+ * __sys_select:
+ */
+ if (__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 = __sys_fcntl(_thread_kern_pipe[0], F_GETFL, NULL)) == -1) {
+ /* Abort this application: */
+ abort();
+ }
+ /* Make the read pipe non-blocking: */
+ else if (__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 = __sys_fcntl(_thread_kern_pipe[1], F_GETFL, NULL)) == -1) {
+ /* Abort this application: */
+ abort();
+ }
+ /* Make the write pipe non-blocking: */
+ else if (__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:
+ */
+ if ((pthread = TAILQ_FIRST(&_thread_list)) == NULL) {
+ pthread = TAILQ_FIRST(&_dead_list);
+ use_deadlist = 1;
+ }
+ while (pthread != NULL) {
+ /* Save the thread to be freed: */
+ pthread_save = pthread;
+
+ /*
+ * Advance to the next thread before
+ * destroying the current thread:
+ */
+ if (use_deadlist != 0)
+ pthread = TAILQ_NEXT(pthread, dle);
+ else
+ pthread = TAILQ_NEXT(pthread, tle);
+
+ /* Make sure this isn't the running thread: */
+ if (pthread_save != curthread) {
+ /*
+ * Remove this thread from the
+ * appropriate list:
+ */
+ if (use_deadlist != 0)
+ TAILQ_REMOVE(&_thread_list,
+ pthread_save, dle);
+ else
+ TAILQ_REMOVE(&_thread_list,
+ pthread_save, tle);
+
+ free_thread_resources(pthread_save);
+ }
+
+ /*
+ * Switch to the deadlist when the active
+ * thread list has been consumed. This can't
+ * be at the top of the loop because it is
+ * used to determine to which list the thread
+ * belongs (when it is removed from the list).
+ */
+ if (pthread == NULL) {
+ pthread = TAILQ_FIRST(&_dead_list);
+ use_deadlist = 1;
+ }
+ }
+
+ /* Treat the current thread as the initial thread: */
+ _thread_initial = curthread;
+
+ /* 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(&curthread->mutexq);
+
+ /* No spinlocks yet: */
+ _spinblock_count = 0;
+
+ /* Don't queue signals yet: */
+ _queue_signals = 0;
+
+ /* 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);
+}
+
+static void
+free_thread_resources(struct pthread *thread)
+{
+
+ /* Check to see if the threads library allocated the stack. */
+ if ((thread->attr.stackaddr_attr == NULL) && (thread->stack != NULL)) {
+ /*
+ * Since this is being called from fork, we are currently single
+ * threaded so there is no need to protect the call to
+ * _thread_stack_free() with _gc_mutex.
+ */
+ _thread_stack_free(thread->stack, thread->attr.stacksize_attr,
+ thread->attr.guardsize_attr);
+ }
+
+ if (thread->specific != NULL)
+ free(thread->specific);
+
+ if (thread->poll_data.fds != NULL)
+ free(thread->poll_data.fds);
+
+ free(thread);
+}
diff --git a/lib/libpthread/thread/thr_fsync.c b/lib/libpthread/thread/thr_fsync.c
new file mode 100644
index 0000000..b8b9f3c
--- /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>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(__fsync, fsync);
+
+int
+_fsync(int fd)
+{
+ int ret;
+
+ if ((ret = _FD_LOCK(fd, FD_RDWR, NULL)) == 0) {
+ ret = __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;
+}
diff --git a/lib/libpthread/thread/thr_gc.c b/lib/libpthread/thread/thr_gc.c
new file mode 100644
index 0000000..9c93028
--- /dev/null
+++ b/lib/libpthread/thread/thr_gc.c
@@ -0,0 +1,219 @@
+/*
+ * 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 <sys/param.h>
+#include <errno.h>
+#include <time.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+pthread_addr_t
+_thread_gc(pthread_addr_t arg)
+{
+ struct pthread *curthread = _get_curthread();
+ 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);
+ pthread_sigmask(SIG_BLOCK, &mask, NULL);
+
+ /* Mark this thread as a library thread (not a user thread). */
+ curthread->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(curthread,"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) == curthread &&
+ TAILQ_NEXT(curthread, 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();
+
+ /* No stack of thread structure to free yet: */
+ p_stack = NULL;
+ pthread_cln = NULL;
+
+ /*
+ * 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");
+
+ /*
+ * 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) {
+ _thread_stack_free(pthread->stack,
+ pthread->attr.stacksize_attr,
+ pthread->attr.guardsize_attr);
+ }
+
+ /*
+ * 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) {
+ _thread_stack_free(pthread->stack,
+ pthread->attr.stacksize_attr,
+ pthread->attr.guardsize_attr);
+
+ /*
+ * 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..a10c889
--- /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>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_pthread_getprio, pthread_getprio);
+
+int
+_pthread_getprio(pthread_t pthread)
+{
+ int policy, ret;
+ struct sched_param param;
+
+ if ((ret = pthread_getschedparam(pthread, &policy, &param)) == 0)
+ ret = param.sched_priority;
+ else {
+ /* Invalid thread: */
+ errno = ret;
+ ret = -1;
+ }
+
+ /* Return the thread priority or an error status: */
+ return (ret);
+}
diff --git a/lib/libpthread/thread/thr_getschedparam.c b/lib/libpthread/thread/thr_getschedparam.c
new file mode 100644
index 0000000..0d1ffe9
--- /dev/null
+++ b/lib/libpthread/thread/thr_getschedparam.c
@@ -0,0 +1,59 @@
+/*
+ * 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 <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_pthread_getschedparam, pthread_getschedparam);
+
+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(pthread->base_priority);
+ *policy = pthread->attr.sched_policy;
+ }
+
+ return(ret);
+}
diff --git a/lib/libpthread/thread/thr_info.c b/lib/libpthread/thread/thr_info.c
new file mode 100644
index 0000000..305a2b9
--- /dev/null
+++ b/lib/libpthread/thread/thr_info.c
@@ -0,0 +1,290 @@
+/*
+ * 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 <stdlib.h>
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <errno.h>
+#include "pthread_private.h"
+
+#ifndef NELEMENTS
+#define NELEMENTS(arr) (sizeof(arr) / sizeof(arr[0]))
+#endif
+
+static void dump_thread(int fd, pthread_t pthread, int long_version);
+
+__weak_reference(_pthread_set_name_np, pthread_set_name_np);
+
+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;
+ 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 = __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");
+ __sys_write(fd, s, strlen(s));
+
+ /* Enter a loop to report each thread in the global list: */
+ TAILQ_FOREACH(pthread, &_thread_list, tle) {
+ dump_thread(fd, pthread, /*long_verson*/ 1);
+ }
+
+ /* Output a header for ready threads: */
+ strcpy(s, "\n\n=============\nREADY THREADS\n\n");
+ __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) {
+ dump_thread(fd, pthread, /*long_version*/ 0);
+ }
+ }
+
+ /* Output a header for waiting threads: */
+ strcpy(s, "\n\n=============\nWAITING THREADS\n\n");
+ __sys_write(fd, s, strlen(s));
+
+ /* Enter a loop to report each thread in the waiting queue: */
+ TAILQ_FOREACH (pthread, &_waitingq, pqe) {
+ dump_thread(fd, pthread, /*long_version*/ 0);
+ }
+
+ /* Output a header for threads in the work queue: */
+ strcpy(s, "\n\n=============\nTHREADS IN WORKQ\n\n");
+ __sys_write(fd, s, strlen(s));
+
+ /* Enter a loop to report each thread in the waiting queue: */
+ TAILQ_FOREACH (pthread, &_workq, qe) {
+ dump_thread(fd, pthread, /*long_version*/ 0);
+ }
+
+ /* 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");
+ __sys_write(fd, s, strlen(s));
+ } else {
+ /* Output a header for dead threads: */
+ strcpy(s, "\n\nDEAD THREADS\n\n");
+ __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) {
+ dump_thread(fd, pthread, /*long_version*/ 0);
+ }
+ }
+
+ /* Output a header for file descriptors: */
+ snprintf(s, sizeof(s), "\n\n=============\nFILE DESCRIPTOR "
+ "TABLE (table size %d)\n\n", _thread_dtablesize);
+ __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);
+ __sys_write(fd, s, strlen(s));
+ }
+ }
+
+ /* Close the dump file: */
+ __sys_close(fd);
+ }
+}
+
+static void
+dump_thread(int fd, pthread_t pthread, int long_version)
+{
+ struct pthread *curthread = _get_curthread();
+ char s[512];
+ int i;
+
+ /* Find the state: */
+ for (i = 0; i < NELEMENTS(thread_info) - 1; i++)
+ if (thread_info[i].state == pthread->state)
+ break;
+
+ /* Output a record for the thread: */
+ snprintf(s, sizeof(s),
+ "--------------------\nThread %p (%s) prio %3d state %s [%s:%d]\n",
+ pthread, (pthread->name == NULL) ? "" : pthread->name,
+ pthread->active_priority, thread_info[i].name, pthread->fname,
+ pthread->lineno);
+ __sys_write(fd, s, strlen(s));
+
+ if (long_version != 0) {
+ /* Check if this is the running thread: */
+ if (pthread == curthread) {
+ /* Output a record for the running thread: */
+ strcpy(s, "This is the running thread\n");
+ __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");
+ __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);
+ __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);
+ __sys_write(fd, s, strlen(s));
+ break;
+ case PS_SIGWAIT:
+ snprintf(s, sizeof(s), "sigmask (hi)");
+ __sys_write(fd, s, strlen(s));
+ for (i = _SIG_WORDS - 1; i >= 0; i--) {
+ snprintf(s, sizeof(s), "%08x\n",
+ pthread->sigmask.__bits[i]);
+ __sys_write(fd, s, strlen(s));
+ }
+ snprintf(s, sizeof(s), "(lo)\n");
+ __sys_write(fd, s, strlen(s));
+ break;
+ /*
+ * Trap other states that are not explicitly
+ * coded to dump information:
+ */
+ default:
+ /* Nothing to do here. */
+ break;
+ }
+ }
+}
+
+/* Set the thread name for debug: */
+void
+_pthread_set_name_np(pthread_t thread, const 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);
+ }
+}
diff --git a/lib/libpthread/thread/thr_init.c b/lib/libpthread/thread/thr_init.c
new file mode 100644
index 0000000..a3d62ae
--- /dev/null
+++ b/lib/libpthread/thread/thr_init.c
@@ -0,0 +1,475 @@
+/*
+ * 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 "namespace.h"
+#include <sys/param.h>
+#include <sys/types.h>
+#include <machine/reg.h>
+
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/uio.h>
+#include <sys/socket.h>
+#include <sys/event.h>
+#include <sys/stat.h>
+#include <sys/sysctl.h>
+#include <sys/time.h>
+#include <sys/ttycom.h>
+#include <sys/user.h>
+#include <sys/wait.h>
+#include <sys/mman.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <paths.h>
+#include <poll.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "un-namespace.h"
+
+#include "pthread_private.h"
+
+/*
+ * All weak references used within libc should be in this table.
+ * This will is so that static libraries will work.
+ */
+static void *references[] = {
+ &_accept,
+ &_bind,
+ &_close,
+ &_connect,
+ &_dup,
+ &_dup2,
+ &_execve,
+ &_fcntl,
+ &_flock,
+ &_flockfile,
+ &_fstat,
+ &_fstatfs,
+ &_fsync,
+ &_funlockfile,
+ &_getdirentries,
+ &_getlogin,
+ &_getpeername,
+ &_getsockname,
+ &_getsockopt,
+ &_ioctl,
+ &_kevent,
+ &_listen,
+ &_nanosleep,
+ &_open,
+ &_pthread_getspecific,
+ &_pthread_key_create,
+ &_pthread_key_delete,
+ &_pthread_mutex_destroy,
+ &_pthread_mutex_init,
+ &_pthread_mutex_lock,
+ &_pthread_mutex_trylock,
+ &_pthread_mutex_unlock,
+ &_pthread_mutexattr_init,
+ &_pthread_mutexattr_destroy,
+ &_pthread_mutexattr_settype,
+ &_pthread_once,
+ &_pthread_setspecific,
+ &_read,
+ &_readv,
+ &_recvfrom,
+ &_recvmsg,
+ &_select,
+ &_sendmsg,
+ &_sendto,
+ &_setsockopt,
+ &_sigaction,
+ &_sigprocmask,
+ &_sigsuspend,
+ &_socket,
+ &_socketpair,
+ &_wait4,
+ &_write,
+ &_writev
+};
+
+/*
+ * These are needed when linking statically. All references within
+ * libgcc (and in the future libc) to these routines are weak, but
+ * if they are not (strongly) referenced by the application or other
+ * libraries, then the actual functions will not be loaded.
+ */
+static void *libgcc_references[] = {
+ &_pthread_once,
+ &_pthread_key_create,
+ &_pthread_key_delete,
+ &_pthread_getspecific,
+ &_pthread_setspecific,
+ &_pthread_mutex_init,
+ &_pthread_mutex_destroy,
+ &_pthread_mutex_lock,
+ &_pthread_mutex_trylock,
+ &_pthread_mutex_unlock
+};
+
+
+/*
+ * Threaded process initialization
+ */
+void
+_thread_init(void)
+{
+ int fd;
+ int flags;
+ int i;
+ size_t len;
+ int mib[2];
+ struct clockinfo clockinfo;
+ struct sigaction act;
+
+ /* Check if this function has already been called: */
+ if (_thread_initial)
+ /* Only initialise the threaded application once. */
+ return;
+
+ /*
+ * Make gcc quiescent about {,libgcc_}references not being
+ * referenced:
+ */
+ if ((references[0] == NULL) || (libgcc_references[0] == NULL))
+ PANIC("Failed loading mandatory references in _thread_init");
+
+ /*
+ * 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 = __sys_open(_PATH_CONSOLE, O_RDWR)) < 0)
+ PANIC("Can't open console");
+ if (setlogin("root") == -1)
+ PANIC("Can't set login to root");
+ if (__sys_ioctl(fd,TIOCSCTTY, (char *) NULL) == -1)
+ PANIC("Can't set controlling terminal");
+ if (__sys_dup2(fd,0) == -1 ||
+ __sys_dup2(fd,1) == -1 ||
+ __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] =
+ __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 (__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 = __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 (__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 = __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 (__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_LAST_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");
+ }
+ /* Allocate memory for the scheduler stack: */
+ else if ((_thread_kern_sched_stack = malloc(SCHED_STACK_SIZE)) == NULL)
+ PANIC("Failed to allocate stack for scheduler");
+ 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));
+
+ /* Find the stack top */
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_USRSTACK;
+ len = sizeof (_usrstack);
+ if (sysctl(mib, 2, &_usrstack, &len, NULL, 0) == -1)
+ _usrstack = (void *)USRSTACK;
+ /*
+ * 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(_usrstack - PTHREAD_STACK_INITIAL -
+ PTHREAD_GUARD_DEFAULT, PTHREAD_GUARD_DEFAULT, 0, MAP_ANON,
+ -1, 0) == MAP_FAILED)
+ PANIC("Cannot allocate red zone for initial thread");
+
+ /* Set the main thread stack pointer. */
+ _thread_initial->stack = _usrstack - PTHREAD_STACK_INITIAL;
+
+ /* Set the stack attributes: */
+ _thread_initial->attr.stackaddr_attr = _thread_initial->stack;
+ _thread_initial->attr.stacksize_attr = PTHREAD_STACK_INITIAL;
+
+ /* Setup the context for the scheduler: */
+ _setjmp(_thread_kern_sched_jb);
+ SET_STACK_JB(_thread_kern_sched_jb, _thread_kern_sched_stack +
+ SCHED_STACK_SIZE - sizeof(double));
+ SET_RETURN_ADDR_JB(_thread_kern_sched_jb, _thread_kern_scheduler);
+
+ /*
+ * 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;
+
+ /* Set the name of the thread: */
+ _thread_initial->name = strdup("_thread_initial");
+
+ /* Initialize joiner to NULL (no joiner): */
+ _thread_initial->joiner = NULL;
+
+ /* Initialize the owned mutex queue and count: */
+ TAILQ_INIT(&(_thread_initial->mutexq));
+ _thread_initial->priority_mutex_count = 0;
+
+ /* Initialize the global scheduling time: */
+ _sched_ticks = 0;
+ gettimeofday((struct timeval *) &_sched_tod, NULL);
+
+ /* Initialize last active: */
+ _thread_initial->last_active = (long) _sched_ticks;
+
+ /* Initialize the initial context: */
+ _thread_initial->curframe = NULL;
+
+ /* 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 = 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);
+ _set_curthread(_thread_initial);
+
+ /* Initialise the global signal action structure: */
+ sigfillset(&act.sa_mask);
+ act.sa_handler = (void (*) ()) _thread_sig_handler;
+ act.sa_flags = SA_SIGINFO | SA_ONSTACK;
+
+ /* Clear pending signals for the process: */
+ sigemptyset(&_process_sigpending);
+
+ /* Clear the signal queue: */
+ memset(_thread_sigq, 0, sizeof(_thread_sigq));
+
+ /* 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 (__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 (__sys_sigaction(_SCHED_SIGNAL, &act, NULL) != 0 ||
+ __sys_sigaction(SIGINFO, &act, NULL) != 0 ||
+ __sys_sigaction(SIGCHLD, &act, NULL) != 0) {
+ /*
+ * Abort this process if signal initialisation fails:
+ */
+ PANIC("Cannot initialise signal handler");
+ }
+ _thread_sigact[_SCHED_SIGNAL - 1].sa_flags = SA_SIGINFO;
+ _thread_sigact[SIGINFO - 1].sa_flags = SA_SIGINFO;
+ _thread_sigact[SIGCHLD - 1].sa_flags = SA_SIGINFO;
+
+ /* Get the process signal mask: */
+ __sys_sigprocmask(SIG_SETMASK, NULL, &_process_sigmask);
+
+ /* 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_usec = clockinfo.tick > CLOCK_RES_USEC_MIN ?
+ clockinfo.tick : CLOCK_RES_USEC_MIN;
+
+ /* 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");
+ }
+ }
+ }
+
+ /* 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");
+}
+
+/*
+ * 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
diff --git a/lib/libpthread/thread/thr_join.c b/lib/libpthread/thread/thr_join.c
new file mode 100644
index 0000000..0f5e8fc
--- /dev/null
+++ b/lib/libpthread/thread/thr_join.c
@@ -0,0 +1,162 @@
+/*
+ * 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>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_pthread_join, pthread_join);
+
+int
+_pthread_join(pthread_t pthread, void **thread_return)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret = 0;
+ pthread_t thread;
+
+ _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 == curthread) {
+ /* Avoid a deadlock condition: */
+ _thread_leave_cancellation_point();
+ return(EDEADLK);
+ }
+
+ /*
+ * 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");
+
+ /*
+ * Defer signals to protect the thread list from access
+ * by the signal handler:
+ */
+ _thread_kern_sig_defer();
+
+ /*
+ * Unlock the garbage collector mutex, now that the garbage collector
+ * can't be run:
+ */
+ if (pthread_mutex_unlock(&_gc_mutex) != 0)
+ PANIC("Cannot lock gc mutex");
+
+ /*
+ * Search for the specified thread in the list of active threads. This
+ * is done manually here rather than calling _find_thread() because
+ * the searches in _thread_list and _dead_list (as well as setting up
+ * join/detach state) have to be done atomically.
+ */
+ TAILQ_FOREACH(thread, &_thread_list, tle) {
+ if (thread == pthread)
+ break;
+ }
+ if (thread == NULL) {
+ /*
+ * Search for the specified thread in the list of dead threads:
+ */
+ TAILQ_FOREACH(thread, &_dead_list, dle) {
+ if (thread == pthread)
+ break;
+ }
+ }
+
+ /* Check if the thread was not found or has been detached: */
+ if (thread == NULL ||
+ ((pthread->attr.flags & PTHREAD_DETACHED) != 0)) {
+ /* Undefer and handle pending signals, yielding if necessary: */
+ _thread_kern_sig_undefer();
+
+ /* Return an error: */
+ ret = ESRCH;
+
+ } else if (pthread->joiner != NULL) {
+ /* Undefer and handle pending signals, yielding if necessary: */
+ _thread_kern_sig_undefer();
+
+ /* Multiple joiners are not supported. */
+ ret = ENOTSUP;
+
+ /* Check if the thread is not dead: */
+ } else if (pthread->state != PS_DEAD) {
+ /* Set the running thread to be the joiner: */
+ pthread->joiner = curthread;
+
+ /* Keep track of which thread we're joining to: */
+ curthread->join_status.thread = pthread;
+
+ while (curthread->join_status.thread == pthread) {
+ /* Schedule the next thread: */
+ _thread_kern_sched_state(PS_JOIN, __FILE__, __LINE__);
+ }
+
+ /*
+ * The thread return value and error are set by the thread we're
+ * joining to when it exits or detaches:
+ */
+ ret = curthread->join_status.error;
+ if ((ret == 0) && (thread_return != NULL))
+ *thread_return = curthread->join_status.ret;
+ } else {
+ /*
+ * The thread exited (is dead) without being detached, and no
+ * thread has joined it.
+ */
+
+ /* Check if the return value is required: */
+ if (thread_return != NULL) {
+ /* Return the thread's return value: */
+ *thread_return = pthread->ret;
+ }
+
+ /* Make the thread collectable by the garbage collector. */
+ pthread->attr.flags |= PTHREAD_DETACHED;
+
+ /* Undefer and handle pending signals, yielding if necessary: */
+ _thread_kern_sig_undefer();
+ }
+
+ _thread_leave_cancellation_point();
+
+ /* Return the completion status: */
+ return (ret);
+}
diff --git a/lib/libpthread/thread/thr_kern.c b/lib/libpthread/thread/thr_kern.c
new file mode 100644
index 0000000..a4cc3c3
--- /dev/null
+++ b/lib/libpthread/thread/thr_kern.c
@@ -0,0 +1,1139 @@
+/*
+ * 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>
+#include <pthread.h>
+#include "pthread_private.h"
+
+/* #define DEBUG_THREAD_KERN */
+#ifdef DEBUG_THREAD_KERN
+#define DBG_MSG stdout_debug
+#else
+#define DBG_MSG(x...)
+#endif
+
+/* 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);
+
+/* Static variables: */
+static int last_tick = 0;
+static int called_from_handler = 0;
+
+/*
+ * This is called when a signal handler finishes and wants to
+ * return to a previous frame.
+ */
+void
+_thread_kern_sched_frame(struct pthread_signal_frame *psf)
+{
+ struct pthread *curthread = _get_curthread();
+
+ /*
+ * Flag the pthread kernel as executing scheduler code
+ * to avoid a signal from interrupting this execution and
+ * corrupting the (soon-to-be) current frame.
+ */
+ _thread_kern_in_sched = 1;
+
+ /* Restore the signal frame: */
+ _thread_sigframe_restore(curthread, psf);
+
+ /* The signal mask was restored; check for any pending signals: */
+ curthread->check_pending = 1;
+
+ /* Switch to the thread scheduler: */
+ ___longjmp(_thread_kern_sched_jb, 1);
+}
+
+
+void
+_thread_kern_sched(ucontext_t *ucp)
+{
+ struct pthread *curthread = _get_curthread();
+
+ /*
+ * 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 (ucp != NULL) {
+ /* XXX - Save FP registers? */
+ FP_SAVE_UC(ucp);
+ called_from_handler = 1;
+ DBG_MSG("Entering scheduler due to signal\n");
+ }
+
+ /* Save the state of the current thread: */
+ if (_setjmp(curthread->ctx.jb) != 0) {
+ DBG_MSG("Returned from ___longjmp, thread %p\n",
+ curthread);
+ /*
+ * 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 (curthread->sig_defer_count == 0) {
+ if (((curthread->cancelflags &
+ PTHREAD_AT_CANCEL_POINT) == 0) &&
+ ((curthread->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();
+ }
+
+ if (_sched_switch_hook != NULL) {
+ /* Run the installed switch hook: */
+ thread_run_switch_hook(_last_user_thread, curthread);
+ }
+ if (ucp == NULL)
+ return;
+ else {
+ /* XXX - Restore FP registers? */
+ FP_RESTORE_UC(ucp);
+
+ /*
+ * Set the process signal mask in the context; it
+ * could have changed by the handler.
+ */
+ ucp->uc_sigmask = _process_sigmask;
+
+ /* Resume the interrupted thread: */
+ __sys_sigreturn(ucp);
+ }
+ }
+ /* Switch to the thread scheduler: */
+ ___longjmp(_thread_kern_sched_jb, 1);
+}
+
+void
+_thread_kern_sched_sig(void)
+{
+ struct pthread *curthread = _get_curthread();
+
+ curthread->check_pending = 1;
+ _thread_kern_sched(NULL);
+}
+
+
+void
+_thread_kern_scheduler(void)
+{
+ struct timespec ts;
+ struct timeval tv;
+ struct pthread *curthread = _get_curthread();
+ pthread_t pthread, pthread_h;
+ unsigned int current_tick;
+ int add_to_prioq;
+
+ /* If the currently running thread is a user thread, save it: */
+ if ((curthread->flags & PTHREAD_FLAGS_PRIVATE) == 0)
+ _last_user_thread = curthread;
+
+ if (called_from_handler != 0) {
+ called_from_handler = 0;
+
+ /*
+ * We were called from a signal handler; restore the process
+ * signal mask.
+ */
+ if (__sys_sigprocmask(SIG_SETMASK,
+ &_process_sigmask, NULL) != 0)
+ PANIC("Unable to restore process mask after signal");
+ }
+
+ /*
+ * 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: */
+ GET_CURRENT_TOD(tv);
+ TIMEVAL_TO_TIMESPEC(&tv, &ts);
+ current_tick = _sched_ticks;
+
+ /*
+ * Protect the scheduling queues from access by the signal
+ * handler.
+ */
+ _queue_signals = 1;
+ add_to_prioq = 0;
+
+ if (curthread != &_thread_kern_thread) {
+ /*
+ * This thread no longer needs to yield the CPU.
+ */
+ curthread->yield_on_sig_undefer = 0;
+
+ if (curthread->state != PS_RUNNING) {
+ /*
+ * Save the current time as the time that the
+ * thread became inactive:
+ */
+ curthread->last_inactive = (long)current_tick;
+ if (curthread->last_inactive <
+ curthread->last_active) {
+ /* Account for a rollover: */
+ curthread->last_inactive =+
+ UINT_MAX + 1;
+ }
+ }
+
+ /*
+ * Place the currently running thread into the
+ * appropriate queue(s).
+ */
+ switch (curthread->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).
+ */
+ add_to_prioq = 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: */
+ curthread->wakeup_time.tv_sec = -1;
+ curthread->wakeup_time.tv_nsec = -1;
+
+ /* Restart the time slice: */
+ curthread->slice_usec = -1;
+
+ /* Insert into the waiting queue: */
+ PTHREAD_WAITQ_INSERT(curthread);
+ break;
+
+ /* States which can timeout: */
+ case PS_COND_WAIT:
+ case PS_SLEEP_WAIT:
+ /* Restart the time slice: */
+ curthread->slice_usec = -1;
+
+ /* Insert into the waiting queue: */
+ PTHREAD_WAITQ_INSERT(curthread);
+ break;
+
+ /* States that require periodic work: */
+ case PS_SPINBLOCK:
+ /* No timeouts for this state: */
+ curthread->wakeup_time.tv_sec = -1;
+ curthread->wakeup_time.tv_nsec = -1;
+
+ /* Increment spinblock count: */
+ _spinblock_count++;
+
+ /* FALLTHROUGH */
+ case PS_FDR_WAIT:
+ case PS_FDW_WAIT:
+ case PS_POLL_WAIT:
+ case PS_SELECT_WAIT:
+ /* Restart the time slice: */
+ curthread->slice_usec = -1;
+
+ /* Insert into the waiting queue: */
+ PTHREAD_WAITQ_INSERT(curthread);
+
+ /* Insert into the work queue: */
+ PTHREAD_WORKQ_INSERT(curthread);
+ break;
+ }
+
+ /*
+ * Are there pending signals for this thread?
+ *
+ * This check has to be performed after the thread
+ * has been placed in the queue(s) appropriate for
+ * its state. The process of adding pending signals
+ * can change a threads state, which in turn will
+ * attempt to add or remove the thread from any
+ * scheduling queue to which it belongs.
+ */
+ if (curthread->check_pending != 0) {
+ curthread->check_pending = 0;
+ _thread_sig_check_pending(curthread);
+ }
+ }
+
+ /*
+ * Avoid polling file descriptors if there are none
+ * waiting:
+ */
+ if (TAILQ_EMPTY(&_workq) != 0) {
+ }
+ /*
+ * Poll file descriptors only if a new scheduling signal
+ * has occurred or if we have no more runnable threads.
+ */
+ else if (((current_tick = _sched_ticks) != last_tick) ||
+ ((curthread->state != PS_RUNNING) &&
+ (PTHREAD_PRIOQ_FIRST() == NULL))) {
+ /* 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;
+ }
+ last_tick = current_tick;
+
+ /*
+ * 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 to see if the current thread needs to be added
+ * to the priority queue:
+ */
+ if (add_to_prioq != 0) {
+ /*
+ * Save the current time as the time that the
+ * thread became inactive:
+ */
+ current_tick = _sched_ticks;
+ curthread->last_inactive = (long)current_tick;
+ if (curthread->last_inactive <
+ curthread->last_active) {
+ /* Account for a rollover: */
+ curthread->last_inactive =+ UINT_MAX + 1;
+ }
+
+ if ((curthread->slice_usec != -1) &&
+ (curthread->attr.sched_policy != SCHED_FIFO)) {
+ /*
+ * Accumulate the number of microseconds for
+ * which the current thread has run:
+ */
+ curthread->slice_usec +=
+ (curthread->last_inactive -
+ curthread->last_active) *
+ (long)_clock_res_usec;
+ /* Check for time quantum exceeded: */
+ if (curthread->slice_usec > TIMESLICE_USEC)
+ curthread->slice_usec = -1;
+ }
+
+ if (curthread->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(curthread);
+ } else {
+ /*
+ * The thread hasn't exceeded its
+ * interval. Place it at the head
+ * of the queue for its priority.
+ */
+ PTHREAD_PRIOQ_INSERT_HEAD(curthread);
+ }
+ }
+
+ /*
+ * 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:
+ */
+ _set_curthread(&_thread_kern_thread);
+ curthread = &_thread_kern_thread;
+
+ DBG_MSG("No runnable threads, using kernel thread %p\n",
+ curthread);
+
+ /* 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);
+
+ /*
+ * This process' usage will likely be very small
+ * while waiting in a poll. Since the scheduling
+ * clock is based on the profiling timer, it is
+ * unlikely that the profiling timer will fire
+ * and update the time of day. To account for this,
+ * get the time of day after polling with a timeout.
+ */
+ gettimeofday((struct timeval *) &_sched_tod, NULL);
+
+ /* Check once more for a runnable thread: */
+ _queue_signals = 1;
+ pthread_h = PTHREAD_PRIOQ_FIRST();
+ _queue_signals = 0;
+ }
+
+ if (pthread_h != NULL) {
+ /* Remove the thread from the ready queue: */
+ PTHREAD_PRIOQ_REMOVE(pthread_h);
+
+ /* 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)) {
+ /* Remove the thread from the ready queue: */
+ PTHREAD_PRIOQ_REMOVE(pthread);
+
+ /*
+ * Insert the lower priority thread
+ * at the head of its priority list:
+ */
+ PTHREAD_PRIOQ_INSERT_HEAD(pthread_h);
+
+ /* There's a new thread in town: */
+ pthread_h = pthread;
+ }
+
+ /* Unprotect the scheduling queues: */
+ _queue_signals = 0;
+ }
+
+ /* Make the selected thread the current thread: */
+ _set_curthread(pthread_h);
+ curthread = pthread_h;
+
+ /*
+ * Save the current time as the time that the thread
+ * became active:
+ */
+ current_tick = _sched_ticks;
+ curthread->last_active = (long) current_tick;
+
+ /*
+ * Check if this thread is running for the first time
+ * or running again after using its full time slice
+ * allocation:
+ */
+ if (curthread->slice_usec == -1) {
+ /* Reset the accumulated time slice period: */
+ curthread->slice_usec = 0;
+ }
+
+ /*
+ * If we had a context switch, run any
+ * installed switch hooks.
+ */
+ if ((_sched_switch_hook != NULL) &&
+ (_last_user_thread != curthread)) {
+ thread_run_switch_hook(_last_user_thread,
+ curthread);
+ }
+ /*
+ * Continue the thread at its current frame:
+ */
+#if NOT_YET
+ _setcontext(&curthread->ctx.uc);
+#else
+ ___longjmp(curthread->ctx.jb, 1);
+#endif
+ /* 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)
+{
+ struct pthread *curthread = _get_curthread();
+
+ /*
+ * 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: */
+ curthread->state = state;
+ curthread->fname = fname;
+ curthread->lineno = lineno;
+
+ /* Schedule the next thread that is ready: */
+ _thread_kern_sched(NULL);
+}
+
+void
+_thread_kern_sched_state_unlock(enum pthread_state state,
+ spinlock_t *lock, char *fname, int lineno)
+{
+ struct pthread *curthread = _get_curthread();
+
+ /*
+ * 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: */
+ curthread->state = state;
+ curthread->fname = fname;
+ curthread->lineno = lineno;
+
+ _SPINUNLOCK(lock);
+
+ /* Schedule the next thread that is ready: */
+ _thread_kern_sched(NULL);
+}
+
+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: */
+ GET_CURRENT_TOD(tv);
+ 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 if (pthread->wakeup_time.tv_sec - ts.tv_sec > 60000)
+ /* Limit maximum timeout to prevent rollover. */
+ timeout_ms = 60000;
+ else {
+ /*
+ * Calculate the time left for the next thread to
+ * timeout:
+ */
+ timeout_ms = ((pthread->wakeup_time.tv_sec - ts.tv_sec) *
+ 1000) + ((pthread->wakeup_time.tv_nsec - ts.tv_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 = __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;
+ }
+}
+
+void
+_thread_kern_set_timeout(const struct timespec * timeout)
+{
+ struct pthread *curthread = _get_curthread();
+ struct timespec current_time;
+ struct timeval tv;
+
+ /* Reset the timeout flag for the running thread: */
+ curthread->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:
+ */
+ curthread->wakeup_time.tv_sec = -1;
+ curthread->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': */
+ curthread->wakeup_time.tv_sec = 0;
+ curthread->wakeup_time.tv_nsec = 0;
+ } else {
+ /* Get the current time: */
+ GET_CURRENT_TOD(tv);
+ TIMEVAL_TO_TIMESPEC(&tv, &current_time);
+
+ /* Calculate the time for the current thread to wake up: */
+ curthread->wakeup_time.tv_sec = current_time.tv_sec + timeout->tv_sec;
+ curthread->wakeup_time.tv_nsec = current_time.tv_nsec + timeout->tv_nsec;
+
+ /* Check if the nanosecond field needs to wrap: */
+ if (curthread->wakeup_time.tv_nsec >= 1000000000) {
+ /* Wrap the nanosecond field: */
+ curthread->wakeup_time.tv_sec += 1;
+ curthread->wakeup_time.tv_nsec -= 1000000000;
+ }
+ }
+}
+
+void
+_thread_kern_sig_defer(void)
+{
+ struct pthread *curthread = _get_curthread();
+
+ /* Allow signal deferral to be recursive. */
+ curthread->sig_defer_count++;
+}
+
+void
+_thread_kern_sig_undefer(void)
+{
+ struct pthread *curthread = _get_curthread();
+
+ /*
+ * Perform checks to yield only if we are about to undefer
+ * signals.
+ */
+ if (curthread->sig_defer_count > 1) {
+ /* Decrement the signal deferral count. */
+ curthread->sig_defer_count--;
+ }
+ else if (curthread->sig_defer_count == 1) {
+ /* Reenable signals: */
+ curthread->sig_defer_count = 0;
+
+ /*
+ * Check if there are queued signals:
+ */
+ if (_sigq_check_reqd != 0)
+ _thread_kern_sched(NULL);
+
+ /*
+ * Check for asynchronous cancellation before delivering any
+ * pending signals:
+ */
+ if (((curthread->cancelflags & PTHREAD_AT_CANCEL_POINT) == 0) &&
+ ((curthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS) != 0))
+ pthread_testcancel();
+
+ /*
+ * If there are pending signals or this thread has
+ * to yield the CPU, call the kernel scheduler:
+ *
+ * XXX - Come back and revisit the pending signal problem
+ */
+ if ((curthread->yield_on_sig_undefer != 0) ||
+ SIGNOTEMPTY(curthread->sigpend)) {
+ curthread->yield_on_sig_undefer = 0;
+ _thread_kern_sched(NULL);
+ }
+ }
+}
+
+static void
+dequeue_signals(void)
+{
+ char bufr[128];
+ int num;
+
+ /*
+ * Enter a loop to clear the pthread kernel pipe:
+ */
+ while (((num = __sys_read(_thread_kern_pipe[0], bufr,
+ sizeof(bufr))) > 0) || (num == -1 && errno == EINTR)) {
+ }
+ 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");
+ }
+ /* Handle any pending signals: */
+ _thread_sig_handle_pending();
+}
+
+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);
+ }
+}
+
+struct pthread *
+_get_curthread(void)
+{
+ if (_thread_initial == NULL)
+ _thread_init();
+
+ return (_thread_run);
+}
+
+void
+_set_curthread(struct pthread *newthread)
+{
+ _thread_run = newthread;
+}
diff --git a/lib/libpthread/thread/thr_kill.c b/lib/libpthread/thread/thr_kill.c
new file mode 100644
index 0000000..29e1814
--- /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>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_pthread_kill, pthread_kill);
+
+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);
+}
diff --git a/lib/libpthread/thread/thr_main_np.c b/lib/libpthread/thread/thr_main_np.c
new file mode 100644
index 0000000..6ae7d1e
--- /dev/null
+++ b/lib/libpthread/thread/thr_main_np.c
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2001 Alfred Perlstein
+ * Author: Alfred Perlstein <alfred@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.
+ *
+ * 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$
+ */
+
+#include <pthread.h>
+#include <pthread_np.h>
+#include "pthread_private.h"
+
+/*
+ * Provide the equivelant to Solaris thr_main() function
+ */
+#pragma weak pthread_main_np=_pthread_main_np
+int
+_pthread_main_np()
+{
+
+ if (!_thread_initial)
+ return (-1);
+ else
+ return (pthread_equal(pthread_self(), _thread_initial) ? 1 : 0);
+}
diff --git a/lib/libpthread/thread/thr_mattr_init.c b/lib/libpthread/thread/thr_mattr_init.c
new file mode 100644
index 0000000..e4e2e50
--- /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>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_pthread_mutexattr_init, pthread_mutexattr_init);
+
+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);
+}
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..04db2a0
--- /dev/null
+++ b/lib/libpthread/thread/thr_mattr_kind_np.c
@@ -0,0 +1,97 @@
+/*
+ * 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>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_pthread_mutexattr_setkind_np, pthread_mutexattr_setkind_np);
+__weak_reference(_pthread_mutexattr_getkind_np, pthread_mutexattr_getkind_np);
+__weak_reference(_pthread_mutexattr_gettype, pthread_mutexattr_gettype);
+__weak_reference(_pthread_mutexattr_settype, pthread_mutexattr_settype);
+
+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;
+}
diff --git a/lib/libpthread/thread/thr_msync.c b/lib/libpthread/thread/thr_msync.c
new file mode 100644
index 0000000..24cbaa6
--- /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>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(__msync, msync);
+
+int
+_msync(void *addr, size_t len, int flags)
+{
+ int ret;
+
+ ret = __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;
+}
diff --git a/lib/libpthread/thread/thr_multi_np.c b/lib/libpthread/thread/thr_multi_np.c
new file mode 100644
index 0000000..c1a069f
--- /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>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_pthread_multi_np, pthread_multi_np);
+
+int
+_pthread_multi_np()
+{
+ /* Return to multi-threaded scheduling mode: */
+ _thread_single = NULL;
+ return(0);
+}
diff --git a/lib/libpthread/thread/thr_mutex.c b/lib/libpthread/thread/thr_mutex.c
new file mode 100644
index 0000000..0f67b4b
--- /dev/null
+++ b/lib/libpthread/thread/thr_mutex.c
@@ -0,0 +1,1576 @@
+/*
+ * 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>
+#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;
+
+static struct pthread_mutex_attr static_mutex_attr =
+ PTHREAD_MUTEXATTR_STATIC_INITIALIZER;
+static pthread_mutexattr_t static_mattr = &static_mutex_attr;
+
+/* Single underscore versions provided for libc internal usage: */
+__weak_reference(__pthread_mutex_trylock, pthread_mutex_trylock);
+__weak_reference(__pthread_mutex_lock, pthread_mutex_lock);
+
+/* No difference between libc and application usage of these: */
+__weak_reference(_pthread_mutex_init, pthread_mutex_init);
+__weak_reference(_pthread_mutex_destroy, pthread_mutex_destroy);
+__weak_reference(_pthread_mutex_unlock, pthread_mutex_unlock);
+
+
+/* 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;
+ int flags;
+ 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;
+ flags = 0;
+ }
+
+ /* 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;
+ flags = (*mutex_attr)->m_flags;
+ }
+
+ /* Check no errors so far: */
+ if (ret == 0) {
+ if ((pmutex = (pthread_mutex_t)
+ malloc(sizeof(struct pthread_mutex))) == NULL)
+ ret = ENOMEM;
+ else {
+ /* Set the mutex flags: */
+ pmutex->m_flags = flags;
+
+ /* 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);
+}
+
+static int
+init_static_private(pthread_mutex_t *mutex)
+{
+ int ret;
+
+ _SPINLOCK(&static_init_lock);
+
+ if (*mutex == NULL)
+ ret = pthread_mutex_init(mutex, &static_mattr);
+ else
+ ret = 0;
+
+ _SPINUNLOCK(&static_init_lock);
+
+ return(ret);
+}
+
+static int
+mutex_trylock_common(pthread_mutex_t *mutex)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret = 0;
+
+ PTHREAD_ASSERT((mutex != NULL) && (*mutex != NULL),
+ "Uninitialized mutex in pthread_mutex_trylock_basic");
+
+ /*
+ * 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 = curthread;
+
+ /* Add to the list of owned mutexes: */
+ _MUTEX_ASSERT_NOT_OWNED(*mutex);
+ TAILQ_INSERT_TAIL(&curthread->mutexq,
+ (*mutex), m_qe);
+ } else if ((*mutex)->m_owner == curthread)
+ 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 = curthread;
+
+ /* Track number of priority mutexes owned: */
+ curthread->priority_mutex_count++;
+
+ /*
+ * The mutex takes on the attributes of the
+ * running thread when there are no waiters.
+ */
+ (*mutex)->m_prio = curthread->active_priority;
+ (*mutex)->m_saved_prio =
+ curthread->inherited_priority;
+
+ /* Add to the list of owned mutexes: */
+ _MUTEX_ASSERT_NOT_OWNED(*mutex);
+ TAILQ_INSERT_TAIL(&curthread->mutexq,
+ (*mutex), m_qe);
+ } else if ((*mutex)->m_owner == curthread)
+ 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 (curthread->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 = curthread;
+
+ /* Track number of priority mutexes owned: */
+ curthread->priority_mutex_count++;
+
+ /*
+ * The running thread inherits the ceiling
+ * priority of the mutex and executes at that
+ * priority.
+ */
+ curthread->active_priority = (*mutex)->m_prio;
+ (*mutex)->m_saved_prio =
+ curthread->inherited_priority;
+ curthread->inherited_priority =
+ (*mutex)->m_prio;
+
+ /* Add to the list of owned mutexes: */
+ _MUTEX_ASSERT_NOT_OWNED(*mutex);
+ TAILQ_INSERT_TAIL(&curthread->mutexq,
+ (*mutex), m_qe);
+ } else if ((*mutex)->m_owner == curthread)
+ 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_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)
+ ret = mutex_trylock_common(mutex);
+
+ 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 marking the mutex private (delete safe):
+ */
+ else if ((*mutex != NULL) || (ret = init_static_private(mutex)) == 0)
+ ret = mutex_trylock_common(mutex);
+
+ return (ret);
+}
+
+static int
+mutex_lock_common(pthread_mutex_t * mutex)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret = 0;
+
+ PTHREAD_ASSERT((mutex != NULL) && (*mutex != NULL),
+ "Uninitialized mutex in pthread_mutex_trylock_basic");
+
+ /* Reset the interrupted flag: */
+ curthread->interrupted = 0;
+
+ /*
+ * Enter a loop waiting to become the mutex owner. We need a
+ * loop in case the waiting thread is interrupted by a signal
+ * to execute a signal handler. It is not (currently) possible
+ * to remain in the waiting queue while running a handler.
+ * Instead, the thread is interrupted and backed out of the
+ * waiting queue prior to executing the signal handler.
+ */
+ do {
+ /*
+ * 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);
+ }
+
+ /* 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 = curthread;
+
+ /* Add to the list of owned mutexes: */
+ _MUTEX_ASSERT_NOT_OWNED(*mutex);
+ TAILQ_INSERT_TAIL(&curthread->mutexq,
+ (*mutex), m_qe);
+
+ } else if ((*mutex)->m_owner == curthread)
+ ret = mutex_self_lock(*mutex);
+ else {
+ /*
+ * Join the queue of threads waiting to lock
+ * the mutex:
+ */
+ mutex_queue_enq(*mutex, curthread);
+
+ /*
+ * Keep a pointer to the mutex this thread
+ * is waiting on:
+ */
+ curthread->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 = curthread;
+
+ /* Track number of priority mutexes owned: */
+ curthread->priority_mutex_count++;
+
+ /*
+ * The mutex takes on attributes of the
+ * running thread when there are no waiters.
+ */
+ (*mutex)->m_prio = curthread->active_priority;
+ (*mutex)->m_saved_prio =
+ curthread->inherited_priority;
+ curthread->inherited_priority =
+ (*mutex)->m_prio;
+
+ /* Add to the list of owned mutexes: */
+ _MUTEX_ASSERT_NOT_OWNED(*mutex);
+ TAILQ_INSERT_TAIL(&curthread->mutexq,
+ (*mutex), m_qe);
+
+ } else if ((*mutex)->m_owner == curthread)
+ ret = mutex_self_lock(*mutex);
+ else {
+ /*
+ * Join the queue of threads waiting to lock
+ * the mutex:
+ */
+ mutex_queue_enq(*mutex, curthread);
+
+ /*
+ * Keep a pointer to the mutex this thread
+ * is waiting on:
+ */
+ curthread->data.mutex = *mutex;
+
+ if (curthread->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 (curthread->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 = curthread;
+
+ /* Track number of priority mutexes owned: */
+ curthread->priority_mutex_count++;
+
+ /*
+ * The running thread inherits the ceiling
+ * priority of the mutex and executes at that
+ * priority:
+ */
+ curthread->active_priority = (*mutex)->m_prio;
+ (*mutex)->m_saved_prio =
+ curthread->inherited_priority;
+ curthread->inherited_priority =
+ (*mutex)->m_prio;
+
+ /* Add to the list of owned mutexes: */
+ _MUTEX_ASSERT_NOT_OWNED(*mutex);
+ TAILQ_INSERT_TAIL(&curthread->mutexq,
+ (*mutex), m_qe);
+ } else if ((*mutex)->m_owner == curthread)
+ ret = mutex_self_lock(*mutex);
+ else {
+ /*
+ * Join the queue of threads waiting to lock
+ * the mutex:
+ */
+ mutex_queue_enq(*mutex, curthread);
+
+ /*
+ * Keep a pointer to the mutex this thread
+ * is waiting on:
+ */
+ curthread->data.mutex = *mutex;
+
+ /* Clear any previous error: */
+ curthread->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 = curthread->error;
+ curthread->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 (curthread->interrupted != 0)
+ mutex_queue_remove(*mutex, curthread);
+
+ /* Unlock the mutex structure: */
+ _SPINUNLOCK(&(*mutex)->lock);
+
+ /*
+ * Undefer and handle pending signals, yielding if
+ * necessary:
+ */
+ _thread_kern_sig_undefer();
+ } while (((*mutex)->m_owner != curthread) && (ret == 0) &&
+ (curthread->interrupted == 0));
+
+ if (curthread->interrupted != 0 &&
+ curthread->continuation != NULL)
+ curthread->continuation((void *) curthread);
+
+ /* Return the completion status: */
+ return (ret);
+}
+
+int
+__pthread_mutex_lock(pthread_mutex_t *mutex)
+{
+ int ret = 0;
+
+ if (_thread_initial == NULL)
+ _thread_init();
+
+ if (mutex == NULL)
+ ret = EINVAL;
+
+ /*
+ * If the mutex is statically initialized, perform the dynamic
+ * initialization:
+ */
+ else if ((*mutex != NULL) || ((ret = init_static(mutex)) == 0))
+ ret = mutex_lock_common(mutex);
+
+ return (ret);
+}
+
+int
+_pthread_mutex_lock(pthread_mutex_t *mutex)
+{
+ int ret = 0;
+
+ if (_thread_initial == NULL)
+ _thread_init();
+
+ if (mutex == NULL)
+ ret = EINVAL;
+
+ /*
+ * If the mutex is statically initialized, perform the dynamic
+ * initialization marking it private (delete safe):
+ */
+ else if ((*mutex != NULL) || ((ret = init_static_private(mutex)) == 0))
+ ret = mutex_lock_common(mutex);
+
+ 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)
+{
+ struct pthread *curthread = _get_curthread();
+ 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 != curthread) {
+ /*
+ * 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 != curthread) {
+ /*
+ * 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).
+ */
+ curthread->inherited_priority =
+ (*mutex)->m_saved_prio;
+ curthread->active_priority =
+ MAX(curthread->inherited_priority,
+ curthread->base_priority);
+
+ /*
+ * This thread now owns one less priority mutex.
+ */
+ curthread->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 != curthread) {
+ /*
+ * 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).
+ */
+ curthread->inherited_priority =
+ (*mutex)->m_saved_prio;
+ curthread->active_priority =
+ MAX(curthread->inherited_priority,
+ curthread->base_priority);
+
+ /*
+ * This thread now owns one less priority mutex.
+ */
+ curthread->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);
+ }
+}
+
+void
+_mutex_lock_backout(pthread_t pthread)
+{
+ struct pthread_mutex *mutex;
+
+ /*
+ * Defer signals to protect the scheduling queues from
+ * access by the signal handler:
+ */
+ _thread_kern_sig_defer();
+ if ((pthread->flags & PTHREAD_FLAGS_IN_MUTEXQ) != 0) {
+ mutex = pthread->data.mutex;
+
+ /* Lock the mutex structure: */
+ _SPINLOCK(&mutex->lock);
+
+ mutex_queue_remove(mutex, pthread);
+
+ /* This thread is no longer waiting for the mutex: */
+ pthread->data.mutex = NULL;
+
+ /* Unlock the mutex structure: */
+ _SPINUNLOCK(&mutex->lock);
+
+ }
+ /*
+ * Undefer and handle pending signals, yielding if
+ * necessary:
+ */
+ _thread_kern_sig_undefer();
+}
+
+/*
+ * 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, sqe);
+ 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, sqe);
+ 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);
+
+ PTHREAD_ASSERT_NOT_IN_SYNCQ(pthread);
+ /*
+ * 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, sqe);
+ else {
+ tid = TAILQ_FIRST(&mutex->m_queue);
+ while (pthread->active_priority <= tid->active_priority)
+ tid = TAILQ_NEXT(tid, sqe);
+ TAILQ_INSERT_BEFORE(tid, pthread, sqe);
+ }
+ pthread->flags |= PTHREAD_FLAGS_IN_MUTEXQ;
+}
+
diff --git a/lib/libpthread/thread/thr_mutex_prioceiling.c b/lib/libpthread/thread/thr_mutex_prioceiling.c
new file mode 100644
index 0000000..2682abc
--- /dev/null
+++ b/lib/libpthread/thread/thr_mutex_prioceiling.c
@@ -0,0 +1,113 @@
+/*
+ * 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>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_pthread_mutexattr_getprioceiling, pthread_mutexattr_getprioceiling);
+__weak_reference(_pthread_mutexattr_setprioceiling, pthread_mutexattr_setprioceiling);
+__weak_reference(_pthread_mutex_getprioceiling, pthread_mutex_getprioceiling);
+__weak_reference(_pthread_mutex_setprioceiling, pthread_mutex_setprioceiling);
+
+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);
+}
diff --git a/lib/libpthread/thread/thr_mutex_protocol.c b/lib/libpthread/thread/thr_mutex_protocol.c
new file mode 100644
index 0000000..4d020d6
--- /dev/null
+++ b/lib/libpthread/thread/thr_mutex_protocol.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 <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_pthread_mutexattr_getprotocol, pthread_mutexattr_getprotocol);
+__weak_reference(_pthread_mutexattr_setprotocol, pthread_mutexattr_setprotocol);
+
+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);
+}
+
diff --git a/lib/libpthread/thread/thr_mutexattr_destroy.c b/lib/libpthread/thread/thr_mutexattr_destroy.c
new file mode 100644
index 0000000..bdc85a5
--- /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>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_pthread_mutexattr_destroy, pthread_mutexattr_destroy);
+
+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);
+}
diff --git a/lib/libpthread/thread/thr_nanosleep.c b/lib/libpthread/thread/thr_nanosleep.c
new file mode 100644
index 0000000..e5569e7
--- /dev/null
+++ b/lib/libpthread/thread/thr_nanosleep.c
@@ -0,0 +1,143 @@
+/*
+ * 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>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(__nanosleep, nanosleep);
+
+int
+_nanosleep(const struct timespec * time_to_sleep,
+ struct timespec * time_remaining)
+{
+ struct pthread *curthread = _get_curthread();
+ 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 {
+ /*
+ * As long as we're going to get the time of day, we
+ * might as well store it in the global time of day:
+ */
+ gettimeofday((struct timeval *) &_sched_tod, NULL);
+ GET_CURRENT_TOD(tv);
+ TIMEVAL_TO_TIMESPEC(&tv, &current_time);
+
+ /* Calculate the time for the current thread to wake up: */
+ curthread->wakeup_time.tv_sec = current_time.tv_sec + time_to_sleep->tv_sec;
+ curthread->wakeup_time.tv_nsec = current_time.tv_nsec + time_to_sleep->tv_nsec;
+
+ /* Check if the nanosecond field has overflowed: */
+ if (curthread->wakeup_time.tv_nsec >= 1000000000) {
+ /* Wrap the nanosecond field: */
+ curthread->wakeup_time.tv_sec += 1;
+ curthread->wakeup_time.tv_nsec -= 1000000000;
+ }
+ curthread->interrupted = 0;
+
+ /* Reschedule the current thread to sleep: */
+ _thread_kern_sched_state(PS_SLEEP_WAIT, __FILE__, __LINE__);
+
+ /*
+ * As long as we're going to get the time of day, we
+ * might as well store it in the global time of day:
+ */
+ gettimeofday((struct timeval *) &_sched_tod, NULL);
+ GET_CURRENT_TOD(tv);
+ TIMEVAL_TO_TIMESPEC(&tv, &current_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 (curthread->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;
+}
diff --git a/lib/libpthread/thread/thr_once.c b/lib/libpthread/thread/thr_once.c
new file mode 100644
index 0000000..20e2904
--- /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$
+ */
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_pthread_once, pthread_once);
+
+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);
+}
diff --git a/lib/libpthread/thread/thr_open.c b/lib/libpthread/thread/thr_open.c
new file mode 100644
index 0000000..380761b
--- /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>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(__open, open);
+
+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 = __sys_open(path, flags, mode)) < 0) {
+ }
+ /* Initialise the file descriptor table entry: */
+ else if (_thread_fd_table_init(fd) != 0) {
+ /* Quietly close the file: */
+ __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;
+}
diff --git a/lib/libpthread/thread/thr_pause.c b/lib/libpthread/thread/thr_pause.c
new file mode 100644
index 0000000..57b508f
--- /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>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_pause, pause);
+
+int
+_pause(void)
+{
+ int ret;
+
+ _thread_enter_cancellation_point();
+ ret = __pause();
+ _thread_leave_cancellation_point();
+
+ return ret;
+}
diff --git a/lib/libpthread/thread/thr_poll.c b/lib/libpthread/thread/thr_poll.c
new file mode 100644
index 0000000..e2a7cc0
--- /dev/null
+++ b/lib/libpthread/thread/thr_poll.c
@@ -0,0 +1,99 @@
+/*
+ * 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>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_poll, poll);
+
+int
+_poll(struct pollfd *fds, unsigned int nfds, int timeout)
+{
+ struct pthread *curthread = _get_curthread();
+ 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 = __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;
+ }
+
+ curthread->data.poll_data = &data;
+ curthread->interrupted = 0;
+ _thread_kern_sched_state(PS_POLL_WAIT, __FILE__, __LINE__);
+ if (curthread->interrupted) {
+ errno = EINTR;
+ ret = -1;
+ } else {
+ ret = data.nfds;
+ }
+ }
+
+ return (ret);
+}
diff --git a/lib/libpthread/thread/thr_priority_queue.c b/lib/libpthread/thread/thr_priority_queue.c
new file mode 100644
index 0000000..55d742b
--- /dev/null
+++ b/lib/libpthread/thread/thr_priority_queue.c
@@ -0,0 +1,337 @@
+/*
+ * 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>
+#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) != 0) \
+ PANIC(msg); \
+} while (0)
+#define _PQ_ASSERT_PROTECTED(msg) \
+ PTHREAD_ASSERT((_thread_kern_in_sched != 0) || \
+ ((_get_curthread())->sig_defer_count > 0) ||\
+ (_sig_in_handler != 0), msg);
+
+#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_ASSERT_PROTECTED(msg)
+
+#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");
+ _PQ_ASSERT_PROTECTED("_pq_remove: prioq not protected!");
+
+ /*
+ * 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");
+ _PQ_ASSERT_PROTECTED("_pq_insert_head: prioq not protected!");
+
+ 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");
+ _PQ_ASSERT_PROTECTED("_pq_insert_tail: prioq not protected!");
+
+ 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();
+ _PQ_ASSERT_PROTECTED("_pq_first: prioq not protected!");
+
+ 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");
+ _PQ_ASSERT_PROTECTED("_pq_insert_prio_list: prioq not protected!");
+
+ /*
+ * 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;
+}
+
+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();
+}
diff --git a/lib/libpthread/thread/thr_private.h b/lib/libpthread/thread/thr_private.h
new file mode 100644
index 0000000..ec15c3a
--- /dev/null
+++ b/lib/libpthread/thread/thr_private.h
@@ -0,0 +1,1362 @@
+/*
+ * 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 <stdio.h>
+#include <sys/queue.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/cdefs.h>
+#include <sched.h>
+#include <spinlock.h>
+#include <ucontext.h>
+#include <pthread_np.h>
+
+/*
+ * Define machine dependent macros to get and set the stack pointer
+ * from the supported contexts. Also define a macro to set the return
+ * address in a jmp_buf context.
+ *
+ * XXX - These need to be moved into architecture dependent support files.
+ */
+#if defined(__i386__)
+#define GET_STACK_JB(jb) ((unsigned long)((jb)[0]._jb[2]))
+#define GET_STACK_SJB(sjb) ((unsigned long)((sjb)[0]._sjb[2]))
+#define GET_STACK_UC(ucp) ((unsigned long)((ucp)->uc_mcontext.mc_esp))
+#define SET_STACK_JB(jb, stk) (jb)[0]._jb[2] = (int)(stk)
+#define SET_STACK_SJB(sjb, stk) (sjb)[0]._sjb[2] = (int)(stk)
+#define SET_STACK_UC(ucp, stk) (ucp)->uc_mcontext.mc_esp = (int)(stk)
+#define FP_SAVE_UC(ucp) do { \
+ char *fdata; \
+ fdata = (char *) (ucp)->uc_mcontext.mc_fpregs; \
+ __asm__("fnsave %0": :"m"(*fdata)); \
+} while (0)
+#define FP_RESTORE_UC(ucp) do { \
+ char *fdata; \
+ fdata = (char *) (ucp)->uc_mcontext.mc_fpregs; \
+ __asm__("frstor %0": :"m"(*fdata)); \
+} while (0)
+#define SET_RETURN_ADDR_JB(jb, ra) (jb)[0]._jb[0] = (int)(ra)
+#elif defined(__alpha__)
+#include <machine/reg.h>
+#define GET_STACK_JB(jb) ((unsigned long)((jb)[0]._jb[R_SP + 4]))
+#define GET_STACK_SJB(sjb) ((unsigned long)((sjb)[0]._sjb[R_SP + 4]))
+#define GET_STACK_UC(ucp) ((ucp)->uc_mcontext.mc_regs[R_SP])
+#define SET_STACK_JB(jb, stk) (jb)[0]._jb[R_SP + 4] = (long)(stk)
+#define SET_STACK_SJB(sjb, stk) (sjb)[0]._sjb[R_SP + 4] = (long)(stk)
+#define SET_STACK_UC(ucp, stk) (ucp)->uc_mcontext.mc_regs[R_SP] = (unsigned long)(stk)
+#define FP_SAVE_UC(ucp)
+#define FP_RESTORE_UC(ucp)
+#define SET_RETURN_ADDR_JB(jb, ra) do { \
+ (jb)[0]._jb[2] = (long)(ra); \
+ (jb)[0]._jb[R_RA + 4] = (long)(ra); \
+ (jb)[0]._jb[R_T12 + 4] = (long)(ra); \
+} while (0)
+#else
+#error "Don't recognize this architecture!"
+#endif
+
+/*
+ * Kernel fatal error handler macro.
+ */
+#define PANIC(string) _thread_exit(__FILE__,__LINE__,string)
+
+
+/* Output debug messages like this: */
+#define stdout_debug(args...) do { \
+ char buf[128]; \
+ snprintf(buf, sizeof(buf), ##args); \
+ __sys_write(1, buf, strlen(buf)); \
+} while (0)
+#define stderr_debug(args...) do { \
+ char buf[128]; \
+ snprintf(buf, sizeof(buf), ##args); \
+ __sys_write(2, buf, strlen(buf)); \
+} while (0)
+
+
+
+/*
+ * 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):
+ */
+#define PTHREAD_WAITQ_REMOVE(thrd) _waitq_remove(thrd)
+#define PTHREAD_WAITQ_INSERT(thrd) _waitq_insert(thrd)
+
+#if defined(_PTHREADS_INVARIANTS)
+#define PTHREAD_WAITQ_CLEARACTIVE() _waitq_clearactive()
+#define PTHREAD_WAITQ_SETACTIVE() _waitq_setactive()
+#else
+#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)
+#include <assert.h>
+#define PTHREAD_ASSERT(cond, msg) do { \
+ if (!(cond)) \
+ PANIC(msg); \
+} while (0)
+#define PTHREAD_ASSERT_NOT_IN_SYNCQ(thrd) \
+ PTHREAD_ASSERT((((thrd)->flags & PTHREAD_FLAGS_IN_SYNCQ) == 0), \
+ "Illegal call from signal handler");
+#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_ASSERT(cond, msg)
+#define PTHREAD_ASSERT_NOT_IN_SYNCQ(thrd)
+#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;
+};
+
+#define PTHREAD_MUTEXATTR_STATIC_INITIALIZER \
+ { PTHREAD_MUTEX_DEFAULT, PTHREAD_PRIO_NONE, 0, MUTEX_FLAGS_PRIVATE }
+
+/*
+ * 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;
+ int c_seqno;
+
+ /*
+ * 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, 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;
+ size_t guardsize_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_JOIN, /* Suspended, joining. */
+ 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 default 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_GUARD_DEFAULT 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
+
+/* Size of the scheduler stack: */
+#define SCHED_STACK_SIZE PAGE_SIZE
+
+/*
+ * Define the different priority ranges. All applications have thread
+ * priorities constrained within 0-31. The threads library raises the
+ * priority when delivering signals in order to ensure that signal
+ * delivery happens (from the POSIX spec) "as soon as possible".
+ * In the future, the threads library will also be able to map specific
+ * threads into real-time (cooperating) processes or kernel threads.
+ * The RT and SIGNAL priorities will be used internally and added to
+ * thread base priorities so that the scheduling queue can handle both
+ * normal and RT priority threads with and without signal handling.
+ *
+ * The approach taken is that, within each class, signal delivery
+ * always has priority over thread execution.
+ */
+#define PTHREAD_DEFAULT_PRIORITY 15
+#define PTHREAD_MIN_PRIORITY 0
+#define PTHREAD_MAX_PRIORITY 31 /* 0x1F */
+#define PTHREAD_SIGNAL_PRIORITY 32 /* 0x20 */
+#define PTHREAD_RT_PRIORITY 64 /* 0x40 */
+#define PTHREAD_FIRST_PRIORITY PTHREAD_MIN_PRIORITY
+#define PTHREAD_LAST_PRIORITY \
+ (PTHREAD_MAX_PRIORITY + PTHREAD_SIGNAL_PRIORITY + PTHREAD_RT_PRIORITY)
+#define PTHREAD_BASE_PRIORITY(prio) ((prio) & PTHREAD_MAX_PRIORITY)
+
+/*
+ * Clock resolution in microseconds.
+ */
+#define CLOCK_RES_USEC 10000
+#define CLOCK_RES_USEC_MIN 1000
+
+/*
+ * Time slice period in microseconds.
+ */
+#define TIMESLICE_USEC 20000
+
+/*
+ * Define a thread-safe macro to get the current time of day
+ * which is updated at regular intervals by the scheduling signal
+ * handler.
+ */
+#define GET_CURRENT_TOD(tv) \
+ do { \
+ tv.tv_sec = _sched_tod.tv_sec; \
+ tv.tv_usec = _sched_tod.tv_usec; \
+ } while (tv.tv_sec != _sched_tod.tv_sec)
+
+
+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;
+ FILE *fp;
+ struct pthread_poll_data *poll_data;
+ spinlock_t *spinlock;
+ struct pthread *thread;
+};
+
+/*
+ * Define a continuation routine that can be used to perform a
+ * transfer of control:
+ */
+typedef void (*thread_continuation_t) (void *);
+
+struct pthread_signal_frame;
+
+struct pthread_state_data {
+ struct pthread_signal_frame *psd_curframe;
+ sigset_t psd_sigmask;
+ struct timespec psd_wakeup_time;
+ union pthread_wait_data psd_wait_data;
+ enum pthread_state psd_state;
+ int psd_flags;
+ int psd_interrupted;
+ int psd_longjmp_val;
+ int psd_sigmask_seqno;
+ int psd_signo;
+ int psd_sig_defer_count;
+ /* XXX - What about thread->timeout and/or thread->error? */
+};
+
+struct join_status {
+ struct pthread *thread;
+ void *ret;
+ int error;
+};
+
+/*
+ * The frame that is added to the top of a threads stack when setting up
+ * up the thread to run a signal handler.
+ */
+struct pthread_signal_frame {
+ /*
+ * This stores the threads state before the signal.
+ */
+ struct pthread_state_data saved_state;
+
+ /*
+ * Threads return context; we use only jmp_buf's for now.
+ */
+ union {
+ jmp_buf jb;
+ ucontext_t uc;
+ } ctx;
+ int signo; /* signal, arg 1 to sighandler */
+ int sig_has_args; /* use signal args if true */
+ ucontext_t uc;
+ siginfo_t siginfo;
+};
+
+struct pthread_specific_elem {
+ const void *data;
+ int seqno;
+};
+
+/*
+ * 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;
+
+ /*
+ * Threads return context; we use only jmp_buf's for now.
+ */
+ union {
+ jmp_buf jb;
+ ucontext_t uc;
+ } ctx;
+
+ /*
+ * Used for tracking delivery of signal handlers.
+ */
+ struct pthread_signal_frame *curframe;
+
+ /*
+ * 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;
+ int sigmask_seqno;
+ int check_pending;
+
+ /* Thread state: */
+ enum pthread_state state;
+
+ /* Scheduling clock when this thread was last made active. */
+ long last_active;
+
+ /* Scheduling clock when this thread was last made inactive. */
+ long last_inactive;
+
+ /*
+ * Number of microseconds accumulated by this thread when
+ * time slicing is active.
+ */
+ long slice_usec;
+
+ /*
+ * 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;
+
+ /*
+ * The joiner is the thread that is joining to this thread. The
+ * join status keeps track of a join operation to another thread.
+ */
+ struct pthread *joiner;
+ struct join_status join_status;
+
+ /*
+ * The current thread can belong to only one scheduling queue at
+ * a time (ready or waiting queue). It can also belong to:
+ *
+ * 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 a file descriptor lock
+ * o A queue of threads needing work done by the kernel thread
+ * (waiting for a spinlock or file I/O)
+ *
+ * A thread can also be joining a thread (the joiner field above).
+ *
+ * It must not be possible for a thread to belong to any of the
+ * above queues while it is handling a signal. Signal handlers
+ * may longjmp back to previous stack frames circumventing normal
+ * control flow. This could corrupt queue integrity if the thread
+ * retains membership in the queue. Therefore, if a thread is a
+ * member of one of these queues when a signal handler is invoked,
+ * it must remove itself from the queue before calling the signal
+ * handler and reinsert itself after normal return of the handler.
+ *
+ * Use pqe for the scheduling queue link (both ready and waiting),
+ * sqe for synchronization (mutex and condition variable) queue
+ * links, and qe for all other links.
+ */
+ TAILQ_ENTRY(pthread) pqe; /* priority queue link */
+ TAILQ_ENTRY(pthread) sqe; /* synchronization queue link */
+ TAILQ_ENTRY(pthread) qe; /* all other queues link */
+
+ /* 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_WAITQ 0x0004 /* in waiting queue using pqe link */
+#define PTHREAD_FLAGS_IN_PRIOQ 0x0008 /* in priority queue using pqe link */
+#define PTHREAD_FLAGS_IN_WORKQ 0x0010 /* in work queue using qe link */
+#define PTHREAD_FLAGS_IN_FILEQ 0x0020 /* in file lock queue using qe link */
+#define PTHREAD_FLAGS_IN_FDQ 0x0040 /* in fd lock queue using qe link */
+#define PTHREAD_FLAGS_IN_CONDQ 0x0080 /* in condition queue using sqe link*/
+#define PTHREAD_FLAGS_IN_MUTEXQ 0x0100 /* in mutex queue using sqe link */
+#define PTHREAD_FLAGS_TRACE 0x0200 /* for debugging purposes */
+#define PTHREAD_FLAGS_IN_SYNCQ \
+ (PTHREAD_FLAGS_IN_CONDQ | PTHREAD_FLAGS_IN_MUTEXQ)
+
+ /*
+ * 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;
+ struct pthread_specific_elem *specific;
+ int specific_data_count;
+
+ /* Cleanup handlers Link List */
+ struct pthread_cleanup *cleanup;
+ char *fname; /* Ptr to source file name */
+ int lineno; /* Source line number. */
+};
+
+/*
+ * Global variables for the uthread kernel.
+ */
+
+SCLASS void *_usrstack
+#ifdef GLOBAL_PTHREAD_PRIVATE
+= (void *) USRSTACK;
+#else
+;
+#endif
+
+/* 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
+
+SCLASS int _sig_in_handler
+#ifdef GLOBAL_PTHREAD_PRIVATE
+= 0;
+#else
+;
+#endif
+
+/* Time of day at last scheduling timer signal: */
+SCLASS struct timeval volatile _sched_tod
+#ifdef GLOBAL_PTHREAD_PRIVATE
+= { 0, 0 };
+#else
+;
+#endif
+
+/*
+ * Current scheduling timer ticks; used as resource usage.
+ */
+SCLASS unsigned int volatile _sched_ticks
+#ifdef GLOBAL_PTHREAD_PRIVATE
+= 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, PTHREAD_GUARD_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_usec /* Clock resolution in usec. */
+#ifdef GLOBAL_PTHREAD_PRIVATE
+= CLOCK_RES_USEC;
+#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 and mask for this process:
+ */
+SCLASS sigset_t _process_sigpending;
+SCLASS sigset_t _process_sigmask
+#ifdef GLOBAL_PTHREAD_PRIVATE
+= { {0, 0, 0, 0} }
+#endif
+;
+
+/*
+ * 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
+;
+
+/* Used to maintain pending and active signals: */
+struct sigstatus {
+ int pending; /* Is this a pending signal? */
+ int blocked; /*
+ * A handler is currently active for
+ * this signal; ignore subsequent
+ * signals until the handler is done.
+ */
+ int signo; /* arg 1 to signal handler */
+ siginfo_t siginfo; /* arg 2 to signal handler */
+ ucontext_t uc; /* arg 3 to signal handler */
+};
+
+SCLASS struct sigstatus _thread_sigq[NSIG];
+
+/* 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
+;
+
+/*
+ * Declare the kernel scheduler jump buffer and stack:
+ */
+SCLASS jmp_buf _thread_kern_sched_jb;
+
+SCLASS void * _thread_kern_sched_stack
+#ifdef GLOBAL_PTHREAD_PRIVATE
+= NULL
+#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);
+void _cond_wait_backout(pthread_t);
+void _fd_lock_backout(pthread_t);
+int _find_thread(pthread_t);
+struct pthread *_get_curthread(void);
+void _set_curthread(struct pthread *);
+void *_thread_stack_alloc(size_t, size_t);
+void _thread_stack_free(void *, size_t, size_t);
+int _thread_create(pthread_t *,const pthread_attr_t *,void *(*start_routine)(void *),void *,pthread_t);
+int _thread_fd_lock(int, int, struct timespec *);
+int _thread_fd_lock_debug(int, int, struct timespec *,char *fname,int lineno);
+int _mutex_cv_lock(pthread_mutex_t *);
+int _mutex_cv_unlock(pthread_mutex_t *);
+void _mutex_lock_backout(pthread_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);
+void *_pthread_getspecific(pthread_key_t);
+int _pthread_key_create(pthread_key_t *, void (*) (void *));
+int _pthread_key_delete(pthread_key_t);
+int _pthread_mutex_destroy(pthread_mutex_t *);
+int _pthread_mutex_init(pthread_mutex_t *, const pthread_mutexattr_t *);
+int _pthread_mutex_lock(pthread_mutex_t *);
+int _pthread_mutex_trylock(pthread_mutex_t *);
+int _pthread_mutex_unlock(pthread_mutex_t *);
+int _pthread_mutexattr_init(pthread_mutexattr_t *);
+int _pthread_mutexattr_destroy(pthread_mutexattr_t *);
+int _pthread_mutexattr_settype(pthread_mutexattr_t *, int);
+int _pthread_once(pthread_once_t *, void (*) (void));
+pthread_t _pthread_self(void);
+int _pthread_setspecific(pthread_key_t, const void *);
+void _waitq_insert(pthread_t pthread);
+void _waitq_remove(pthread_t pthread);
+#if defined(_PTHREADS_INVARIANTS)
+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_scheduler(void);
+void _thread_kern_sched_frame(struct pthread_signal_frame *psf);
+void _thread_kern_sched_sig(void);
+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, siginfo_t *, ucontext_t *);
+void _thread_sig_check_pending(struct pthread *pthread);
+void _thread_sig_handle_pending(void);
+void _thread_sig_send(struct pthread *pthread, int sig);
+void _thread_sig_wrapper(void);
+void _thread_sigframe_restore(struct pthread *thread,
+ struct pthread_signal_frame *psf);
+void _thread_start(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 <sys/acl.h> */
+#ifdef _SYS_ACL_H
+int __sys___acl_aclcheck_fd(int, acl_type_t, struct acl *);
+int __sys___acl_delete_fd(int, acl_type_t);
+int __sys___acl_get_fd(int, acl_type_t, struct acl *);
+int __sys___acl_set_fd(int, acl_type_t, struct acl *);
+#endif
+
+/* #include <sys/aio.h> */
+#ifdef _SYS_AIO_H_
+int __sys_aio_suspend(const struct aiocb * const[], int, const struct timespec *);
+#endif
+
+/* #include <sys/capability.h> */
+#ifdef _SYS_CAPABILITY_H
+int __sys___cap_get_fd(int, struct cap *);
+int __sys___cap_set_fd(int, struct cap *);
+#endif
+
+/* #include <sys/event.h> */
+#ifdef _SYS_EVENT_H_
+int __sys_kevent(int, const struct kevent *, int, struct kevent *,
+ int, const struct timespec *);
+#endif
+
+/* #include <sys/ioctl.h> */
+#ifdef _SYS_IOCTL_H_
+int __sys_ioctl(int, unsigned long, ...);
+#endif
+
+/* #include <sys/mman.h> */
+#ifdef _SYS_MMAN_H_
+int __sys_msync(void *, size_t, int);
+#endif
+
+/* #include <sys/mount.h> */
+#ifdef _SYS_MOUNT_H_
+int __sys_fstatfs(int, struct statfs *);
+#endif
+
+/* #include <sys/socket.h> */
+#ifdef _SYS_SOCKET_H_
+int __sys_accept(int, struct sockaddr *, socklen_t *);
+int __sys_bind(int, const struct sockaddr *, socklen_t);
+int __sys_connect(int, const struct sockaddr *, socklen_t);
+int __sys_getpeername(int, struct sockaddr *, socklen_t *);
+int __sys_getsockname(int, struct sockaddr *, socklen_t *);
+int __sys_getsockopt(int, int, int, void *, socklen_t *);
+int __sys_listen(int, int);
+ssize_t __sys_recvfrom(int, void *, size_t, int, struct sockaddr *, socklen_t *);
+ssize_t __sys_recvmsg(int, struct msghdr *, int);
+int __sys_sendfile(int, int, off_t, size_t, struct sf_hdtr *, off_t *, int);
+ssize_t __sys_sendmsg(int, const struct msghdr *, int);
+ssize_t __sys_sendto(int, const void *,size_t, int, const struct sockaddr *, socklen_t);
+int __sys_setsockopt(int, int, int, const void *, socklen_t);
+int __sys_shutdown(int, int);
+int __sys_socket(int, int, int);
+int __sys_socketpair(int, int, int, int *);
+#endif
+
+/* #include <sys/stat.h> */
+#ifdef _SYS_STAT_H_
+int __sys_fchflags(int, u_long);
+int __sys_fchmod(int, mode_t);
+int __sys_fstat(int, struct stat *);
+#endif
+
+/* #include <sys/uio.h> */
+#ifdef _SYS_UIO_H_
+ssize_t __sys_readv(int, const struct iovec *, int);
+ssize_t __sys_writev(int, const struct iovec *, int);
+#endif
+
+/* #include <sys/wait.h> */
+#ifdef WNOHANG
+pid_t __sys_wait4(pid_t, int *, int, struct rusage *);
+#endif
+
+/* #include <dirent.h> */
+#ifdef _DIRENT_H_
+int __sys_getdirentries(int, char *, int, long *);
+#endif
+
+/* #include <fcntl.h> */
+#ifdef _SYS_FCNTL_H_
+int __sys_fcntl(int, int, ...);
+int __sys_flock(int, int);
+int __sys_open(const char *, int, ...);
+#endif
+
+/* #include <poll.h> */
+#ifdef _SYS_POLL_H_
+int __sys_poll(struct pollfd *, unsigned, int);
+#endif
+
+/* #include <signal.h> */
+#ifdef _SIGNAL_H_
+int __sys_sigaction(int, const struct sigaction *, struct sigaction *);
+int __sys_sigaltstack(const struct sigaltstack *, struct sigaltstack *);
+int __sys_sigprocmask(int, const sigset_t *, sigset_t *);
+int __sys_sigreturn(ucontext_t *);
+#endif
+
+/* #include <unistd.h> */
+#ifdef _UNISTD_H_
+int __sys_close(int);
+int __sys_dup(int);
+int __sys_dup2(int, int);
+int __sys_execve(const char *, char * const *, char * const *);
+void __sys_exit(int);
+int __sys_fchown(int, uid_t, gid_t);
+pid_t __sys_fork(void);
+long __sys_fpathconf(int, int);
+int __sys_fsync(int);
+int __sys_pipe(int *);
+ssize_t __sys_read(int, void *, size_t);
+ssize_t __sys_write(int, const void *, size_t);
+#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..4d81414
--- /dev/null
+++ b/lib/libpthread/thread/thr_read.c
@@ -0,0 +1,111 @@
+/*
+ * 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>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(__read, read);
+
+ssize_t
+_read(int fd, void *buf, size_t nbytes)
+{
+ struct pthread *curthread = _get_curthread();
+ 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 = __sys_read(fd, buf, nbytes)) < 0) {
+ if ((_thread_fd_table[fd]->flags & O_NONBLOCK) == 0 &&
+ (errno == EWOULDBLOCK || errno == EAGAIN)) {
+ curthread->data.fd.fd = fd;
+ _thread_kern_set_timeout(NULL);
+
+ /* Reset the interrupted operation flag: */
+ curthread->interrupted = 0;
+
+ _thread_kern_sched_state(PS_FDR_WAIT,
+ __FILE__, __LINE__);
+
+ /*
+ * Check if the operation was
+ * interrupted by a signal
+ */
+ if (curthread->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;
+}
diff --git a/lib/libpthread/thread/thr_readv.c b/lib/libpthread/thread/thr_readv.c
new file mode 100644
index 0000000..2759819
--- /dev/null
+++ b/lib/libpthread/thread/thr_readv.c
@@ -0,0 +1,94 @@
+/*
+ * 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>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_readv, readv);
+
+ssize_t
+_readv(int fd, const struct iovec * iov, int iovcnt)
+{
+ struct pthread *curthread = _get_curthread();
+ 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 = __sys_readv(fd, iov, iovcnt)) < 0) {
+ if ((_thread_fd_table[fd]->flags & O_NONBLOCK) == 0 &&
+ (errno == EWOULDBLOCK || errno == EAGAIN)) {
+ curthread->data.fd.fd = fd;
+ _thread_kern_set_timeout(NULL);
+
+ /* Reset the interrupted operation flag: */
+ curthread->interrupted = 0;
+
+ _thread_kern_sched_state(PS_FDR_WAIT,
+ __FILE__, __LINE__);
+
+ /*
+ * Check if the operation was
+ * interrupted by a signal
+ */
+ if (curthread->interrupted) {
+ errno = EINTR;
+ ret = -1;
+ break;
+ }
+ } else {
+ break;
+ }
+ }
+ _FD_UNLOCK(fd, FD_READ);
+ }
+ return (ret);
+}
diff --git a/lib/libpthread/thread/thr_resume_np.c b/lib/libpthread/thread/thr_resume_np.c
new file mode 100644
index 0000000..9cbcf85
--- /dev/null
+++ b/lib/libpthread/thread/thr_resume_np.c
@@ -0,0 +1,96 @@
+/*
+ * 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>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_pthread_resume_np, pthread_resume_np);
+
+/* 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_JOIN:
+ /* Set the thread's state back. */
+ PTHREAD_SET_STATE(thread,PS_JOIN);
+ 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);
+}
diff --git a/lib/libpthread/thread/thr_rwlock.c b/lib/libpthread/thread/thr_rwlock.c
new file mode 100644
index 0000000..2f55f03
--- /dev/null
+++ b/lib/libpthread/thread/thr_rwlock.c
@@ -0,0 +1,341 @@
+/*-
+ * 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$
+ */
+
+#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)
+
+__weak_reference(_pthread_rwlock_destroy, pthread_rwlock_destroy);
+__weak_reference(_pthread_rwlock_init, pthread_rwlock_init);
+__weak_reference(_pthread_rwlock_rdlock, pthread_rwlock_rdlock);
+__weak_reference(_pthread_rwlock_tryrdlock, pthread_rwlock_tryrdlock);
+__weak_reference(_pthread_rwlock_trywrlock, pthread_rwlock_trywrlock);
+__weak_reference(_pthread_rwlock_unlock, pthread_rwlock_unlock);
+__weak_reference(_pthread_rwlock_wrlock, pthread_rwlock_wrlock);
+
+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 = EBUSY;
+ 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 = EBUSY;
+ 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);
+}
+
diff --git a/lib/libpthread/thread/thr_rwlockattr.c b/lib/libpthread/thread/thr_rwlockattr.c
new file mode 100644
index 0000000..bc1b9ee
--- /dev/null
+++ b/lib/libpthread/thread/thr_rwlockattr.c
@@ -0,0 +1,98 @@
+/*-
+ * 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$
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_pthread_rwlockattr_destroy, pthread_rwlockattr_destroy);
+__weak_reference(_pthread_rwlockattr_getpshared, pthread_rwlockattr_getpshared);
+__weak_reference(_pthread_rwlockattr_init, pthread_rwlockattr_init);
+__weak_reference(_pthread_rwlockattr_setpshared, pthread_rwlockattr_setpshared);
+
+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);
+}
+
diff --git a/lib/libpthread/thread/thr_select.c b/lib/libpthread/thread/thr_select.c
new file mode 100644
index 0000000..5860efe
--- /dev/null
+++ b/lib/libpthread/thread/thr_select.c
@@ -0,0 +1,207 @@
+/*
+ * 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>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_select, select);
+
+int
+_select(int numfds, fd_set * readfds, fd_set * writefds, fd_set * exceptfds,
+ struct timeval * timeout)
+{
+ struct pthread *curthread = _get_curthread();
+ 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 ((curthread->poll_data.fds == NULL) ||
+ (curthread->poll_data.nfds < fd_count)) {
+ data.fds = (struct pollfd *) realloc(curthread->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.
+ */
+ curthread->poll_data.fds = data.fds;
+ curthread->poll_data.nfds = MAX(128, fd_count);
+ }
+ }
+ if (ret == 0) {
+ /* Setup the wait data. */
+ data.fds = curthread->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 = __sys_poll(data.fds, data.nfds, 0)) == 0) &&
+ (f_wait != 0)) {
+ curthread->data.poll_data = &data;
+ curthread->interrupted = 0;
+ _thread_kern_sched_state(PS_SELECT_WAIT, __FILE__, __LINE__);
+ if (curthread->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);
+}
diff --git a/lib/libpthread/thread/thr_self.c b/lib/libpthread/thread/thr_self.c
new file mode 100644
index 0000000..1c09e3d
--- /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$
+ */
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_pthread_self, pthread_self);
+
+pthread_t
+_pthread_self(void)
+{
+ /* Return the running thread pointer: */
+ return (_get_curthread());
+}
diff --git a/lib/libpthread/thread/thr_sem.c b/lib/libpthread/thread/thr_sem.c
new file mode 100644
index 0000000..851eca2
--- /dev/null
+++ b/lib/libpthread/thread/thr_sem.c
@@ -0,0 +1,254 @@
+/*
+ * 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>
+#include <errno.h>
+#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; \
+ }
+
+__weak_reference(_sem_init, sem_init);
+__weak_reference(_sem_destroy, sem_destroy);
+__weak_reference(_sem_open, sem_open);
+__weak_reference(_sem_close, sem_close);
+__weak_reference(_sem_unlink, sem_unlink);
+__weak_reference(_sem_wait, sem_wait);
+__weak_reference(_sem_trywait, sem_trywait);
+__weak_reference(_sem_post, sem_post);
+__weak_reference(_sem_getvalue, sem_getvalue);
+
+
+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)
+ pthread_cond_signal(&(*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;
+}
diff --git a/lib/libpthread/thread/thr_seterrno.c b/lib/libpthread/thread/thr_seterrno.c
new file mode 100644
index 0000000..0d9474f
--- /dev/null
+++ b/lib/libpthread/thread/thr_seterrno.c
@@ -0,0 +1,59 @@
+/*
+ * 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 <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;
+}
diff --git a/lib/libpthread/thread/thr_setprio.c b/lib/libpthread/thread/thr_setprio.c
new file mode 100644
index 0000000..9099a6e
--- /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$
+ */
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_pthread_setprio, pthread_setprio);
+
+int
+_pthread_setprio(pthread_t pthread, int prio)
+{
+ int ret, policy;
+ struct sched_param param;
+
+ if ((ret = pthread_getschedparam(pthread, &policy, &param)) == 0) {
+ param.sched_priority = prio;
+ ret = pthread_setschedparam(pthread, policy, &param);
+ }
+
+ /* Return the error status: */
+ return (ret);
+}
diff --git a/lib/libpthread/thread/thr_setschedparam.c b/lib/libpthread/thread/thr_setschedparam.c
new file mode 100644
index 0000000..7696762
--- /dev/null
+++ b/lib/libpthread/thread/thr_setschedparam.c
@@ -0,0 +1,119 @@
+/*
+ * 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>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_pthread_setschedparam, pthread_setschedparam);
+
+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(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 &=
+ (PTHREAD_SIGNAL_PRIORITY | PTHREAD_RT_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);
+}
diff --git a/lib/libpthread/thread/thr_sig.c b/lib/libpthread/thread/thr_sig.c
new file mode 100644
index 0000000..1bd93b7
--- /dev/null
+++ b/lib/libpthread/thread/thr_sig.c
@@ -0,0 +1,1117 @@
+/*
+ * 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>
+#include <pthread.h>
+#include "pthread_private.h"
+
+/* Prototypes: */
+static void thread_sig_add(struct pthread *pthread, int sig, int has_args);
+static void thread_sig_check_state(struct pthread *pthread, int sig);
+static struct pthread *thread_sig_find(int sig);
+static void thread_sig_handle_special(int sig);
+static void thread_sigframe_add(struct pthread *thread, int sig,
+ int has_args);
+static void thread_sigframe_save(struct pthread *thread,
+ struct pthread_signal_frame *psf);
+static void thread_sig_invoke_handler(int sig, siginfo_t *info,
+ ucontext_t *ucp);
+
+/* #define DEBUG_SIGNAL */
+#ifdef DEBUG_SIGNAL
+#define DBG_MSG stdout_debug
+#else
+#define DBG_MSG(x...)
+#endif
+
+#if defined(_PTHREADS_INVARIANTS)
+#define SIG_SET_ACTIVE() _sig_in_handler = 1
+#define SIG_SET_INACTIVE() _sig_in_handler = 0
+#else
+#define SIG_SET_ACTIVE()
+#define SIG_SET_INACTIVE()
+#endif
+
+void
+_thread_sig_handler(int sig, siginfo_t *info, ucontext_t *ucp)
+{
+ struct pthread *curthread = _get_curthread();
+ struct pthread *pthread, *pthread_h;
+ int in_sched = _thread_kern_in_sched;
+ char c;
+
+ if (ucp == NULL)
+ PANIC("Thread signal handler received null context");
+ DBG_MSG("Got signal %d, current thread %p\n", sig, curthread);
+
+ /* Check if an interval timer signal: */
+ if (sig == _SCHED_SIGNAL) {
+ /* Update the scheduling clock: */
+ gettimeofday((struct timeval *)&_sched_tod, NULL);
+ _sched_ticks++;
+
+ if (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 (curthread->sig_defer_count > 0)
+ curthread->yield_on_sig_undefer = 1;
+ else {
+ /* Schedule the next thread: */
+ _thread_kern_sched(ucp);
+
+ /*
+ * 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 ((in_sched != 0) || (curthread->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.
+ */
+ if (_queue_signals != 0) {
+ __sys_write(_thread_kern_pipe[1], &c, 1);
+ DBG_MSG("Got signal %d, queueing to kernel pipe\n", sig);
+ }
+ if (_thread_sigq[sig - 1].blocked == 0) {
+ DBG_MSG("Got signal %d, adding to _thread_sigq\n", sig);
+ /*
+ * Do not block this signal; it will be blocked
+ * when the pending signals are run down.
+ */
+ /* _thread_sigq[sig - 1].blocked = 1; */
+
+ /*
+ * Queue the signal, saving siginfo and sigcontext
+ * (ucontext).
+ *
+ * XXX - Do we need to copy siginfo and ucp?
+ */
+ _thread_sigq[sig - 1].signo = sig;
+ if (info != NULL)
+ memcpy(&_thread_sigq[sig - 1].siginfo, info,
+ sizeof(*info));
+ memcpy(&_thread_sigq[sig - 1].uc, ucp, sizeof(*ucp));
+
+ /* Indicate that there are queued signals: */
+ _thread_sigq[sig - 1].pending = 1;
+ _sigq_check_reqd = 1;
+ }
+ /* These signals need special handling: */
+ else if (sig == SIGCHLD || sig == SIGTSTP ||
+ sig == SIGTTIN || sig == SIGTTOU) {
+ _thread_sigq[sig - 1].pending = 1;
+ _thread_sigq[sig - 1].signo = sig;
+ _sigq_check_reqd = 1;
+ }
+ else
+ DBG_MSG("Got signal %d, ignored.\n", sig);
+ }
+ /*
+ * The signal handlers should have been installed so that they
+ * cannot be interrupted by other signals.
+ */
+ else if (_thread_sigq[sig - 1].blocked == 0) {
+ /*
+ * The signal is not blocked; handle the signal.
+ *
+ * Ignore subsequent occurrences of this signal
+ * until the current signal is handled:
+ */
+ _thread_sigq[sig - 1].blocked = 1;
+
+ /* This signal will be handled; clear the pending flag: */
+ _thread_sigq[sig - 1].pending = 0;
+
+ /*
+ * Save siginfo and sigcontext (ucontext).
+ *
+ * XXX - Do we need to copy siginfo and ucp?
+ */
+ _thread_sigq[sig - 1].signo = sig;
+
+ if (info != NULL)
+ memcpy(&_thread_sigq[sig - 1].siginfo, info,
+ sizeof(*info));
+ memcpy(&_thread_sigq[sig - 1].uc, ucp, sizeof(*ucp));
+ SIG_SET_ACTIVE();
+
+ /* Handle special signals: */
+ thread_sig_handle_special(sig);
+
+ pthread_h = NULL;
+ if ((pthread = thread_sig_find(sig)) == NULL)
+ DBG_MSG("No thread to handle signal %d\n", sig);
+ else if (pthread == curthread) {
+ /*
+ * Unblock the signal and restore the process signal
+ * mask in case we don't return from the handler:
+ */
+ _thread_sigq[sig - 1].blocked = 0;
+ __sys_sigprocmask(SIG_SETMASK, &_process_sigmask, NULL);
+
+ /* Call the signal handler for the current thread: */
+ thread_sig_invoke_handler(sig, info, ucp);
+
+ /*
+ * Set the process signal mask in the context; it
+ * could have changed by the handler.
+ */
+ ucp->uc_sigmask = _process_sigmask;
+
+ /* Resume the interrupted thread: */
+ __sys_sigreturn(ucp);
+ } else {
+ DBG_MSG("Got signal %d, adding frame to thread %p\n",
+ sig, pthread);
+
+ /* Setup the target thread to receive the signal: */
+ thread_sig_add(pthread, sig, /*has_args*/ 1);
+
+ /* Take a peek at the next ready to run thread: */
+ pthread_h = PTHREAD_PRIOQ_FIRST();
+ DBG_MSG("Finished adding frame, head of prio list %p\n",
+ pthread_h);
+ }
+ SIG_SET_INACTIVE();
+
+ /*
+ * Switch to a different context if the currently running
+ * thread takes a signal, or if another thread takes a
+ * signal and the currently running thread is not in a
+ * signal handler.
+ */
+ if ((pthread_h != NULL) &&
+ (pthread_h->active_priority > curthread->active_priority)) {
+ /* Enter the kernel scheduler: */
+ _thread_kern_sched(ucp);
+ }
+ }
+ else {
+ SIG_SET_ACTIVE();
+ thread_sig_handle_special(sig);
+ SIG_SET_INACTIVE();
+ }
+}
+
+static void
+thread_sig_invoke_handler(int sig, siginfo_t *info, ucontext_t *ucp)
+ {
+ struct pthread *curthread = _get_curthread();
+ void (*sigfunc)(int, siginfo_t *, void *);
+ int saved_seqno;
+ sigset_t saved_sigmask;
+
+ /* Invoke the signal handler without going through the scheduler:
+ */
+ DBG_MSG("Got signal %d, calling handler for current thread %p\n",
+ sig, curthread);
+
+ /* Save the threads signal mask: */
+ saved_sigmask = curthread->sigmask;
+ saved_seqno = curthread->sigmask_seqno;
+
+ /* Setup the threads signal mask: */
+ SIGSETOR(curthread->sigmask, _thread_sigact[sig - 1].sa_mask);
+ sigaddset(&curthread->sigmask, sig);
+
+ /*
+ * Check that a custom handler is installed and if
+ * the signal is not blocked:
+ */
+ sigfunc = _thread_sigact[sig - 1].sa_sigaction;
+ if (((__sighandler_t *)sigfunc != SIG_DFL) &&
+ ((__sighandler_t *)sigfunc != SIG_IGN)) {
+ if (((_thread_sigact[sig - 1].sa_flags & SA_SIGINFO) != 0) ||
+ (info == NULL))
+ (*(sigfunc))(sig, info, ucp);
+ else
+ (*(sigfunc))(sig, (siginfo_t *)info->si_code, ucp);
+ }
+ /*
+ * Only restore the signal mask if it hasn't been changed by the
+ * application during invocation of the signal handler:
+ */
+ if (curthread->sigmask_seqno == saved_seqno)
+ curthread->sigmask = saved_sigmask;
+}
+
+/*
+ * Find a thread that can handle the signal.
+ */
+struct pthread *
+thread_sig_find(int sig)
+{
+ struct pthread *curthread = _get_curthread();
+ int handler_installed;
+ struct pthread *pthread, *pthread_next;
+ struct pthread *suspended_thread, *signaled_thread;
+
+ DBG_MSG("Looking for thread to handle signal %d\n", sig);
+ /* Check if the signal requires a dump of thread information: */
+ if (sig == SIGINFO) {
+ /* Dump thread information to file: */
+ _thread_dump_info();
+
+ /* Unblock this signal to allow further dumps: */
+ _thread_sigq[sig - 1].blocked = 0;
+ }
+ /* Check if an interval timer signal: */
+ else if (sig == _SCHED_SIGNAL) {
+ /*
+ * This shouldn't ever occur (should this panic?).
+ */
+ } else {
+ /*
+ * 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. Third
+ * preference will be the current thread. If none of the
+ * above, then the signal is delivered to the first thread
+ * that is found. Note that if a custom handler is not
+ * installed, the signal only affects threads in sigwait.
+ */
+ suspended_thread = NULL;
+ if ((curthread != &_thread_kern_thread) &&
+ !sigismember(&curthread->sigmask, sig))
+ signaled_thread = curthread;
+ else
+ 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);
+ /*
+ * A signal handler is not invoked for threads
+ * in sigwait. Clear the blocked and pending
+ * flags.
+ */
+ _thread_sigq[sig - 1].blocked = 0;
+ _thread_sigq[sig - 1].pending = 0;
+
+ /* 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 and do not add the signal
+ * to the process pending set.
+ */
+ 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) {
+ /*
+ * There is no handler installed. Unblock the
+ * signal so that if a handler _is_ installed, any
+ * subsequent signals can be handled.
+ */
+ _thread_sigq[sig - 1].blocked = 0;
+ } else {
+ /*
+ * 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;
+ return (pthread);
+ }
+ }
+ }
+
+ /* Returns nothing. */
+ return (NULL);
+}
+
+void
+_thread_sig_check_pending(struct pthread *pthread)
+{
+ sigset_t sigset;
+ int i;
+
+ /*
+ * Check if there are pending signals for the running
+ * thread or process that aren't blocked:
+ */
+ sigset = pthread->sigpend;
+ SIGSETOR(sigset, _process_sigpending);
+ SIGSETNAND(sigset, pthread->sigmask);
+ if (SIGNOTEMPTY(sigset)) {
+ for (i = 1; i < NSIG; i++) {
+ if (sigismember(&sigset, i) != 0) {
+ if (sigismember(&pthread->sigpend, i) != 0)
+ thread_sig_add(pthread, i,
+ /*has_args*/ 0);
+ else {
+ thread_sig_add(pthread, i,
+ /*has_args*/ 1);
+ sigdelset(&_process_sigpending, i);
+ }
+ }
+ }
+ }
+}
+
+/*
+ * This can only be called from the kernel scheduler. It assumes that
+ * all thread contexts are saved and that a signal frame can safely be
+ * added to any user thread.
+ */
+void
+_thread_sig_handle_pending(void)
+{
+ struct pthread *pthread;
+ int i, sig;
+
+ PTHREAD_ASSERT(_thread_kern_in_sched != 0,
+ "_thread_sig_handle_pending called from outside kernel schedule");
+ /*
+ * Check the array of pending signals:
+ */
+ for (i = 0; i < NSIG; i++) {
+ if (_thread_sigq[i].pending != 0) {
+ /* This signal is no longer pending. */
+ _thread_sigq[i].pending = 0;
+
+ sig = _thread_sigq[i].signo;
+
+ /* Some signals need special handling: */
+ thread_sig_handle_special(sig);
+
+ if (_thread_sigq[i].blocked == 0) {
+ /*
+ * Block future signals until this one
+ * is handled:
+ */
+ _thread_sigq[i].blocked = 1;
+
+ if ((pthread = thread_sig_find(sig)) != NULL) {
+ /*
+ * Setup the target thread to receive
+ * the signal:
+ */
+ thread_sig_add(pthread, sig,
+ /*has_args*/ 1);
+ }
+ }
+ }
+ }
+}
+
+static void
+thread_sig_handle_special(int sig)
+{
+ struct pthread *pthread, *pthread_next;
+ int i;
+
+ switch (sig) {
+ case 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:
+ */
+ __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;
+ }
+ }
+ break;
+
+ /*
+ * POSIX says that pending SIGCONT signals are
+ * discarded when one of these signals occurs.
+ */
+ case SIGTSTP:
+ case SIGTTIN:
+ case SIGTTOU:
+ /*
+ * Enter a loop to discard pending SIGCONT
+ * signals:
+ */
+ TAILQ_FOREACH(pthread, &_thread_list, tle) {
+ sigdelset(&pthread->sigpend, SIGCONT);
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+/*
+ * Perform thread specific actions in response to a signal.
+ * This function is only called if there is a handler installed
+ * for the signal, and if the target thread has the signal
+ * unmasked.
+ */
+static void
+thread_sig_add(struct pthread *pthread, int sig, int has_args)
+{
+ int restart;
+ int suppress_handler = 0;
+ int thread_is_active = 0;
+
+ restart = _thread_sigact[sig - 1].sa_flags & SA_RESTART;
+
+ /* Make sure this signal isn't still in the pending set: */
+ sigdelset(&pthread->sigpend, sig);
+
+ /*
+ * Process according to thread state:
+ */
+ switch (pthread->state) {
+ /*
+ * States which do not change when a signal is trapped:
+ */
+ case PS_DEAD:
+ case PS_DEADLOCK:
+ case PS_STATE_MAX:
+ case PS_SIGTHREAD:
+ /*
+ * You can't call a signal handler for threads in these
+ * states.
+ */
+ suppress_handler = 1;
+ break;
+
+ /*
+ * States which do not need any cleanup handling when signals
+ * occur:
+ */
+ case PS_RUNNING:
+ /*
+ * Remove the thread from the queue before changing its
+ * priority:
+ */
+ if ((pthread->flags & PTHREAD_FLAGS_IN_PRIOQ) != 0)
+ PTHREAD_PRIOQ_REMOVE(pthread);
+ else
+ /*
+ * This thread is running; avoid placing it in
+ * the run queue:
+ */
+ thread_is_active = 1;
+ break;
+
+ case PS_SUSPENDED:
+ break;
+
+ case PS_SPINBLOCK:
+ /* Remove the thread from the workq and waitq: */
+ PTHREAD_WORKQ_REMOVE(pthread);
+ PTHREAD_WAITQ_REMOVE(pthread);
+ /* Make the thread runnable: */
+ PTHREAD_SET_STATE(pthread, PS_RUNNING);
+ break;
+
+ case PS_SIGWAIT:
+ /* The signal handler is not called for threads in SIGWAIT. */
+ suppress_handler = 1;
+ /* 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:
+ if (sig == SIGCHLD) {
+ /* Change the state of the thread to run: */
+ PTHREAD_WAITQ_REMOVE(pthread);
+ PTHREAD_SET_STATE(pthread, PS_RUNNING);
+
+ /* Return the signal number: */
+ pthread->signo = sig;
+ }
+ else {
+ /*
+ * Mark the thread as interrupted only if the
+ * restart flag is not set on the signal action:
+ */
+ if (restart == 0)
+ pthread->interrupted = 1;
+ PTHREAD_WAITQ_REMOVE(pthread);
+ PTHREAD_SET_STATE(pthread, PS_RUNNING);
+ }
+ break;
+
+ /*
+ * States which cannot be interrupted but still require the
+ * signal handler to run:
+ */
+ case PS_COND_WAIT:
+ case PS_MUTEX_WAIT:
+ /*
+ * Remove the thread from the wait queue. It will
+ * be added back to the wait queue once all signal
+ * handlers have been invoked.
+ */
+ PTHREAD_WAITQ_REMOVE(pthread);
+ break;
+
+ case PS_JOIN:
+ /*
+ * Remove the thread from the wait queue. It will
+ * be added back to the wait queue once all signal
+ * handlers have been invoked.
+ */
+ PTHREAD_WAITQ_REMOVE(pthread);
+ /* Make the thread runnable: */
+ PTHREAD_SET_STATE(pthread, PS_RUNNING);
+ break;
+
+ /*
+ * States which are interruptible but may need to be removed
+ * from queues before any signal handler is called.
+ *
+ * XXX - We may not need to handle this condition, but will
+ * mark it as a potential problem.
+ */
+ case PS_FDLR_WAIT:
+ case PS_FDLW_WAIT:
+ case PS_FILE_WAIT:
+ if (restart == 0)
+ pthread->interrupted = 1;
+ /*
+ * Remove the thread from the wait queue. Our
+ * signal handler hook will remove this thread
+ * from the fd or file queue before invoking
+ * the actual handler.
+ */
+ PTHREAD_WAITQ_REMOVE(pthread);
+ break;
+
+ /*
+ * States which are interruptible:
+ */
+ case PS_FDR_WAIT:
+ case PS_FDW_WAIT:
+ if (restart == 0) {
+ /*
+ * Flag the operation as interrupted and
+ * set the state to running:
+ */
+ pthread->interrupted = 1;
+ PTHREAD_SET_STATE(pthread, PS_RUNNING);
+ }
+ PTHREAD_WORKQ_REMOVE(pthread);
+ PTHREAD_WAITQ_REMOVE(pthread);
+ break;
+
+ case PS_POLL_WAIT:
+ case PS_SELECT_WAIT:
+ case PS_SLEEP_WAIT:
+ /*
+ * Unmasked signals always cause poll, select, and sleep
+ * to terminate early, regardless of SA_RESTART:
+ */
+ pthread->interrupted = 1;
+ /* Remove threads in poll and select from the workq: */
+ if ((pthread->flags & PTHREAD_FLAGS_IN_WORKQ) != 0)
+ PTHREAD_WORKQ_REMOVE(pthread);
+ PTHREAD_WAITQ_REMOVE(pthread);
+ PTHREAD_SET_STATE(pthread, PS_RUNNING);
+ break;
+
+ case PS_SIGSUSPEND:
+ PTHREAD_WAITQ_REMOVE(pthread);
+ PTHREAD_SET_STATE(pthread, PS_RUNNING);
+ break;
+ }
+
+ if (suppress_handler == 0) {
+ /* Setup a signal frame and save the current threads state: */
+ thread_sigframe_add(pthread, sig, has_args);
+
+ /*
+ * Signals are deferred until just before the threads
+ * signal handler is invoked:
+ */
+ pthread->sig_defer_count = 1;
+
+ /* Make sure the thread is runnable: */
+ if (pthread->state != PS_RUNNING)
+ PTHREAD_SET_STATE(pthread, PS_RUNNING);
+ /*
+ * The thread should be removed from all scheduling
+ * queues at this point. Raise the priority and place
+ * the thread in the run queue.
+ */
+ pthread->active_priority |= PTHREAD_SIGNAL_PRIORITY;
+ if (thread_is_active == 0)
+ PTHREAD_PRIOQ_INSERT_TAIL(pthread);
+ }
+}
+
+static void
+thread_sig_check_state(struct pthread *pthread, int sig)
+{
+ /*
+ * Process according to thread state:
+ */
+ switch (pthread->state) {
+ /*
+ * States which do not change when a signal is trapped:
+ */
+ case PS_DEAD:
+ case PS_DEADLOCK:
+ case PS_STATE_MAX:
+ case PS_SIGTHREAD:
+ case PS_RUNNING:
+ case PS_SUSPENDED:
+ case PS_SPINBLOCK:
+ case PS_COND_WAIT:
+ case PS_JOIN:
+ case PS_MUTEX_WAIT:
+ 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:
+ if (sig == SIGCHLD) {
+ /*
+ * Remove the thread from the wait queue and
+ * make it runnable:
+ */
+ PTHREAD_NEW_STATE(pthread, PS_RUNNING);
+
+ /* Return the signal number: */
+ pthread->signo = sig;
+ }
+ break;
+
+ case PS_FDLR_WAIT:
+ case PS_FDLW_WAIT:
+ case PS_SIGSUSPEND:
+ case PS_SLEEP_WAIT:
+ /*
+ * Remove the thread from the wait queue and make it
+ * runnable:
+ */
+ PTHREAD_NEW_STATE(pthread, PS_RUNNING);
+
+ /* Flag the operation as interrupted: */
+ pthread->interrupted = 1;
+ break;
+
+ /*
+ * These states are additionally in the work queue:
+ */
+ case PS_FDR_WAIT:
+ case PS_FDW_WAIT:
+ case PS_FILE_WAIT:
+ case PS_POLL_WAIT:
+ case PS_SELECT_WAIT:
+ /*
+ * Remove the thread from the wait and work queues, and
+ * make it runnable:
+ */
+ PTHREAD_WORKQ_REMOVE(pthread);
+ PTHREAD_NEW_STATE(pthread, PS_RUNNING);
+
+ /* Flag the operation as interrupted: */
+ pthread->interrupted = 1;
+ break;
+ }
+}
+
+/*
+ * Send a signal to a specific thread (ala pthread_kill):
+ */
+void
+_thread_sig_send(struct pthread *pthread, int sig)
+{
+ struct pthread *curthread = _get_curthread();
+
+ /* Check for signals whose actions are SIG_DFL: */
+ if (_thread_sigact[sig - 1].sa_handler == SIG_DFL) {
+ /*
+ * Check to see if a temporary signal handler is
+ * installed for sigwaiters:
+ */
+ if (_thread_dfl_count[sig] == 0)
+ /*
+ * Deliver the signal to the process if a handler
+ * is not installed:
+ */
+ kill(getpid(), sig);
+ /*
+ * Assuming we're still running after the above kill(),
+ * make any necessary state changes to the thread:
+ */
+ thread_sig_check_state(pthread, sig);
+ }
+ /*
+ * Check that the signal is not being ignored:
+ */
+ else 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 (sigismember(&pthread->sigmask, sig))
+ /* Add the signal to the pending set: */
+ sigaddset(&pthread->sigpend, sig);
+ else if (pthread == curthread)
+ /* Call the signal handler for the current thread: */
+ thread_sig_invoke_handler(sig, NULL, NULL);
+ else {
+ /* Protect the scheduling queues: */
+ _thread_kern_sig_defer();
+ /*
+ * Perform any state changes due to signal
+ * arrival:
+ */
+ thread_sig_add(pthread, sig, /* has args */ 0);
+ /* Unprotect the scheduling queues: */
+ _thread_kern_sig_undefer();
+ }
+ }
+}
+
+/*
+ * User thread signal handler wrapper.
+ *
+ * thread - current running thread
+ */
+void
+_thread_sig_wrapper(void)
+{
+ struct pthread_signal_frame *psf;
+ struct pthread *thread = _get_curthread();
+
+ /* Get the current frame and state: */
+ psf = thread->curframe;
+ thread->curframe = NULL;
+ PTHREAD_ASSERT(psf != NULL, "Invalid signal frame in signal handler");
+
+ /*
+ * We're coming from the kernel scheduler; clear the in
+ * scheduler flag:
+ */
+ _thread_kern_in_sched = 0;
+
+ /* Check the threads previous state: */
+ if (psf->saved_state.psd_state != PS_RUNNING) {
+ /*
+ * Do a little cleanup handling for those threads in
+ * queues before calling the signal handler. Signals
+ * for these threads are temporarily blocked until
+ * after cleanup handling.
+ */
+ switch (psf->saved_state.psd_state) {
+ case PS_FDLR_WAIT:
+ case PS_FDLW_WAIT:
+ _fd_lock_backout(thread);
+ psf->saved_state.psd_state = PS_RUNNING;
+ break;
+
+ case PS_COND_WAIT:
+ _cond_wait_backout(thread);
+ psf->saved_state.psd_state = PS_RUNNING;
+ break;
+
+ case PS_MUTEX_WAIT:
+ _mutex_lock_backout(thread);
+ psf->saved_state.psd_state = PS_RUNNING;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ /* Unblock the signal in case we don't return from the handler: */
+ _thread_sigq[psf->signo - 1].blocked = 0;
+
+ /*
+ * Lower the priority before calling the handler in case
+ * it never returns (longjmps back):
+ */
+ thread->active_priority &= ~PTHREAD_SIGNAL_PRIORITY;
+
+ /*
+ * Reenable interruptions without checking for the need to
+ * context switch:
+ */
+ thread->sig_defer_count = 0;
+
+ /*
+ * Dispatch the signal via the custom signal handler:
+ */
+ if (psf->sig_has_args == 0)
+ thread_sig_invoke_handler(psf->signo, NULL, NULL);
+ else
+ thread_sig_invoke_handler(psf->signo, &psf->siginfo, &psf->uc);
+
+ /*
+ * Call the kernel scheduler to safely restore the frame and
+ * schedule the next thread:
+ */
+ _thread_kern_sched_frame(psf);
+}
+
+static void
+thread_sigframe_add(struct pthread *thread, int sig, int has_args)
+{
+ struct pthread_signal_frame *psf = NULL;
+ unsigned long stackp;
+
+ /* Get the top of the threads stack: */
+ stackp = GET_STACK_JB(thread->ctx.jb);
+
+ /*
+ * Leave a little space on the stack and round down to the
+ * nearest aligned word:
+ */
+ stackp -= sizeof(double);
+ stackp &= ~0x3UL;
+
+ /* Allocate room on top of the stack for a new signal frame: */
+ stackp -= sizeof(struct pthread_signal_frame);
+
+ psf = (struct pthread_signal_frame *) stackp;
+
+ /* Save the current context in the signal frame: */
+ thread_sigframe_save(thread, psf);
+
+ /* Set handler specific information: */
+ psf->sig_has_args = has_args;
+ psf->signo = sig;
+ if (has_args) {
+ /* Copy the signal handler arguments to the signal frame: */
+ memcpy(&psf->uc, &_thread_sigq[psf->signo - 1].uc,
+ sizeof(psf->uc));
+ memcpy(&psf->siginfo, &_thread_sigq[psf->signo - 1].siginfo,
+ sizeof(psf->siginfo));
+ }
+
+ /* Setup the signal mask: */
+ SIGSETOR(thread->sigmask, _thread_sigact[sig - 1].sa_mask);
+ sigaddset(&thread->sigmask, sig);
+
+ /* Set up the new frame: */
+ thread->curframe = psf;
+ thread->flags &= PTHREAD_FLAGS_PRIVATE | PTHREAD_FLAGS_TRACE |
+ PTHREAD_FLAGS_IN_SYNCQ;
+ /*
+ * Set up the context:
+ */
+ stackp -= sizeof(double);
+ _setjmp(thread->ctx.jb);
+ SET_STACK_JB(thread->ctx.jb, stackp);
+ SET_RETURN_ADDR_JB(thread->ctx.jb, _thread_sig_wrapper);
+}
+
+void
+_thread_sigframe_restore(struct pthread *thread,
+ struct pthread_signal_frame *psf)
+{
+ memcpy(&thread->ctx, &psf->ctx, sizeof(thread->ctx));
+ /*
+ * Only restore the signal mask if it hasn't been changed
+ * by the application during invocation of the signal handler:
+ */
+ if (thread->sigmask_seqno == psf->saved_state.psd_sigmask_seqno)
+ thread->sigmask = psf->saved_state.psd_sigmask;
+ thread->curframe = psf->saved_state.psd_curframe;
+ thread->wakeup_time = psf->saved_state.psd_wakeup_time;
+ thread->data = psf->saved_state.psd_wait_data;
+ thread->state = psf->saved_state.psd_state;
+ thread->flags = psf->saved_state.psd_flags;
+ thread->interrupted = psf->saved_state.psd_interrupted;
+ thread->signo = psf->saved_state.psd_signo;
+ thread->sig_defer_count = psf->saved_state.psd_sig_defer_count;
+}
+
+static void
+thread_sigframe_save(struct pthread *thread, struct pthread_signal_frame *psf)
+{
+ memcpy(&psf->ctx, &thread->ctx, sizeof(thread->ctx));
+ psf->saved_state.psd_sigmask = thread->sigmask;
+ psf->saved_state.psd_curframe = thread->curframe;
+ psf->saved_state.psd_wakeup_time = thread->wakeup_time;
+ psf->saved_state.psd_wait_data = thread->data;
+ psf->saved_state.psd_state = thread->state;
+ psf->saved_state.psd_flags = thread->flags &
+ (PTHREAD_FLAGS_PRIVATE | PTHREAD_FLAGS_TRACE);
+ psf->saved_state.psd_interrupted = thread->interrupted;
+ psf->saved_state.psd_sigmask_seqno = thread->sigmask_seqno;
+ psf->saved_state.psd_signo = thread->signo;
+ psf->saved_state.psd_sig_defer_count = thread->sig_defer_count;
+}
+
diff --git a/lib/libpthread/thread/thr_sigaction.c b/lib/libpthread/thread/thr_sigaction.c
new file mode 100644
index 0000000..2be587c
--- /dev/null
+++ b/lib/libpthread/thread/thr_sigaction.c
@@ -0,0 +1,112 @@
+/*
+ * 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>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_sigaction, sigaction);
+
+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 {
+ if (_thread_initial == NULL)
+ _thread_init();
+
+ /*
+ * 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) {
+ /*
+ * Ensure the signal handler cannot be interrupted
+ * by other signals. Always request the POSIX signal
+ * handler arguments.
+ */
+ sigfillset(&gact.sa_mask);
+ gact.sa_flags = SA_SIGINFO | SA_ONSTACK;
+
+ /*
+ * 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 (__sys_sigaction(sig,&gact,NULL) != 0)
+ ret = -1;
+ }
+ }
+
+ /* Return the completion status: */
+ return (ret);
+}
diff --git a/lib/libpthread/thread/thr_sigmask.c b/lib/libpthread/thread/thr_sigmask.c
new file mode 100644
index 0000000..040e7aa
--- /dev/null
+++ b/lib/libpthread/thread/thr_sigmask.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 <sys/param.h>
+#include <sys/types.h>
+#include <sys/signalvar.h>
+#include <errno.h>
+#include <signal.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_pthread_sigmask, pthread_sigmask);
+
+int
+_pthread_sigmask(int how, const sigset_t *set, sigset_t *oset)
+{
+ struct pthread *curthread = _get_curthread();
+ sigset_t sigset;
+ int ret = 0;
+
+ /* Check if the existing signal process mask is to be returned: */
+ if (oset != NULL) {
+ /* Return the current mask: */
+ *oset = curthread->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(curthread->sigmask, *set);
+ break;
+
+ /* Unblock signals: */
+ case SIG_UNBLOCK:
+ /* Clear signals from the existing mask: */
+ SIGSETNAND(curthread->sigmask, *set);
+ break;
+
+ /* Set the signal process mask: */
+ case SIG_SETMASK:
+ /* Set the new mask: */
+ curthread->sigmask = *set;
+ break;
+
+ /* Trap invalid actions: */
+ default:
+ /* Return an invalid argument: */
+ errno = EINVAL;
+ ret = -1;
+ break;
+ }
+
+ /* Increment the sequence number: */
+ curthread->sigmask_seqno++;
+
+ /*
+ * Check if there are pending signals for the running
+ * thread or process that aren't blocked:
+ */
+ sigset = curthread->sigpend;
+ SIGSETOR(sigset, _process_sigpending);
+ SIGSETNAND(sigset, curthread->sigmask);
+ if (SIGNOTEMPTY(sigset))
+ /*
+ * Call the kernel scheduler which will safely
+ * install a signal frame for the running thread:
+ */
+ _thread_kern_sched_sig();
+ }
+
+ /* Return the completion status: */
+ return (ret);
+}
diff --git a/lib/libpthread/thread/thr_sigpending.c b/lib/libpthread/thread/thr_sigpending.c
new file mode 100644
index 0000000..3c7efa4
--- /dev/null
+++ b/lib/libpthread/thread/thr_sigpending.c
@@ -0,0 +1,57 @@
+/*
+ * 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>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_sigpending, sigpending);
+
+int
+_sigpending(sigset_t * set)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret = 0;
+
+ /* Check for a null signal set pointer: */
+ if (set == NULL) {
+ /* Return an invalid argument: */
+ ret = EINVAL;
+ }
+ else {
+ *set = curthread->sigpend;
+ }
+ /* Return the completion status: */
+ return (ret);
+}
diff --git a/lib/libpthread/thread/thr_sigprocmask.c b/lib/libpthread/thread/thr_sigprocmask.c
new file mode 100644
index 0000000..cc0b8da
--- /dev/null
+++ b/lib/libpthread/thread/thr_sigprocmask.c
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE 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>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_sigprocmask, sigprocmask);
+
+int
+_sigprocmask(int how, const sigset_t *set, sigset_t *oset)
+{
+ return (pthread_sigmask(how, set, oset));
+}
diff --git a/lib/libpthread/thread/thr_sigsuspend.c b/lib/libpthread/thread/thr_sigsuspend.c
new file mode 100644
index 0000000..1201097
--- /dev/null
+++ b/lib/libpthread/thread/thr_sigsuspend.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE 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 <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(__sigsuspend, sigsuspend);
+
+int
+_sigsuspend(const sigset_t * set)
+{
+ struct pthread *curthread = _get_curthread();
+ 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 = curthread->sigmask;
+
+ /* Change the caller's mask: */
+ curthread->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: */
+ curthread->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;
+}
diff --git a/lib/libpthread/thread/thr_sigwait.c b/lib/libpthread/thread/thr_sigwait.c
new file mode 100644
index 0000000..1e87249
--- /dev/null
+++ b/lib/libpthread/thread/thr_sigwait.c
@@ -0,0 +1,174 @@
+/*
+ * 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>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_sigwait, sigwait);
+
+int
+_sigwait(const sigset_t *set, int *sig)
+{
+ struct pthread *curthread = _get_curthread();
+ 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 | SA_SIGINFO;
+ /* Ensure the signal handler cannot be interrupted by other signals: */
+ sigfillset(&act.sa_mask);
+
+ /*
+ * 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 = curthread->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(&curthread->sigpend,i))
+ sigdelset(&curthread->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.
+ */
+ sigemptyset(&tempset);
+ for (i = 1; i < NSIG; i++) {
+ if (sigismember(&waitset, i) &&
+ (_thread_sigact[i - 1].sa_handler == SIG_DFL)) {
+ _thread_dfl_count[i]++;
+ sigaddset(&tempset, i);
+ if (_thread_dfl_count[i] == 1) {
+ if (__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.
+ */
+ curthread->data.sigwait = &waitset;
+
+ /* Wait for a signal: */
+ _thread_kern_sched_state(PS_SIGWAIT, __FILE__, __LINE__);
+
+ /* Return the signal number to the caller: */
+ *sig = curthread->signo;
+
+ /*
+ * Probably unnecessary, but since it's in a union struct
+ * we don't know how it could be used in the future.
+ */
+ curthread->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(&tempset, i)) {
+ _thread_dfl_count[i]--;
+ if ((_thread_sigact[i - 1].sa_handler == SIG_DFL) &&
+ (_thread_dfl_count[i] == 0)) {
+ if (__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);
+}
diff --git a/lib/libpthread/thread/thr_single_np.c b/lib/libpthread/thread/thr_single_np.c
new file mode 100644
index 0000000..85471b8
--- /dev/null
+++ b/lib/libpthread/thread/thr_single_np.c
@@ -0,0 +1,47 @@
+/*
+ * 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 <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_pthread_single_np, pthread_single_np);
+
+int _pthread_single_np()
+{
+ struct pthread *curthread = _get_curthread();
+
+ /* Enter single-threaded (non-POSIX) scheduling mode: */
+ _thread_single = curthread;
+ return(0);
+}
diff --git a/lib/libpthread/thread/thr_sleep.c b/lib/libpthread/thread/thr_sleep.c
new file mode 100644
index 0000000..9e09db7
--- /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>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_sleep, sleep);
+
+unsigned int
+_sleep(unsigned int seconds)
+{
+ unsigned int ret;
+
+ _thread_enter_cancellation_point();
+ ret = __sleep(seconds);
+ _thread_leave_cancellation_point();
+
+ return ret;
+}
diff --git a/lib/libpthread/thread/thr_spec.c b/lib/libpthread/thread/thr_spec.c
new file mode 100644
index 0000000..e71f75f
--- /dev/null
+++ b/lib/libpthread/thread/thr_spec.c
@@ -0,0 +1,225 @@
+/*
+ * 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>
+#include <pthread.h>
+#include "pthread_private.h"
+
+struct pthread_key {
+ spinlock_t lock;
+ volatile int allocated;
+ volatile int count;
+ int seqno;
+ void (*destructor) ();
+};
+
+/* Static variables: */
+static struct pthread_key key_table[PTHREAD_KEYS_MAX];
+
+__weak_reference(_pthread_key_create, pthread_key_create);
+__weak_reference(_pthread_key_delete, pthread_key_delete);
+__weak_reference(_pthread_getspecific, pthread_getspecific);
+__weak_reference(_pthread_setspecific, pthread_setspecific);
+
+
+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;
+ key_table[(*key)].seqno++;
+
+ /* 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)
+{
+ struct pthread *curthread = _get_curthread();
+ 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 (curthread->specific_data_count > 0) {
+ /* Lock the key table entry: */
+ _SPINLOCK(&key_table[key].lock);
+ destructor = NULL;
+
+ if (key_table[key].allocated &&
+ (curthread->specific[key].data != NULL)) {
+ if (curthread->specific[key].seqno ==
+ key_table[key].seqno) {
+ data = (void *) curthread->specific[key].data;
+ destructor = key_table[key].destructor;
+ }
+ curthread->specific[key].data = NULL;
+ curthread->specific_data_count--;
+ }
+
+ /* 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(curthread->specific);
+ curthread->specific = NULL;
+ return;
+ }
+ }
+ }
+ if (curthread->specific != NULL) {
+ free(curthread->specific);
+ curthread->specific = NULL;
+ }
+}
+
+static inline struct pthread_specific_elem *
+pthread_key_allocate_data(void)
+{
+ struct pthread_specific_elem *new_data;
+
+ new_data = (struct pthread_specific_elem *)
+ malloc(sizeof(struct pthread_specific_elem) * PTHREAD_KEYS_MAX);
+ if (new_data != NULL) {
+ memset((void *) new_data, 0,
+ sizeof(struct pthread_specific_elem) * PTHREAD_KEYS_MAX);
+ }
+ return (new_data);
+}
+
+int
+_pthread_setspecific(pthread_key_t key, const void *value)
+{
+ struct pthread *pthread;
+ int ret = 0;
+
+ /* Point to the running thread: */
+ pthread = _get_curthread();
+
+ if ((pthread->specific) ||
+ (pthread->specific = pthread_key_allocate_data())) {
+ if (key < PTHREAD_KEYS_MAX) {
+ if (key_table[key].allocated) {
+ if (pthread->specific[key].data == NULL) {
+ if (value != NULL)
+ pthread->specific_data_count++;
+ } else {
+ if (value == NULL)
+ pthread->specific_data_count--;
+ }
+ pthread->specific[key].data = value;
+ pthread->specific[key].seqno =
+ key_table[key].seqno;
+ ret = 0;
+ } else
+ ret = EINVAL;
+ } else
+ ret = EINVAL;
+ } else
+ ret = ENOMEM;
+ return (ret);
+}
+
+void *
+_pthread_getspecific(pthread_key_t key)
+{
+ struct pthread *pthread;
+ void *data;
+
+ /* Point to the running thread: */
+ pthread = _get_curthread();
+
+ /* Check if there is specific data: */
+ if (pthread->specific != NULL && key < PTHREAD_KEYS_MAX) {
+ /* Check if this key has been used before: */
+ if (key_table[key].allocated &&
+ (pthread->specific[key].seqno == key_table[key].seqno)) {
+ /* Return the value: */
+ data = (void *) pthread->specific[key].data;
+ } 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);
+}
diff --git a/lib/libpthread/thread/thr_spinlock.c b/lib/libpthread/thread/thr_spinlock.c
new file mode 100644
index 0000000..7333709
--- /dev/null
+++ b/lib/libpthread/thread/thr_spinlock.c
@@ -0,0 +1,111 @@
+/*
+ * 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 <stdio.h>
+#include <string.h>
+#include <sched.h>
+#include <pthread.h>
+#include <unistd.h>
+
+#include <libc_private.h>
+
+#include "pthread_private.h"
+
+/*
+ * 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)
+{
+ struct pthread *curthread = _get_curthread();
+
+ /*
+ * 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. */
+ curthread->data.spinlock = lck;
+ _thread_kern_sched_state(PS_SPINBLOCK, __FILE__, __LINE__);
+ }
+
+ /* The running thread now owns the lock: */
+ lck->lock_owner = (long) curthread;
+}
+
+/*
+ * 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)
+{
+ struct pthread *curthread = _get_curthread();
+ 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", _getprogname(), curthread, lck, fname, lineno, lck->fname, lck->lineno);
+ __sys_write(2,str,strlen(str));
+ __sleep(1);
+ cnt = 0;
+ }
+
+ /* Block the thread until the lock. */
+ curthread->data.spinlock = lck;
+ _thread_kern_sched_state(PS_SPINBLOCK, fname, lineno);
+ }
+
+ /* The running thread now owns the lock: */
+ lck->lock_owner = (long) curthread;
+ lck->fname = fname;
+ lck->lineno = lineno;
+}
diff --git a/lib/libpthread/thread/thr_stack.c b/lib/libpthread/thread/thr_stack.c
new file mode 100644
index 0000000..86f0a2d
--- /dev/null
+++ b/lib/libpthread/thread/thr_stack.c
@@ -0,0 +1,237 @@
+/*
+ * Copyright (c) 2001 Daniel Eischen <deischen@freebsd.org>
+ * Copyright (c) 2000-2001 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, 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 AUTHORS 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 AUTHORS 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/mman.h>
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/user.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+/* Spare thread stack. */
+struct stack {
+ LIST_ENTRY(stack) qe; /* Stack queue linkage. */
+ size_t stacksize; /* Stack size (rounded up). */
+ size_t guardsize; /* Guard size. */
+ void *stackaddr; /* Stack address. */
+};
+
+/*
+ * Default sized (stack and guard) spare stack queue. Stacks are cached to
+ * avoid additional complexity managing mmap()ed stack regions. Spare stacks
+ * are used in LIFO order to increase cache locality.
+ */
+static LIST_HEAD(, stack) _dstackq = LIST_HEAD_INITIALIZER(_dstackq);
+
+/*
+ * Miscellaneous sized (non-default stack and/or guard) spare stack queue.
+ * Stacks are cached to avoid additional complexity managing mmap()ed stack
+ * regions. This list is unordered, since ordering on both stack size and guard
+ * size would be more trouble than it's worth. Stacks are allocated from this
+ * cache on a first size match basis.
+ */
+static LIST_HEAD(, stack) _mstackq = LIST_HEAD_INITIALIZER(_mstackq);
+
+/**
+ * Base address of the last stack allocated (including its red zone, if there is
+ * one). Stacks are allocated contiguously, starting beyond the top of the main
+ * stack. When a new stack is created, a red zone is typically created
+ * (actually, the red zone is simply left unmapped) above the top of the stack,
+ * such that the stack will not be able to grow all the way to the bottom 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.
+ *
+ * low memory
+ * . . . . . . . . . . . . . . . . . .
+ * | |
+ * | stack 3 | start of 3rd thread stack
+ * +-----------------------------------+
+ * | |
+ * | Red Zone (guard page) | red zone for 2nd thread
+ * | |
+ * +-----------------------------------+
+ * | stack 2 - PTHREAD_STACK_DEFAULT | top of 2nd thread stack
+ * | |
+ * | |
+ * | |
+ * | |
+ * | stack 2 |
+ * +-----------------------------------+ <-- start of 2nd thread stack
+ * | |
+ * | Red Zone | red zone for 1st thread
+ * | |
+ * +-----------------------------------+
+ * | stack 1 - PTHREAD_STACK_DEFAULT | top of 1st thread stack
+ * | |
+ * | |
+ * | |
+ * | |
+ * | stack 1 |
+ * +-----------------------------------+ <-- start of 1st thread stack
+ * | | (initial value of last_stack)
+ * | Red Zone |
+ * | | red zone for main thread
+ * +-----------------------------------+
+ * | USRSTACK - PTHREAD_STACK_INITIAL | top of main thread stack
+ * | | ^
+ * | | |
+ * | | |
+ * | | | stack growth
+ * | |
+ * +-----------------------------------+ <-- start of main thread stack
+ * (USRSTACK)
+ * high memory
+ *
+ */
+static void * last_stack;
+
+void *
+_thread_stack_alloc(size_t stacksize, size_t guardsize)
+{
+ void *stack = NULL;
+ struct stack *spare_stack;
+ size_t stack_size;
+
+ /*
+ * Round up stack size to nearest multiple of PAGE_SIZE, so that mmap()
+ * will work. If the stack size is not an even multiple, we end up
+ * initializing things such that there is unused space above the
+ * beginning of the stack, so the stack sits snugly against its guard.
+ */
+ if (stacksize % PAGE_SIZE != 0)
+ stack_size = ((stacksize / PAGE_SIZE) + 1) * PAGE_SIZE;
+ else
+ stack_size = stacksize;
+
+ /*
+ * If the stack and guard sizes are default, try to allocate a stack
+ * from the default-size stack cache:
+ */
+ if (stack_size == PTHREAD_STACK_DEFAULT &&
+ guardsize == PTHREAD_GUARD_DEFAULT) {
+ /*
+ * 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 = LIST_FIRST(&_dstackq)) != NULL) {
+ /* Use the spare stack. */
+ LIST_REMOVE(spare_stack, qe);
+ stack = spare_stack->stackaddr;
+ }
+
+ /* Unlock the garbage collector mutex. */
+ if (pthread_mutex_unlock(&_gc_mutex) != 0)
+ PANIC("Cannot unlock gc mutex");
+ }
+ /*
+ * The user specified a non-default stack and/or guard size, so try to
+ * allocate a stack from the non-default size stack cache, using the
+ * rounded up stack size (stack_size) in the search:
+ */
+ else {
+ /*
+ * Use the garbage collector mutex for synchronization of the
+ * spare stack list.
+ */
+ if (pthread_mutex_lock(&_gc_mutex) != 0)
+ PANIC("Cannot lock gc mutex");
+
+ LIST_FOREACH(spare_stack, &_mstackq, qe) {
+ if (spare_stack->stacksize == stack_size &&
+ spare_stack->guardsize == guardsize) {
+ LIST_REMOVE(spare_stack, qe);
+ stack = spare_stack->stackaddr;
+ break;
+ }
+ }
+
+ /* Unlock the garbage collector mutex. */
+ if (pthread_mutex_unlock(&_gc_mutex) != 0)
+ PANIC("Cannot unlock gc mutex");
+ }
+
+ /* Check if a stack was not allocated from a stack cache: */
+ if (stack == NULL) {
+
+ if (last_stack == NULL)
+ last_stack = _usrstack - PTHREAD_STACK_INITIAL -
+ PTHREAD_GUARD_DEFAULT;
+
+ /* Allocate a new stack. */
+ stack = last_stack - stack_size;
+
+ /*
+ * Even if stack allocation fails, we don't want to try to use
+ * this location again, so unconditionally decrement
+ * last_stack. Under normal operating conditions, the most
+ * likely reason for an mmap() error is a stack overflow of the
+ * adjacent thread stack.
+ */
+ last_stack -= (stack_size + guardsize);
+
+ /* Stack: */
+ if (mmap(stack, stack_size, PROT_READ | PROT_WRITE, MAP_STACK,
+ -1, 0) == MAP_FAILED)
+ stack = NULL;
+ }
+
+ return (stack);
+}
+
+/* This function must be called with _gc_mutex held. */
+void
+_thread_stack_free(void *stack, size_t stacksize, size_t guardsize)
+{
+ struct stack *spare_stack;
+
+ spare_stack = (stack + stacksize - sizeof(struct stack));
+ /* Round stacksize up to nearest multiple of PAGE_SIZE. */
+ if (stacksize % PAGE_SIZE != 0) {
+ spare_stack->stacksize = ((stacksize / PAGE_SIZE) + 1) *
+ PAGE_SIZE;
+ } else
+ spare_stack->stacksize = stacksize;
+ spare_stack->guardsize = guardsize;
+ spare_stack->stackaddr = stack;
+
+ if (spare_stack->stacksize == PTHREAD_STACK_DEFAULT &&
+ spare_stack->guardsize == PTHREAD_GUARD_DEFAULT) {
+ /* Default stack/guard size. */
+ LIST_INSERT_HEAD(&_dstackq, spare_stack, qe);
+ } else {
+ /* Non-default stack/guard size. */
+ LIST_INSERT_HEAD(&_mstackq, spare_stack, qe);
+ }
+}
diff --git a/lib/libpthread/thread/thr_suspend_np.c b/lib/libpthread/thread/thr_suspend_np.c
new file mode 100644
index 0000000..0e272ff
--- /dev/null
+++ b/lib/libpthread/thread/thr_suspend_np.c
@@ -0,0 +1,161 @@
+/*
+ * 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 <pthread.h>
+#include "pthread_private.h"
+
+static void finish_suspension(void *arg);
+
+__weak_reference(_pthread_suspend_np, pthread_suspend_np);
+
+/* 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);
+
+ /* FALLTHROUGH */
+ case PS_SLEEP_WAIT:
+ thread->interrupted = 1;
+
+ /* FALLTHROUGH */
+ case PS_SIGTHREAD:
+ 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_JOIN:
+ /* Mark the thread as suspended and joining: */
+ thread->suspended = SUSP_JOIN;
+
+ PTHREAD_NEW_STATE(thread, PS_SUSPENDED);
+ break;
+ case PS_FDLR_WAIT:
+ case PS_FDLW_WAIT:
+ case PS_FILE_WAIT:
+ /* 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)
+{
+ struct pthread *curthread = _get_curthread();
+
+ if (curthread->suspended != SUSP_NO)
+ _thread_kern_sched_state(PS_SUSPENDED, __FILE__, __LINE__);
+}
+
+
diff --git a/lib/libpthread/thread/thr_switch_np.c b/lib/libpthread/thread/thr_switch_np.c
new file mode 100644
index 0000000..f24d99f
--- /dev/null
+++ b/lib/libpthread/thread/thr_switch_np.c
@@ -0,0 +1,71 @@
+/*
+ * 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 <pthread.h>
+#include <pthread_np.h>
+#include "pthread_private.h"
+
+
+__weak_reference(_pthread_switch_add_np, pthread_switch_add_np);
+__weak_reference(_pthread_switch_delete_np, pthread_switch_delete_np);
+
+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);
+}
diff --git a/lib/libpthread/thread/thr_system.c b/lib/libpthread/thread/thr_system.c
new file mode 100644
index 0000000..d63969b
--- /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>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_system, system);
+
+int
+_system(const char *string)
+{
+ int ret;
+
+ _thread_enter_cancellation_point();
+ ret = __system(string);
+ _thread_leave_cancellation_point();
+
+ return ret;
+}
diff --git a/lib/libpthread/thread/thr_tcdrain.c b/lib/libpthread/thread/thr_tcdrain.c
new file mode 100644
index 0000000..272bdf6
--- /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>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_tcdrain, tcdrain);
+
+int
+_tcdrain(int fd)
+{
+ int ret;
+
+ _thread_enter_cancellation_point();
+ ret = __tcdrain(fd);
+ _thread_leave_cancellation_point();
+
+ return ret;
+}
diff --git a/lib/libpthread/thread/thr_vfork.c b/lib/libpthread/thread/thr_vfork.c
new file mode 100644
index 0000000..dbefc65
--- /dev/null
+++ b/lib/libpthread/thread/thr_vfork.c
@@ -0,0 +1,12 @@
+/*
+ * $FreeBSD$
+ */
+#include <unistd.h>
+
+__weak_reference(_vfork, vfork);
+
+int
+_vfork(void)
+{
+ return (fork());
+}
diff --git a/lib/libpthread/thread/thr_wait.c b/lib/libpthread/thread/thr_wait.c
new file mode 100644
index 0000000..e61138b
--- /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$
+ */
+
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_wait, wait);
+
+pid_t
+_wait(int *istat)
+{
+ pid_t ret;
+
+ _thread_enter_cancellation_point();
+ ret = __wait(istat);
+ _thread_leave_cancellation_point();
+
+ return ret;
+}
diff --git a/lib/libpthread/thread/thr_wait4.c b/lib/libpthread/thread/thr_wait4.c
new file mode 100644
index 0000000..6c4e068
--- /dev/null
+++ b/lib/libpthread/thread/thr_wait4.c
@@ -0,0 +1,70 @@
+/*
+ * 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 <errno.h>
+#include <sys/wait.h>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_wait4, wait4);
+
+pid_t
+_wait4(pid_t pid, int *istat, int options, struct rusage * rusage)
+{
+ struct pthread *curthread = _get_curthread();
+ pid_t ret;
+
+ _thread_kern_sig_defer();
+
+ /* Perform a non-blocking wait4 syscall: */
+ while ((ret = __sys_wait4(pid, istat, options | WNOHANG, rusage)) == 0 && (options & WNOHANG) == 0) {
+ /* Reset the interrupted operation flag: */
+ curthread->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 (curthread->interrupted) {
+ errno = EINTR;
+ ret = -1;
+ break;
+ }
+ }
+
+ _thread_kern_sig_undefer();
+
+ return (ret);
+}
diff --git a/lib/libpthread/thread/thr_waitpid.c b/lib/libpthread/thread/thr_waitpid.c
new file mode 100644
index 0000000..fcbbc9f
--- /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>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_waitpid, waitpid);
+
+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;
+}
diff --git a/lib/libpthread/thread/thr_write.c b/lib/libpthread/thread/thr_write.c
new file mode 100644
index 0000000..e655a34
--- /dev/null
+++ b/lib/libpthread/thread/thr_write.c
@@ -0,0 +1,147 @@
+/*
+ * 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>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(__write, write);
+
+ssize_t
+_write(int fd, const void *buf, size_t nbytes)
+{
+ struct pthread *curthread = _get_curthread();
+ 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 = __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))) {
+ curthread->data.fd.fd = fd;
+ _thread_kern_set_timeout(NULL);
+
+ /* Reset the interrupted operation flag: */
+ curthread->interrupted = 0;
+
+ _thread_kern_sched_state(PS_FDW_WAIT,
+ __FILE__, __LINE__);
+
+ /*
+ * Check if the operation was
+ * interrupted by a signal
+ */
+ if (curthread->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_WRITE);
+ }
+ 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;
+}
diff --git a/lib/libpthread/thread/thr_writev.c b/lib/libpthread/thread/thr_writev.c
new file mode 100644
index 0000000..c084cd0
--- /dev/null
+++ b/lib/libpthread/thread/thr_writev.c
@@ -0,0 +1,204 @@
+/*
+ * 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>
+#include <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_writev, writev);
+
+ssize_t
+_writev(int fd, const struct iovec * iov, int iovcnt)
+{
+ struct pthread *curthread = _get_curthread();
+ 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 = __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))) {
+ curthread->data.fd.fd = fd;
+ _thread_kern_set_timeout(NULL);
+
+ /* Reset the interrupted operation flag: */
+ curthread->interrupted = 0;
+
+ _thread_kern_sched_state(PS_FDW_WAIT,
+ __FILE__, __LINE__);
+
+ /*
+ * Check if the operation was
+ * interrupted by a signal
+ */
+ if (curthread->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);
+}
diff --git a/lib/libpthread/thread/thr_yield.c b/lib/libpthread/thread/thr_yield.c
new file mode 100644
index 0000000..ec89255
--- /dev/null
+++ b/lib/libpthread/thread/thr_yield.c
@@ -0,0 +1,66 @@
+/*
+ * 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 <pthread.h>
+#include "pthread_private.h"
+
+__weak_reference(_sched_yield, sched_yield);
+__weak_reference(_pthread_yield, pthread_yield);
+
+int
+_sched_yield(void)
+{
+ struct pthread *curthread = _get_curthread();
+
+ /* Reset the accumulated time slice value for the current thread: */
+ curthread->slice_usec = -1;
+
+ /* Schedule the next thread: */
+ _thread_kern_sched(NULL);
+
+ /* Always return no error. */
+ return(0);
+}
+
+/* Draft 4 yield */
+void
+_pthread_yield(void)
+{
+ struct pthread *curthread = _get_curthread();
+
+ /* Reset the accumulated time slice value for the current thread: */
+ curthread->slice_usec = -1;
+
+ /* Schedule the next thread: */
+ _thread_kern_sched(NULL);
+}
OpenPOWER on IntegriCloud