summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorjeff <jeff@FreeBSD.org>2003-04-01 03:46:29 +0000
committerjeff <jeff@FreeBSD.org>2003-04-01 03:46:29 +0000
commit08f648d4cdd32dc685715d9d1bb328fcc2ccd6c8 (patch)
tree75b07bcd4aade0c64c83c4ed577634d9b54a88ad /lib
parent7bada9c1ac5ea35ab3525f1e9a8d4d5383e20f5c (diff)
downloadFreeBSD-src-08f648d4cdd32dc685715d9d1bb328fcc2ccd6c8.zip
FreeBSD-src-08f648d4cdd32dc685715d9d1bb328fcc2ccd6c8.tar.gz
- Add libthr but don't hook it up to the regular build yet. This is an
adaptation of libc_r for the thr system call interface. This is beta quality code.
Diffstat (limited to 'lib')
-rw-r--r--lib/libthr/Makefile26
-rw-r--r--lib/libthr/arch/i386/i386/_curthread.S17
-rw-r--r--lib/libthr/arch/i386/i386/_setcurthread.c122
-rw-r--r--lib/libthr/thread/Makefile.inc50
-rw-r--r--lib/libthr/thread/thr_attr.c450
-rw-r--r--lib/libthr/thread/thr_autoinit.c61
-rw-r--r--lib/libthr/thread/thr_cancel.c205
-rw-r--r--lib/libthr/thread/thr_clean.c72
-rw-r--r--lib/libthr/thread/thr_cond.c544
-rw-r--r--lib/libthr/thread/thr_condattr_destroy.c53
-rw-r--r--lib/libthr/thread/thr_condattr_init.c58
-rw-r--r--lib/libthr/thread/thr_create.c228
-rw-r--r--lib/libthr/thread/thr_detach.c82
-rw-r--r--lib/libthr/thread/thr_equal.c44
-rw-r--r--lib/libthr/thread/thr_exit.c186
-rw-r--r--lib/libthr/thread/thr_find_thread.c61
-rw-r--r--lib/libthr/thread/thr_gc.c211
-rw-r--r--lib/libthr/thread/thr_getprio.c56
-rw-r--r--lib/libthr/thread/thr_getschedparam.c59
-rw-r--r--lib/libthr/thread/thr_info.c193
-rw-r--r--lib/libthr/thread/thr_init.c363
-rw-r--r--lib/libthr/thread/thr_join.c161
-rw-r--r--lib/libthr/thread/thr_kern.c188
-rw-r--r--lib/libthr/thread/thr_main_np.c47
-rw-r--r--lib/libthr/thread/thr_mattr_init.c56
-rw-r--r--lib/libthr/thread/thr_mattr_kind_np.c97
-rw-r--r--lib/libthr/thread/thr_multi_np.c50
-rw-r--r--lib/libthr/thread/thr_mutex.c432
-rw-r--r--lib/libthr/thread/thr_mutex_prioceiling.c122
-rw-r--r--lib/libthr/thread/thr_mutex_protocol.c70
-rw-r--r--lib/libthr/thread/thr_mutexattr_destroy.c53
-rw-r--r--lib/libthr/thread/thr_once.c53
-rw-r--r--lib/libthr/thread/thr_printf.c124
-rw-r--r--lib/libthr/thread/thr_private.h804
-rw-r--r--lib/libthr/thread/thr_resume_np.c87
-rw-r--r--lib/libthr/thread/thr_rwlock.c341
-rw-r--r--lib/libthr/thread/thr_rwlockattr.c98
-rw-r--r--lib/libthr/thread/thr_self.c44
-rw-r--r--lib/libthr/thread/thr_sem.c257
-rw-r--r--lib/libthr/thread/thr_seterrno.c59
-rw-r--r--lib/libthr/thread/thr_setprio.c52
-rw-r--r--lib/libthr/thread/thr_setschedparam.c115
-rw-r--r--lib/libthr/thread/thr_sig.c166
-rw-r--r--lib/libthr/thread/thr_spec.c225
-rw-r--r--lib/libthr/thread/thr_spinlock.c88
-rw-r--r--lib/libthr/thread/thr_stack.c240
-rw-r--r--lib/libthr/thread/thr_suspend_np.c53
-rw-r--r--lib/libthr/thread/thr_syscalls.c418
-rw-r--r--lib/libthr/thread/thr_yield.c45
49 files changed, 7686 insertions, 0 deletions
diff --git a/lib/libthr/Makefile b/lib/libthr/Makefile
new file mode 100644
index 0000000..7bd4c63
--- /dev/null
+++ b/lib/libthr/Makefile
@@ -0,0 +1,26 @@
+# $FreeBSD$
+#
+# All library objects contain FreeBSD revision strings by default; they may be
+# excluded as a space-saving measure. To produce a library that does
+# not contain these strings, add -DSTRIP_FBSDID (see <sys/cdefs.h>) to CFLAGS
+# below. Note, there are no IDs for syscall stubs whose sources are generated.
+# To included legacy CSRG sccsid strings, add -DLIBC_SCCS and -DSYSLIBC_SCCS
+# (for system call stubs) to CFLAGS below. -DSYSLIBC_SCCS affects just the
+# system call stubs.
+LIB=thr
+SHLIB_MAJOR= 1
+DEBUG_FLAGS=-g
+CFLAGS+=-DPTHREAD_KERNEL -D_THREAD_SAFE
+CFLAGS+=-I${.CURDIR}/../libc/include -I${.CURDIR}/thread \
+ -I${.CURDIR}/../../include
+
+# enable extra internal consistancy checks
+CFLAGS+=-D_PTHREADS_INVARIANTS
+
+AINC= -I${.CURDIR}/../libc/${MACHINE_ARCH} -I${.CURDIR}/thread
+PRECIOUSLIB= yes
+
+.include "${.CURDIR}/thread/Makefile.inc"
+.include "${.CURDIR}/sys/Makefile.inc"
+
+.include <bsd.lib.mk>
diff --git a/lib/libthr/arch/i386/i386/_curthread.S b/lib/libthr/arch/i386/i386/_curthread.S
new file mode 100644
index 0000000..7e8dbd9
--- /dev/null
+++ b/lib/libthr/arch/i386/i386/_curthread.S
@@ -0,0 +1,17 @@
+# $FreeBSD$
+
+#include <machine/asm.h>
+
+ENTRY(_get_curthread)
+ cmpl $0, _thread_initial
+ je nothreads
+ movl %gs:0, %eax
+ ret
+nothreads:
+ xor %eax, %eax
+ ret
+
+ENTRY(_set_gs)
+ movl 4(%esp), %eax
+ movl %eax, %gs
+ ret
diff --git a/lib/libthr/arch/i386/i386/_setcurthread.c b/lib/libthr/arch/i386/i386/_setcurthread.c
new file mode 100644
index 0000000..2e8150f
--- /dev/null
+++ b/lib/libthr/arch/i386/i386/_setcurthread.c
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2003, Jeffrey Roberson <jeff@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 unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must 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 ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED 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 BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING 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 <stdio.h>
+
+#include <machine/sysarch.h>
+#include <machine/segments.h>
+
+#define MAXTHR 128
+
+#define LDT_INDEX(x) (((long)(x) - (long)ldt_entries) / sizeof(ldt_entries[0]))
+
+void **ldt_free = NULL;
+static int ldt_inited = 0;
+void *ldt_entries[MAXTHR];
+
+static void ldt_init(void);
+
+static void
+ldt_init(void)
+{
+ int i;
+
+ ldt_free = &ldt_entries[NLDT];
+
+ for (i = 0; i < MAXTHR; i++)
+ ldt_entries[i] = (void *)&ldt_entries[i + 1];
+
+ ldt_entries[MAXTHR] = NULL;
+
+ ldt_inited = 1;
+}
+
+void
+_retire_thread(void *entry)
+{
+ *(void **)entry = *ldt_free;
+ ldt_free = entry;
+}
+
+void *
+_set_curthread(void *thr)
+{
+ union descriptor desc;
+ void **ldt_entry;
+ int ldt_index;
+ int error;
+
+ if (ldt_inited == NULL)
+ ldt_init();
+
+ if (ldt_free == NULL)
+ abort();
+
+ /*
+ * Pull one off of the free list and update the free list pointer.
+ */
+ ldt_entry = ldt_free;
+ ldt_free = (void **)*ldt_entry;
+
+ /*
+ * Cache the address of the thread structure here. This is
+ * what the gs register will point to.
+ */
+ *ldt_entry = thr;
+ ldt_index = LDT_INDEX(ldt_entry);
+
+ bzero(&desc, sizeof(desc));
+
+ /*
+ * Set up the descriptor to point into the ldt table which contains
+ * only a pointer to the thread.
+ */
+ desc.sd.sd_lolimit = sizeof(*ldt_entry);
+ desc.sd.sd_lobase = (unsigned int)ldt_entry & 0xFFFFFF;
+ desc.sd.sd_type = SDT_MEMRO;
+ desc.sd.sd_dpl = SEL_UPL;
+ desc.sd.sd_p = 1;
+ desc.sd.sd_hilimit = 0;
+ desc.sd.sd_xx = 0;
+ desc.sd.sd_def32 = 1;
+ desc.sd.sd_gran = 0;
+ desc.sd.sd_hibase = (unsigned int)ldt_entry >> 24;
+
+ error = i386_set_ldt(ldt_index, &desc, 1);
+ if (error == -1)
+ abort();
+
+ /*
+ * Set up our gs with the index into the ldt for this entry.
+ */
+ _set_gs(LSEL(ldt_index, SEL_UPL));
+
+ return (ldt_entry);
+}
diff --git a/lib/libthr/thread/Makefile.inc b/lib/libthr/thread/Makefile.inc
new file mode 100644
index 0000000..a8c9177
--- /dev/null
+++ b/lib/libthr/thread/Makefile.inc
@@ -0,0 +1,50 @@
+# $FreeBSD$
+
+# thr sources
+.PATH: ${.CURDIR}/thread
+
+SRCS+= \
+ thr_attr.c \
+ thr_autoinit.c \
+ thr_cancel.c \
+ thr_clean.c \
+ thr_cond.c \
+ thr_condattr_destroy.c \
+ thr_condattr_init.c \
+ thr_create.c \
+ thr_detach.c \
+ thr_equal.c \
+ thr_exit.c \
+ thr_find_thread.c \
+ thr_gc.c \
+ thr_getprio.c \
+ thr_getschedparam.c \
+ thr_info.c \
+ thr_init.c \
+ thr_join.c \
+ thr_kern.c \
+ thr_main_np.c \
+ thr_mattr_init.c \
+ thr_mattr_kind_np.c \
+ thr_multi_np.c \
+ thr_mutex.c \
+ thr_mutex_prioceiling.c \
+ thr_mutex_protocol.c \
+ thr_mutexattr_destroy.c \
+ thr_once.c \
+ thr_printf.c \
+ thr_resume_np.c \
+ thr_rwlock.c \
+ thr_rwlockattr.c \
+ thr_self.c \
+ thr_sem.c \
+ thr_seterrno.c \
+ thr_setprio.c \
+ thr_setschedparam.c \
+ thr_sig.c \
+ thr_spec.c \
+ thr_spinlock.c \
+ thr_stack.c \
+ thr_suspend_np.c \
+ thr_syscalls.c \
+ thr_yield.c
diff --git a/lib/libthr/thread/thr_attr.c b/lib/libthr/thread/thr_attr.c
new file mode 100644
index 0000000..1b25b10
--- /dev/null
+++ b/lib/libthr/thread/thr_attr.c
@@ -0,0 +1,450 @@
+/*
+ * Copyright (c) 1995-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$
+ */
+
+/*
+ * Copyright (c) 2003 Craig Rodrigues <rodrigc@attbi.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 Craig Rodrigues.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CRAIG RODRIGUES AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED 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.
+ *
+ */
+
+/*
+ * Copyright (c) 1998 Daniel Eischen <eischen@vigrid.com>.
+ * Copyright (C) 2001 Jason Evans <jasone@freebsd.org>.
+ * Copyright (c) 2002,2003 Alexey Zelkin <phantom@FreeBSD.org>
+ * Copyright (c) 2003 Jeff Roberson <jeff@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.
+ */
+
+/* XXXTHR I rewrote the entire file, can we lose some of the copyrights? */
+
+#include <sys/param.h>
+
+#include <errno.h>
+#include <pthread.h>
+#include <pthread_np.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "thr_private.h"
+
+__weak_reference(_pthread_attr_init, pthread_attr_init);
+
+int
+_pthread_attr_init(pthread_attr_t *attr)
+{
+ pthread_attr_t pattr;
+
+ if ((pattr = (pthread_attr_t)
+ malloc(sizeof(struct pthread_attr))) == NULL)
+ return (ENOMEM);
+
+ memcpy(pattr, &pthread_attr_default, sizeof(struct pthread_attr));
+ *attr = pattr;
+
+ return (0);
+}
+
+__weak_reference(_pthread_attr_destroy, pthread_attr_destroy);
+
+int
+_pthread_attr_destroy(pthread_attr_t *attr)
+{
+ if (attr == NULL || *attr == NULL)
+ return (EINVAL);
+
+ free(*attr);
+ *attr = NULL;
+
+ return (0);
+}
+
+__weak_reference(_pthread_attr_setcreatesuspend_np, pthread_attr_setcreatesuspend_np);
+
+int
+_pthread_attr_setcreatesuspend_np(pthread_attr_t *attr)
+{
+ if (attr == NULL || *attr == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+ (*attr)->suspend = PTHREAD_CREATE_SUSPENDED;
+
+ return (0);
+}
+
+__weak_reference(_pthread_attr_setdetachstate, pthread_attr_setdetachstate);
+
+int
+_pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate)
+{
+ if (attr == NULL || *attr == NULL ||
+ (detachstate != PTHREAD_CREATE_DETACHED &&
+ detachstate != PTHREAD_CREATE_JOINABLE))
+ return (EINVAL);
+
+ if (detachstate == PTHREAD_CREATE_DETACHED)
+ (*attr)->flags |= PTHREAD_DETACHED;
+ else
+ (*attr)->flags &= ~PTHREAD_DETACHED;
+
+ return (0);
+}
+
+
+__weak_reference(_pthread_attr_setguardsize, pthread_attr_setguardsize);
+
+int
+_pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize)
+{
+
+ if (attr == NULL || *attr == NULL)
+ return (EINVAL);
+
+ (*attr)->guardsize_attr = roundup(guardsize, _pthread_page_size);
+
+ return (0);
+}
+
+__weak_reference(_pthread_attr_setinheritsched, pthread_attr_setinheritsched);
+
+int
+_pthread_attr_setinheritsched(pthread_attr_t *attr, int sched_inherit)
+{
+ if (attr == NULL || *attr == NULL)
+ return (EINVAL);
+
+ (*attr)->sched_inherit = sched_inherit;
+
+ return (0);
+}
+
+__weak_reference(_pthread_attr_setschedparam, pthread_attr_setschedparam);
+
+int
+_pthread_attr_setschedparam(pthread_attr_t *attr,
+ const struct sched_param *param)
+{
+ if (attr == NULL || *attr == NULL)
+ return (EINVAL);
+
+ if (param == NULL)
+ return (ENOTSUP);
+
+ if (param->sched_priority < PTHREAD_MIN_PRIORITY ||
+ param->sched_priority > PTHREAD_MAX_PRIORITY)
+ return (ENOTSUP);
+
+ (*attr)->prio = param->sched_priority;
+
+ return (0);
+}
+
+__weak_reference(_pthread_attr_setschedpolicy, pthread_attr_setschedpolicy);
+
+int
+_pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy)
+{
+ if (attr == NULL || *attr == NULL)
+ return (EINVAL);
+
+ if (policy < SCHED_FIFO || policy > SCHED_RR)
+ return (ENOTSUP);
+
+ (*attr)->sched_policy = policy;
+
+ return (0);
+}
+
+__weak_reference(_pthread_attr_setscope, pthread_attr_setscope);
+
+int
+_pthread_attr_setscope(pthread_attr_t *attr, int contentionscope)
+{
+ if (attr == NULL || *attr == NULL)
+ return (EINVAL);
+
+ if (contentionscope != PTHREAD_SCOPE_PROCESS ||
+ contentionscope == PTHREAD_SCOPE_SYSTEM)
+ /* We don't support PTHREAD_SCOPE_SYSTEM. */
+ return (ENOTSUP);
+
+ (*attr)->flags |= contentionscope;
+
+ return (0);
+}
+
+__weak_reference(_pthread_attr_setstack, pthread_attr_setstack);
+
+int
+_pthread_attr_setstack(pthread_attr_t *attr, void *stackaddr,
+ size_t stacksize)
+{
+ if (attr == NULL || *attr == NULL || stackaddr == NULL
+ || stacksize < PTHREAD_STACK_MIN)
+ return (EINVAL);
+
+ (*attr)->stackaddr_attr = stackaddr;
+ (*attr)->stacksize_attr = stacksize;
+
+ return (0);
+}
+
+__weak_reference(_pthread_attr_setstackaddr, pthread_attr_setstackaddr);
+
+int
+_pthread_attr_setstackaddr(pthread_attr_t *attr, void *stackaddr)
+{
+ if (attr == NULL || *attr == NULL || stackaddr == NULL)
+ return (EINVAL);
+
+ (*attr)->stackaddr_attr = stackaddr;
+
+ return (0);
+}
+
+__weak_reference(_pthread_attr_setstacksize, pthread_attr_setstacksize);
+
+int
+_pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize)
+{
+ if (attr == NULL || *attr == NULL || stacksize < PTHREAD_STACK_MIN)
+ return (EINVAL);
+
+ (*attr)->stacksize_attr = stacksize;
+
+ return (0);
+}
+
+__weak_reference(_pthread_attr_get_np, pthread_attr_get_np);
+
+int
+_pthread_attr_get_np(pthread_t pid, pthread_attr_t *dst)
+{
+ int ret;
+
+ if (pid == NULL || dst == NULL || *dst == NULL)
+ return (EINVAL);
+
+ if ((ret = _find_thread(pid)) != 0)
+ return (ret);
+
+ memcpy(*dst, &pid->attr, sizeof(struct pthread_attr));
+
+ /*
+ * Special case, if stack address was not provided by caller
+ * of pthread_create(), then return address allocated internally
+ */
+ if ((*dst)->stackaddr_attr == NULL)
+ (*dst)->stackaddr_attr = pid->stack;
+
+ return (0);
+}
+
+__weak_reference(_pthread_attr_getdetachstate, pthread_attr_getdetachstate);
+
+int
+_pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate)
+{
+
+ if (attr == NULL || *attr == NULL || detachstate == NULL)
+ return (EINVAL);
+
+ /* Check if the detached flag is set: */
+ if ((*attr)->flags & PTHREAD_DETACHED)
+ *detachstate = PTHREAD_CREATE_DETACHED;
+ else
+ *detachstate = PTHREAD_CREATE_JOINABLE;
+
+ return (0);
+}
+
+__weak_reference(_pthread_attr_getguardsize, pthread_attr_getguardsize);
+
+int
+_pthread_attr_getguardsize(const pthread_attr_t *attr, size_t *guardsize)
+{
+ if (attr == NULL || *attr == NULL || guardsize == NULL)
+ return (EINVAL);
+
+ *guardsize = (*attr)->guardsize_attr;
+
+ return (0);
+}
+
+__weak_reference(_pthread_attr_getinheritsched, pthread_attr_getinheritsched);
+
+int
+_pthread_attr_getinheritsched(const pthread_attr_t *attr, int *sched_inherit)
+{
+ if (attr == NULL || *attr == NULL)
+ return (EINVAL);
+
+ *sched_inherit = (*attr)->sched_inherit;
+
+ return (0);
+}
+
+__weak_reference(_pthread_attr_getschedparam, pthread_attr_getschedparam);
+
+int
+_pthread_attr_getschedparam(const pthread_attr_t *attr, struct sched_param *param)
+{
+ if (attr == NULL || *attr == NULL || param == NULL)
+ return (EINVAL);
+
+ param->sched_priority = (*attr)->prio;
+
+ return (0);
+}
+
+__weak_reference(_pthread_attr_getschedpolicy, pthread_attr_getschedpolicy);
+
+int
+_pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy)
+{
+ if (attr == NULL || *attr == NULL || policy == NULL)
+ return (EINVAL);
+
+ *policy = (*attr)->sched_policy;
+
+ return (0);
+}
+
+__weak_reference(_pthread_attr_getscope, pthread_attr_getscope);
+
+int
+_pthread_attr_getscope(const pthread_attr_t *attr, int *contentionscope)
+{
+ if (attr == NULL || *attr == NULL || contentionscope == NULL)
+ return (EINVAL);
+
+ *contentionscope = (*attr)->flags & PTHREAD_SCOPE_SYSTEM ?
+ PTHREAD_SCOPE_SYSTEM : PTHREAD_SCOPE_PROCESS;
+
+ return (0);
+}
+
+__weak_reference(_pthread_attr_getstack, pthread_attr_getstack);
+
+int
+_pthread_attr_getstack(const pthread_attr_t * __restrict attr,
+ void ** __restrict stackaddr,
+ size_t * __restrict stacksize)
+{
+ if (attr == NULL || *attr == NULL || stackaddr == NULL
+ || stacksize == NULL)
+ return (EINVAL);
+
+ *stackaddr = (*attr)->stackaddr_attr;
+ *stacksize = (*attr)->stacksize_attr;
+
+ return (0);
+}
+
+__weak_reference(_pthread_attr_getstackaddr, pthread_attr_getstackaddr);
+
+int
+_pthread_attr_getstackaddr(const pthread_attr_t *attr, void **stackaddr)
+{
+ if (attr == NULL || *attr == NULL || stackaddr == NULL)
+ return (EINVAL);
+
+ *stackaddr = (*attr)->stackaddr_attr;
+
+ return (0);
+}
+
+__weak_reference(_pthread_attr_getstacksize, pthread_attr_getstacksize);
+
+int
+_pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *stacksize)
+{
+ if (attr == NULL || *attr == NULL || stacksize == NULL)
+ return (EINVAL);
+
+ *stacksize = (*attr)->stacksize_attr;
+
+ return (0);
+}
diff --git a/lib/libthr/thread/thr_autoinit.c b/lib/libthr/thread/thr_autoinit.c
new file mode 100644
index 0000000..31e2d48
--- /dev/null
+++ b/lib/libthr/thread/thr_autoinit.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2002 Alfred Perlstein <alfred@freebsd.org>.
+ * 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$
+ */
+
+/*
+ * This module uses GCC extentions to initialize the
+ * threads package at program start-up time.
+ */
+
+void _thread_init_hack(void) __attribute__ ((constructor));
+
+void
+_thread_init_hack(void)
+{
+
+ _thread_init();
+}
+
+/*
+ * For the shared version of the threads library, the above is sufficient.
+ * But for the archive version of the library, we need a little bit more.
+ * Namely, we must arrange for this particular module to be pulled in from
+ * the archive library at link time. To accomplish that, we define and
+ * initialize a variable, "_thread_autoinit_dummy_decl". This variable is
+ * referenced (as an extern) from libc/stdlib/exit.c. This will always
+ * create a need for this module, ensuring that it is present in the
+ * executable.
+ */
+extern int _thread_autoinit_dummy_decl;
+int _thread_autoinit_dummy_decl = 0;
diff --git a/lib/libthr/thread/thr_cancel.c b/lib/libthr/thread/thr_cancel.c
new file mode 100644
index 0000000..0695fbc
--- /dev/null
+++ b/lib/libthr/thread/thr_cancel.c
@@ -0,0 +1,205 @@
+/*
+ * David Leonard <d@openbsd.org>, 1999. Public domain.
+ * $FreeBSD$
+ */
+#include <sys/errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+__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;
+ pthread_t curthread;
+
+ if ((ret = _find_thread(pthread)) != 0) {
+ /* NOTHING */
+ } else if (pthread->state == PS_DEAD || pthread->state == PS_DEADLOCK
+ || (pthread->flags & PTHREAD_EXITING) != 0) {
+ ret = 0;
+ } else {
+ curthread = _get_curthread();
+ GIANT_LOCK(curthread);
+
+ 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_SLEEP_WAIT:
+ case PS_WAIT_WAIT:
+ 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_MUTEX_WAIT:
+ case PS_COND_WAIT:
+ /*
+ * Threads in these states may be in queues.
+ * In order to preserve queue integrity, the
+ * cancelled thread must remove itself from the
+ * queue. When the thread resumes, it will
+ * remove itself from the queue and call the
+ * cancellation routine.
+ */
+ pthread->cancelflags |= PTHREAD_CANCELLING;
+ PTHREAD_NEW_STATE(pthread, PS_RUNNING);
+ break;
+
+ case PS_DEAD:
+ case PS_DEADLOCK:
+ case PS_STATE_MAX:
+ /* Ignore - only here to silence -Wall: */
+ break;
+ }
+ }
+
+ /* Unprotect the scheduling queues: */
+ GIANT_UNLOCK(curthread);
+
+ ret = 0;
+ }
+ return (ret);
+}
+
+int
+_pthread_setcancelstate(int state, int *oldstate)
+{
+ struct pthread *curthread = _get_curthread();
+ int ostate;
+
+ GIANT_LOCK(curthread);
+ 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)
+ break;
+ GIANT_UNLOCK(curthread);
+ pthread_testcancel();
+ break;
+ case PTHREAD_CANCEL_DISABLE:
+ if (oldstate != NULL)
+ *oldstate = ostate;
+ curthread->cancelflags |= PTHREAD_CANCEL_DISABLE;
+ GIANT_UNLOCK(curthread);
+ break;
+ default:
+ GIANT_UNLOCK(curthread);
+ return (EINVAL);
+ }
+
+ return (0);
+}
+
+int
+_pthread_setcanceltype(int type, int *oldtype)
+{
+ struct pthread *curthread = _get_curthread();
+ int otype;
+
+ GIANT_LOCK(curthread);
+ otype = curthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS;
+ switch (type) {
+ case PTHREAD_CANCEL_ASYNCHRONOUS:
+ if (oldtype != NULL)
+ *oldtype = otype;
+ curthread->cancelflags |= PTHREAD_CANCEL_ASYNCHRONOUS;
+ GIANT_UNLOCK(curthread);
+ pthread_testcancel();
+ break;
+ case PTHREAD_CANCEL_DEFERRED:
+ if (oldtype != NULL)
+ *oldtype = otype;
+ curthread->cancelflags &= ~PTHREAD_CANCEL_ASYNCHRONOUS;
+ GIANT_UNLOCK(curthread);
+ break;
+ default:
+ GIANT_UNLOCK(curthread);
+ return (EINVAL);
+ }
+
+ return (0);
+}
+
+/*
+ * XXXTHR Make an internal locked version.
+ */
+void
+_pthread_testcancel(void)
+{
+ struct pthread *curthread = _get_curthread();
+
+ GIANT_LOCK(curthread);
+ if (((curthread->cancelflags & PTHREAD_CANCEL_DISABLE) == 0) &&
+ ((curthread->cancelflags & PTHREAD_CANCELLING) != 0) &&
+ ((curthread->flags & PTHREAD_EXITING) == 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;
+ GIANT_UNLOCK(curthread);
+ _thread_exit_cleanup();
+ pthread_exit(PTHREAD_CANCELED);
+ PANIC("cancel");
+ }
+ GIANT_UNLOCK(curthread);
+}
+
+void
+_thread_enter_cancellation_point(void)
+{
+ struct pthread *curthread = _get_curthread();
+
+ pthread_testcancel();
+
+ GIANT_LOCK(curthread);
+ curthread->cancelflags |= PTHREAD_AT_CANCEL_POINT;
+ GIANT_UNLOCK(curthread);
+}
+
+void
+_thread_leave_cancellation_point(void)
+{
+ struct pthread *curthread = _get_curthread();
+
+ GIANT_LOCK(curthread);
+ curthread->cancelflags &= ~PTHREAD_AT_CANCEL_POINT;
+ GIANT_UNLOCK(curthread);
+
+ pthread_testcancel();
+}
diff --git a/lib/libthr/thread/thr_clean.c b/lib/libthr/thread/thr_clean.c
new file mode 100644
index 0000000..8ae6b42
--- /dev/null
+++ b/lib/libthr/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 "thr_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/libthr/thread/thr_cond.c b/lib/libthr/thread/thr_cond.c
new file mode 100644
index 0000000..0327575
--- /dev/null
+++ b/lib/libthr/thread/thr_cond.c
@@ -0,0 +1,544 @@
+/*
+ * 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 "thr_private.h"
+
+/*
+ * Prototypes
+ */
+static pthread_t cond_queue_deq(pthread_cond_t);
+static void cond_queue_remove(pthread_cond_t, pthread_t);
+static 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);
+
+#define COND_LOCK(c) \
+do { \
+ if (umtx_lock(&(c)->c_lock, curthread->thr_id)) \
+ abort(); \
+} while (0)
+
+#define COND_UNLOCK(c) \
+do { \
+ if (umtx_unlock(&(c)->c_lock, curthread->thr_id)) \
+ abort(); \
+} while (0)
+
+
+/* Reinitialize a condition variable to defaults. */
+int
+_cond_reinit(pthread_cond_t *cond)
+{
+ if (cond == NULL)
+ return (EINVAL);
+
+ if (*cond == NULL)
+ return (pthread_cond_init(cond, NULL));
+
+ /*
+ * 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;
+ bzero(&(*cond)->c_lock, sizeof((*cond)->c_lock));
+
+ return (0);
+}
+
+int
+_pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *cond_attr)
+{
+ enum pthread_cond_type type;
+ pthread_cond_t pcond;
+
+ if (cond == NULL)
+ return (EINVAL);
+
+ /*
+ * Check if a pointer to a condition variable attribute
+ * structure was passed by the caller:
+ */
+ if (cond_attr != NULL && *cond_attr != NULL)
+ type = (*cond_attr)->c_type;
+ else
+ /* Default to a fast condition variable: */
+ type = COND_TYPE_FAST;
+
+ /* Process according to condition variable type: */
+ switch (type) {
+ case COND_TYPE_FAST:
+ break;
+ default:
+ return (EINVAL);
+ break;
+ }
+
+ if ((pcond = (pthread_cond_t)
+ malloc(sizeof(struct pthread_cond))) == NULL)
+ return (ENOMEM);
+ /*
+ * 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;
+ bzero(&pcond->c_lock, sizeof(pcond->c_lock));
+
+ *cond = pcond;
+
+ return (0);
+}
+
+int
+_pthread_cond_destroy(pthread_cond_t *cond)
+{
+ struct pthread *curthread = _get_curthread();
+
+ if (cond == NULL || *cond == NULL)
+ return (EINVAL);
+
+ COND_LOCK(*cond);
+
+ /*
+ * 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 (0);
+}
+
+int
+_pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
+{
+ int rval;
+ struct timespec abstime = { 0, 0 };
+
+ /*
+ * XXXTHR This is a hack. Make a pthread_cond_common function that
+ * accepts NULL so we don't change posix semantics for timedwait.
+ */
+ rval = pthread_cond_timedwait(cond, mutex, &abstime);
+
+ /* This should never happen. */
+ if (rval == ETIMEDOUT)
+ abort();
+
+ return (rval);
+}
+
+int
+_pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex,
+ const struct timespec * abstime)
+{
+ struct pthread *curthread = _get_curthread();
+ struct timespec *time;
+ int rval = 0;
+ int done = 0;
+ int seqno;
+ int mtxrval;
+
+
+ _thread_enter_cancellation_point();
+
+ if (abstime == NULL || abstime->tv_nsec >= 1000000000)
+ return (EINVAL);
+
+ if (abstime->tv_sec == 0 && abstime->tv_nsec == 0)
+ time = NULL;
+ else
+ time = abstime;
+ /*
+ * If the condition variable is statically initialized, perform dynamic
+ * initialization.
+ */
+ if (*cond == NULL && (rval = pthread_cond_init(cond, NULL)) != 0)
+ return (rval);
+
+
+ COND_LOCK(*cond);
+
+ /*
+ * 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))) {
+ COND_UNLOCK(*cond);
+ rval = EINVAL;
+ break;
+ }
+ /* Remember the mutex */
+ (*cond)->c_mutex = *mutex;
+
+ if ((rval = _mutex_cv_unlock(mutex)) != 0) {
+ if (rval == -1){
+ printf("foo");
+ fflush(stdout);
+ abort();
+ }
+
+ COND_UNLOCK(*cond);
+ break;
+ }
+ COND_UNLOCK(*cond);
+
+ /*
+ * We need giant for the queue operations. It also
+ * protects seqno and the pthread flag fields. This is
+ * dropped and reacquired in _thread_suspend().
+ */
+
+ GIANT_LOCK(curthread);
+ /*
+ * c_seqno is protected by giant.
+ */
+ seqno = (*cond)->c_seqno;
+
+ do {
+ /*
+ * Queue the running thread on the condition
+ * variable.
+ */
+ cond_queue_enq(*cond, curthread);
+
+ if (curthread->cancelflags & PTHREAD_CANCELLING) {
+ /*
+ * POSIX Says that we must relock the mutex
+ * even if we're being canceled.
+ */
+ GIANT_UNLOCK(curthread);
+ _mutex_cv_lock(mutex);
+ pthread_testcancel();
+ PANIC("Shouldn't have come back.");
+ }
+
+ PTHREAD_SET_STATE(curthread, PS_COND_WAIT);
+ rval = _thread_suspend(curthread, time);
+ if (rval == -1) {
+ printf("foo");
+ fflush(stdout);
+ abort();
+ }
+
+ done = (seqno != (*cond)->c_seqno);
+
+ cond_queue_remove(*cond, curthread);
+
+ } while ((done == 0) && (rval == 0));
+ /*
+ * If we timed out someone still may have signaled us
+ * before we got a chance to run again. We check for
+ * this by looking to see if our state is RUNNING.
+ */
+ if (rval == EAGAIN) {
+ if (curthread->state != PS_RUNNING) {
+ PTHREAD_SET_STATE(curthread, PS_RUNNING);
+ rval = ETIMEDOUT;
+ } else
+ rval = 0;
+ }
+ GIANT_UNLOCK(curthread);
+
+ mtxrval = _mutex_cv_lock(mutex);
+
+ /*
+ * If the mutex failed return that error, otherwise we're
+ * returning ETIMEDOUT.
+ */
+ if (mtxrval == -1) {
+ printf("foo");
+ fflush(stdout);
+ abort();
+ }
+ if (mtxrval != 0)
+ rval = mtxrval;
+
+ break;
+
+ /* Trap invalid condition variable types: */
+ default:
+ COND_UNLOCK(*cond);
+ rval = EINVAL;
+ break;
+ }
+
+ /*
+ * See if we have to cancel before we retry. We could be
+ * canceled with the mutex held here!
+ */
+ pthread_testcancel();
+
+ _thread_leave_cancellation_point();
+
+ return (rval);
+}
+
+int
+_pthread_cond_signal(pthread_cond_t * cond)
+{
+ struct pthread *curthread = _get_curthread();
+ int rval = 0;
+ pthread_t pthread;
+
+ if (cond == NULL)
+ return (EINVAL);
+ /*
+ * If the condition variable is statically initialized, perform dynamic
+ * initialization.
+ */
+ if (*cond == NULL && (rval = pthread_cond_init(cond, NULL)) != 0)
+ return (rval);
+
+
+ COND_LOCK(*cond);
+
+ /* Process according to condition variable type: */
+ switch ((*cond)->c_type) {
+ /* Fast condition variable: */
+ case COND_TYPE_FAST:
+ GIANT_LOCK(curthread);
+ (*cond)->c_seqno++;
+
+ if ((pthread = cond_queue_deq(*cond)) != NULL) {
+ /*
+ * Wake up the signaled thread:
+ */
+ PTHREAD_NEW_STATE(pthread, PS_RUNNING);
+ }
+
+ GIANT_UNLOCK(curthread);
+ break;
+
+ /* Trap invalid condition variable types: */
+ default:
+ rval = EINVAL;
+ break;
+ }
+
+
+ COND_UNLOCK(*cond);
+
+ return (rval);
+}
+
+int
+_pthread_cond_broadcast(pthread_cond_t * cond)
+{
+ struct pthread *curthread = _get_curthread();
+ int rval = 0;
+ pthread_t pthread;
+
+ if (cond == NULL)
+ return (EINVAL);
+ /*
+ * If the condition variable is statically initialized, perform dynamic
+ * initialization.
+ */
+ if (*cond == NULL && (rval = pthread_cond_init(cond, NULL)) != 0)
+ return (rval);
+
+ COND_LOCK(*cond);
+
+ /* Process according to condition variable type: */
+ switch ((*cond)->c_type) {
+ /* Fast condition variable: */
+ case COND_TYPE_FAST:
+ GIANT_LOCK(curthread);
+ (*cond)->c_seqno++;
+
+ /*
+ * Enter a loop to bring all threads off the
+ * condition queue:
+ */
+ while ((pthread = cond_queue_deq(*cond)) != NULL) {
+ /*
+ * Wake up the signaled thread:
+ */
+ PTHREAD_NEW_STATE(pthread, PS_RUNNING);
+ }
+ GIANT_UNLOCK(curthread);
+
+ /* There are no more waiting threads: */
+ (*cond)->c_mutex = NULL;
+
+ break;
+
+ /* Trap invalid condition variable types: */
+ default:
+ rval = EINVAL;
+ break;
+ }
+
+ COND_UNLOCK(*cond);
+
+
+ return (rval);
+}
+
+void
+_cond_wait_backout(pthread_t pthread)
+{
+ struct pthread *curthread = _get_curthread();
+ pthread_cond_t cond;
+
+ cond = pthread->data.cond;
+ if (cond == NULL)
+ return;
+
+ COND_LOCK(cond);
+
+ /* Process according to condition variable type: */
+ switch (cond->c_type) {
+ /* Fast condition variable: */
+ case COND_TYPE_FAST:
+ GIANT_LOCK(curthread);
+
+ cond_queue_remove(cond, pthread);
+
+ GIANT_UNLOCK(curthread);
+ break;
+
+ default:
+ break;
+ }
+
+ COND_UNLOCK(cond);
+}
+
+/*
+ * Dequeue a waiting thread from the head of a condition queue in
+ * descending priority order.
+ */
+static 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);
+ cond_queue_remove(cond, pthread);
+ if ((pthread->cancelflags & PTHREAD_CANCELLING) == 0 &&
+ pthread->state == PS_COND_WAIT)
+ /*
+ * 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 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;
+ }
+ /* Check for no more waiters. */
+ if (TAILQ_FIRST(&cond->c_queue) == NULL)
+ cond->c_mutex = NULL;
+}
+
+/*
+ * Enqueue a waiting thread to a condition queue in descending priority
+ * order.
+ */
+static 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/libthr/thread/thr_condattr_destroy.c b/lib/libthr/thread/thr_condattr_destroy.c
new file mode 100644
index 0000000..e0ade00
--- /dev/null
+++ b/lib/libthr/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 "thr_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/libthr/thread/thr_condattr_init.c b/lib/libthr/thread/thr_condattr_init.c
new file mode 100644
index 0000000..1af12e1
--- /dev/null
+++ b/lib/libthr/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 "thr_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/libthr/thread/thr_create.c b/lib/libthr/thread/thr_create.c
new file mode 100644
index 0000000..9a663b4
--- /dev/null
+++ b/lib/libthr/thread/thr_create.c
@@ -0,0 +1,228 @@
+/*
+ * 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 "thr_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;
+ int flags;
+ 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)
+ return (EAGAIN);
+
+ /* Check if default thread attributes are required: */
+ if (attr == NULL || *attr == NULL)
+ pattr = &pthread_attr_default;
+ else
+ pattr = *attr;
+
+ /* Check if a stack was specified in the thread attributes: */
+ if ((stack = pattr->stackaddr_attr) == NULL) {
+ stack = _thread_stack_alloc(pattr->stacksize_attr,
+ pattr->guardsize_attr);
+ if (stack == NULL) {
+ free(new_thread);
+ return (EAGAIN);
+ }
+ }
+
+ /* Initialise the thread structure: */
+ memset(new_thread, 0, sizeof(struct pthread));
+ 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 machine context: */
+ getcontext(&new_thread->ctx);
+ new_thread->ctx.uc_stack.ss_sp = new_thread->stack;
+ new_thread->ctx.uc_stack.ss_size = pattr->stacksize_attr;
+ makecontext(&new_thread->ctx, _thread_start, 1);
+
+ /* 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;
+
+ /*
+ * Protect the scheduling queues.
+ */
+ GIANT_LOCK(curthread);
+
+ /*
+ * 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);
+
+ /*
+ * Create the thread.
+ *
+ */
+ if (pattr->suspend == PTHREAD_FLAGS_SUSPENDED)
+ flags = THR_SUSPENDED;
+ else
+ flags = 0;
+
+ ret = thr_create(&new_thread->ctx, &new_thread->thr_id, flags);
+
+ if (ret != 0) {
+ _thread_printf("thr_create() == %d\n", ret);
+ PANIC("thr_create");
+ }
+
+ GIANT_UNLOCK(curthread);
+
+ /* Return a pointer to the thread structure: */
+ (*thread) = new_thread;
+
+ /*
+ * Start a garbage collector thread
+ * if necessary.
+ */
+#if 0
+ if (f_gc && pthread_create(&gc_thread,NULL, _thread_gc,NULL) != 0)
+ PANIC("Can't create gc thread");
+#endif
+
+ return (0);
+}
+
+void
+_thread_start(void)
+{
+ struct pthread *curthread = _get_curthread_slow();
+
+ curthread->arch_id = _set_curthread(curthread);
+
+ if (_get_curthread() != curthread) {
+ _thread_printf("%x - %x\n", _get_curthread(), curthread);
+ abort();
+ }
+
+ /* 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/libthr/thread/thr_detach.c b/lib/libthr/thread/thr_detach.c
new file mode 100644
index 0000000..ca1b473
--- /dev/null
+++ b/lib/libthr/thread/thr_detach.c
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+__weak_reference(_pthread_detach, pthread_detach);
+
+int
+_pthread_detach(pthread_t pthread)
+{
+ pthread_t curthread;
+
+ if (pthread == NULL || pthread->magic != PTHREAD_MAGIC)
+ return (EINVAL);
+
+ if (pthread->attr.flags & PTHREAD_DETACHED)
+ return (EINVAL);
+
+ curthread = _get_curthread();
+
+ pthread->attr.flags |= PTHREAD_DETACHED;
+
+ /*
+ * Defer signals to protect the scheduling queues from
+ * access by the signal handler:
+ */
+ GIANT_LOCK(curthread);
+
+ /* 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;
+ }
+
+ GIANT_UNLOCK(curthread);
+
+ return (0);
+}
diff --git a/lib/libthr/thread/thr_equal.c b/lib/libthr/thread/thr_equal.c
new file mode 100644
index 0000000..f8882f5
--- /dev/null
+++ b/lib/libthr/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 "thr_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/libthr/thread/thr_exit.c b/lib/libthr/thread/thr_exit.c
new file mode 100644
index 0000000..2d791d2
--- /dev/null
+++ b/lib/libthr/thread/thr_exit.c
@@ -0,0 +1,186 @@
+/*
+ * 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 "thr_private.h"
+
+__weak_reference(_pthread_exit, pthread_exit);
+
+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 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();
+ }
+
+ /*
+ * 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.
+ */
+ GIANT_LOCK(curthread);
+
+ /* 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;
+
+ /* Make the joining thread runnable: */
+ PTHREAD_NEW_STATE(pthread, PS_RUNNING);
+
+ /* 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);
+
+ PTHREAD_SET_STATE(curthread, PS_DEAD);
+ GIANT_UNLOCK(curthread);
+
+ /*
+ * Retire the architecture specific id so that it can be used for
+ * new threads.
+ */
+ _retire_thread(curthread->arch_id);
+ _thr_exit();
+
+ /* This point should not be reached. */
+ PANIC("Dead thread has resumed");
+}
diff --git a/lib/libthr/thread/thr_find_thread.c b/lib/libthr/thread/thr_find_thread.c
new file mode 100644
index 0000000..a784818
--- /dev/null
+++ b/lib/libthr/thread/thr_find_thread.c
@@ -0,0 +1,61 @@
+/*
+ * 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 "thr_private.h"
+
+/* Find a thread in the linked list of active threads: */
+int
+_find_thread(pthread_t pthread)
+{
+ pthread_t curthread;
+ pthread_t pthread1;
+
+ if (pthread == NULL || pthread->magic != PTHREAD_MAGIC)
+ return(EINVAL);
+
+ curthread = _get_curthread();
+ GIANT_LOCK(curthread);
+
+ /* Search for the specified thread: */
+ TAILQ_FOREACH(pthread1, &_thread_list, tle) {
+ if (pthread == pthread1)
+ break;
+ }
+
+ GIANT_UNLOCK(curthread);
+
+ /* Return zero if the thread exists: */
+ return ((pthread1 != NULL) ? 0:ESRCH);
+}
diff --git a/lib/libthr/thread/thr_gc.c b/lib/libthr/thread/thr_gc.c
new file mode 100644
index 0000000..987f88f
--- /dev/null
+++ b/lib/libthr/thread/thr_gc.c
@@ -0,0 +1,211 @@
+/*
+ * 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 "thr_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();
+
+ /*
+ * Lock the garbage collector mutex which ensures that
+ * this thread sees another thread exit:
+ */
+ if (pthread_mutex_lock(&_gc_mutex) != 0)
+ PANIC("Cannot lock gc mutex");
+
+ /* No stack or thread structure to free yet. */
+ p_stack = NULL;
+ pthread_cln = NULL;
+
+ GIANT_LOCK(curthread);
+
+ /* 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;
+
+ /*
+ * 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)) {
+ /* Don't destroy the initial thread. */
+ if (pthread == _thread_initial)
+ continue;
+ /*
+ * Check if this thread has detached:
+ */
+ 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;
+ }
+ }
+ }
+
+ GIANT_UNLOCK(curthread);
+ /*
+ * 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) {
+ _thread_printf("ret = %d", ret);
+ 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/libthr/thread/thr_getprio.c b/lib/libthr/thread/thr_getprio.c
new file mode 100644
index 0000000..fa95ef9
--- /dev/null
+++ b/lib/libthr/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 "thr_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/libthr/thread/thr_getschedparam.c b/lib/libthr/thread/thr_getschedparam.c
new file mode 100644
index 0000000..7f1503c
--- /dev/null
+++ b/lib/libthr/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 "thr_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/libthr/thread/thr_info.c b/lib/libthr/thread/thr_info.c
new file mode 100644
index 0000000..2e2f9de
--- /dev/null
+++ b/lib/libthr/thread/thr_info.c
@@ -0,0 +1,193 @@
+/*
+ * 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 "thr_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_MUTEX_WAIT , "Waiting on a mutex"},
+ {PS_COND_WAIT , "Waiting on a condition variable"},
+ {PS_SLEEP_WAIT , "Sleeping"},
+ {PS_WAIT_WAIT , "Waiting process"},
+ {PS_JOIN , "Waiting to join"},
+ {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];
+
+ 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);
+ }
+
+ /* 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);
+ }
+ }
+
+ /* 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) {
+ /*
+ * 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/libthr/thread/thr_init.c b/lib/libthr/thread/thr_init.c
new file mode 100644
index 0000000..266ff16
--- /dev/null
+++ b/lib/libthr/thread/thr_init.c
@@ -0,0 +1,363 @@
+/*
+ * 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 <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "un-namespace.h"
+
+#include "thr_private.h"
+
+/*
+ * All weak references used within libc should be in this table.
+ * This will is so that static libraries will work.
+ *
+ * XXXTHR - Check this list.
+ */
+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
+};
+
+int _pthread_guard_default;
+int _pthread_page_size;
+
+/*
+ * Threaded process initialization
+ */
+void
+_thread_init(void)
+{
+ struct pthread *pthread;
+ int fd;
+ int flags;
+ int i;
+ size_t len;
+ int mib[2];
+ sigset_t set;
+
+ struct clockinfo clockinfo;
+ struct sigaction act;
+
+ /* Check if this function has already been called: */
+ if (_thread_initial)
+ /* Only initialise the threaded application once. */
+ return;
+
+ _pthread_page_size = getpagesize();
+ _pthread_guard_default = getpagesize();
+
+ pthread_attr_default.guardsize_attr = _pthread_guard_default;
+
+
+ /*
+ * 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");
+ }
+
+ /* Allocate memory for the thread structure of the initial thread: */
+ if ((pthread = (pthread_t) malloc(sizeof(struct pthread))) == NULL) {
+ /*
+ * Insufficient memory to initialise this application, so
+ * abort:
+ */
+ PANIC("Cannot allocate memory for initial thread");
+ }
+ _thread_initial = pthread;
+ pthread->arch_id = _set_curthread(pthread);
+
+ /* Zero the initial thread structure: */
+ memset(pthread, 0, sizeof(struct pthread));
+ /* Get our thread id. */
+ thr_self(&pthread->thr_id);
+
+ /* Give this thread default attributes: */
+ memcpy((void *) &pthread->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. */
+ pthread->stack = _usrstack - PTHREAD_STACK_INITIAL;
+
+ /* Set the stack attributes. */
+ pthread->attr.stackaddr_attr = pthread->stack;
+ pthread->attr.stacksize_attr = PTHREAD_STACK_INITIAL;
+
+ /*
+ * Write a magic value to the thread structure
+ * to help identify valid ones:
+ */
+ pthread->magic = PTHREAD_MAGIC;
+
+ /* Set the initial cancel state */
+ pthread->cancelflags = PTHREAD_CANCEL_ENABLE | PTHREAD_CANCEL_DEFERRED;
+
+ /* Setup the context for initial thread. */
+ getcontext(&pthread->ctx);
+ pthread->ctx.uc_stack.ss_sp = pthread->stack;
+ pthread->ctx.uc_stack.ss_size = PTHREAD_STACK_INITIAL;
+
+ /* Default the priority of the initial thread: */
+ pthread->base_priority = PTHREAD_DEFAULT_PRIORITY;
+ pthread->active_priority = PTHREAD_DEFAULT_PRIORITY;
+ pthread->inherited_priority = 0;
+
+ /* Initialise the state of the initial thread: */
+ pthread->state = PS_RUNNING;
+
+ /* Set the name of the thread: */
+ pthread->name = strdup("_thread_initial");
+
+ /* Initialize joiner to NULL (no joiner): */
+ pthread->joiner = NULL;
+
+ /* Initialize the owned mutex queue and count: */
+ TAILQ_INIT(&(pthread->mutexq));
+ pthread->priority_mutex_count = 0;
+
+ /* Initialise the rest of the fields: */
+ pthread->specific = NULL;
+ pthread->cleanup = NULL;
+ pthread->flags = 0;
+ pthread->error = 0;
+ TAILQ_INIT(&_thread_list);
+ TAILQ_INSERT_HEAD(&_thread_list, pthread, tle);
+
+ /* 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)
+ continue;
+
+ /* Get the signal handler details. */
+ if (__sys_sigaction(i, NULL,
+ &_thread_sigact[i - 1]) != 0)
+ PANIC("Cannot read signal handler info");
+ }
+ act.sa_sigaction = _thread_sig_wrapper;
+ act.sa_flags = SA_SIGINFO;
+ SIGFILLSET(act.sa_mask);
+
+ if (__sys_sigaction(SIGTHR, &act, NULL))
+ PANIC("Cannot set SIGTHR handler.\n");
+
+ SIGEMPTYSET(set);
+ SIGADDSET(set, SIGTHR);
+ __sys_sigprocmask(SIG_BLOCK, &set, 0);
+
+ /* 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;
+
+ /* 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");
+}
+
+struct pthread *
+_get_curthread_slow(void)
+{
+ struct pthread *td;
+ thr_id_t id;
+
+ if (_thread_initial == NULL)
+ _thread_init();
+
+ thr_self(&id);
+ TAILQ_FOREACH(td, &_thread_list, tle)
+ if (td->thr_id == id)
+ return (td);
+ return (NULL);
+}
+
+/*
+ * 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/libthr/thread/thr_join.c b/lib/libthr/thread/thr_join.c
new file mode 100644
index 0000000..e22408c
--- /dev/null
+++ b/lib/libthr/thread/thr_join.c
@@ -0,0 +1,161 @@
+/*
+ * 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 "thr_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");
+
+ GIANT_LOCK(curthread);
+
+ /*
+ * 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)) {
+ if (pthread_mutex_unlock(&_gc_mutex) != 0)
+ PANIC("Cannot lock gc mutex");
+ ret = ESRCH;
+ goto out;
+
+ }
+ if (pthread->joiner != NULL) {
+ /* Multiple joiners are not supported. */
+ /* XXXTHR - support multiple joiners. */
+ if (pthread_mutex_unlock(&_gc_mutex) != 0)
+ PANIC("Cannot lock gc mutex");
+ ret = ENOTSUP;
+ goto out;
+
+ /* Check if the thread is not dead: */
+ }
+ /*
+ * 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");
+
+ 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) {
+ PTHREAD_SET_STATE(curthread, PS_JOIN);
+ /* Wait for our signal to wake up. */
+ _thread_suspend(curthread, NULL);
+ }
+
+ /*
+ * 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;
+
+ }
+
+out:
+ GIANT_UNLOCK(curthread);
+
+ _thread_leave_cancellation_point();
+
+ /* Return the completion status: */
+ return (ret);
+}
diff --git a/lib/libthr/thread/thr_kern.c b/lib/libthr/thread/thr_kern.c
new file mode 100644
index 0000000..1ad8526
--- /dev/null
+++ b/lib/libthr/thread/thr_kern.c
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 2003 Jeffrey Roberson <jeff@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 unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must 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 ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED 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 BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING 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/cdefs.h>
+#include <sys/types.h>
+#include <sys/signalvar.h>
+#include <sys/time.h>
+#include <sys/timespec.h>
+#include <pthread.h>
+#include <signal.h>
+#include <errno.h>
+
+#include "thr_private.h"
+
+/* XXX Why can't I get this from time.h? :-( */
+#define timespecsub(vvp, uvp) \
+ do { \
+ (vvp)->tv_sec -= (uvp)->tv_sec; \
+ (vvp)->tv_nsec -= (uvp)->tv_nsec; \
+ if ((vvp)->tv_nsec < 0) { \
+ (vvp)->tv_sec--; \
+ (vvp)->tv_nsec += 1000000000; \
+ } \
+ } while (0)
+
+static sigset_t restore;
+
+pthread_t _giant_owner = NULL;
+int _giant_count = 0;
+
+void
+GIANT_LOCK(pthread_t pthread)
+{
+ sigset_t set;
+ sigset_t sav;
+ int error;
+
+ if (_giant_owner == pthread) {
+ abort();
+ _giant_count++;
+ }
+
+ /*
+ * Block all signals.
+ */
+ SIGFILLSET(set);
+
+ /*
+ * We can not use the global 'restore' set until after we have
+ * acquired the giant lock.
+ */
+#if 0
+ error = __sys_sigprocmask(SIG_SETMASK, &set, &sav);
+ if (error) {
+ _thread_printf(0, "GIANT_LOCK: sig err %d\n", errno);
+ abort();
+ }
+#endif
+
+ error = umtx_lock(&_giant_mutex, pthread->thr_id);
+ if (error) {
+ _thread_printf(0, "GIANT_LOCK: %d\n", errno);
+ abort();
+ }
+
+ _giant_owner = pthread;
+ _giant_count = 1;
+
+ restore = sav;
+}
+
+void
+GIANT_UNLOCK(pthread_t pthread)
+{
+ sigset_t set;
+ int error;
+
+ if (_giant_owner != pthread)
+ abort();
+
+ if (--_giant_count > 0)
+ return;
+
+ _giant_owner = NULL;
+
+ /*
+ * restore is protected by giant. We could restore our signal state
+ * incorrectly if someone else set restore between unlocking giant
+ * and restoring the signal mask. To avoid this we cache a copy prior
+ * to the unlock.
+ */
+ set = restore;
+
+ error = umtx_unlock(&_giant_mutex, pthread->thr_id);
+ if (error) {
+ _thread_printf(0, "GIANT_UNLOCK: %d\n", errno);
+ abort();
+ }
+
+#if 0
+ /*
+ * Restore signals.
+ */
+ error = __sys_sigprocmask(SIG_SETMASK, &set, NULL);
+ if (error) {
+ _thread_printf(0, "GIANT_UNLOCK: sig err %d\n", errno);
+ abort();
+ }
+#endif
+}
+
+int
+_thread_suspend(pthread_t thread, struct timespec *abstime)
+{
+ struct timespec remaining;
+ struct timespec *ts;
+ siginfo_t info;
+ sigset_t set;
+ int giant_count; /* Saved recursion */
+ int error;
+
+ /*
+ * Catch SIGTHR.
+ */
+ SIGFILLSET(set);
+ SIGDELSET(set, SIGTHR);
+
+ if (abstime) {
+ struct timespec now;
+ struct timeval tv;
+
+ GET_CURRENT_TOD(tv);
+ TIMEVAL_TO_TIMESPEC(&tv, &now);
+
+ remaining = *abstime;
+ timespecsub(&remaining, &now);
+ ts = &remaining;
+ } else
+ ts = NULL;
+
+ /*
+ * Save and unroll the recursion count.
+ */
+ giant_count = _giant_count;
+ _giant_count = 1;
+ GIANT_UNLOCK(thread);
+
+ error = sigtimedwait(&set, &info, ts);
+ if (error == -1)
+ error = errno;
+
+ /* XXX Kernel bug. */
+ if (error == EINTR)
+ error = 0;
+
+ /*
+ * Restore the recursion count.
+ */
+ GIANT_LOCK(thread);
+ _giant_count = giant_count;
+
+ return (error);
+}
diff --git a/lib/libthr/thread/thr_main_np.c b/lib/libthr/thread/thr_main_np.c
new file mode 100644
index 0000000..1d5849d
--- /dev/null
+++ b/lib/libthr/thread/thr_main_np.c
@@ -0,0 +1,47 @@
+/*
+ * 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 "thr_private.h"
+
+__weak_reference(_pthread_main_np, pthread_main_np);
+
+/*
+ * Provide the equivelant to Solaris thr_main() function
+ */
+int
+_pthread_main_np()
+{
+
+ if (!_thread_initial)
+ return (-1);
+ else
+ return (pthread_equal(pthread_self(), _thread_initial) ? 1 : 0);
+}
diff --git a/lib/libthr/thread/thr_mattr_init.c b/lib/libthr/thread/thr_mattr_init.c
new file mode 100644
index 0000000..3d4195c
--- /dev/null
+++ b/lib/libthr/thread/thr_mattr_init.c
@@ -0,0 +1,56 @@
+/*
+ * 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 "thr_private.h"
+
+__weak_reference(_pthread_mutexattr_init, pthread_mutexattr_init);
+
+int
+_pthread_mutexattr_init(pthread_mutexattr_t *attr)
+{
+ pthread_mutexattr_t pattr;
+
+ if ((pattr = (pthread_mutexattr_t)
+ malloc(sizeof(struct pthread_mutex_attr))) == NULL)
+ return (ENOMEM);
+
+ memcpy(pattr, &pthread_mutexattr_default,
+ sizeof(struct pthread_mutex_attr));
+ *attr = pattr;
+
+ return (0);
+}
diff --git a/lib/libthr/thread/thr_mattr_kind_np.c b/lib/libthr/thread/thr_mattr_kind_np.c
new file mode 100644
index 0000000..f3d30ff
--- /dev/null
+++ b/lib/libthr/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 "thr_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/libthr/thread/thr_multi_np.c b/lib/libthr/thread/thr_multi_np.c
new file mode 100644
index 0000000..bd42365
--- /dev/null
+++ b/lib/libthr/thread/thr_multi_np.c
@@ -0,0 +1,50 @@
+/*
+ * 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 <pthread.h>
+#include <pthread_np.h>
+
+__weak_reference(_pthread_multi_np, pthread_multi_np);
+
+int
+_pthread_multi_np()
+{
+
+ /* Return to multi-threaded scheduling mode: */
+ /*
+ * XXX - Do we want to do this?
+ * __is_threaded = 1;
+ */
+ pthread_resume_all_np();
+ return (0);
+}
diff --git a/lib/libthr/thread/thr_mutex.c b/lib/libthr/thread/thr_mutex.c
new file mode 100644
index 0000000..9b57b69
--- /dev/null
+++ b/lib/libthr/thread/thr_mutex.c
@@ -0,0 +1,432 @@
+/*
+ * 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 "thr_private.h"
+
+/*
+ * Prototypes
+ */
+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)
+ return (EINVAL);
+ if (*mutex == NULL)
+ return (pthread_mutex_init(mutex, NULL));
+
+ (*mutex)->m_attr.m_type = PTHREAD_MUTEX_DEFAULT;
+ (*mutex)->m_attr.m_protocol = PTHREAD_PRIO_NONE;
+ (*mutex)->m_attr.m_ceiling = 0;
+ (*mutex)->m_attr.m_flags &= MUTEX_FLAGS_PRIVATE;
+ (*mutex)->m_attr.m_flags |= MUTEX_FLAGS_INITED;
+ bzero(&(*mutex)->m_mtx, sizeof(struct umtx));
+ (*mutex)->m_owner = NULL;
+ (*mutex)->m_count = 0;
+ (*mutex)->m_refcount = 0;
+
+ return (0);
+}
+
+int
+_pthread_mutex_init(pthread_mutex_t * mutex,
+ const pthread_mutexattr_t * mutex_attr)
+{
+ enum pthread_mutextype type;
+ pthread_mutex_t pmutex;
+
+ if (mutex == NULL)
+ return (EINVAL);
+
+ /*
+ * Allocate mutex.
+ */
+ pmutex = (pthread_mutex_t)calloc(1, sizeof(struct pthread_mutex));
+ if (pmutex == NULL)
+ return (ENOMEM);
+
+ bzero(pmutex, sizeof(*pmutex));
+
+ /* Set mutex attributes. */
+ if (mutex_attr == NULL || *mutex_attr == NULL) {
+ /* Default to a (error checking) POSIX mutex. */
+ pmutex->m_attr.m_type = PTHREAD_MUTEX_ERRORCHECK;
+ pmutex->m_attr.m_protocol = PTHREAD_PRIO_NONE;
+ pmutex->m_attr.m_ceiling = 0;
+ pmutex->m_attr.m_flags = 0;
+ } else
+ bcopy(*mutex_attr, &pmutex->m_attr, sizeof(mutex_attr));
+
+ /*
+ * Sanity check mutex type.
+ */
+ if ((pmutex->m_attr.m_type < PTHREAD_MUTEX_ERRORCHECK) ||
+ (pmutex->m_attr.m_type >= MUTEX_TYPE_MAX) ||
+ (pmutex->m_attr.m_protocol < PTHREAD_PRIO_NONE) ||
+ (pmutex->m_attr.m_protocol > PTHREAD_MUTEX_RECURSIVE))
+ goto err;
+
+
+ /*
+ * Initialize mutex.
+ */
+ pmutex->m_attr.m_flags |= MUTEX_FLAGS_INITED;
+ *mutex = pmutex;
+
+ return (0);
+err:
+ free(pmutex);
+ return (EINVAL);
+}
+
+int
+_pthread_mutex_destroy(pthread_mutex_t * mutex)
+{
+ int ret = 0;
+
+ if (mutex == NULL || *mutex == NULL)
+ return (EINVAL);
+
+ /* Ensure that the mutex is unlocked. */
+ if (((*mutex)->m_owner != NULL) ||
+ ((*mutex)->m_refcount != 0))
+ return (EBUSY);
+
+
+ /* Free it. */
+ free(*mutex);
+ *mutex = NULL;
+ return (0);
+}
+
+static int
+init_static(pthread_mutex_t *mutex)
+{
+ pthread_t curthread;
+ int ret;
+
+ curthread = _get_curthread();
+ GIANT_LOCK(curthread);
+ if (*mutex == NULL)
+ ret = pthread_mutex_init(mutex, NULL);
+ else
+ ret = 0;
+ GIANT_UNLOCK(curthread);
+ return (ret);
+}
+
+static int
+init_static_private(pthread_mutex_t *mutex)
+{
+ pthread_t curthread;
+ int ret;
+
+ curthread = _get_curthread();
+ GIANT_LOCK(curthread);
+ if (*mutex == NULL)
+ ret = pthread_mutex_init(mutex, &static_mattr);
+ else
+ ret = 0;
+ GIANT_UNLOCK(curthread);
+ return(ret);
+}
+
+static int
+mutex_trylock_common(pthread_mutex_t *mutex)
+{
+ struct pthread *curthread = _get_curthread();
+ int error;
+
+ PTHREAD_ASSERT((mutex != NULL) && (*mutex != NULL),
+ "Uninitialized mutex in pthread_mutex_trylock_common");
+
+ /*
+ * Attempt to obtain the lock.
+ */
+ if ((error = umtx_trylock(&(*mutex)->m_mtx, curthread->thr_id)) == 0) {
+ (*mutex)->m_owner = curthread;
+ TAILQ_INSERT_TAIL(&curthread->mutexq, *mutex, m_qe);
+
+ return (0);
+ }
+ /* The lock was invalid. */
+ if (error != EBUSY)
+ abort();
+
+ if ((*mutex)->m_owner == curthread) {
+ if ((*mutex)->m_attr.m_type == PTHREAD_MUTEX_RECURSIVE) {
+ (*mutex)->m_count++;
+ return (0);
+ } else
+ return (EDEADLK);
+ }
+
+ return (error);
+}
+
+int
+__pthread_mutex_trylock(pthread_mutex_t *mutex)
+{
+ int ret;
+
+ if (mutex == NULL)
+ return (EINVAL);
+
+ /*
+ * If the mutex is statically initialized, perform the dynamic
+ * initialization:
+ */
+ if ((*mutex == NULL) && (ret = init_static(mutex)) != 0)
+ return (ret);
+
+
+ return (mutex_trylock_common(mutex));
+}
+
+int
+_pthread_mutex_trylock(pthread_mutex_t *mutex)
+{
+ int ret;
+
+ if (mutex == NULL)
+ return (EINVAL);
+
+ /*
+ * If the mutex is statically initialized, perform the dynamic
+ * initialization marking the mutex private (delete safe):
+ */
+ if ((*mutex == NULL) && (ret = init_static_private(mutex)) != 0)
+ return (ret);
+
+ return (mutex_trylock_common(mutex));
+}
+
+static int
+mutex_lock_common(pthread_mutex_t * mutex)
+{
+ struct pthread *curthread = _get_curthread();
+ int giant_count;
+ int error;
+
+ PTHREAD_ASSERT((mutex != NULL) && (*mutex != NULL),
+ "Uninitialized mutex in pthread_mutex_trylock_common");
+
+ /*
+ * Obtain the lock.
+ */
+ if ((error = umtx_trylock(&(*mutex)->m_mtx, curthread->thr_id)) == 0) {
+ (*mutex)->m_owner = curthread;
+ TAILQ_INSERT_TAIL(&curthread->mutexq, *mutex, m_qe);
+
+ return (0);
+ }
+ /* The lock was invalid. */
+ if (error != EBUSY)
+ abort();
+
+ if ((*mutex)->m_owner == curthread) {
+ if ((*mutex)->m_attr.m_type == PTHREAD_MUTEX_RECURSIVE) {
+ (*mutex)->m_count++;
+
+ return (0);
+ } else
+ return (EDEADLK);
+ }
+
+ /*
+ * Lock Giant so we can save the recursion count and set our
+ * state. Then we'll call into the kernel to block on this mutex.
+ */
+
+ GIANT_LOCK(curthread);
+ PTHREAD_SET_STATE(curthread, PS_MUTEX_WAIT);
+ if (_giant_count != 1)
+ abort();
+ giant_count = _giant_count;
+
+ /*
+ * This will unwind all references.
+ */
+ _giant_count = 1;
+ GIANT_UNLOCK(curthread);
+
+ if ((error = umtx_lock(&(*mutex)->m_mtx, curthread->thr_id)) == 0) {
+ (*mutex)->m_owner = curthread;
+ TAILQ_INSERT_TAIL(&curthread->mutexq, *mutex, m_qe);
+ } else
+ _thread_printf(0, "umtx_lock(%d)\n", error);
+
+ /*
+ * Set our state and restore our recursion count.
+ */
+ GIANT_LOCK(curthread);
+ PTHREAD_SET_STATE(curthread, PS_RUNNING);
+
+ giant_count = _giant_count;
+ GIANT_UNLOCK(curthread);
+
+ return (error);
+}
+
+int
+__pthread_mutex_lock(pthread_mutex_t *mutex)
+{
+ int ret;
+
+ if (_thread_initial == NULL)
+ _thread_init();
+
+ if (mutex == NULL)
+ return (EINVAL);
+
+ /*
+ * If the mutex is statically initialized, perform the dynamic
+ * initialization:
+ */
+ if ((*mutex == NULL) && ((ret = init_static(mutex)) != 0))
+ return (ret);
+
+ return (mutex_lock_common(mutex));
+}
+
+int
+_pthread_mutex_lock(pthread_mutex_t *mutex)
+{
+ int ret = 0;
+
+ if (_thread_initial == NULL)
+ _thread_init();
+
+ if (mutex == NULL)
+ return (EINVAL);
+
+ /*
+ * If the mutex is statically initialized, perform the dynamic
+ * initialization marking it private (delete safe):
+ */
+ if ((*mutex == NULL) && ((ret = init_static_private(mutex)) != 0))
+ return (ret);
+
+ return (mutex_lock_common(mutex));
+}
+
+
+int
+_mutex_cv_unlock(pthread_mutex_t * mutex)
+{
+ int ret;
+
+ if ((ret = pthread_mutex_unlock(mutex)) == 0)
+ (*mutex)->m_refcount++;
+
+ return (ret);
+}
+
+int
+_mutex_cv_lock(pthread_mutex_t * mutex)
+{
+ int ret;
+
+
+ if ((ret = pthread_mutex_lock(mutex)) == 0)
+ (*mutex)->m_refcount--;
+
+ return (ret);
+}
+
+int
+_pthread_mutex_unlock(pthread_mutex_t * mutex)
+{
+ struct pthread *curthread = _get_curthread();
+ thr_id_t sav;
+ int ret = 0;
+
+ if (mutex == NULL || *mutex == NULL)
+ return (EINVAL);
+
+ if ((*mutex)->m_owner != curthread)
+ return (EPERM);
+
+ if ((*mutex)->m_count != 0) {
+ (*mutex)->m_count--;
+ return (0);
+ }
+
+ TAILQ_REMOVE(&curthread->mutexq, *mutex, m_qe);
+ (*mutex)->m_owner = NULL;
+
+ sav = (*mutex)->m_mtx.u_owner;
+ ret = umtx_unlock(&(*mutex)->m_mtx, curthread->thr_id);
+ if (ret) {
+ _thread_printf(0, "umtx_unlock(%d)", ret);
+ _thread_printf(0, "%x : %x : %x\n", curthread, (*mutex)->m_mtx.u_owner, sav);
+ }
+
+ return (ret);
+}
+
+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_attr.m_flags & MUTEX_FLAGS_PRIVATE) != 0)
+ pthread_mutex_unlock(&m);
+ }
+}
diff --git a/lib/libthr/thread/thr_mutex_prioceiling.c b/lib/libthr/thread/thr_mutex_prioceiling.c
new file mode 100644
index 0000000..4d50038
--- /dev/null
+++ b/lib/libthr/thread/thr_mutex_prioceiling.c
@@ -0,0 +1,122 @@
+/*
+ * 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 "thr_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)
+{
+ return (EINVAL);
+#if 0
+ 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);
+#endif
+}
+
+int
+_pthread_mutex_getprioceiling(pthread_mutex_t *mutex,
+ int *prioceiling)
+{
+ return (EINVAL);
+#if 0
+ int ret;
+
+ if ((mutex == NULL) || (*mutex == NULL))
+ ret = EINVAL;
+ else if ((*mutex)->m_attr.m_protocol != PTHREAD_PRIO_PROTECT)
+ ret = EINVAL;
+ else
+ ret = (*mutex)->m_attr.m_prio;
+
+ return (ret);
+#endif
+}
+
+int
+_pthread_mutex_setprioceiling(pthread_mutex_t *mutex,
+ int prioceiling, int *old_ceiling)
+{
+ return (EINVAL);
+#if 0
+ int ret = 0;
+
+ if ((mutex == NULL) || (*mutex == NULL))
+ ret = EINVAL;
+ else if ((*mutex)->m_protocol != PTHREAD_PRIO_PROTECT)
+ ret = EINVAL;
+ else {
+ /* Lock the mutex: */
+ if ((ret = pthread_mutex_lock(mutex)) == 0) {
+ /* Return the old ceiling and set the new ceiling: */
+ *old_ceiling = (*mutex)->m_prio;
+ (*mutex)->m_prio = prioceiling;
+
+ /* Unlock the mutex: */
+ ret = pthread_mutex_unlock(mutex);
+ }
+ }
+ return(ret);
+#endif
+}
diff --git a/lib/libthr/thread/thr_mutex_protocol.c b/lib/libthr/thread/thr_mutex_protocol.c
new file mode 100644
index 0000000..f7be5a6
--- /dev/null
+++ b/lib/libthr/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 "thr_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/libthr/thread/thr_mutexattr_destroy.c b/lib/libthr/thread/thr_mutexattr_destroy.c
new file mode 100644
index 0000000..b9852b5
--- /dev/null
+++ b/lib/libthr/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 "thr_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/libthr/thread/thr_once.c b/lib/libthr/thread/thr_once.c
new file mode 100644
index 0000000..cef478d
--- /dev/null
+++ b/lib/libthr/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 "thr_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/libthr/thread/thr_printf.c b/lib/libthr/thread/thr_printf.c
new file mode 100644
index 0000000..0da9ae5
--- /dev/null
+++ b/lib/libthr/thread/thr_printf.c
@@ -0,0 +1,124 @@
+/*-
+ * Copyright (c) 2002 Jonathan Mini <mini@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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/fcntl.h>
+#include <sys/uio.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <pthread.h>
+
+#include "thr_private.h"
+
+static void pchar(int fd, char c);
+static void pstr(int fd, const char *s);
+
+/*
+ * Write formatted output to stdout, in a thread-safe manner.
+ *
+ * Recognises the following conversions:
+ * %c -> char
+ * %d -> signed int (base 10)
+ * %s -> string
+ * %u -> unsigned int (base 10)
+ * %x -> unsigned int (base 16)
+ * %p -> unsigned int (base 16)
+ */
+void
+_thread_printf(int fd, const char *fmt, ...)
+{
+ static const char digits[16] = "0123456789abcdef";
+ va_list ap;
+ char buf[10];
+ char *s;
+ unsigned r, u;
+ int c, d;
+
+ va_start(ap, fmt);
+ while ((c = *fmt++)) {
+ if (c == '%') {
+ c = *fmt++;
+ switch (c) {
+ case 'c':
+ pchar(fd, va_arg(ap, int));
+ continue;
+ case 's':
+ pstr(fd, va_arg(ap, char *));
+ continue;
+ case 'd':
+ case 'u':
+ case 'p':
+ case 'x':
+ r = ((c == 'u') || (c == 'd')) ? 10 : 16;
+ if (c == 'd') {
+ d = va_arg(ap, unsigned);
+ if (d < 0) {
+ pchar(fd, '-');
+ u = (unsigned)(d * -1);
+ } else
+ u = (unsigned)d;
+ } else
+ u = va_arg(ap, unsigned);
+ s = buf;
+ do {
+ *s++ = digits[u % r];
+ } while (u /= r);
+ while (--s >= buf)
+ pchar(fd, *s);
+ continue;
+ }
+ }
+ pchar(fd, c);
+ }
+ va_end(ap);
+}
+
+/*
+ * Write a single character to stdout, in a thread-safe manner.
+ */
+static void
+pchar(int fd, char c)
+{
+
+ write(fd, &c, 1);
+}
+
+/*
+ * Write a string to stdout, in a thread-safe manner.
+ */
+static void
+pstr(int fd, const char *s)
+{
+
+ write(fd, s, strlen(s));
+}
+
diff --git a/lib/libthr/thread/thr_private.h b/lib/libthr/thread/thr_private.h
new file mode 100644
index 0000000..8a31ffa
--- /dev/null
+++ b/lib/libthr/thread/thr_private.h
@@ -0,0 +1,804 @@
+/*
+ * 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 _THR_PRIVATE_H
+#define _THR_PRIVATE_H
+
+/*
+ * Evaluate the storage class specifier.
+ */
+#ifdef GLOBAL_PTHREAD_PRIVATE
+#define SCLASS
+#else
+#define SCLASS extern
+#endif
+
+/*
+ * Include files.
+ */
+#include <sys/types.h>
+#include <sys/cdefs.h>
+#include <sys/errno.h>
+#include <sys/time.h>
+#include <sys/queue.h>
+#include <pthread_np.h>
+#include <sched.h>
+#include <signal.h>
+#include <spinlock.h>
+#include <stdio.h>
+#include <ucontext.h>
+
+#include <machine/atomic.h>
+#include <sys/thr.h>
+#include <sys/umtx.h>
+
+/*
+ * Kernel fatal error handler macro.
+ */
+#define PANIC(string) _thread_exit(__FILE__,__LINE__,string)
+
+
+/* Output debug messages like this: */
+#define stdout_debug(args...) _thread_printf(STDOUT_FILENO, args)
+#define stderr_debug(args...) _thread_printf(STDOUT_FILENO, args)
+
+/*
+ * 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 GIANT held.
+ */
+#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 ((thrd)->state != newstate) { \
+ if ((thrd)->state == PS_RUNNING) { \
+ PTHREAD_SET_STATE(thrd, newstate); \
+ } else if (newstate == PS_RUNNING) { \
+ if (thr_kill(thrd->thr_id, SIGTHR)) \
+ abort(); \
+ 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 (thr_kill(thrd->thr_id, SIGTHR)) \
+ abort(); \
+ PTHREAD_SET_STATE(thrd, newstate); \
+} while (0)
+#if 0
+#define PTHREAD_NEW_STATE(thrd, newstate) do { \
+ if ((thrd)->state != newstate) { \
+ if ((thrd)->state == PS_RUNNING) { \
+ } else if (newstate == PS_RUNNING) { \
+ if (thr_kill(thrd->thr_id, SIGTHR)) \
+ abort(); \
+ } \
+ } \
+ PTHREAD_SET_STATE(thrd, newstate); \
+} while (0)
+#endif
+#endif
+
+
+/*
+ * TailQ initialization values.
+ */
+#define TAILQ_INITIALIZER { NULL, NULL }
+
+#define UMTX_INITIALIZER { NULL, NULL }
+
+struct pthread_mutex_attr {
+ enum pthread_mutextype m_type;
+ int m_protocol;
+ int m_ceiling;
+ long m_flags;
+};
+
+/*
+ * Static mutex initialization values.
+ */
+
+#define PTHREAD_MUTEXATTR_STATIC_INITIALIZER \
+ { PTHREAD_MUTEX_DEFAULT, PTHREAD_PRIO_NONE, 0, MUTEX_FLAGS_PRIVATE }
+
+#define PTHREAD_MUTEX_STATIC_INITIALIZER \
+ { PTHREAD_MUTEXATTR_STATIC_INITIALIZER, UMTX_INITIALIZER, NULL, \
+ 0, 0, TAILQ_INITIALIZER }
+
+struct pthread_mutex {
+ struct pthread_mutex_attr m_attr; /* Mutex attributes. */
+ struct umtx m_mtx; /* Mutex. */
+ struct pthread *m_owner; /* Current owner. */
+ int m_count; /* Recursion count. */
+ int m_refcount; /* Reference count. */
+ TAILQ_ENTRY(pthread_mutex) m_qe; /* All locks held. */
+};
+
+/*
+ * Flags for mutexes.
+ */
+#define MUTEX_FLAGS_PRIVATE 0x01
+#define MUTEX_FLAGS_INITED 0x02
+#define MUTEX_FLAGS_BUSY 0x04
+
+/*
+ * 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.
+ */
+ struct umtx c_lock;
+};
+
+struct pthread_cond_attr {
+ enum pthread_cond_type c_type;
+ long c_flags;
+};
+
+/*
+ * Flags for condition variables.
+ */
+#define COND_FLAGS_INITED 0x01
+
+/*
+ * Static cond initialization values.
+ */
+#define PTHREAD_COND_STATIC_INITIALIZER \
+ { COND_TYPE_FAST, TAILQ_INITIALIZER, NULL, NULL, \
+ 0, 0, UMTX_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
+
+/*
+ * 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.
+ * This is declared and initialized in uthread_init.c.
+ */
+extern int _pthread_guard_default;
+
+extern int _pthread_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
+
+/*
+ * 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
+
+/*
+ * XXX 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) gettimeofday(&(tv), NULL)
+
+
+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_MUTEX_WAIT,
+ PS_COND_WAIT,
+ PS_SLEEP_WAIT, /* XXX We need to wrap syscalls to set this state */
+ PS_WAIT_WAIT,
+ PS_JOIN,
+ 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)
+
+union pthread_wait_data {
+ pthread_mutex_t mutex;
+ pthread_cond_t cond;
+ spinlock_t *spinlock;
+ struct pthread *thread;
+};
+
+struct join_status {
+ struct pthread *thread;
+ void *ret;
+ int error;
+};
+
+struct pthread_state_data {
+ union pthread_wait_data psd_wait_data;
+ enum pthread_state psd_state;
+ int psd_flags;
+};
+
+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 */
+ thr_id_t thr_id;
+
+ /*
+ * 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;
+
+ /*
+ * Machine context, including signal state.
+ */
+ ucontext_t ctx;
+
+ /*
+ * Cancelability flags - the lower 2 bits are used by cancel
+ * definitions in pthread.h
+ */
+#define PTHREAD_AT_CANCEL_POINT 0x0004
+#define PTHREAD_CANCELLING 0x0008
+
+ /*
+ * Protected by Giant.
+ */
+ int cancelflags;
+
+ /* Thread state: */
+ enum pthread_state state;
+
+ /*
+ * 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;
+
+ /*
+ * A thread can belong to:
+ *
+ * o A queue of threads waiting for a mutex
+ * o A queue of threads waiting for a condition variable
+ *
+ * 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 sqe for synchronization (mutex and condition variable) queue
+ * links.
+ */
+ TAILQ_ENTRY(pthread) sqe; /* synchronization queue link */
+
+ /* Wait data. */
+ union pthread_wait_data data;
+
+ /* Miscellaneous flags; only set with signals deferred. */
+ int flags;
+#define PTHREAD_FLAGS_PRIVATE 0x0001
+#define PTHREAD_EXITING 0x0002
+#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_SUSPENDED 0x0200 /* thread is suspended */
+#define PTHREAD_FLAGS_TRACE 0x0400 /* 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;
+
+ /*
+ * Architecture specific id field used for _{get, set}_curthread()
+ * interface.
+ */
+ void *arch_id;
+
+ /* 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
+
+/* List of all threads: */
+SCLASS TAILQ_HEAD(, pthread) _thread_list
+#ifdef GLOBAL_PTHREAD_PRIVATE
+= TAILQ_HEAD_INITIALIZER(_thread_list);
+#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, -1 };
+#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
+
+SCLASS int _clock_res_usec /* Clock resolution in usec. */
+#ifdef GLOBAL_PTHREAD_PRIVATE
+= CLOCK_RES_USEC;
+#else
+;
+#endif
+
+/* Giant lock. */
+SCLASS struct umtx _giant_mutex
+#ifdef GLOBAL_PTHREAD_PRIVATE
+= UMTX_INITIALIZER
+#endif
+;
+
+SCLASS int _giant_count;
+
+/* 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];
+
+/* Tracks the number of threads blocked while waiting for a spinlock. */
+SCLASS volatile int _spinblock_count
+#ifdef GLOBAL_PTHREAD_PRIVATE
+= 0
+#endif
+;
+
+/*
+ * And, should we climb the beanstalk,
+ * We'll meet his brother, Giant.
+ */
+void GIANT_LOCK(pthread_t curthread);
+void GIANT_UNLOCK(pthread_t curthread);
+
+/* Undefine the storage class specifier: */
+#undef SCLASS
+
+/*
+ * Function prototype definitions.
+ */
+__BEGIN_DECLS
+char *__ttyname_basic(int);
+char *__ttyname_r_basic(int, char *, size_t);
+char *ttyname_r(int, char *, size_t);
+void _cond_wait_backout(pthread_t);
+int _find_thread(pthread_t);
+struct pthread *_get_curthread_slow(void);
+struct pthread *_get_curthread(void);
+void *_set_curthread(struct pthread *);
+void _retire_thread(void *arch_id);
+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 _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 *);
+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 _thread_exit(char *, int, char *);
+void _thread_exit_cleanup(void);
+void *_thread_cleanup(pthread_t);
+void _thread_cleanupspecific(void);
+void _thread_dump_info(void);
+void _thread_init(void);
+void _thread_sig_wrapper(int sig, siginfo_t *info, ucontext_t *context);
+void _thread_printf(int fd, const char *, ...);
+void _thread_start(void);
+void _thread_seterrno(pthread_t, int);
+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);
+int _thread_suspend(pthread_t thread, struct timespec *abstime);
+
+/* #include <sys/aio.h> */
+#ifdef _SYS_AIO_H_
+int __sys_aio_suspend(const struct aiocb * const[], int, const struct timespec *);
+#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
+
+__END_DECLS
+
+#endif /* !_PTHREAD_PRIVATE_H */
diff --git a/lib/libthr/thread/thr_resume_np.c b/lib/libthr/thread/thr_resume_np.c
new file mode 100644
index 0000000..783c45f
--- /dev/null
+++ b/lib/libthr/thread/thr_resume_np.c
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE 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 "thr_private.h"
+
+static void resume_common(struct pthread *);
+
+__weak_reference(_pthread_resume_np, pthread_resume_np);
+__weak_reference(_pthread_resume_all_np, pthread_resume_all_np);
+
+/* Resume a thread: */
+int
+_pthread_resume_np(pthread_t thread)
+{
+ int ret;
+
+ /* Find the thread in the list of active threads: */
+ if ((ret = _find_thread(thread)) == 0) {
+ pthread_t curthread;
+
+ curthread = _get_curthread();
+ GIANT_LOCK(curthread);
+
+ if ((thread->flags & PTHREAD_FLAGS_SUSPENDED) != 0)
+ resume_common(thread);
+
+ GIANT_UNLOCK(curthread);
+ }
+ return (ret);
+}
+
+void
+_pthread_resume_all_np(void)
+{
+ struct pthread *curthread = _get_curthread();
+ struct pthread *thread;
+
+ GIANT_LOCK(curthread);
+
+ TAILQ_FOREACH(thread, &_thread_list, tle) {
+ if ((thread != curthread) &&
+ ((thread->flags & PTHREAD_FLAGS_SUSPENDED) != 0))
+ resume_common(thread);
+ }
+
+ GIANT_UNLOCK(curthread);
+}
+
+static void
+resume_common(struct pthread *thread)
+{
+ thread->flags &= ~PTHREAD_FLAGS_SUSPENDED;
+ if (thr_kill(thread->thr_id, SIGTHR))
+ abort();
+}
diff --git a/lib/libthr/thread/thr_rwlock.c b/lib/libthr/thread/thr_rwlock.c
new file mode 100644
index 0000000..f41e8a2
--- /dev/null
+++ b/lib/libthr/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 "thr_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/libthr/thread/thr_rwlockattr.c b/lib/libthr/thread/thr_rwlockattr.c
new file mode 100644
index 0000000..8c0697b
--- /dev/null
+++ b/lib/libthr/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 "thr_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/libthr/thread/thr_self.c b/lib/libthr/thread/thr_self.c
new file mode 100644
index 0000000..d213e5e
--- /dev/null
+++ b/lib/libthr/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 "thr_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/libthr/thread/thr_sem.c b/lib/libthr/thread/thr_sem.c
new file mode 100644
index 0000000..17059e3
--- /dev/null
+++ b/lib/libthr/thread/thr_sem.c
@@ -0,0 +1,257 @@
+/*
+ * 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 "thr_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)
+{
+ pthread_t curthread;
+ int retval;
+
+ _SEM_CHECK_VALIDITY(sem);
+
+ curthread = _get_curthread();
+ /*
+ * sem_post() is required to be safe to call from within signal
+ * handlers. Thus, we must defer signals.
+ */
+ pthread_mutex_lock(&(*sem)->lock);
+
+ /* GIANT_LOCK(curthread); */
+
+ (*sem)->count++;
+ if ((*sem)->nwaiters > 0)
+ pthread_cond_signal(&(*sem)->gtzero);
+
+ /* GIANT_UNLOCK(curthread); */
+
+ pthread_mutex_unlock(&(*sem)->lock);
+
+ 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/libthr/thread/thr_seterrno.c b/lib/libthr/thread/thr_seterrno.c
new file mode 100644
index 0000000..ec801d6
--- /dev/null
+++ b/lib/libthr/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 "thr_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/libthr/thread/thr_setprio.c b/lib/libthr/thread/thr_setprio.c
new file mode 100644
index 0000000..c5a9506
--- /dev/null
+++ b/lib/libthr/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 "thr_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/libthr/thread/thr_setschedparam.c b/lib/libthr/thread/thr_setschedparam.c
new file mode 100644
index 0000000..f9551e0
--- /dev/null
+++ b/lib/libthr/thread/thr_setschedparam.c
@@ -0,0 +1,115 @@
+/*
+ * 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 "thr_private.h"
+
+__weak_reference(_pthread_setschedparam, pthread_setschedparam);
+
+int
+_pthread_setschedparam(pthread_t pthread, int policy,
+ const struct sched_param *param)
+{
+#if 0 /* XXXTHR */
+ int old_prio, in_readyq = 0, ret = 0;
+#endif
+
+ if ((param == NULL) || (policy < SCHED_FIFO) || (policy > SCHED_RR))
+ return (EINVAL);
+
+ if ((param->sched_priority < PTHREAD_MIN_PRIORITY) ||
+ (param->sched_priority > PTHREAD_MAX_PRIORITY))
+ return (ENOTSUP);
+
+ return (0);
+#if 0 /* XXXTHR */
+ /* Find the thread in the list of active threads: */
+ if ((ret = _find_thread(pthread)) == 0) {
+ GIANT_LOCK();
+
+ 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;
+
+ GIANT_UNLOCK();
+ }
+ return(ret);
+#endif
+}
diff --git a/lib/libthr/thread/thr_sig.c b/lib/libthr/thread/thr_sig.c
new file mode 100644
index 0000000..3aee706
--- /dev/null
+++ b/lib/libthr/thread/thr_sig.c
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2003 Jeffrey Roberson <jeff@freebsd.org>
+ * Copyright (c) 2003 Jonathan Mini <mini@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 unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must 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 ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED 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 BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING 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 "thr_private.h"
+
+/* #define DEBUG_SIGNAL */
+#ifdef DEBUG_SIGNAL
+#define DBG_MSG stdout_debug
+#else
+#define DBG_MSG(x...)
+#endif
+
+__weak_reference(_sigprocmask, sigprocmask);
+
+int
+_sigprocmask(int how, const sigset_t *set, sigset_t *oset)
+{
+ sigset_t new;
+
+ /*
+ * Make sure applications can't unblock our synchronization
+ * signal. We always want to take this with sigwait().
+ */
+ if (set != NULL) {
+ new = *set;
+ switch (how) {
+ case SIG_BLOCK:
+ case SIG_SETMASK:
+ SIGADDSET(new, SIGTHR);
+ break;
+ case SIG_UNBLOCK:
+ SIGDELSET(new, SIGTHR);
+ break;
+ default:
+ break;
+ }
+ set = &new;
+ }
+
+ return (__sys_sigprocmask(how, set, oset));
+}
+
+__weak_reference(_pthread_sigmask, pthread_sigmask);
+
+int
+_pthread_sigmask(int how, const sigset_t *set, sigset_t *oset)
+{
+ int error;
+
+ /*
+ * This always sets the mask on the current thread.
+ */
+ error = sigprocmask(how, set, oset);
+
+ /*
+ * pthread_sigmask returns errno or success while sigprocmask returns
+ * -1 and sets errno.
+ */
+ if (error == -1)
+ error = errno;
+
+ return (error);
+}
+
+
+__weak_reference(_pthread_kill, pthread_kill);
+
+int
+_pthread_kill(pthread_t pthread, int sig)
+{
+
+ if (_thread_initial == NULL)
+ _thread_init();
+ return (thr_kill(pthread->thr_id, sig));
+}
+
+/*
+ * User thread signal handler wrapper.
+ */
+void
+_thread_sig_wrapper(int sig, siginfo_t *info, ucontext_t *context)
+{
+ struct pthread_state_data psd;
+ struct pthread *curthread = _get_curthread();
+ __siginfohandler_t *handler;
+
+ GIANT_LOCK(curthread);
+ /* Save the thread's previous state. */
+ curthread->data = psd.psd_wait_data;
+ curthread->state = psd.psd_state;
+ curthread->flags = psd.psd_flags;
+
+ /* Check the threads previous state: */
+ if (psd.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 (psd.psd_state) {
+ case PS_COND_WAIT:
+ _cond_wait_backout(curthread);
+ psd.psd_state = PS_RUNNING;
+ break;
+
+ case PS_MUTEX_WAIT:
+ /* _mutex_lock_backout(curthread); XXXTHR */
+ psd.psd_state = PS_RUNNING;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (_thread_sigact[sig -1].sa_handler != NULL) {
+ GIANT_UNLOCK(curthread);
+ handler = (__siginfohandler_t *)
+ _thread_sigact[sig - 1].sa_handler;
+ handler(sig, info, context);
+ GIANT_LOCK(curthread);
+ }
+
+ /* Restore the signal frame. */
+ psd.psd_wait_data = curthread->data;
+ psd.psd_state = curthread->state;
+ psd.psd_flags = curthread->flags &
+ (PTHREAD_FLAGS_PRIVATE | PTHREAD_FLAGS_TRACE);
+ GIANT_UNLOCK(curthread);
+}
diff --git a/lib/libthr/thread/thr_spec.c b/lib/libthr/thread/thr_spec.c
new file mode 100644
index 0000000..07ef387
--- /dev/null
+++ b/lib/libthr/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 "thr_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/libthr/thread/thr_spinlock.c b/lib/libthr/thread/thr_spinlock.c
new file mode 100644
index 0000000..20b33f2
--- /dev/null
+++ b/lib/libthr/thread/thr_spinlock.c
@@ -0,0 +1,88 @@
+/*
+ * 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 "thr_private.h"
+
+void
+_spinunlock(spinlock_t *lck)
+{
+ struct pthread *curthread = _get_curthread();
+
+ if (umtx_unlock((struct umtx *)lck, curthread->thr_id))
+ abort();
+}
+
+/*
+ * 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();
+
+ if (umtx_lock((struct umtx *)lck, curthread->thr_id))
+ abort();
+}
+
+/*
+ * 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();
+
+ if (umtx_lock((struct umtx *)lck, curthread->thr_id))
+ abort();
+}
diff --git a/lib/libthr/thread/thr_stack.c b/lib/libthr/thread/thr_stack.c
new file mode 100644
index 0000000..c75d6ee
--- /dev/null
+++ b/lib/libthr/thread/thr_stack.c
@@ -0,0 +1,240 @@
+/*
+ * 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 "thr_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 _pthread_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 % _pthread_page_size != 0)
+ stack_size = ((stacksize / _pthread_page_size) + 1) *
+ _pthread_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 _pthread_page_size. */
+ if (stacksize % _pthread_page_size != 0) {
+ spare_stack->stacksize =
+ ((stacksize / _pthread_page_size) + 1) *
+ _pthread_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/libthr/thread/thr_suspend_np.c b/lib/libthr/thread/thr_suspend_np.c
new file mode 100644
index 0000000..7fa668d
--- /dev/null
+++ b/lib/libthr/thread/thr_suspend_np.c
@@ -0,0 +1,53 @@
+/*
+ * 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 "thr_private.h"
+
+__weak_reference(_pthread_suspend_np, pthread_suspend_np);
+__weak_reference(_pthread_suspend_all_np, pthread_suspend_all_np);
+
+/* Suspend a thread: */
+int
+_pthread_suspend_np(pthread_t thread)
+{
+ /* XXXTHR */
+ return (-1);
+}
+
+void
+_pthread_suspend_all_np(void)
+{
+ /* XXXTHR */
+}
diff --git a/lib/libthr/thread/thr_syscalls.c b/lib/libthr/thread/thr_syscalls.c
new file mode 100644
index 0000000..d8fa348
--- /dev/null
+++ b/lib/libthr/thread/thr_syscalls.c
@@ -0,0 +1,418 @@
+/*
+ * Copyright (c) 2000 Jason Evans <jasone@freebsd.org>.
+ * Copyright (c) 2002 Daniel M. Eischen <deischen@freebsd.org>
+ * Copyright (c) 2003 Jeff Roberson <jeff@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$
+ */
+
+/*
+ * 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.
+ *
+ */
+
+#include <sys/cdefs.h>
+#include <sys/fcntl.h>
+#include <sys/mman.h>
+#include <sys/param.h>
+#include <sys/select.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/wait.h>
+
+#include <aio.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+
+#include "thr_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;
+}
+
+__weak_reference(__close, close);
+
+int
+__close(int fd)
+{
+ int ret;
+
+ _thread_enter_cancellation_point();
+ ret = __sys_close(fd);
+ _thread_leave_cancellation_point();
+
+ return ret;
+}
+__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;
+}
+
+__weak_reference(__fcntl, fcntl);
+
+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 = __sys_fcntl(fd, cmd, va_arg(ap, int));
+ break;
+ case F_GETFD:
+ case F_GETFL:
+ ret = __sys_fcntl(fd, cmd);
+ break;
+ default:
+ ret = __sys_fcntl(fd, cmd, va_arg(ap, void *));
+ }
+ va_end(ap);
+
+ _thread_leave_cancellation_point();
+
+ return ret;
+}
+
+__weak_reference(__fsync, fsync);
+
+int
+__fsync(int fd)
+{
+ int ret;
+
+ _thread_enter_cancellation_point();
+ ret = __sys_fsync(fd);
+ _thread_leave_cancellation_point();
+
+ return ret;
+}
+
+__weak_reference(__msync, msync);
+
+int
+__msync(void *addr, size_t len, int flags)
+{
+ int ret;
+
+ _thread_enter_cancellation_point();
+ ret = __sys_msync(addr, len, flags);
+ _thread_leave_cancellation_point();
+
+ return ret;
+}
+
+__weak_reference(_nanosleep, nanosleep);
+
+int
+_nanosleep(const struct timespec * time_to_sleep, struct timespec *
+ time_remaining)
+{
+ int ret;
+
+ _thread_enter_cancellation_point();
+ ret = __sys_nanosleep(time_to_sleep, time_remaining);
+ _thread_leave_cancellation_point();
+
+ return ret;
+}
+
+__weak_reference(__open, open);
+
+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 = __sys_open(path, flags, mode);
+ _thread_leave_cancellation_point();
+
+ return ret;
+}
+
+__weak_reference(__poll, poll);
+
+int
+__poll(struct pollfd *fds, unsigned int nfds, int timeout)
+{
+ int ret;
+
+ _thread_enter_cancellation_point();
+ ret = __sys_poll(fds, nfds, timeout);
+ _thread_leave_cancellation_point();
+
+ return ret;
+}
+
+extern int __pselect(int count, fd_set *rfds, fd_set *wfds, fd_set *efds,
+ const struct timespec *timo, const sigset_t *mask);
+
+int
+pselect(int count, fd_set *rfds, fd_set *wfds, fd_set *efds,
+ const struct timespec *timo, const sigset_t *mask)
+{
+ int ret;
+
+ _thread_enter_cancellation_point();
+ ret = __pselect(count, rfds, wfds, efds, timo, mask);
+ _thread_leave_cancellation_point();
+
+ return (ret);
+}
+
+__weak_reference(__read, read);
+
+ssize_t
+__read(int fd, void *buf, size_t nbytes)
+{
+ ssize_t ret;
+
+ _thread_enter_cancellation_point();
+ ret = __sys_read(fd, buf, nbytes);
+ _thread_leave_cancellation_point();
+
+ return ret;
+}
+
+__weak_reference(__readv, readv);
+
+ssize_t
+__readv(int fd, const struct iovec *iov, int iovcnt)
+{
+ ssize_t ret;
+
+ _thread_enter_cancellation_point();
+ ret = __sys_readv(fd, iov, iovcnt);
+ _thread_leave_cancellation_point();
+
+ return ret;
+}
+
+__weak_reference(__select, select);
+
+int
+__select(int numfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
+ struct timeval *timeout)
+{
+ int ret;
+
+ _thread_enter_cancellation_point();
+ ret = __sys_select(numfds, readfds, writefds, exceptfds, timeout);
+ _thread_leave_cancellation_point();
+
+ return ret;
+}
+
+__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;
+}
+
+__weak_reference(_system, system);
+
+int
+_system(const char *string)
+{
+ int ret;
+
+ _thread_enter_cancellation_point();
+ ret = __system(string);
+ _thread_leave_cancellation_point();
+
+ return ret;
+}
+
+
+__weak_reference(_tcdrain, tcdrain);
+
+int
+_tcdrain(int fd)
+{
+ int ret;
+
+ _thread_enter_cancellation_point();
+ ret = __tcdrain(fd);
+ _thread_leave_cancellation_point();
+
+ return ret;
+}
+
+__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;
+}
+
+__weak_reference(__wait4, wait4);
+
+pid_t
+__wait4(pid_t pid, int *istat, int options, struct rusage *rusage)
+{
+ pid_t ret;
+
+ _thread_enter_cancellation_point();
+ ret = _wait4(pid, istat, options, rusage);
+ _thread_leave_cancellation_point();
+
+ return ret;
+}
+
+__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;
+}
+
+__weak_reference(__write, write);
+
+ssize_t
+__write(int fd, const void *buf, size_t nbytes)
+{
+ ssize_t ret;
+
+ _thread_enter_cancellation_point();
+ ret = __sys_write(fd, buf, nbytes);
+ _thread_leave_cancellation_point();
+
+ return ret;
+}
+
+__weak_reference(__writev, writev);
+
+ssize_t
+__writev(int fd, const struct iovec *iov, int iovcnt)
+{
+ ssize_t ret;
+
+ _thread_enter_cancellation_point();
+ ret = __sys_writev(fd, iov, iovcnt);
+ _thread_leave_cancellation_point();
+
+ return ret;
+}
diff --git a/lib/libthr/thread/thr_yield.c b/lib/libthr/thread/thr_yield.c
new file mode 100644
index 0000000..2c96820
--- /dev/null
+++ b/lib/libthr/thread/thr_yield.c
@@ -0,0 +1,45 @@
+/*
+ * 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 "thr_private.h"
+
+__weak_reference(_pthread_yield, pthread_yield);
+
+/* Draft 4 yield */
+void
+_pthread_yield(void)
+{
+
+ sched_yield();
+}
OpenPOWER on IntegriCloud