summaryrefslogtreecommitdiffstats
path: root/lib/libthr
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libthr')
-rw-r--r--lib/libthr/Makefile55
-rw-r--r--lib/libthr/arch/alpha/Makefile.inc5
-rw-r--r--lib/libthr/arch/alpha/alpha/pthread_md.c53
-rw-r--r--lib/libthr/arch/alpha/include/pthread_md.h75
-rw-r--r--lib/libthr/arch/amd64/Makefile.inc5
-rw-r--r--lib/libthr/arch/amd64/amd64/pthread_md.c55
-rw-r--r--lib/libthr/arch/amd64/include/pthread_md.h99
-rw-r--r--lib/libthr/arch/arm/Makefile.inc5
-rw-r--r--lib/libthr/arch/arm/arm/pthread_md.c50
-rw-r--r--lib/libthr/arch/arm/include/pthread_md.h83
-rw-r--r--lib/libthr/arch/i386/Makefile.inc5
-rw-r--r--lib/libthr/arch/i386/i386/pthread_md.c57
-rw-r--r--lib/libthr/arch/i386/include/pthread_md.h103
-rw-r--r--lib/libthr/arch/ia64/Makefile.inc5
-rw-r--r--lib/libthr/arch/ia64/ia64/pthread_md.c58
-rw-r--r--lib/libthr/arch/ia64/include/pthread_md.h78
-rw-r--r--lib/libthr/arch/powerpc/Makefile.inc5
-rw-r--r--lib/libthr/arch/powerpc/include/pthread_md.h80
-rw-r--r--lib/libthr/arch/powerpc/powerpc/pthread_md.c58
-rw-r--r--lib/libthr/arch/sparc64/Makefile.inc5
-rw-r--r--lib/libthr/arch/sparc64/include/pthread_md.h87
-rw-r--r--lib/libthr/arch/sparc64/sparc64/pthread_md.c56
-rw-r--r--lib/libthr/libthr.370
-rw-r--r--lib/libthr/pthread.map761
-rw-r--r--lib/libthr/support/Makefile.inc22
-rw-r--r--lib/libthr/sys/Makefile.inc5
-rw-r--r--lib/libthr/sys/thr_error.c54
-rw-r--r--lib/libthr/thread/Makefile.inc54
-rw-r--r--lib/libthr/thread/thr_atfork.c57
-rw-r--r--lib/libthr/thread/thr_attr.c540
-rw-r--r--lib/libthr/thread/thr_autoinit.c65
-rw-r--r--lib/libthr/thread/thr_barrier.c111
-rw-r--r--lib/libthr/thread/thr_barrierattr.c96
-rw-r--r--lib/libthr/thread/thr_cancel.c163
-rw-r--r--lib/libthr/thread/thr_clean.c78
-rw-r--r--lib/libthr/thread/thr_concurrency.c65
-rw-r--r--lib/libthr/thread/thr_cond.c350
-rw-r--r--lib/libthr/thread/thr_condattr.c130
-rw-r--r--lib/libthr/thread/thr_create.c251
-rw-r--r--lib/libthr/thread/thr_detach.c71
-rw-r--r--lib/libthr/thread/thr_equal.c46
-rw-r--r--lib/libthr/thread/thr_event.c65
-rw-r--r--lib/libthr/thread/thr_exit.c146
-rw-r--r--lib/libthr/thread/thr_fork.c198
-rw-r--r--lib/libthr/thread/thr_getprio.c58
-rw-r--r--lib/libthr/thread/thr_getschedparam.c77
-rw-r--r--lib/libthr/thread/thr_info.c73
-rw-r--r--lib/libthr/thread/thr_init.c466
-rw-r--r--lib/libthr/thread/thr_join.c146
-rw-r--r--lib/libthr/thread/thr_kern.c98
-rw-r--r--lib/libthr/thread/thr_kill.c69
-rw-r--r--lib/libthr/thread/thr_list.c343
-rw-r--r--lib/libthr/thread/thr_main_np.c50
-rw-r--r--lib/libthr/thread/thr_multi_np.c53
-rw-r--r--lib/libthr/thread/thr_mutex.c669
-rw-r--r--lib/libthr/thread/thr_mutex_prioceiling.c116
-rw-r--r--lib/libthr/thread/thr_mutex_protocol.c71
-rw-r--r--lib/libthr/thread/thr_mutexattr.c262
-rw-r--r--lib/libthr/thread/thr_once.c99
-rw-r--r--lib/libthr/thread/thr_printf.c135
-rw-r--r--lib/libthr/thread/thr_private.h741
-rw-r--r--lib/libthr/thread/thr_pspinlock.c136
-rw-r--r--lib/libthr/thread/thr_resume_np.c94
-rw-r--r--lib/libthr/thread/thr_rtld.c219
-rw-r--r--lib/libthr/thread/thr_rwlock.c417
-rw-r--r--lib/libthr/thread/thr_rwlockattr.c100
-rw-r--r--lib/libthr/thread/thr_self.c50
-rw-r--r--lib/libthr/thread/thr_sem.c271
-rw-r--r--lib/libthr/thread/thr_seterrno.c59
-rw-r--r--lib/libthr/thread/thr_setprio.c56
-rw-r--r--lib/libthr/thread/thr_setschedparam.c95
-rw-r--r--lib/libthr/thread/thr_sig.c284
-rw-r--r--lib/libthr/thread/thr_sigmask.c52
-rw-r--r--lib/libthr/thread/thr_single_np.c52
-rw-r--r--lib/libthr/thread/thr_spec.c230
-rw-r--r--lib/libthr/thread/thr_spinlock.c126
-rw-r--r--lib/libthr/thread/thr_stack.c256
-rw-r--r--lib/libthr/thread/thr_suspend_np.c145
-rw-r--r--lib/libthr/thread/thr_switch_np.c57
-rw-r--r--lib/libthr/thread/thr_symbols.c61
-rw-r--r--lib/libthr/thread/thr_syscalls.c675
-rw-r--r--lib/libthr/thread/thr_umtx.c83
-rw-r--r--lib/libthr/thread/thr_umtx.h87
-rw-r--r--lib/libthr/thread/thr_yield.c48
84 files changed, 11659 insertions, 0 deletions
diff --git a/lib/libthr/Makefile b/lib/libthr/Makefile
new file mode 100644
index 0000000..37073ea
--- /dev/null
+++ b/lib/libthr/Makefile
@@ -0,0 +1,55 @@
+# $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.
+
+.if ${MACHINE_ARCH} == "alpha" || ${MACHINE_ARCH} == "sparc64"
+SHLIBDIR?= /lib
+.endif
+
+.include <bsd.own.mk>
+
+LIB=thr
+SHLIB_MAJOR= 2
+CFLAGS+=-DPTHREAD_KERNEL
+CFLAGS+=-I${.CURDIR}/../libc/include -I${.CURDIR}/thread \
+ -I${.CURDIR}/../../include
+CFLAGS+=-I${.CURDIR}/arch/${MACHINE_ARCH}/include
+CFLAGS+=-I${.CURDIR}/sys
+CFLAGS+=-I${.CURDIR}/../../libexec/rtld-elf
+CFLAGS+=-I${.CURDIR}/../../libexec/rtld-elf/${MACHINE_ARCH}
+CFLAGS+=-I${.CURDIR}/../libthread_db
+CFLAGS+=-Winline
+
+# CFLAGS+=-DSYSTEM_SCOPE_ONLY
+
+LDFLAGS= -Wl,--version-script=${.CURDIR}/pthread.map
+
+MAN= libthr.3
+
+# enable extra internal consistancy checks
+CFLAGS+=-D_PTHREADS_INVARIANTS -Wall
+#CFLAGS+=-g
+
+PRECIOUSLIB=
+
+.include "${.CURDIR}/arch/${MACHINE_ARCH}/Makefile.inc"
+.include "${.CURDIR}/sys/Makefile.inc"
+.include "${.CURDIR}/thread/Makefile.inc"
+
+.if ${MACHINE_ARCH} == "alpha" || ${MACHINE_ARCH} == "sparc64"
+SYMLINKS+=lib${LIB}.a ${LIBDIR}/libpthread.a
+.if !defined(NO_PIC)
+SYMLINKS+=lib${LIB}.so ${LIBDIR}/libpthread.so
+.endif
+.if ${MK_PROFILE} != "no"
+SYMLINKS+=lib${LIB}_p.a ${LIBDIR}/libpthread_p.a
+.endif
+.endif
+
+.include <bsd.lib.mk>
diff --git a/lib/libthr/arch/alpha/Makefile.inc b/lib/libthr/arch/alpha/Makefile.inc
new file mode 100644
index 0000000..508d2b4
--- /dev/null
+++ b/lib/libthr/arch/alpha/Makefile.inc
@@ -0,0 +1,5 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/arch/${MACHINE_ARCH}/${MACHINE_ARCH}
+
+SRCS+= pthread_md.c
diff --git a/lib/libthr/arch/alpha/alpha/pthread_md.c b/lib/libthr/arch/alpha/alpha/pthread_md.c
new file mode 100644
index 0000000..1a82341
--- /dev/null
+++ b/lib/libthr/arch/alpha/alpha/pthread_md.c
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2003 Daniel Eischen <deischen@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. Neither the name of the author nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * 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 <stdlib.h>
+#include <string.h>
+
+#include "pthread_md.h"
+
+/*
+ * The constructors.
+ */
+struct tcb *
+_tcb_ctor(struct pthread *thread, int initial)
+{
+ struct tcb *tcb;
+
+ if ((tcb = malloc(sizeof(struct tcb))) != NULL) {
+ memset(tcb, 0, sizeof(struct tcb));
+ tcb->tcb_thread = thread;
+ }
+ return (tcb);
+}
+
+void
+_tcb_dtor(struct tcb *tcb)
+{
+ free(tcb);
+}
diff --git a/lib/libthr/arch/alpha/include/pthread_md.h b/lib/libthr/arch/alpha/include/pthread_md.h
new file mode 100644
index 0000000..003cba0
--- /dev/null
+++ b/lib/libthr/arch/alpha/include/pthread_md.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2003 Marcel Moolenaar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must 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$
+ */
+
+#ifndef _PTHREAD_MD_H_
+#define _PTHREAD_MD_H_
+
+#include <stddef.h>
+#include <sys/types.h>
+
+#define DTV_OFFSET offsetof(struct tcb, tcb_dtv)
+
+/*
+ * Variant I tcb. The structure layout is fixed, don't blindly
+ * change it!
+ */
+struct tcb {
+ void *tcb_dtv;
+ struct pthread *tcb_thread;
+};
+
+#define _tp __builtin_thread_pointer()
+#define _tcb ((struct tcb *)_tp)
+
+struct tcb *_tcb_ctor(struct pthread *, int);
+void _tcb_dtor(struct tcb *);
+
+/* Called from the thread to set its private data. */
+static __inline void
+_tcb_set(struct tcb *tcb)
+{
+ __builtin_set_thread_pointer(tcb);
+}
+
+static __inline struct tcb *
+_tcb_get(void)
+{
+ return (_tcb);
+}
+
+extern struct pthread *_thr_initial;
+
+static __inline struct pthread *
+_get_curthread(void)
+{
+ if (_thr_initial)
+ return (_tcb->tcb_thread);
+ return (NULL);
+}
+
+#endif /* _PTHREAD_MD_H_ */
diff --git a/lib/libthr/arch/amd64/Makefile.inc b/lib/libthr/arch/amd64/Makefile.inc
new file mode 100644
index 0000000..6e6d577
--- /dev/null
+++ b/lib/libthr/arch/amd64/Makefile.inc
@@ -0,0 +1,5 @@
+#$FreeBSD$
+
+.PATH: ${.CURDIR}/arch/${MACHINE_ARCH}/${MACHINE_ARCH}
+
+SRCS+= pthread_md.c
diff --git a/lib/libthr/arch/amd64/amd64/pthread_md.c b/lib/libthr/arch/amd64/amd64/pthread_md.c
new file mode 100644
index 0000000..b661657
--- /dev/null
+++ b/lib/libthr/arch/amd64/amd64/pthread_md.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2003 Daniel Eischen <deischen@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. Neither the name of the author nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * 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 <rtld_tls.h>
+
+#include "pthread_md.h"
+
+/*
+ * The constructors.
+ */
+struct tcb *
+_tcb_ctor(struct pthread *thread, int initial)
+{
+ struct tcb *tcb;
+
+ if (initial)
+ __asm __volatile("movq %%fs:0, %0" : "=r" (tcb));
+ else
+ tcb = _rtld_allocate_tls(NULL, sizeof(struct tcb), 16);
+ if (tcb)
+ tcb->tcb_thread = thread;
+ return (tcb);
+}
+
+void
+_tcb_dtor(struct tcb *tcb)
+{
+ _rtld_free_tls(tcb, sizeof(struct tcb), 16);
+}
diff --git a/lib/libthr/arch/amd64/include/pthread_md.h b/lib/libthr/arch/amd64/include/pthread_md.h
new file mode 100644
index 0000000..30f63ca
--- /dev/null
+++ b/lib/libthr/arch/amd64/include/pthread_md.h
@@ -0,0 +1,99 @@
+/*-
+ * Copyright (C) 2003 David Xu <davidxu@freebsd.org>
+ * Copyright (c) 2001 Daniel Eischen <deischen@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. Neither the name of the author nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * 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$
+ */
+
+/*
+ * Machine-dependent thread prototypes/definitions.
+ */
+#ifndef _PTHREAD_MD_H_
+#define _PTHREAD_MD_H_
+
+#include <stddef.h>
+#include <sys/types.h>
+#include <machine/sysarch.h>
+#include <ucontext.h>
+
+#define DTV_OFFSET offsetof(struct tcb, tcb_dtv)
+
+/*
+ * Variant II tcb, first two members are required by rtld,
+ * %fs points to the structure.
+ */
+struct tcb {
+ struct tcb *tcb_self; /* required by rtld */
+ void *tcb_dtv; /* required by rtld */
+ struct pthread *tcb_thread;
+ void *tcb_spare[1];
+};
+
+/*
+ * Evaluates to the byte offset of the per-tcb variable name.
+ */
+#define __tcb_offset(name) __offsetof(struct tcb, name)
+
+/*
+ * Evaluates to the type of the per-tcb variable name.
+ */
+#define __tcb_type(name) __typeof(((struct tcb *)0)->name)
+
+/*
+ * Evaluates to the value of the per-tcb variable name.
+ */
+#define TCB_GET64(name) ({ \
+ __tcb_type(name) __result; \
+ \
+ u_long __i; \
+ __asm __volatile("movq %%fs:%1, %0" \
+ : "=r" (__i) \
+ : "m" (*(u_long *)(__tcb_offset(name)))); \
+ __result = (__tcb_type(name))__i; \
+ \
+ __result; \
+})
+
+struct tcb *_tcb_ctor(struct pthread *, int);
+void _tcb_dtor(struct tcb *tcb);
+
+static __inline void
+_tcb_set(struct tcb *tcb)
+{
+ amd64_set_fsbase(tcb);
+}
+
+static __inline struct tcb *
+_tcb_get(void)
+{
+ return (TCB_GET64(tcb_self));
+}
+
+static __inline struct pthread *
+_get_curthread(void)
+{
+ return (TCB_GET64(tcb_thread));
+}
+#endif
diff --git a/lib/libthr/arch/arm/Makefile.inc b/lib/libthr/arch/arm/Makefile.inc
new file mode 100644
index 0000000..508d2b4
--- /dev/null
+++ b/lib/libthr/arch/arm/Makefile.inc
@@ -0,0 +1,5 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/arch/${MACHINE_ARCH}/${MACHINE_ARCH}
+
+SRCS+= pthread_md.c
diff --git a/lib/libthr/arch/arm/arm/pthread_md.c b/lib/libthr/arch/arm/arm/pthread_md.c
new file mode 100644
index 0000000..7ca2b25
--- /dev/null
+++ b/lib/libthr/arch/arm/arm/pthread_md.c
@@ -0,0 +1,50 @@
+/*-
+ * Copyright (C) 2005 David Xu <davidxu@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. Neither the name of the author nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * 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 <stdlib.h>
+#include <sys/types.h>
+#include <rtld_tls.h>
+
+#include "pthread_md.h"
+
+struct tcb *
+_tcb_ctor(struct pthread *thread, int initial)
+{
+ struct tcb *tcb;
+
+ tcb = malloc(sizeof(struct tcb));
+ if (tcb)
+ tcb->tcb_thread = thread;
+ return (tcb);
+}
+
+void
+_tcb_dtor(struct tcb *tcb)
+{
+ free(tcb);
+}
diff --git a/lib/libthr/arch/arm/include/pthread_md.h b/lib/libthr/arch/arm/include/pthread_md.h
new file mode 100644
index 0000000..30f9f86
--- /dev/null
+++ b/lib/libthr/arch/arm/include/pthread_md.h
@@ -0,0 +1,83 @@
+/*-
+ * Copyright (c) 2005 David Xu <davidxu@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 ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED 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$
+ */
+
+/*
+ * Machine-dependent thread prototypes/definitions.
+ */
+#ifndef _PTHREAD_MD_H_
+#define _PTHREAD_MD_H_
+
+#include <sys/types.h>
+#include <machine/sysarch.h>
+#include <stddef.h>
+
+#define DTV_OFFSET offsetof(struct tcb, tcb_dtv)
+
+/*
+ * Variant II tcb, first two members are required by rtld.
+ */
+struct tcb {
+ struct tcb *tcb_self; /* required by rtld */
+ void *tcb_dtv; /* required by rtld */
+ struct pthread *tcb_thread; /* our hook */
+ void *tcb_spare[1];
+};
+
+/*
+ * The tcb constructors.
+ */
+struct tcb *_tcb_ctor(struct pthread *, int);
+void _tcb_dtor(struct tcb *);
+
+/* Called from the thread to set its private data. */
+static __inline void
+_tcb_set(struct tcb *tcb)
+{
+ *((struct tcb **)ARM_TP_ADDRESS) = tcb;
+}
+
+/*
+ * Get the current tcb.
+ */
+static __inline struct tcb *
+_tcb_get(void)
+{
+ return (*((struct tcb **)ARM_TP_ADDRESS));
+}
+
+extern struct pthread *_thr_initial;
+
+static __inline struct pthread *
+_get_curthread(void)
+{
+ if (_thr_initial)
+ return (_tcb_get()->tcb_thread);
+ return (NULL);
+}
+
+#endif /* _PTHREAD_MD_H_ */
diff --git a/lib/libthr/arch/i386/Makefile.inc b/lib/libthr/arch/i386/Makefile.inc
new file mode 100644
index 0000000..508d2b4
--- /dev/null
+++ b/lib/libthr/arch/i386/Makefile.inc
@@ -0,0 +1,5 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/arch/${MACHINE_ARCH}/${MACHINE_ARCH}
+
+SRCS+= pthread_md.c
diff --git a/lib/libthr/arch/i386/i386/pthread_md.c b/lib/libthr/arch/i386/i386/pthread_md.c
new file mode 100644
index 0000000..a8b31d5
--- /dev/null
+++ b/lib/libthr/arch/i386/i386/pthread_md.c
@@ -0,0 +1,57 @@
+/*-
+ * Copyright (C) 2003 David Xu <davidxu@freebsd.org>
+ * Copyright (c) 2001,2003 Daniel Eischen <deischen@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. Neither the name of the author nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+#include <machine/segments.h>
+#include <machine/sysarch.h>
+#include <string.h>
+#include <rtld_tls.h>
+
+#include "pthread_md.h"
+
+struct tcb *
+_tcb_ctor(struct pthread *thread, int initial)
+{
+ struct tcb *tcb;
+
+ if (initial)
+ __asm __volatile("movl %%gs:0, %0" : "=r" (tcb));
+ else
+ tcb = _rtld_allocate_tls(NULL, sizeof(struct tcb), 16);
+ if (tcb)
+ tcb->tcb_thread = thread;
+ return (tcb);
+}
+
+void
+_tcb_dtor(struct tcb *tcb)
+{
+
+ _rtld_free_tls(tcb, sizeof(struct tcb), 16);
+}
diff --git a/lib/libthr/arch/i386/include/pthread_md.h b/lib/libthr/arch/i386/include/pthread_md.h
new file mode 100644
index 0000000..4140b9c
--- /dev/null
+++ b/lib/libthr/arch/i386/include/pthread_md.h
@@ -0,0 +1,103 @@
+/*-
+ * Copyright (c) 2002 Daniel Eischen <deischen@freebsd.org>.
+ * Copyright (c) 2005 David Xu <davidxu@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$
+ */
+
+/*
+ * Machine-dependent thread prototypes/definitions.
+ */
+#ifndef _PTHREAD_MD_H_
+#define _PTHREAD_MD_H_
+
+#include <stddef.h>
+#include <sys/types.h>
+#include <machine/sysarch.h>
+
+#define DTV_OFFSET offsetof(struct tcb, tcb_dtv)
+
+/*
+ * Variant II tcb, first two members are required by rtld,
+ * %gs points to the structure.
+ */
+struct tcb {
+ struct tcb *tcb_self; /* required by rtld */
+ void *tcb_dtv; /* required by rtld */
+ struct pthread *tcb_thread;
+};
+
+/*
+ * Evaluates to the byte offset of the per-tcb variable name.
+ */
+#define __tcb_offset(name) __offsetof(struct tcb, name)
+
+/*
+ * Evaluates to the type of the per-tcb variable name.
+ */
+#define __tcb_type(name) __typeof(((struct tcb *)0)->name)
+
+/*
+ * Evaluates to the value of the per-tcb variable name.
+ */
+#define TCB_GET32(name) ({ \
+ __tcb_type(name) __result; \
+ \
+ u_int __i; \
+ __asm __volatile("movl %%gs:%1, %0" \
+ : "=r" (__i) \
+ : "m" (*(u_int *)(__tcb_offset(name)))); \
+ __result = (__tcb_type(name))__i; \
+ \
+ __result; \
+})
+
+/*
+ * The constructors.
+ */
+struct tcb *_tcb_ctor(struct pthread *, int);
+void _tcb_dtor(struct tcb *tcb);
+
+/* Called from the thread to set its private data. */
+static __inline void
+_tcb_set(struct tcb *tcb)
+{
+ i386_set_gsbase(tcb);
+}
+
+/* Get the current kcb. */
+static __inline struct tcb *
+_tcb_get(void)
+{
+ return (TCB_GET32(tcb_self));
+}
+
+/* Get the current thread. */
+static __inline struct pthread *
+_get_curthread(void)
+{
+ return (TCB_GET32(tcb_thread));
+}
+#endif
diff --git a/lib/libthr/arch/ia64/Makefile.inc b/lib/libthr/arch/ia64/Makefile.inc
new file mode 100644
index 0000000..c07c097
--- /dev/null
+++ b/lib/libthr/arch/ia64/Makefile.inc
@@ -0,0 +1,5 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/arch/${MACHINE_ARCH}/${MACHINE_ARCH}
+
+SRCS+= pthread_md.c
diff --git a/lib/libthr/arch/ia64/ia64/pthread_md.c b/lib/libthr/arch/ia64/ia64/pthread_md.c
new file mode 100644
index 0000000..a6f7def
--- /dev/null
+++ b/lib/libthr/arch/ia64/ia64/pthread_md.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2003 Daniel Eischen <deischen@freebsd.org>
+ * Copyright (c) 2005 David Xu <davidxu@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. Neither the name of the author nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * 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 <rtld_tls.h>
+
+#include "pthread_md.h"
+
+/*
+ * The constructors.
+ */
+struct tcb *
+_tcb_ctor(struct pthread *thread, int initial)
+{
+ struct tcb *tcb;
+ void *oldtls;
+
+ if (initial)
+ oldtls = _tp;
+ else
+ oldtls = NULL;
+ tcb = _rtld_allocate_tls(oldtls, sizeof(struct tcb), 16);
+ if (tcb)
+ tcb->tcb_thread = thread;
+ return (tcb);
+}
+
+void
+_tcb_dtor(struct tcb *tcb)
+{
+ _rtld_free_tls(tcb, sizeof(tcb), 16);
+}
diff --git a/lib/libthr/arch/ia64/include/pthread_md.h b/lib/libthr/arch/ia64/include/pthread_md.h
new file mode 100644
index 0000000..aee5dd2
--- /dev/null
+++ b/lib/libthr/arch/ia64/include/pthread_md.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2003 Marcel Moolenaar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must 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$
+ */
+
+#ifndef _PTHREAD_MD_H_
+#define _PTHREAD_MD_H_
+
+#include <stddef.h>
+
+#define DTV_OFFSET offsetof(struct tcb, tcb_dtv)
+
+/*
+ * Variant I tcb. The structure layout is fixed, don't blindly
+ * change it!
+ */
+struct tcb {
+ void *tcb_dtv;
+ struct pthread *tcb_thread;
+};
+
+register struct tcb *_tp __asm("%r13");
+
+#define _tcb _tp
+
+/*
+ * The tcb constructors.
+ */
+struct tcb *_tcb_ctor(struct pthread *, int);
+void _tcb_dtor(struct tcb *);
+
+/* Called from the thread to set its private data. */
+static __inline void
+_tcb_set(struct tcb *tcb)
+{
+ _tp = tcb;
+}
+
+static __inline struct tcb *
+_tcb_get(void)
+{
+ return (_tcb);
+}
+
+extern struct pthread *_thr_initial;
+
+static __inline struct pthread *
+_get_curthread(void)
+{
+ if (_thr_initial)
+ return (_tcb->tcb_thread);
+ return (NULL);
+}
+
+#endif /* _PTHREAD_MD_H_ */
diff --git a/lib/libthr/arch/powerpc/Makefile.inc b/lib/libthr/arch/powerpc/Makefile.inc
new file mode 100644
index 0000000..508d2b4
--- /dev/null
+++ b/lib/libthr/arch/powerpc/Makefile.inc
@@ -0,0 +1,5 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/arch/${MACHINE_ARCH}/${MACHINE_ARCH}
+
+SRCS+= pthread_md.c
diff --git a/lib/libthr/arch/powerpc/include/pthread_md.h b/lib/libthr/arch/powerpc/include/pthread_md.h
new file mode 100644
index 0000000..008c4cd
--- /dev/null
+++ b/lib/libthr/arch/powerpc/include/pthread_md.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2004 by Peter Grehan. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * 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$
+ */
+
+/*
+ * Machine-dependent thread prototypes/definitions.
+ */
+#ifndef _PTHREAD_MD_H_
+#define _PTHREAD_MD_H_
+
+#include <stddef.h>
+#include <sys/types.h>
+
+#define DTV_OFFSET offsetof(struct tcb, tcb_dtv)
+
+/*
+ * Variant I tcb. The structure layout is fixed, don't blindly
+ * change it.
+ * %r2 points to end of the structure.
+ */
+struct tcb {
+ void *tcb_dtv;
+ struct pthread *tcb_thread;
+};
+
+register uint8_t *_tp __asm("%r2");
+
+#define _tcb ((struct tcb *)(_tp - sizeof(struct tcb)))
+
+struct tcb *_tcb_ctor(struct pthread *, int);
+void _tcb_dtor(struct tcb *);
+
+static __inline void
+_tcb_set(struct tcb *tcb)
+{
+ _tp = (uint8_t *)tcb + sizeof(struct tcb);
+}
+
+static __inline struct tcb *
+_tcb_get(void)
+{
+ return (_tcb);
+}
+
+extern struct pthread *_thr_initial;
+
+static __inline struct pthread *
+_get_curthread(void)
+{
+ if (_thr_initial)
+ return (_tcb->tcb_thread);
+ return (NULL);
+}
+
+#endif /* _PTHREAD_MD_H_ */
diff --git a/lib/libthr/arch/powerpc/powerpc/pthread_md.c b/lib/libthr/arch/powerpc/powerpc/pthread_md.c
new file mode 100644
index 0000000..aa02a8d
--- /dev/null
+++ b/lib/libthr/arch/powerpc/powerpc/pthread_md.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2003 Daniel Eischen <deischen@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. Neither the name of the author nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * 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 <rtld_tls.h>
+
+#include "pthread_md.h"
+
+/*
+ * The constructors.
+ */
+struct tcb *
+_tcb_ctor(struct pthread *thread, int initial)
+{
+ struct tcb *tcb;
+ void *oldtls;
+
+ if (initial)
+ oldtls = _tp;
+ else
+ oldtls = NULL;
+ tcb = _rtld_allocate_tls(oldtls, sizeof(struct tcb), 16);
+ if (tcb)
+ tcb->tcb_thread = thread;
+ return (tcb);
+
+}
+
+void
+_tcb_dtor(struct tcb *tcb)
+{
+ _rtld_free_tls(tcb, sizeof(tcb), 16);
+}
diff --git a/lib/libthr/arch/sparc64/Makefile.inc b/lib/libthr/arch/sparc64/Makefile.inc
new file mode 100644
index 0000000..508d2b4
--- /dev/null
+++ b/lib/libthr/arch/sparc64/Makefile.inc
@@ -0,0 +1,5 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/arch/${MACHINE_ARCH}/${MACHINE_ARCH}
+
+SRCS+= pthread_md.c
diff --git a/lib/libthr/arch/sparc64/include/pthread_md.h b/lib/libthr/arch/sparc64/include/pthread_md.h
new file mode 100644
index 0000000..054c2be
--- /dev/null
+++ b/lib/libthr/arch/sparc64/include/pthread_md.h
@@ -0,0 +1,87 @@
+/*-
+ * Copyright (c) 2003 Jake Burkholder <jake@freebsd.org>.
+ * Copyright (c) 2003 Marcel Moolenaar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must 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$
+ */
+
+/*
+ * Machine-dependent thread prototypes/definitions.
+ */
+#ifndef _PTHREAD_MD_H_
+#define _PTHREAD_MD_H_
+
+#include <stddef.h>
+
+#define DTV_OFFSET offsetof(struct tcb, tcb_dtv)
+
+/*
+ * Variant II tcb, first two members are required by rtld.
+ * %g7 points to the structure.
+ */
+struct tcb {
+ struct tcb *tcb_self; /* required by rtld */
+ void *tcb_dtv; /* required by rtld */
+ struct pthread *tcb_thread; /* our hook */
+ void *tcb_spare[1];
+};
+
+register struct tcb *_tp __asm("%g7");
+
+#define _tcb (_tp)
+
+/*
+ * The tcb constructors.
+ */
+struct tcb *_tcb_ctor(struct pthread *, int);
+void _tcb_dtor(struct tcb *);
+
+/* Called from the thread to set its private data. */
+static __inline void
+_tcb_set(struct tcb *tcb)
+{
+ _tp = tcb;
+}
+
+/*
+ * Get the current tcb.
+ */
+static __inline struct tcb *
+_tcb_get(void)
+{
+ return (_tcb);
+}
+
+extern struct pthread *_thr_initial;
+
+static __inline struct pthread *
+_get_curthread(void)
+{
+ if (_thr_initial)
+ return (_tcb->tcb_thread);
+ return (NULL);
+}
+
+#endif /* _PTHREAD_MD_H_ */
diff --git a/lib/libthr/arch/sparc64/sparc64/pthread_md.c b/lib/libthr/arch/sparc64/sparc64/pthread_md.c
new file mode 100644
index 0000000..3f8e105
--- /dev/null
+++ b/lib/libthr/arch/sparc64/sparc64/pthread_md.c
@@ -0,0 +1,56 @@
+/*-
+ * Copyright (C) 2003 Jake Burkholder <jake@freebsd.org>
+ * Copyright (C) 2003 David Xu <davidxu@freebsd.org>
+ * Copyright (c) 2001,2003 Daniel Eischen <deischen@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. Neither the name of the author nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+#include <rtld_tls.h>
+
+#include "pthread_md.h"
+
+struct tcb *
+_tcb_ctor(struct pthread *thread, int initial)
+{
+ struct tcb *tcb;
+ void *oldtls;
+
+ if (initial)
+ oldtls = _tp;
+ else
+ oldtls = NULL;
+ tcb = _rtld_allocate_tls(oldtls, sizeof(struct tcb), 16);
+ if (tcb)
+ tcb->tcb_thread = thread;
+ return (tcb);
+}
+
+void
+_tcb_dtor(struct tcb *tcb)
+{
+ _rtld_free_tls(tcb, sizeof(struct tcb), 16);
+}
diff --git a/lib/libthr/libthr.3 b/lib/libthr/libthr.3
new file mode 100644
index 0000000..356edd9
--- /dev/null
+++ b/lib/libthr/libthr.3
@@ -0,0 +1,70 @@
+.\" Copyright (c) 2005 Robert N. M. Watson
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must 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$
+.\"
+.Dd June 11, 2005
+.Os
+.Dt LIBTHR 3
+.Sh NAME
+.Nm libthr
+.Nd "alternative POSIX threads library"
+.Sh LIBRARY
+.Lb libthr
+.Sh SYNOPSIS
+.In pthread.h
+.Sh DESCRIPTION
+The
+.Nm
+library provides an alternative 1:1 implementation of the
+.Xr pthread 3
+library interfaces for application threading.
+While applications may be linked directly against
+.Nm ,
+system administrators are offered maximum flexibility by linking against
+.Xr pthread 3 ,
+as they can then use
+.Xr libmap.conf 5
+to select the threading implementation on a per-application basis.
+.Pp
+The
+.Nm
+library
+has been optimized for use by applications expecting system scope thread
+semantics, and can provide significant performance improvements.
+.Sh SEE ALSO
+.Xr pthread 3
+.Sh AUTHORS
+.An -nosplit
+The
+.Nm
+library
+was originally created by
+.An "Jeff Roberson" Aq jeff@FreeBSD.org ,
+and enhanced by
+.An "Jonathan Mini" Aq mini@FreeBSD.org
+and
+.An "Mike Makonnen" Aq mtm@FreeBSD.org .
+It has been substantially rewritten and optimized by
+.An "David Xu" Aq davidxu@FreeBSD.org .
diff --git a/lib/libthr/pthread.map b/lib/libthr/pthread.map
new file mode 100644
index 0000000..66ebf44
--- /dev/null
+++ b/lib/libthr/pthread.map
@@ -0,0 +1,761 @@
+# $FreeBSD$
+LIBTHREAD_1_0 {
+global:
+ ___creat;
+ __accept;
+ __close;
+ __connect;
+ __error;
+ __fcntl;
+ __fsync;
+ __msync;
+ __nanosleep;
+ __open;
+ __poll;
+ __pthread_cond_timedwait;
+ __pthread_cond_wait;
+ __pthread_mutex_init;
+ __pthread_mutex_lock;
+ __pthread_mutex_timedlock;
+ __pthread_mutex_trylock;
+ __read;
+ __readv;
+ __recvfrom;
+ __recvmsg;
+ __select;
+ __sendmsg;
+ __sendto;
+ __sigsuspend;
+ __sigtimedwait;
+ __sigwait;
+ __sigwaitinfo;
+ __wait4;
+ __write;
+ __writev;
+ _aio_suspend;
+ _execve;
+ _fork;
+ _nanosleep;
+ _pause;
+ _pselect;
+ _pthread_atfork;
+ _pthread_barrier_destroy;
+ _pthread_barrier_init;
+ _pthread_barrier_wait;
+ _pthread_barrierattr_destroy;
+ _pthread_barrierattr_getpshared;
+ _pthread_barrierattr_init;
+ _pthread_barrierattr_setpshared;
+ _pthread_attr_destroy;
+ _pthread_attr_get_np;
+ _pthread_attr_getdetachstate;
+ _pthread_attr_getguardsize;
+ _pthread_attr_getinheritsched;
+ _pthread_attr_getschedparam;
+ _pthread_attr_getschedpolicy;
+ _pthread_attr_getscope;
+ _pthread_attr_getstack;
+ _pthread_attr_getstackaddr;
+ _pthread_attr_getstacksize;
+ _pthread_attr_init;
+ _pthread_attr_setcreatesuspend_np;
+ _pthread_attr_setdetachstate;
+ _pthread_attr_setguardsize;
+ _pthread_attr_setinheritsched;
+ _pthread_attr_setschedparam;
+ _pthread_attr_setschedpolicy;
+ _pthread_attr_setscope;
+ _pthread_attr_setstack;
+ _pthread_attr_setstackaddr;
+ _pthread_attr_setstacksize;
+ _pthread_cancel;
+ _pthread_cleanup_pop;
+ _pthread_cleanup_push;
+ _pthread_cond_broadcast;
+ _pthread_cond_destroy;
+ _pthread_cond_init;
+ _pthread_cond_signal;
+ _pthread_cond_timedwait;
+ _pthread_cond_wait;
+ _pthread_condattr_destroy;
+ _pthread_condattr_getclock;
+ _pthread_condattr_getpshared;
+ _pthread_condattr_init;
+ _pthread_condattr_setclock;
+ _pthread_condattr_setpshared;
+ _pthread_create;
+ _pthread_detach;
+ _pthread_equal;
+ _pthread_exit;
+ _pthread_getconcurrency;
+ _pthread_getprio;
+ _pthread_getschedparam;
+ _pthread_getspecific;
+ _pthread_join;
+ _pthread_key_create;
+ _pthread_key_delete;
+ _pthread_kill;
+ _pthread_main_np;
+ _pthread_multi_np;
+ _pthread_mutex_destroy;
+ _pthread_mutex_getprioceiling;
+ _pthread_mutex_init;
+ _pthread_mutex_lock;
+ _pthread_mutex_setprioceiling;
+ _pthread_mutex_timedlock;
+ _pthread_mutex_trylock;
+ _pthread_mutex_unlock;
+ _pthread_mutexattr_destroy;
+ _pthread_mutexattr_getkind_np;
+ _pthread_mutexattr_getprioceiling;
+ _pthread_mutexattr_getprotocol;
+ _pthread_mutexattr_getpshared;
+ _pthread_mutexattr_gettype;
+ _pthread_mutexattr_init;
+ _pthread_mutexattr_setkind_np;
+ _pthread_mutexattr_setprioceiling;
+ _pthread_mutexattr_setprotocol;
+ _pthread_mutexattr_setpshared;
+ _pthread_mutexattr_settype;
+ _pthread_once;
+ _pthread_resume_all_np;
+ _pthread_resume_np;
+ _pthread_rwlock_destroy;
+ _pthread_rwlock_init;
+ _pthread_rwlock_rdlock;
+ _pthread_rwlock_timedrdlock;
+ _pthread_rwlock_timedwrlock;
+ _pthread_rwlock_tryrdlock;
+ _pthread_rwlock_trywrlock;
+ _pthread_rwlock_unlock;
+ _pthread_rwlock_wrlock;
+ _pthread_rwlockattr_destroy;
+ _pthread_rwlockattr_getpshared;
+ _pthread_rwlockattr_init;
+ _pthread_rwlockattr_setpshared;
+ _pthread_self;
+ _pthread_set_name_np;
+ _pthread_setcancelstate;
+ _pthread_setcanceltype;
+ _pthread_setconcurrency;
+ _pthread_setprio;
+ _pthread_setschedparam;
+ _pthread_setspecific;
+ _pthread_sigmask;
+ _pthread_single_np;
+ _pthread_spin_destroy;
+ _pthread_spin_init;
+ _pthread_spin_lock;
+ _pthread_spin_trylock;
+ _pthread_spin_unlock;
+ _pthread_suspend_all_np;
+ _pthread_suspend_np;
+ _pthread_switch_add_np;
+ _pthread_switch_delete_np;
+ _pthread_testcancel;
+ _pthread_timedjoin_np;
+ _pthread_yield;
+ _raise;
+ _sem_destroy;
+ _sem_getvalue;
+ _sem_init;
+ _sem_post;
+ _sem_timedwait;
+ _sem_trywait;
+ _sem_wait;
+ _sigaction;
+ _sigprocmask;
+ _sigsuspend;
+ _sigtimedwait;
+ _sigwait;
+ _sigwaitinfo;
+ _sleep;
+ _spinlock;
+ _spinlock_debug;
+ _spinunlock;
+ _system;
+ _tcdrain;
+ _usleep;
+ _vfork;
+ _wait;
+ _waitpid;
+ accept;
+ aio_suspend;
+ close;
+ connect;
+ creat;
+ execve;
+ fcntl;
+ fork;
+ fsync;
+ msync;
+ nanosleep;
+ open;
+ pause;
+ poll;
+ pselect;
+ pthread_atfork;
+ pthread_barrier_destroy;
+ pthread_barrier_init;
+ pthread_barrier_wait;
+ pthread_barrierattr_destroy;
+ pthread_barrierattr_getpshared;
+ pthread_barrierattr_init;
+ pthread_barrierattr_setpshared;
+ pthread_attr_destroy;
+ pthread_attr_get_np;
+ pthread_attr_getdetachstate;
+ pthread_attr_getguardsize;
+ pthread_attr_getinheritsched;
+ pthread_attr_getschedparam;
+ pthread_attr_getschedpolicy;
+ pthread_attr_getscope;
+ pthread_attr_getstack;
+ pthread_attr_getstackaddr;
+ pthread_attr_getstacksize;
+ pthread_attr_init;
+ pthread_attr_setcreatesuspend_np;
+ pthread_attr_setdetachstate;
+ pthread_attr_setguardsize;
+ pthread_attr_setinheritsched;
+ pthread_attr_setschedparam;
+ pthread_attr_setschedpolicy;
+ pthread_attr_setscope;
+ pthread_attr_setstack;
+ pthread_attr_setstackaddr;
+ pthread_attr_setstacksize;
+ pthread_cancel;
+ pthread_cleanup_pop;
+ pthread_cleanup_push;
+ pthread_cond_broadcast;
+ pthread_cond_destroy;
+ pthread_cond_init;
+ pthread_cond_signal;
+ pthread_cond_timedwait;
+ pthread_cond_wait;
+ pthread_condattr_destroy;
+ pthread_condattr_getclock;
+ pthread_condattr_getpshared;
+ pthread_condattr_init;
+ pthread_condattr_setclock;
+ pthread_condattr_setpshared;
+ pthread_create;
+ pthread_detach;
+ pthread_equal;
+ pthread_exit;
+ pthread_getconcurrency;
+ pthread_getprio;
+ pthread_getschedparam;
+ pthread_getspecific;
+ pthread_join;
+ pthread_key_create;
+ pthread_key_delete;
+ pthread_kill;
+ pthread_main_np;
+ pthread_multi_np;
+ pthread_mutex_destroy;
+ pthread_mutex_getprioceiling;
+ pthread_mutex_init;
+ pthread_mutex_lock;
+ pthread_mutex_setprioceiling;
+ pthread_mutex_timedlock;
+ pthread_mutex_trylock;
+ pthread_mutex_unlock;
+ pthread_mutexattr_destroy;
+ pthread_mutexattr_getkind_np;
+ pthread_mutexattr_getprioceiling;
+ pthread_mutexattr_getpshared;
+ pthread_mutexattr_getprotocol;
+ pthread_mutexattr_gettype;
+ pthread_mutexattr_init;
+ pthread_mutexattr_setkind_np;
+ pthread_mutexattr_setprioceiling;
+ pthread_mutexattr_setprotocol;
+ pthread_mutexattr_setpshared;
+ pthread_mutexattr_settype;
+ pthread_once;
+ pthread_resume_all_np;
+ pthread_resume_np;
+ pthread_rwlock_destroy;
+ pthread_rwlock_init;
+ pthread_rwlock_rdlock;
+ pthread_rwlock_timedrdlock;
+ pthread_rwlock_timedwrlock;
+ pthread_rwlock_tryrdlock;
+ pthread_rwlock_trywrlock;
+ pthread_rwlock_unlock;
+ pthread_rwlock_wrlock;
+ pthread_rwlockattr_destroy;
+ pthread_rwlockattr_getpshared;
+ pthread_rwlockattr_init;
+ pthread_rwlockattr_setpshared;
+ pthread_self;
+ pthread_set_name_np;
+ pthread_setcancelstate;
+ pthread_setcanceltype;
+ pthread_setconcurrency;
+ pthread_setprio;
+ pthread_setschedparam;
+ pthread_setspecific;
+ pthread_sigmask;
+ pthread_single_np;
+ pthread_spin_destroy;
+ pthread_spin_init;
+ pthread_spin_lock;
+ pthread_spin_trylock;
+ pthread_spin_unlock;
+ pthread_suspend_all_np;
+ pthread_suspend_np;
+ pthread_switch_add_np;
+ pthread_switch_delete_np;
+ pthread_testcancel;
+ pthread_timedjoin_np;
+ pthread_yield;
+ raise;
+ read;
+ readv;
+ recvfrom;
+ recvmsg;
+ select;
+ sem_destroy;
+ sem_getvalue;
+ sem_init;
+ sem_post;
+ sem_timedwait;
+ sem_trywait;
+ sem_wait;
+ sendmsg;
+ sendto;
+ sigaction;
+ sigprocmask;
+ sigsuspend;
+ sigwait;
+ sigwaitinfo;
+ sigtimedwait;
+ sleep;
+ system;
+ tcdrain;
+ usleep;
+ vfork;
+ wait;
+ wait4;
+ waitpid;
+ write;
+ writev;
+
+ # Debugger needs these.
+ _libthr_debug;
+ _thread_active_threads;
+ _thread_bp_create;
+ _thread_bp_death;
+ _thread_event_mask;
+ _thread_keytable;
+ _thread_last_event;
+ _thread_list;
+ _thread_max_keys;
+ _thread_off_attr_flags;
+ _thread_off_dtv;
+ _thread_off_event_buf;
+ _thread_off_event_mask;
+ _thread_off_key_allocated;
+ _thread_off_key_destructor;
+ _thread_off_linkmap;
+ _thread_off_next;
+ _thread_off_report_events;
+ _thread_off_state;
+ _thread_off_tcb;
+ _thread_off_tid;
+ _thread_off_tlsindex;
+ _thread_size_key;
+ _thread_state_running;
+ _thread_state_zoombie;
+local:
+ *;
+};
+
+#
+# Use the same naming scheme as libc.
+#
+FBSD_1.0 {
+global:
+ __error;
+ accept;
+ aio_suspend;
+ close;
+ connect;
+ creat;
+ execve;
+ fcntl;
+ fork;
+ fsync;
+ msync;
+ nanosleep;
+ open;
+ pause;
+ poll;
+ pselect;
+ pthread_atfork;
+ pthread_barrier_destroy;
+ pthread_barrier_init;
+ pthread_barrier_wait;
+ pthread_barrierattr_destroy;
+ pthread_barrierattr_getpshared;
+ pthread_barrierattr_init;
+ pthread_barrierattr_setpshared;
+ pthread_attr_destroy;
+ pthread_attr_get_np;
+ pthread_attr_getdetachstate;
+ pthread_attr_getguardsize;
+ pthread_attr_getinheritsched;
+ pthread_attr_getschedparam;
+ pthread_attr_getschedpolicy;
+ pthread_attr_getscope;
+ pthread_attr_getstack;
+ pthread_attr_getstackaddr;
+ pthread_attr_getstacksize;
+ pthread_attr_init;
+ pthread_attr_setcreatesuspend_np;
+ pthread_attr_setdetachstate;
+ pthread_attr_setguardsize;
+ pthread_attr_setinheritsched;
+ pthread_attr_setschedparam;
+ pthread_attr_setschedpolicy;
+ pthread_attr_setscope;
+ pthread_attr_setstack;
+ pthread_attr_setstackaddr;
+ pthread_attr_setstacksize;
+ pthread_cancel;
+ pthread_cleanup_pop;
+ pthread_cleanup_push;
+ pthread_cond_broadcast;
+ pthread_cond_destroy;
+ pthread_cond_init;
+ pthread_cond_signal;
+ pthread_cond_timedwait;
+ pthread_cond_wait;
+ pthread_condattr_destroy;
+ pthread_condattr_getclock;
+ pthread_condattr_getpshared;
+ pthread_condattr_init;
+ pthread_condattr_setclock;
+ pthread_condattr_setpshared;
+ pthread_create;
+ pthread_detach;
+ pthread_equal;
+ pthread_exit;
+ pthread_getconcurrency;
+ pthread_getprio;
+ pthread_getschedparam;
+ pthread_getspecific;
+ pthread_join;
+ pthread_key_create;
+ pthread_key_delete;
+ pthread_kill;
+ pthread_main_np;
+ pthread_multi_np;
+ pthread_mutex_destroy;
+ pthread_mutex_getprioceiling;
+ pthread_mutex_init;
+ pthread_mutex_lock;
+ pthread_mutex_setprioceiling;
+ pthread_mutex_timedlock;
+ pthread_mutex_trylock;
+ pthread_mutex_unlock;
+ pthread_mutexattr_destroy;
+ pthread_mutexattr_getkind_np;
+ pthread_mutexattr_getprioceiling;
+ pthread_mutexattr_getpshared;
+ pthread_mutexattr_getprotocol;
+ pthread_mutexattr_gettype;
+ pthread_mutexattr_init;
+ pthread_mutexattr_setkind_np;
+ pthread_mutexattr_setprioceiling;
+ pthread_mutexattr_setprotocol;
+ pthread_mutexattr_setpshared;
+ pthread_mutexattr_settype;
+ pthread_once;
+ pthread_resume_all_np;
+ pthread_resume_np;
+ pthread_rwlock_destroy;
+ pthread_rwlock_init;
+ pthread_rwlock_rdlock;
+ pthread_rwlock_timedrdlock;
+ pthread_rwlock_timedwrlock;
+ pthread_rwlock_tryrdlock;
+ pthread_rwlock_trywrlock;
+ pthread_rwlock_unlock;
+ pthread_rwlock_wrlock;
+ pthread_rwlockattr_destroy;
+ pthread_rwlockattr_getpshared;
+ pthread_rwlockattr_init;
+ pthread_rwlockattr_setpshared;
+ pthread_self;
+ pthread_set_name_np;
+ pthread_setcancelstate;
+ pthread_setcanceltype;
+ pthread_setconcurrency;
+ pthread_setprio;
+ pthread_setschedparam;
+ pthread_setspecific;
+ pthread_sigmask;
+ pthread_single_np;
+ pthread_spin_destroy;
+ pthread_spin_init;
+ pthread_spin_lock;
+ pthread_spin_trylock;
+ pthread_spin_unlock;
+ pthread_suspend_all_np;
+ pthread_suspend_np;
+ pthread_switch_add_np;
+ pthread_switch_delete_np;
+ pthread_testcancel;
+ pthread_timedjoin_np;
+ pthread_yield;
+ raise;
+ read;
+ readv;
+ recvfrom;
+ recvmsg;
+ select;
+ sem_destroy;
+ sem_getvalue;
+ sem_init;
+ sem_post;
+ sem_timedwait;
+ sem_trywait;
+ sem_wait;
+ sendmsg;
+ sendto;
+ sigaction;
+ sigprocmask;
+ sigsuspend;
+ sigwait;
+ sigwaitinfo;
+ sigtimedwait;
+ sleep;
+ system;
+ tcdrain;
+ usleep;
+ vfork;
+ wait;
+ wait4;
+ waitpid;
+ write;
+ writev;
+local:
+ *;
+};
+
+#
+# List the private interfaces reserved for use in FreeBSD libraries.
+# These are not part of our application ABI.
+#
+FBSDprivate {
+global:
+ ___creat;
+ __accept;
+ __close;
+ __connect;
+ __fcntl;
+ __fsync;
+ __msync;
+ __nanosleep;
+ __open;
+ __poll;
+ __pthread_cond_timedwait;
+ __pthread_cond_wait;
+ __pthread_mutex_init;
+ __pthread_mutex_lock;
+ __pthread_mutex_timedlock;
+ __pthread_mutex_trylock;
+ __read;
+ __readv;
+ __recvfrom;
+ __recvmsg;
+ __select;
+ __sendmsg;
+ __sendto;
+ __sigsuspend;
+ __sigtimedwait;
+ __sigwait;
+ __sigwaitinfo;
+ __wait4;
+ __write;
+ __writev;
+ _aio_suspend;
+ _execve;
+ _fork;
+ _nanosleep;
+ _pause;
+ _pselect;
+ _pthread_atfork;
+ _pthread_barrier_destroy;
+ _pthread_barrier_init;
+ _pthread_barrier_wait;
+ _pthread_barrierattr_destroy;
+ _pthread_barrierattr_getpshared;
+ _pthread_barrierattr_init;
+ _pthread_barrierattr_setpshared;
+ _pthread_attr_destroy;
+ _pthread_attr_get_np;
+ _pthread_attr_getdetachstate;
+ _pthread_attr_getguardsize;
+ _pthread_attr_getinheritsched;
+ _pthread_attr_getschedparam;
+ _pthread_attr_getschedpolicy;
+ _pthread_attr_getscope;
+ _pthread_attr_getstack;
+ _pthread_attr_getstackaddr;
+ _pthread_attr_getstacksize;
+ _pthread_attr_init;
+ _pthread_attr_setcreatesuspend_np;
+ _pthread_attr_setdetachstate;
+ _pthread_attr_setguardsize;
+ _pthread_attr_setinheritsched;
+ _pthread_attr_setschedparam;
+ _pthread_attr_setschedpolicy;
+ _pthread_attr_setscope;
+ _pthread_attr_setstack;
+ _pthread_attr_setstackaddr;
+ _pthread_attr_setstacksize;
+ _pthread_cancel;
+ _pthread_cleanup_pop;
+ _pthread_cleanup_push;
+ _pthread_cond_broadcast;
+ _pthread_cond_destroy;
+ _pthread_cond_init;
+ _pthread_cond_signal;
+ _pthread_cond_timedwait;
+ _pthread_cond_wait;
+ _pthread_condattr_destroy;
+ _pthread_condattr_getclock;
+ _pthread_condattr_getpshared;
+ _pthread_condattr_init;
+ _pthread_condattr_setclock;
+ _pthread_condattr_setpshared;
+ _pthread_create;
+ _pthread_detach;
+ _pthread_equal;
+ _pthread_exit;
+ _pthread_getconcurrency;
+ _pthread_getprio;
+ _pthread_getschedparam;
+ _pthread_getspecific;
+ _pthread_join;
+ _pthread_key_create;
+ _pthread_key_delete;
+ _pthread_kill;
+ _pthread_main_np;
+ _pthread_multi_np;
+ _pthread_mutex_destroy;
+ _pthread_mutex_getprioceiling;
+ _pthread_mutex_init;
+ _pthread_mutex_lock;
+ _pthread_mutex_setprioceiling;
+ _pthread_mutex_timedlock;
+ _pthread_mutex_trylock;
+ _pthread_mutex_unlock;
+ _pthread_mutexattr_destroy;
+ _pthread_mutexattr_getkind_np;
+ _pthread_mutexattr_getprioceiling;
+ _pthread_mutexattr_getprotocol;
+ _pthread_mutexattr_getpshared;
+ _pthread_mutexattr_gettype;
+ _pthread_mutexattr_init;
+ _pthread_mutexattr_setkind_np;
+ _pthread_mutexattr_setprioceiling;
+ _pthread_mutexattr_setprotocol;
+ _pthread_mutexattr_setpshared;
+ _pthread_mutexattr_settype;
+ _pthread_once;
+ _pthread_resume_all_np;
+ _pthread_resume_np;
+ _pthread_rwlock_destroy;
+ _pthread_rwlock_init;
+ _pthread_rwlock_rdlock;
+ _pthread_rwlock_timedrdlock;
+ _pthread_rwlock_timedwrlock;
+ _pthread_rwlock_tryrdlock;
+ _pthread_rwlock_trywrlock;
+ _pthread_rwlock_unlock;
+ _pthread_rwlock_wrlock;
+ _pthread_rwlockattr_destroy;
+ _pthread_rwlockattr_getpshared;
+ _pthread_rwlockattr_init;
+ _pthread_rwlockattr_setpshared;
+ _pthread_self;
+ _pthread_set_name_np;
+ _pthread_setcancelstate;
+ _pthread_setcanceltype;
+ _pthread_setconcurrency;
+ _pthread_setprio;
+ _pthread_setschedparam;
+ _pthread_setspecific;
+ _pthread_sigmask;
+ _pthread_single_np;
+ _pthread_spin_destroy;
+ _pthread_spin_init;
+ _pthread_spin_lock;
+ _pthread_spin_trylock;
+ _pthread_spin_unlock;
+ _pthread_suspend_all_np;
+ _pthread_suspend_np;
+ _pthread_switch_add_np;
+ _pthread_switch_delete_np;
+ _pthread_testcancel;
+ _pthread_timedjoin_np;
+ _pthread_yield;
+ _raise;
+ _sem_destroy;
+ _sem_getvalue;
+ _sem_init;
+ _sem_post;
+ _sem_timedwait;
+ _sem_trywait;
+ _sem_wait;
+ _sigaction;
+ _sigprocmask;
+ _sigsuspend;
+ _sigtimedwait;
+ _sigwait;
+ _sigwaitinfo;
+ _sleep;
+ _spinlock;
+ _spinlock_debug;
+ _spinunlock;
+ _system;
+ _tcdrain;
+ _usleep;
+ _vfork;
+ _wait;
+ _waitpid;
+
+ # Debugger needs these.
+ _libthr_debug;
+ _thread_active_threads;
+ _thread_bp_create;
+ _thread_bp_death;
+ _thread_event_mask;
+ _thread_keytable;
+ _thread_last_event;
+ _thread_list;
+ _thread_max_keys;
+ _thread_off_attr_flags;
+ _thread_off_dtv;
+ _thread_off_event_buf;
+ _thread_off_event_mask;
+ _thread_off_key_allocated;
+ _thread_off_key_destructor;
+ _thread_off_linkmap;
+ _thread_off_next;
+ _thread_off_report_events;
+ _thread_off_state;
+ _thread_off_tcb;
+ _thread_off_tid;
+ _thread_off_tlsindex;
+ _thread_size_key;
+ _thread_state_running;
+ _thread_state_zoombie;
+local:
+ *;
+};
diff --git a/lib/libthr/support/Makefile.inc b/lib/libthr/support/Makefile.inc
new file mode 100644
index 0000000..bcf4393
--- /dev/null
+++ b/lib/libthr/support/Makefile.inc
@@ -0,0 +1,22 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/support ${.CURDIR}/../libc/gen ${.CURDIR}/../libc/string
+.PATH: ${.CURDIR}/../libc/${MACHINE_ARCH}/sys
+
+CFLAGS+= -I${.CURDIR}/../libc/${MACHINE_ARCH}
+
+SYSCALLS= thr_new
+
+SYSCALL_SRC= ${SYSCALLS:S/$/.S/}
+SYSCALL_OBJ= ${SYSCALLS:S/$/.So/}
+
+${SYSCALL_SRC}:
+ printf '#include "SYS.h"\nRSYSCALL(${.PREFIX})\n' > ${.TARGET}
+
+LIBC_OBJS=
+
+SOBJS+= thr_libc.So
+CLEANFILES+= ${SYSCALL_SRC} ${SYSCALL_OBJ} ${LIBC_OBJS}
+
+thr_libc.So: ${SYSCALL_OBJ} ${LIBC_OBJS}
+ ${CC} -fPIC -nostdlib -o ${.TARGET} -r ${.ALLSRC}
diff --git a/lib/libthr/sys/Makefile.inc b/lib/libthr/sys/Makefile.inc
new file mode 100644
index 0000000..70c6dda
--- /dev/null
+++ b/lib/libthr/sys/Makefile.inc
@@ -0,0 +1,5 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/sys
+
+SRCS+= thr_error.c
diff --git a/lib/libthr/sys/thr_error.c b/lib/libthr/sys/thr_error.c
new file mode 100644
index 0000000..902c054
--- /dev/null
+++ b/lib/libthr/sys/thr_error.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>.
+ * Copyright (c) 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell
+ * and Chris Provenzano.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <pthread.h>
+
+#include "libc_private.h"
+#include "thr_private.h"
+
+#undef errno
+extern int errno;
+
+int *
+__error(void)
+{
+ struct pthread *curthread = _get_curthread();
+
+ if (curthread != NULL && curthread != _thr_initial)
+ return (&curthread->error);
+ else
+ return (&errno);
+}
diff --git a/lib/libthr/thread/Makefile.inc b/lib/libthr/thread/Makefile.inc
new file mode 100644
index 0000000..bdae92e
--- /dev/null
+++ b/lib/libthr/thread/Makefile.inc
@@ -0,0 +1,54 @@
+# $FreeBSD$
+
+# thr sources
+.PATH: ${.CURDIR}/thread
+
+SRCS+= \
+ thr_attr.c \
+ thr_barrier.c \
+ thr_barrierattr.c \
+ thr_cancel.c \
+ thr_clean.c \
+ thr_concurrency.c \
+ thr_cond.c \
+ thr_condattr.c \
+ thr_create.c \
+ thr_detach.c \
+ thr_equal.c \
+ thr_event.c \
+ thr_exit.c \
+ thr_fork.c \
+ thr_getprio.c \
+ thr_getschedparam.c \
+ thr_info.c \
+ thr_init.c \
+ thr_join.c \
+ thr_list.c \
+ thr_kern.c \
+ thr_kill.c \
+ thr_main_np.c \
+ thr_multi_np.c \
+ thr_mutex.c \
+ thr_mutexattr.c \
+ thr_once.c \
+ thr_printf.c \
+ thr_pspinlock.c \
+ thr_resume_np.c \
+ thr_rtld.c \
+ thr_rwlock.c \
+ thr_rwlockattr.c \
+ thr_self.c \
+ thr_sem.c \
+ thr_setprio.c \
+ thr_setschedparam.c \
+ thr_sig.c \
+ thr_single_np.c \
+ thr_spec.c \
+ thr_spinlock.c \
+ thr_stack.c \
+ thr_syscalls.c \
+ thr_suspend_np.c \
+ thr_switch_np.c \
+ thr_symbols.c \
+ thr_umtx.c \
+ thr_yield.c
diff --git a/lib/libthr/thread/thr_atfork.c b/lib/libthr/thread/thr_atfork.c
new file mode 100644
index 0000000..370623a
--- /dev/null
+++ b/lib/libthr/thread/thr_atfork.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2003 Daniel Eischen <deischen@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. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * 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 <sys/queue.h>
+#include "thr_private.h"
+
+__weak_reference(_pthread_atfork, pthread_atfork);
+
+int
+_pthread_atfork(void (*prepare)(void), void (*parent)(void),
+ void (*child)(void))
+{
+ struct pthread *curthread;
+ struct pthread_atfork *af;
+
+ _thr_check_init();
+
+ if ((af = malloc(sizeof(struct pthread_atfork))) == NULL)
+ return (ENOMEM);
+
+ curthread = _get_curthread();
+ af->prepare = prepare;
+ af->parent = parent;
+ af->child = child;
+ THR_UMTX_LOCK(curthread, &_thr_atfork_lock);
+ TAILQ_INSERT_TAIL(&_thr_atfork_list, af, qe);
+ THR_UMTX_UNLOCK(curthread, &_thr_atfork_lock);
+ return (0);
+}
diff --git a/lib/libthr/thread/thr_attr.c b/lib/libthr/thread/thr_attr.c
new file mode 100644
index 0000000..24dd064
--- /dev/null
+++ b/lib/libthr/thread/thr_attr.c
@@ -0,0 +1,540 @@
+/*
+ * 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>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, 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.
+ */
+
+/*
+ * 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 "namespace.h"
+#include <errno.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pthread_np.h>
+#include "un-namespace.h"
+
+#include "thr_private.h"
+
+__weak_reference(_pthread_attr_destroy, pthread_attr_destroy);
+
+int
+_pthread_attr_destroy(pthread_attr_t *attr)
+{
+ int ret;
+
+ /* Check for invalid arguments: */
+ if (attr == NULL || *attr == NULL)
+ /* Invalid argument: */
+ ret = EINVAL;
+ else {
+ /* Free the memory allocated to the attribute object: */
+ free(*attr);
+
+ /*
+ * Leave the attribute pointer NULL now that the memory
+ * has been freed:
+ */
+ *attr = NULL;
+ ret = 0;
+ }
+ return(ret);
+}
+
+__weak_reference(_pthread_attr_get_np, pthread_attr_get_np);
+
+int
+_pthread_attr_get_np(pthread_t pid, pthread_attr_t *dst)
+{
+ struct pthread *curthread;
+ struct pthread_attr attr;
+ int ret;
+
+ if (pid == NULL || dst == NULL || *dst == NULL)
+ return (EINVAL);
+
+ curthread = _get_curthread();
+ if ((ret = _thr_ref_add(curthread, pid, /*include dead*/0)) != 0)
+ return (ret);
+ attr = pid->attr;
+ if (pid->tlflags & TLFLAGS_DETACHED)
+ attr.flags |= PTHREAD_DETACHED;
+ _thr_ref_delete(curthread, pid);
+ memcpy(*dst, &attr, sizeof(struct pthread_attr));
+
+ return (0);
+}
+
+__weak_reference(_pthread_attr_getdetachstate, pthread_attr_getdetachstate);
+
+int
+_pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate)
+{
+ int ret;
+
+ /* Check for invalid arguments: */
+ if (attr == NULL || *attr == NULL || detachstate == NULL)
+ ret = EINVAL;
+ else {
+ /* Check if the detached flag is set: */
+ if ((*attr)->flags & PTHREAD_DETACHED)
+ /* Return detached: */
+ *detachstate = PTHREAD_CREATE_DETACHED;
+ else
+ /* Return joinable: */
+ *detachstate = PTHREAD_CREATE_JOINABLE;
+ ret = 0;
+ }
+ return(ret);
+}
+
+__weak_reference(_pthread_attr_getguardsize, pthread_attr_getguardsize);
+
+int
+_pthread_attr_getguardsize(const pthread_attr_t *attr, size_t *guardsize)
+{
+ int ret;
+
+ /* Check for invalid arguments: */
+ if (attr == NULL || *attr == NULL || guardsize == NULL)
+ ret = EINVAL;
+ else {
+ /* Return the guard size: */
+ *guardsize = (*attr)->guardsize_attr;
+ ret = 0;
+ }
+ return(ret);
+}
+
+__weak_reference(_pthread_attr_getinheritsched, pthread_attr_getinheritsched);
+
+int
+_pthread_attr_getinheritsched(const pthread_attr_t *attr, int *sched_inherit)
+{
+ int ret = 0;
+
+ if ((attr == NULL) || (*attr == NULL))
+ ret = EINVAL;
+ else
+ *sched_inherit = (*attr)->sched_inherit;
+
+ return(ret);
+}
+
+__weak_reference(_pthread_attr_getschedparam, pthread_attr_getschedparam);
+
+int
+_pthread_attr_getschedparam(const pthread_attr_t *attr, struct sched_param *param)
+{
+ int ret = 0;
+
+ if ((attr == NULL) || (*attr == NULL) || (param == NULL))
+ ret = EINVAL;
+ else
+ param->sched_priority = (*attr)->prio;
+
+ return(ret);
+}
+
+__weak_reference(_pthread_attr_getschedpolicy, pthread_attr_getschedpolicy);
+
+int
+_pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy)
+{
+ int ret = 0;
+
+ if ((attr == NULL) || (*attr == NULL) || (policy == NULL))
+ ret = EINVAL;
+ else
+ *policy = (*attr)->sched_policy;
+
+ return(ret);
+}
+
+__weak_reference(_pthread_attr_getscope, pthread_attr_getscope);
+
+int
+_pthread_attr_getscope(const pthread_attr_t *attr, int *contentionscope)
+{
+ int ret = 0;
+
+ if ((attr == NULL) || (*attr == NULL) || (contentionscope == NULL))
+ /* Return an invalid argument: */
+ ret = EINVAL;
+
+ else
+ *contentionscope = (*attr)->flags & PTHREAD_SCOPE_SYSTEM ?
+ PTHREAD_SCOPE_SYSTEM : PTHREAD_SCOPE_PROCESS;
+
+ return(ret);
+}
+
+__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)
+{
+ int ret;
+
+ /* Check for invalid arguments: */
+ if (attr == NULL || *attr == NULL || stackaddr == NULL
+ || stacksize == NULL )
+ ret = EINVAL;
+ else {
+ /* Return the stack address and size */
+ *stackaddr = (*attr)->stackaddr_attr;
+ *stacksize = (*attr)->stacksize_attr;
+ ret = 0;
+ }
+ return(ret);
+}
+
+__weak_reference(_pthread_attr_getstackaddr, pthread_attr_getstackaddr);
+
+int
+_pthread_attr_getstackaddr(const pthread_attr_t *attr, void **stackaddr)
+{
+ int ret;
+
+ /* Check for invalid arguments: */
+ if (attr == NULL || *attr == NULL || stackaddr == NULL)
+ ret = EINVAL;
+ else {
+ /* Return the stack address: */
+ *stackaddr = (*attr)->stackaddr_attr;
+ ret = 0;
+ }
+ return(ret);
+}
+
+__weak_reference(_pthread_attr_getstacksize, pthread_attr_getstacksize);
+
+int
+_pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *stacksize)
+{
+ int ret;
+
+ /* Check for invalid arguments: */
+ if (attr == NULL || *attr == NULL || stacksize == NULL)
+ ret = EINVAL;
+ else {
+ /* Return the stack size: */
+ *stacksize = (*attr)->stacksize_attr;
+ ret = 0;
+ }
+ return(ret);
+}
+
+__weak_reference(_pthread_attr_init, pthread_attr_init);
+
+int
+_pthread_attr_init(pthread_attr_t *attr)
+{
+ int ret;
+ pthread_attr_t pattr;
+
+ _thr_check_init();
+
+ /* Allocate memory for the attribute object: */
+ if ((pattr = (pthread_attr_t) malloc(sizeof(struct pthread_attr))) == NULL)
+ /* Insufficient memory: */
+ ret = ENOMEM;
+ else {
+ /* Initialise the attribute object with the defaults: */
+ memcpy(pattr, &_pthread_attr_default, sizeof(struct pthread_attr));
+
+ /* Return a pointer to the attribute object: */
+ *attr = pattr;
+ ret = 0;
+ }
+ return(ret);
+}
+
+__weak_reference(_pthread_attr_setcreatesuspend_np, pthread_attr_setcreatesuspend_np);
+
+int
+_pthread_attr_setcreatesuspend_np(pthread_attr_t *attr)
+{
+ int ret;
+
+ if (attr == NULL || *attr == NULL) {
+ ret = EINVAL;
+ } else {
+ (*attr)->suspend = THR_CREATE_SUSPENDED;
+ ret = 0;
+ }
+ return(ret);
+}
+
+__weak_reference(_pthread_attr_setdetachstate, pthread_attr_setdetachstate);
+
+int
+_pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate)
+{
+ int ret;
+
+ /* Check for invalid arguments: */
+ if (attr == NULL || *attr == NULL ||
+ (detachstate != PTHREAD_CREATE_DETACHED &&
+ detachstate != PTHREAD_CREATE_JOINABLE))
+ ret = EINVAL;
+ else {
+ /* Check if detached state: */
+ if (detachstate == PTHREAD_CREATE_DETACHED)
+ /* Set the detached flag: */
+ (*attr)->flags |= PTHREAD_DETACHED;
+ else
+ /* Reset the detached flag: */
+ (*attr)->flags &= ~PTHREAD_DETACHED;
+ ret = 0;
+ }
+ return(ret);
+}
+
+__weak_reference(_pthread_attr_setguardsize, pthread_attr_setguardsize);
+
+int
+_pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize)
+{
+ int ret;
+
+ /* Check for invalid arguments. */
+ if (attr == NULL || *attr == NULL)
+ ret = EINVAL;
+ else {
+ /* Save the stack size. */
+ (*attr)->guardsize_attr = guardsize;
+ ret = 0;
+ }
+ return(ret);
+}
+
+__weak_reference(_pthread_attr_setinheritsched, pthread_attr_setinheritsched);
+
+int
+_pthread_attr_setinheritsched(pthread_attr_t *attr, int sched_inherit)
+{
+ int ret = 0;
+
+ if ((attr == NULL) || (*attr == NULL))
+ ret = EINVAL;
+ else if (sched_inherit != PTHREAD_INHERIT_SCHED &&
+ sched_inherit != PTHREAD_EXPLICIT_SCHED)
+ ret = ENOTSUP;
+ else
+ (*attr)->sched_inherit = sched_inherit;
+
+ return(ret);
+}
+
+__weak_reference(_pthread_attr_setschedparam, pthread_attr_setschedparam);
+
+int
+_pthread_attr_setschedparam(pthread_attr_t *attr, const struct sched_param *param)
+{
+ int policy;
+
+ if ((attr == NULL) || (*attr == NULL))
+ return (EINVAL);
+
+ if (param == NULL)
+ return (ENOTSUP);
+
+ policy = (*attr)->sched_policy;
+
+ if (param->sched_priority < _thr_priorities[policy-1].pri_min ||
+ param->sched_priority > _thr_priorities[policy-1].pri_max)
+ 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)
+{
+ int ret = 0;
+
+ if ((attr == NULL) || (*attr == NULL))
+ ret = EINVAL;
+ else if ((policy < SCHED_FIFO) || (policy > SCHED_RR)) {
+ ret = ENOTSUP;
+ } else {
+ (*attr)->sched_policy = policy;
+ (*attr)->prio = _thr_priorities[policy-1].pri_default;
+ }
+ return(ret);
+}
+
+__weak_reference(_pthread_attr_setscope, pthread_attr_setscope);
+
+int
+_pthread_attr_setscope(pthread_attr_t *attr, int contentionscope)
+{
+ int ret = 0;
+
+ if ((attr == NULL) || (*attr == NULL)) {
+ /* Return an invalid argument: */
+ ret = EINVAL;
+ } else if ((contentionscope != PTHREAD_SCOPE_PROCESS) &&
+ (contentionscope != PTHREAD_SCOPE_SYSTEM)) {
+ ret = EINVAL;
+ } else if (contentionscope == PTHREAD_SCOPE_SYSTEM) {
+ (*attr)->flags |= contentionscope;
+ } else {
+ (*attr)->flags &= ~PTHREAD_SCOPE_SYSTEM;
+ }
+ return (ret);
+}
+
+__weak_reference(_pthread_attr_setstack, pthread_attr_setstack);
+
+int
+_pthread_attr_setstack(pthread_attr_t *attr, void *stackaddr,
+ size_t stacksize)
+{
+ int ret;
+
+ /* Check for invalid arguments: */
+ if (attr == NULL || *attr == NULL || stackaddr == NULL
+ || stacksize < PTHREAD_STACK_MIN)
+ ret = EINVAL;
+ else {
+ /* Save the stack address and stack size */
+ (*attr)->stackaddr_attr = stackaddr;
+ (*attr)->stacksize_attr = stacksize;
+ ret = 0;
+ }
+ return(ret);
+}
+
+__weak_reference(_pthread_attr_setstackaddr, pthread_attr_setstackaddr);
+
+int
+_pthread_attr_setstackaddr(pthread_attr_t *attr, void *stackaddr)
+{
+ int ret;
+
+ /* Check for invalid arguments: */
+ if (attr == NULL || *attr == NULL || stackaddr == NULL)
+ ret = EINVAL;
+ else {
+ /* Save the stack address: */
+ (*attr)->stackaddr_attr = stackaddr;
+ ret = 0;
+ }
+ return(ret);
+}
+
+__weak_reference(_pthread_attr_setstacksize, pthread_attr_setstacksize);
+
+int
+_pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize)
+{
+ int ret;
+
+ /* Check for invalid arguments: */
+ if (attr == NULL || *attr == NULL || stacksize < PTHREAD_STACK_MIN)
+ ret = EINVAL;
+ else {
+ /* Save the stack size: */
+ (*attr)->stacksize_attr = stacksize;
+ ret = 0;
+ }
+ return(ret);
+}
diff --git a/lib/libthr/thread/thr_autoinit.c b/lib/libthr/thread/thr_autoinit.c
new file mode 100644
index 0000000..c425569
--- /dev/null
+++ b/lib/libthr/thread/thr_autoinit.c
@@ -0,0 +1,65 @@
+/*
+ * 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$
+ */
+
+#include <pthread.h>
+
+#include "thr_private.h"
+
+/*
+ * 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_barrier.c b/lib/libthr/thread/thr_barrier.c
new file mode 100644
index 0000000..8d65d9f
--- /dev/null
+++ b/lib/libthr/thread/thr_barrier.c
@@ -0,0 +1,111 @@
+/*-
+ * Copyright (c) 2003 David Xu <davidxu@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 "namespace.h"
+#include <errno.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include "un-namespace.h"
+
+#include "thr_private.h"
+
+__weak_reference(_pthread_barrier_init, pthread_barrier_init);
+__weak_reference(_pthread_barrier_wait, pthread_barrier_wait);
+__weak_reference(_pthread_barrier_destroy, pthread_barrier_destroy);
+
+int
+_pthread_barrier_destroy(pthread_barrier_t *barrier)
+{
+ pthread_barrier_t bar;
+
+ if (barrier == NULL || *barrier == NULL)
+ return (EINVAL);
+
+ bar = *barrier;
+ if (bar->b_waiters > 0)
+ return (EBUSY);
+ *barrier = NULL;
+ free(bar);
+ return (0);
+}
+
+int
+_pthread_barrier_init(pthread_barrier_t *barrier,
+ const pthread_barrierattr_t *attr, unsigned count)
+{
+ pthread_barrier_t bar;
+
+ (void)attr;
+
+ if (barrier == NULL || count <= 0)
+ return (EINVAL);
+
+ bar = malloc(sizeof(struct pthread_barrier));
+ if (bar == NULL)
+ return (ENOMEM);
+
+ _thr_umtx_init(&bar->b_lock);
+ bar->b_cycle = 0;
+ bar->b_waiters = 0;
+ bar->b_count = count;
+ *barrier = bar;
+
+ return (0);
+}
+
+int
+_pthread_barrier_wait(pthread_barrier_t *barrier)
+{
+ struct pthread *curthread = _get_curthread();
+ pthread_barrier_t bar;
+ long cycle;
+ int ret;
+
+ if (barrier == NULL || *barrier == NULL)
+ return (EINVAL);
+
+ bar = *barrier;
+ THR_UMTX_LOCK(curthread, &bar->b_lock);
+ if (++bar->b_waiters == bar->b_count) {
+ /* Current thread is lastest thread */
+ bar->b_waiters = 0;
+ bar->b_cycle++;
+ _thr_umtx_wake(&bar->b_cycle, bar->b_count - 1);
+ THR_UMTX_UNLOCK(curthread, &bar->b_lock);
+ ret = PTHREAD_BARRIER_SERIAL_THREAD;
+ } else {
+ cycle = bar->b_cycle;
+ THR_UMTX_UNLOCK(curthread, &bar->b_lock);
+ do {
+ _thr_umtx_wait(&bar->b_cycle, cycle, NULL);
+ /* test cycle to avoid bogus wakeup */
+ } while (cycle == bar->b_cycle);
+ ret = 0;
+ }
+ return (ret);
+}
diff --git a/lib/libthr/thread/thr_barrierattr.c b/lib/libthr/thread/thr_barrierattr.c
new file mode 100644
index 0000000..32b9723
--- /dev/null
+++ b/lib/libthr/thread/thr_barrierattr.c
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2003 David Xu <davidxu@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 "namespace.h"
+#include <errno.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include "un-namespace.h"
+
+#include "thr_private.h"
+
+__weak_reference(_pthread_barrierattr_destroy, pthread_barrierattr_destroy);
+__weak_reference(_pthread_barrierattr_init, pthread_barrierattr_init);
+__weak_reference(_pthread_barrierattr_setpshared,
+ pthread_barrierattr_setpshared);
+__weak_reference(_pthread_barrierattr_getpshared,
+ pthread_barrierattr_getpshared);
+
+int
+_pthread_barrierattr_destroy(pthread_barrierattr_t *attr)
+{
+
+ if (attr == NULL || *attr == NULL)
+ return (EINVAL);
+
+ free(*attr);
+ return (0);
+}
+
+int
+_pthread_barrierattr_getpshared(const pthread_barrierattr_t *attr,
+ int *pshared)
+{
+
+ if (attr == NULL || *attr == NULL)
+ return (EINVAL);
+
+ *pshared = (*attr)->pshared;
+ return (0);
+}
+
+int
+_pthread_barrierattr_init(pthread_barrierattr_t *attr)
+{
+
+ if (attr == NULL)
+ return (EINVAL);
+
+ if ((*attr = malloc(sizeof(struct pthread_barrierattr))) == NULL)
+ return (ENOMEM);
+
+ (*attr)->pshared = PTHREAD_PROCESS_PRIVATE;
+ return (0);
+}
+
+int
+_pthread_barrierattr_setpshared(pthread_barrierattr_t *attr, int pshared)
+{
+
+ if (attr == NULL || *attr == NULL)
+ return (EINVAL);
+
+ /* Only PTHREAD_PROCESS_PRIVATE is supported. */
+ if (pshared != PTHREAD_PROCESS_PRIVATE)
+ return (EINVAL);
+
+ (*attr)->pshared = pshared;
+ return (0);
+}
diff --git a/lib/libthr/thread/thr_cancel.c b/lib/libthr/thread/thr_cancel.c
new file mode 100644
index 0000000..1047eb2
--- /dev/null
+++ b/lib/libthr/thread/thr_cancel.c
@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) 2005, David Xu <davidxu@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 "namespace.h"
+#include <pthread.h>
+#include "un-namespace.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)
+{
+ struct pthread *curthread = _get_curthread();
+ int oldval, newval = 0;
+ int oldtype;
+ int ret;
+
+ /*
+ * POSIX says _pthread_cancel should be async cancellation safe,
+ * so we temporarily disable async cancellation.
+ */
+ _pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &oldtype);
+ if ((ret = _thr_ref_add(curthread, pthread, 0)) != 0) {
+ _pthread_setcanceltype(oldtype, NULL);
+ return (ret);
+ }
+
+ do {
+ oldval = pthread->cancelflags;
+ if (oldval & THR_CANCEL_NEEDED)
+ break;
+ newval = oldval | THR_CANCEL_NEEDED;
+ } while (!atomic_cmpset_acq_int(&pthread->cancelflags, oldval, newval));
+
+ if (!(oldval & THR_CANCEL_NEEDED) && SHOULD_ASYNC_CANCEL(newval))
+ _thr_send_sig(pthread, SIGCANCEL);
+
+ _thr_ref_delete(curthread, pthread);
+ _pthread_setcanceltype(oldtype, NULL);
+ return (0);
+}
+
+static inline void
+testcancel(struct pthread *curthread)
+{
+ int newval;
+
+ newval = curthread->cancelflags;
+ if (SHOULD_CANCEL(newval) && !THR_IN_CRITICAL(curthread))
+ _pthread_exit(PTHREAD_CANCELED);
+}
+
+int
+_pthread_setcancelstate(int state, int *oldstate)
+{
+ struct pthread *curthread = _get_curthread();
+ int oldval, ret;
+
+ oldval = curthread->cancelflags;
+ if (oldstate != NULL)
+ *oldstate = ((oldval & THR_CANCEL_DISABLE) ?
+ PTHREAD_CANCEL_DISABLE : PTHREAD_CANCEL_ENABLE);
+ switch (state) {
+ case PTHREAD_CANCEL_DISABLE:
+ atomic_set_int(&curthread->cancelflags, THR_CANCEL_DISABLE);
+ ret = 0;
+ break;
+ case PTHREAD_CANCEL_ENABLE:
+ atomic_clear_int(&curthread->cancelflags, THR_CANCEL_DISABLE);
+ testcancel(curthread);
+ ret = 0;
+ break;
+ default:
+ ret = EINVAL;
+ }
+
+ return (ret);
+}
+
+int
+_pthread_setcanceltype(int type, int *oldtype)
+{
+ struct pthread *curthread = _get_curthread();
+ int oldval, ret;
+
+ oldval = curthread->cancelflags;
+ if (oldtype != NULL)
+ *oldtype = ((oldval & THR_CANCEL_AT_POINT) ?
+ PTHREAD_CANCEL_ASYNCHRONOUS :
+ PTHREAD_CANCEL_DEFERRED);
+ switch (type) {
+ case PTHREAD_CANCEL_ASYNCHRONOUS:
+ atomic_set_int(&curthread->cancelflags, THR_CANCEL_AT_POINT);
+ testcancel(curthread);
+ ret = 0;
+ break;
+ case PTHREAD_CANCEL_DEFERRED:
+ atomic_clear_int(&curthread->cancelflags, THR_CANCEL_AT_POINT);
+ ret = 0;
+ break;
+ default:
+ ret = EINVAL;
+ }
+
+ return (ret);
+}
+
+void
+_pthread_testcancel(void)
+{
+ testcancel(_get_curthread());
+}
+
+int
+_thr_cancel_enter(struct pthread *curthread)
+{
+ int oldval;
+
+ oldval = curthread->cancelflags;
+ if (!(oldval & THR_CANCEL_AT_POINT)) {
+ atomic_set_int(&curthread->cancelflags, THR_CANCEL_AT_POINT);
+ testcancel(curthread);
+ }
+ return (oldval);
+}
+
+void
+_thr_cancel_leave(struct pthread *curthread, int previous)
+{
+ if (!(previous & THR_CANCEL_AT_POINT))
+ atomic_clear_int(&curthread->cancelflags, THR_CANCEL_AT_POINT);
+}
diff --git a/lib/libthr/thread/thr_clean.c b/lib/libthr/thread/thr_clean.c
new file mode 100644
index 0000000..a5e9378
--- /dev/null
+++ b/lib/libthr/thread/thr_clean.c
@@ -0,0 +1,78 @@
+/*
+ * 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 "namespace.h"
+#include <signal.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include "un-namespace.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->onstack = 0;
+ 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);
+ }
+ if (old->onstack == 0)
+ free(old);
+ }
+}
diff --git a/lib/libthr/thread/thr_concurrency.c b/lib/libthr/thread/thr_concurrency.c
new file mode 100644
index 0000000..61f0c4a
--- /dev/null
+++ b/lib/libthr/thread/thr_concurrency.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2003 Sergey Osokin <osa@FreeBSD.org.ru>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Sergey Osokin.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY SERGEY OSOKIN AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED 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 "namespace.h"
+#include <errno.h>
+#include <pthread.h>
+#include "un-namespace.h"
+
+#include "thr_private.h"
+
+static int current_concurrency = 0;
+
+__weak_reference(_pthread_getconcurrency, pthread_getconcurrency);
+__weak_reference(_pthread_setconcurrency, pthread_setconcurrency);
+
+int
+_pthread_getconcurrency(void)
+{
+ return current_concurrency;
+}
+
+int
+_pthread_setconcurrency(int new_level)
+{
+ int ret;
+
+ if (new_level < 0) {
+ ret = EINVAL;
+ } else {
+ current_concurrency = new_level;
+ ret = 0;
+ }
+ return (ret);
+}
diff --git a/lib/libthr/thread/thr_cond.c b/lib/libthr/thread/thr_cond.c
new file mode 100644
index 0000000..f786062
--- /dev/null
+++ b/lib/libthr/thread/thr_cond.c
@@ -0,0 +1,350 @@
+/*
+ * Copyright (c) 2005 David Xu <davidxu@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 "namespace.h"
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <pthread.h>
+#include <limits.h>
+#include "un-namespace.h"
+
+#include "thr_private.h"
+
+/*
+ * Prototypes
+ */
+int __pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
+int __pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
+ const struct timespec * abstime);
+static int cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr);
+static int cond_wait_common(pthread_cond_t *cond, pthread_mutex_t *mutex,
+ const struct timespec *abstime, int cancel);
+static int cond_signal_common(pthread_cond_t *cond, int broadcast);
+
+/*
+ * Double underscore versions are cancellation points. Single underscore
+ * versions are not and are provided for libc internal usage (which
+ * shouldn't introduce cancellation points).
+ */
+__weak_reference(__pthread_cond_wait, pthread_cond_wait);
+__weak_reference(__pthread_cond_timedwait, pthread_cond_timedwait);
+
+__weak_reference(_pthread_cond_init, pthread_cond_init);
+__weak_reference(_pthread_cond_destroy, pthread_cond_destroy);
+__weak_reference(_pthread_cond_signal, pthread_cond_signal);
+__weak_reference(_pthread_cond_broadcast, pthread_cond_broadcast);
+
+static int
+cond_init(pthread_cond_t *cond, const pthread_condattr_t *cond_attr)
+{
+ pthread_cond_t pcond;
+ int rval = 0;
+
+ if ((pcond = (pthread_cond_t)
+ malloc(sizeof(struct pthread_cond))) == NULL) {
+ rval = ENOMEM;
+ } else {
+ /*
+ * Initialise the condition variable structure:
+ */
+ _thr_umtx_init(&pcond->c_lock);
+ pcond->c_seqno = 0;
+ pcond->c_waiters = 0;
+ pcond->c_wakeups = 0;
+ if (cond_attr == NULL || *cond_attr == NULL) {
+ pcond->c_pshared = 0;
+ pcond->c_clockid = CLOCK_REALTIME;
+ } else {
+ pcond->c_pshared = (*cond_attr)->c_pshared;
+ pcond->c_clockid = (*cond_attr)->c_clockid;
+ }
+ *cond = pcond;
+ }
+ /* Return the completion status: */
+ return (rval);
+}
+
+static int
+init_static(struct pthread *thread, pthread_cond_t *cond)
+{
+ int ret;
+
+ THR_LOCK_ACQUIRE(thread, &_cond_static_lock);
+
+ if (*cond == NULL)
+ ret = cond_init(cond, NULL);
+ else
+ ret = 0;
+
+ THR_LOCK_RELEASE(thread, &_cond_static_lock);
+
+ return (ret);
+}
+
+int
+_pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *cond_attr)
+{
+
+ *cond = NULL;
+ return (cond_init(cond, cond_attr));
+}
+
+int
+_pthread_cond_destroy(pthread_cond_t *cond)
+{
+ struct pthread_cond *cv;
+ struct pthread *curthread = _get_curthread();
+ int rval = 0;
+
+ if (*cond == NULL)
+ rval = EINVAL;
+ else {
+ /* Lock the condition variable structure: */
+ THR_LOCK_ACQUIRE(curthread, &(*cond)->c_lock);
+ if ((*cond)->c_waiters + (*cond)->c_wakeups != 0) {
+ THR_LOCK_RELEASE(curthread, &(*cond)->c_lock);
+ return (EBUSY);
+ }
+
+ /*
+ * NULL the caller's pointer now that the condition
+ * variable has been destroyed:
+ */
+ cv = *cond;
+ *cond = NULL;
+
+ /* Unlock the condition variable structure: */
+ THR_LOCK_RELEASE(curthread, &cv->c_lock);
+
+ /* Free the cond lock structure: */
+
+ /*
+ * Free the memory allocated for the condition
+ * variable structure:
+ */
+ free(cv);
+
+ }
+ /* Return the completion status: */
+ return (rval);
+}
+
+struct cond_cancel_info
+{
+ pthread_mutex_t *mutex;
+ pthread_cond_t *cond;
+ long seqno;
+ int count;
+};
+
+static void
+cond_cancel_handler(void *arg)
+{
+ struct pthread *curthread = _get_curthread();
+ struct cond_cancel_info *info = (struct cond_cancel_info *)arg;
+ pthread_cond_t cv;
+
+ cv = *(info->cond);
+ THR_LOCK_ACQUIRE(curthread, &cv->c_lock);
+ if (cv->c_seqno != info->seqno && cv->c_wakeups != 0) {
+ if (cv->c_waiters > 0) {
+ cv->c_seqno++;
+ _thr_umtx_wake(&cv->c_seqno, 1);
+ } else
+ cv->c_wakeups--;
+ } else {
+ cv->c_waiters--;
+ }
+ THR_LOCK_RELEASE(curthread, &cv->c_lock);
+
+ _mutex_cv_lock(info->mutex, info->count);
+}
+
+static int
+cond_wait_common(pthread_cond_t *cond, pthread_mutex_t *mutex,
+ const struct timespec *abstime, int cancel)
+{
+ struct pthread *curthread = _get_curthread();
+ struct timespec ts, ts2, *tsp;
+ struct cond_cancel_info info;
+ pthread_cond_t cv;
+ long seq, oldseq;
+ int oldcancel;
+ int ret = 0;
+
+ /*
+ * If the condition variable is statically initialized,
+ * perform the dynamic initialization:
+ */
+ if (__predict_false(*cond == NULL &&
+ (ret = init_static(curthread, cond)) != 0))
+ return (ret);
+
+ cv = *cond;
+ THR_LOCK_ACQUIRE(curthread, &cv->c_lock);
+ ret = _mutex_cv_unlock(mutex, &info.count);
+ if (ret) {
+ THR_LOCK_RELEASE(curthread, &cv->c_lock);
+ return (ret);
+ }
+ oldseq = seq = cv->c_seqno;
+ info.mutex = mutex;
+ info.cond = cond;
+ info.seqno = oldseq;
+
+ cv->c_waiters++;
+ do {
+ THR_LOCK_RELEASE(curthread, &cv->c_lock);
+
+ if (abstime != NULL) {
+ clock_gettime(cv->c_clockid, &ts);
+ TIMESPEC_SUB(&ts2, abstime, &ts);
+ tsp = &ts2;
+ } else
+ tsp = NULL;
+
+ if (cancel) {
+ THR_CLEANUP_PUSH(curthread, cond_cancel_handler, &info);
+ oldcancel = _thr_cancel_enter(curthread);
+ ret = _thr_umtx_wait(&cv->c_seqno, seq, tsp);
+ _thr_cancel_leave(curthread, oldcancel);
+ THR_CLEANUP_POP(curthread, 0);
+ } else {
+ ret = _thr_umtx_wait(&cv->c_seqno, seq, tsp);
+ }
+
+ THR_LOCK_ACQUIRE(curthread, &cv->c_lock);
+ seq = cv->c_seqno;
+ if (abstime != NULL && ret == ETIMEDOUT)
+ break;
+
+ /*
+ * loop if we have never been told to wake up
+ * or we lost a race.
+ */
+ } while (seq == oldseq || cv->c_wakeups == 0);
+
+ if (seq != oldseq && cv->c_wakeups != 0) {
+ cv->c_wakeups--;
+ ret = 0;
+ } else {
+ cv->c_waiters--;
+ }
+ THR_LOCK_RELEASE(curthread, &cv->c_lock);
+ _mutex_cv_lock(mutex, info.count);
+ return (ret);
+}
+
+int
+_pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
+{
+
+ return (cond_wait_common(cond, mutex, NULL, 0));
+}
+
+int
+__pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
+{
+
+ return (cond_wait_common(cond, mutex, NULL, 1));
+}
+
+int
+_pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex,
+ const struct timespec * abstime)
+{
+
+ if (abstime == NULL || abstime->tv_sec < 0 || abstime->tv_nsec < 0 ||
+ abstime->tv_nsec >= 1000000000)
+ return (EINVAL);
+
+ return (cond_wait_common(cond, mutex, abstime, 0));
+}
+
+int
+__pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
+ const struct timespec *abstime)
+{
+
+ if (abstime == NULL || abstime->tv_sec < 0 || abstime->tv_nsec < 0 ||
+ abstime->tv_nsec >= 1000000000)
+ return (EINVAL);
+
+ return (cond_wait_common(cond, mutex, abstime, 1));
+}
+
+static int
+cond_signal_common(pthread_cond_t *cond, int broadcast)
+{
+ struct pthread *curthread = _get_curthread();
+ pthread_cond_t cv;
+ int ret = 0, oldwaiters;
+
+ /*
+ * If the condition variable is statically initialized, perform dynamic
+ * initialization.
+ */
+ if (__predict_false(*cond == NULL &&
+ (ret = init_static(curthread, cond)) != 0))
+ return (ret);
+
+ cv = *cond;
+ /* Lock the condition variable structure. */
+ THR_LOCK_ACQUIRE(curthread, &cv->c_lock);
+ if (cv->c_waiters) {
+ if (!broadcast) {
+ cv->c_wakeups++;
+ cv->c_waiters--;
+ cv->c_seqno++;
+ _thr_umtx_wake(&cv->c_seqno, 1);
+ } else {
+ oldwaiters = cv->c_waiters;
+ cv->c_wakeups += cv->c_waiters;
+ cv->c_waiters = 0;
+ cv->c_seqno++;
+ _thr_umtx_wake(&cv->c_seqno, oldwaiters);
+ }
+ }
+ THR_LOCK_RELEASE(curthread, &cv->c_lock);
+ return (ret);
+}
+
+int
+_pthread_cond_signal(pthread_cond_t * cond)
+{
+
+ return (cond_signal_common(cond, 0));
+}
+
+int
+_pthread_cond_broadcast(pthread_cond_t * cond)
+{
+
+ return (cond_signal_common(cond, 1));
+}
diff --git a/lib/libthr/thread/thr_condattr.c b/lib/libthr/thread/thr_condattr.c
new file mode 100644
index 0000000..9e14dc2
--- /dev/null
+++ b/lib/libthr/thread/thr_condattr.c
@@ -0,0 +1,130 @@
+/*
+ * 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 "namespace.h"
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <pthread.h>
+#include "un-namespace.h"
+
+#include "thr_private.h"
+
+__weak_reference(_pthread_condattr_init, pthread_condattr_init);
+__weak_reference(_pthread_condattr_destroy, pthread_condattr_destroy);
+__weak_reference(_pthread_condattr_getclock, pthread_condattr_getclock);
+__weak_reference(_pthread_condattr_setclock, pthread_condattr_setclock);
+__weak_reference(_pthread_condattr_getpshared, pthread_condattr_getpshared);
+__weak_reference(_pthread_condattr_setpshared, pthread_condattr_setpshared);
+
+int
+_pthread_condattr_init(pthread_condattr_t *attr)
+{
+ pthread_condattr_t pattr;
+ int ret;
+
+ 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);
+}
+
+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);
+}
+
+int
+_pthread_condattr_getclock(const pthread_condattr_t *attr,
+ clockid_t *clock_id)
+{
+ if (attr == NULL || *attr == NULL)
+ return (EINVAL);
+ *clock_id = (*attr)->c_clockid;
+ return (0);
+}
+
+int
+_pthread_condattr_setclock(pthread_condattr_t *attr,
+ clockid_t clock_id)
+{
+ if (attr == NULL || *attr == NULL)
+ return (EINVAL);
+ if (clock_id != CLOCK_REALTIME &&
+ clock_id != CLOCK_VIRTUAL &&
+ clock_id != CLOCK_PROF &&
+ clock_id != CLOCK_MONOTONIC) {
+ return (EINVAL);
+ }
+ (*attr)->c_clockid = clock_id;
+ return (0);
+}
+
+int
+_pthread_condattr_getpshared(const pthread_condattr_t *attr,
+ int *pshared)
+{
+ if (attr == NULL || *attr == NULL)
+ return (EINVAL);
+
+ pshared = PTHREAD_PROCESS_PRIVATE;
+ return (0);
+}
+
+int
+_pthread_condattr_setpshared(pthread_condattr_t *attr, int pshared)
+{
+ if (attr == NULL || *attr == NULL)
+ return (EINVAL);
+
+ if (pshared != PTHREAD_PROCESS_PRIVATE)
+ return (EINVAL);
+ return (0);
+}
diff --git a/lib/libthr/thread/thr_create.c b/lib/libthr/thread/thr_create.c
new file mode 100644
index 0000000..bb5724a
--- /dev/null
+++ b/lib/libthr/thread/thr_create.c
@@ -0,0 +1,251 @@
+/*
+ * Copyright (c) 2003 Daniel M. Eischen <deischen@gdeb.com>
+ * Copyright (c) 2005, David Xu <davidxu@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 "namespace.h"
+#include <sys/types.h>
+#include <sys/signalvar.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stddef.h>
+#include <pthread.h>
+#include "un-namespace.h"
+
+#include "thr_private.h"
+
+static int create_stack(struct pthread_attr *pattr);
+static void thread_start(struct pthread *curthread);
+
+__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, *new_thread;
+ struct thr_param param;
+ int ret = 0, locked, create_suspended;
+ sigset_t set, oset;
+
+ _thr_check_init();
+
+ /*
+ * Tell libc and others now they need lock to protect their data.
+ */
+ if (_thr_isthreaded() == 0 && _thr_setthreaded(1))
+ return (EAGAIN);
+
+ curthread = _get_curthread();
+ if ((new_thread = _thr_alloc(curthread)) == NULL)
+ return (EAGAIN);
+
+ memset(&param, 0, sizeof(param));
+
+ if (attr == NULL || *attr == NULL)
+ /* Use the default thread attributes: */
+ new_thread->attr = _pthread_attr_default;
+ else
+ new_thread->attr = *(*attr);
+ if (new_thread->attr.sched_inherit == PTHREAD_INHERIT_SCHED) {
+ /* inherit scheduling contention scope */
+ if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM)
+ new_thread->attr.flags |= PTHREAD_SCOPE_SYSTEM;
+ else
+ new_thread->attr.flags &= ~PTHREAD_SCOPE_SYSTEM;
+ /*
+ * scheduling policy and scheduling parameters will be
+ * inherited in following code.
+ */
+ }
+
+ if (_thr_scope_system > 0)
+ new_thread->attr.flags |= PTHREAD_SCOPE_SYSTEM;
+ else if (_thr_scope_system < 0)
+ new_thread->attr.flags &= ~PTHREAD_SCOPE_SYSTEM;
+
+ new_thread->tid = TID_TERMINATED;
+
+ if (create_stack(&new_thread->attr) != 0) {
+ /* Insufficient memory to create a stack: */
+ _thr_free(curthread, new_thread);
+ return (EAGAIN);
+ }
+ /*
+ * Write a magic value to the thread structure
+ * to help identify valid ones:
+ */
+ new_thread->magic = THR_MAGIC;
+ new_thread->start_routine = start_routine;
+ new_thread->arg = arg;
+ new_thread->cancelflags = PTHREAD_CANCEL_ENABLE |
+ PTHREAD_CANCEL_DEFERRED;
+ /*
+ * Check if this thread is to inherit the scheduling
+ * attributes from its parent:
+ */
+ if (new_thread->attr.sched_inherit == PTHREAD_INHERIT_SCHED) {
+ /*
+ * Copy the scheduling attributes. Lock the scheduling
+ * lock to get consistent scheduling parameters.
+ */
+ THR_LOCK(curthread);
+ new_thread->base_priority = curthread->base_priority;
+ new_thread->attr.prio = curthread->base_priority;
+ new_thread->attr.sched_policy = curthread->attr.sched_policy;
+ THR_UNLOCK(curthread);
+ } 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;
+
+ /* Initialize the mutex queue: */
+ TAILQ_INIT(&new_thread->mutexq);
+
+ /* Initialise hooks in the thread structure: */
+ if (new_thread->attr.suspend == THR_CREATE_SUSPENDED) {
+ new_thread->flags = THR_FLAGS_NEED_SUSPEND;
+ create_suspended = 1;
+ } else {
+ create_suspended = 0;
+ }
+
+ new_thread->state = PS_RUNNING;
+
+ if (new_thread->attr.flags & PTHREAD_CREATE_DETACHED)
+ new_thread->tlflags |= TLFLAGS_DETACHED;
+
+ /* Add the new thread. */
+ new_thread->refcount = 1;
+ _thr_link(curthread, new_thread);
+ /* Return thread pointer eariler so that new thread can use it. */
+ (*thread) = new_thread;
+ if (SHOULD_REPORT_EVENT(curthread, TD_CREATE)) {
+ THR_THREAD_LOCK(curthread, new_thread);
+ locked = 1;
+ } else
+ locked = 0;
+ param.start_func = (void (*)(void *)) thread_start;
+ param.arg = new_thread;
+ param.stack_base = new_thread->attr.stackaddr_attr;
+ param.stack_size = new_thread->attr.stacksize_attr;
+ param.tls_base = (char *)new_thread->tcb;
+ param.tls_size = sizeof(struct tcb);
+ param.child_tid = &new_thread->tid;
+ param.parent_tid = &new_thread->tid;
+ param.flags = 0;
+ if (new_thread->attr.flags & PTHREAD_SCOPE_SYSTEM)
+ param.flags |= THR_SYSTEM_SCOPE;
+
+ /* Schedule the new thread. */
+ if (create_suspended) {
+ SIGFILLSET(set);
+ SIGDELSET(set, SIGTRAP);
+ __sys_sigprocmask(SIG_SETMASK, &set, &oset);
+ new_thread->sigmask = oset;
+ }
+
+ ret = thr_new(&param, sizeof(param));
+
+ if (create_suspended)
+ __sys_sigprocmask(SIG_SETMASK, &oset, NULL);
+
+ if (ret != 0) {
+ if (!locked)
+ THR_THREAD_LOCK(curthread, new_thread);
+ new_thread->state = PS_DEAD;
+ new_thread->tid = TID_TERMINATED;
+ if (new_thread->flags & THR_FLAGS_NEED_SUSPEND) {
+ new_thread->cycle++;
+ _thr_umtx_wake(&new_thread->cycle, INT_MAX);
+ }
+ THR_THREAD_UNLOCK(curthread, new_thread);
+ THREAD_LIST_LOCK(curthread);
+ _thread_active_threads--;
+ new_thread->tlflags |= TLFLAGS_DETACHED;
+ _thr_ref_delete_unlocked(curthread, new_thread);
+ THREAD_LIST_UNLOCK(curthread);
+ (*thread) = 0;
+ ret = EAGAIN;
+ } else if (locked) {
+ _thr_report_creation(curthread, new_thread);
+ THR_THREAD_UNLOCK(curthread, new_thread);
+ }
+ return (ret);
+}
+
+static int
+create_stack(struct pthread_attr *pattr)
+{
+ int ret;
+
+ /* Check if a stack was specified in the thread attributes: */
+ if ((pattr->stackaddr_attr) != NULL) {
+ pattr->guardsize_attr = 0;
+ pattr->flags |= THR_STACK_USER;
+ ret = 0;
+ }
+ else
+ ret = _thr_stack_alloc(pattr);
+ return (ret);
+}
+
+static void
+thread_start(struct pthread *curthread)
+{
+ if (curthread->attr.suspend == THR_CREATE_SUSPENDED) {
+ sigset_t set = curthread->sigmask;
+
+ _thr_ast(curthread);
+
+ /*
+ * Parent thread have stored signal mask for us,
+ * we should restore it now.
+ */
+ sigprocmask(SIG_SETMASK, &set, NULL);
+ }
+
+ /*
+ * This is used as a serialization point to allow parent
+ * to report 'new thread' event to debugger before the thread
+ * does real work.
+ */
+ THR_LOCK(curthread);
+ THR_UNLOCK(curthread);
+
+ /* 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..bfcb6e6
--- /dev/null
+++ b/lib/libthr/thread/thr_detach.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2005 David Xu <davidxu@freebsd.org>
+ * Copyright (C) 2003 Daniel M. Eischen <deischen@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 "namespace.h"
+#include <sys/types.h>
+#include <errno.h>
+#include <pthread.h>
+#include "un-namespace.h"
+
+#include "thr_private.h"
+
+__weak_reference(_pthread_detach, pthread_detach);
+
+int
+_pthread_detach(pthread_t pthread)
+{
+ struct pthread *curthread = _get_curthread();
+ int rval;
+
+ if (pthread == NULL)
+ return (EINVAL);
+
+ THREAD_LIST_LOCK(curthread);
+ if ((rval = _thr_find_thread(curthread, pthread,
+ /*include dead*/1)) != 0) {
+ THREAD_LIST_UNLOCK(curthread);
+ return (rval);
+ }
+
+ /* Check if the thread is already detached or has a joiner. */
+ if ((pthread->tlflags & TLFLAGS_DETACHED) != 0 ||
+ (pthread->joiner != NULL)) {
+ THREAD_LIST_UNLOCK(curthread);
+ return (EINVAL);
+ }
+
+ /* Flag the thread as detached. */
+ pthread->tlflags |= TLFLAGS_DETACHED;
+ if (pthread->state == PS_DEAD)
+ THR_GCLIST_ADD(pthread);
+ THREAD_LIST_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..f9f4916
--- /dev/null
+++ b/lib/libthr/thread/thr_equal.c
@@ -0,0 +1,46 @@
+/*
+ * 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 "namespace.h"
+#include <pthread.h>
+#include "un-namespace.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_event.c b/lib/libthr/thread/thr_event.c
new file mode 100644
index 0000000..6a64cf9
--- /dev/null
+++ b/lib/libthr/thread/thr_event.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2005 David Xu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * 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 "thr_private.h"
+
+void
+_thread_bp_create(void)
+{
+}
+
+void
+_thread_bp_death(void)
+{
+}
+
+void
+_thr_report_creation(struct pthread *curthread, struct pthread *newthread)
+{
+ curthread->event_buf.event = TD_CREATE;
+ curthread->event_buf.th_p = (td_thrhandle_t *)newthread;
+ curthread->event_buf.data = 0;
+ THR_UMTX_LOCK(curthread, &_thr_event_lock);
+ _thread_last_event = curthread;
+ _thread_bp_create();
+ _thread_last_event = NULL;
+ THR_UMTX_UNLOCK(curthread, &_thr_event_lock);
+}
+
+void
+_thr_report_death(struct pthread *curthread)
+{
+ curthread->event_buf.event = TD_DEATH;
+ curthread->event_buf.th_p = (td_thrhandle_t *)curthread;
+ curthread->event_buf.data = 0;
+ THR_UMTX_LOCK(curthread, &_thr_event_lock);
+ _thread_last_event = curthread;
+ _thread_bp_death();
+ _thread_last_event = NULL;
+ THR_UMTX_UNLOCK(curthread, &_thr_event_lock);
+}
diff --git a/lib/libthr/thread/thr_exit.c b/lib/libthr/thread/thr_exit.c
new file mode 100644
index 0000000..d438ac5
--- /dev/null
+++ b/lib/libthr/thread/thr_exit.c
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <pthread.h>
+
+#include "thr_private.h"
+
+void _pthread_exit(void *status);
+
+__weak_reference(_pthread_exit, pthread_exit);
+
+void
+_thread_exit(const char *fname, int lineno, const char *msg)
+{
+
+ /* Write an error message to the standard error file descriptor: */
+ _thread_printf(2,
+ "Fatal error '%s' at line %d in file %s (errno = %d)\n",
+ msg, lineno, fname, errno);
+
+ abort();
+}
+
+/*
+ * 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
+_thr_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();
+
+ /* Check if this thread is already in the process of exiting: */
+ if ((curthread->cancelflags & THR_CANCEL_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. */
+ atomic_set_int(&curthread->cancelflags, THR_CANCEL_EXITING);
+
+ _thr_exit_cleanup();
+
+ /* Save the return value: */
+ curthread->ret = status;
+ while (curthread->cleanup != NULL) {
+ pthread_cleanup_pop(1);
+ }
+
+ /* Check if there is thread specific data: */
+ if (curthread->specific != NULL) {
+ /* Run the thread-specific data destructors: */
+ _thread_cleanupspecific();
+ }
+
+ if (!_thr_isthreaded())
+ exit(0);
+
+ THREAD_LIST_LOCK(curthread);
+ _thread_active_threads--;
+ if (_thread_active_threads == 0) {
+ THREAD_LIST_UNLOCK(curthread);
+ exit(0);
+ /* Never reach! */
+ }
+ THR_LOCK(curthread);
+ curthread->state = PS_DEAD;
+ THR_UNLOCK(curthread);
+ /*
+ * Thread was created with initial refcount 1, we drop the
+ * reference count to allow it to be garbage collected.
+ */
+ curthread->refcount--;
+ if (curthread->tlflags & TLFLAGS_DETACHED)
+ THR_GCLIST_ADD(curthread);
+ THREAD_LIST_UNLOCK(curthread);
+ if (SHOULD_REPORT_EVENT(curthread, TD_DEATH))
+ _thr_report_death(curthread);
+
+ /*
+ * Kernel will do wakeup at the address, so joiner thread
+ * will be resumed if it is sleeping at the address.
+ */
+ thr_exit(&curthread->tid);
+ PANIC("thr_exit() returned");
+ /* Never reach! */
+}
diff --git a/lib/libthr/thread/thr_fork.c b/lib/libthr/thread/thr_fork.c
new file mode 100644
index 0000000..558a036
--- /dev/null
+++ b/lib/libthr/thread/thr_fork.c
@@ -0,0 +1,198 @@
+/*
+ * Copyright (c) 2005 David Xu <davidxu@freebsd.org>
+ * Copyright (c) 2003 Daniel Eischen <deischen@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. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * 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$
+ */
+
+/*
+ * 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 "namespace.h"
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <spinlock.h>
+#include "un-namespace.h"
+
+#include "libc_private.h"
+#include "thr_private.h"
+
+__weak_reference(_pthread_atfork, pthread_atfork);
+
+int
+_pthread_atfork(void (*prepare)(void), void (*parent)(void),
+ void (*child)(void))
+{
+ struct pthread *curthread;
+ struct pthread_atfork *af;
+
+ _thr_check_init();
+
+ if ((af = malloc(sizeof(struct pthread_atfork))) == NULL)
+ return (ENOMEM);
+
+ curthread = _get_curthread();
+ af->prepare = prepare;
+ af->parent = parent;
+ af->child = child;
+ THR_UMTX_LOCK(curthread, &_thr_atfork_lock);
+ TAILQ_INSERT_TAIL(&_thr_atfork_list, af, qe);
+ THR_UMTX_UNLOCK(curthread, &_thr_atfork_lock);
+ return (0);
+}
+
+__weak_reference(_fork, fork);
+
+pid_t _fork(void);
+
+pid_t
+_fork(void)
+{
+ struct pthread *curthread;
+ struct pthread_atfork *af;
+ pid_t ret;
+ int errsave;
+ int unlock_malloc;
+
+ if (!_thr_is_inited())
+ return (__sys_fork());
+
+ curthread = _get_curthread();
+
+ THR_UMTX_LOCK(curthread, &_thr_atfork_lock);
+
+ /* Run down atfork prepare handlers. */
+ TAILQ_FOREACH_REVERSE(af, &_thr_atfork_list, atfork_head, qe) {
+ if (af->prepare != NULL)
+ af->prepare();
+ }
+
+ /*
+ * Try our best to protect memory from being corrupted in
+ * child process because another thread in malloc code will
+ * simply be kill by fork().
+ */
+ if (_thr_isthreaded() != 0) {
+ unlock_malloc = 1;
+ _malloc_prefork();
+ } else {
+ unlock_malloc = 0;
+ }
+
+ /*
+ * Block all signals until we reach a safe point.
+ */
+ _thr_signal_block(curthread);
+
+ /* Fork a new process: */
+ if ((ret = __sys_fork()) == 0) {
+ /* Child process */
+ errsave = errno;
+ curthread->cancelflags &= ~THR_CANCEL_NEEDED;
+ /*
+ * Thread list will be reinitialized, and later we call
+ * _libpthread_init(), it will add us back to list.
+ */
+ curthread->tlflags &= ~(TLFLAGS_IN_TDLIST | TLFLAGS_DETACHED);
+
+ /* child is a new kernel thread. */
+ thr_self(&curthread->tid);
+
+ /* clear other threads locked us. */
+ _thr_umtx_init(&curthread->lock);
+ _thr_umtx_init(&_thr_atfork_lock);
+ _thr_setthreaded(0);
+
+ /* reinitialize libc spinlocks. */
+ _thr_spinlock_init();
+ _mutex_fork(curthread);
+
+ /* reinitalize library. */
+ _libpthread_init(curthread);
+
+ /* Ready to continue, unblock signals. */
+ _thr_signal_unblock(curthread);
+
+ /* Run down atfork child handlers. */
+ TAILQ_FOREACH(af, &_thr_atfork_list, qe) {
+ if (af->child != NULL)
+ af->child();
+ }
+ } else {
+ /* Parent process */
+ errsave = errno;
+
+ /* Ready to continue, unblock signals. */
+ _thr_signal_unblock(curthread);
+
+ if (unlock_malloc)
+ _malloc_postfork();
+
+ /* Run down atfork parent handlers. */
+ TAILQ_FOREACH(af, &_thr_atfork_list, qe) {
+ if (af->parent != NULL)
+ af->parent();
+ }
+
+ THR_UMTX_UNLOCK(curthread, &_thr_atfork_lock);
+ }
+ errno = errsave;
+
+ /* Return the process ID: */
+ return (ret);
+}
diff --git a/lib/libthr/thread/thr_getprio.c b/lib/libthr/thread/thr_getprio.c
new file mode 100644
index 0000000..e2cac2f
--- /dev/null
+++ b/lib/libthr/thread/thr_getprio.c
@@ -0,0 +1,58 @@
+/*
+ * 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 "namespace.h"
+#include <errno.h>
+#include <pthread.h>
+#include "un-namespace.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..31b3268
--- /dev/null
+++ b/lib/libthr/thread/thr_getschedparam.c
@@ -0,0 +1,77 @@
+/*
+ * 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 "namespace.h"
+#include <errno.h>
+#include <pthread.h>
+#include "un-namespace.h"
+
+#include "thr_private.h"
+
+__weak_reference(_pthread_getschedparam, pthread_getschedparam);
+
+int
+_pthread_getschedparam(pthread_t pthread, int *policy,
+ struct sched_param *param)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret, tmp;
+
+ if ((param == NULL) || (policy == NULL))
+ /* Return an invalid argument error: */
+ ret = EINVAL;
+ else if (pthread == curthread) {
+ /*
+ * Avoid searching the thread list when it is the current
+ * thread.
+ */
+ THR_THREAD_LOCK(curthread, curthread);
+ param->sched_priority = pthread->base_priority;
+ tmp = pthread->attr.sched_policy;
+ THR_THREAD_UNLOCK(curthread, curthread);
+ *policy = tmp;
+ ret = 0;
+ }
+ /* Find the thread in the list of active threads. */
+ else if ((ret = _thr_ref_add(curthread, pthread, /*include dead*/0))
+ == 0) {
+ THR_THREAD_LOCK(curthread, pthread);
+ param->sched_priority = pthread->base_priority;
+ tmp = pthread->attr.sched_policy;
+ THR_THREAD_UNLOCK(curthread, pthread);
+ _thr_ref_delete(curthread, pthread);
+ *policy = tmp;
+ }
+ return (ret);
+}
diff --git a/lib/libthr/thread/thr_info.c b/lib/libthr/thread/thr_info.c
new file mode 100644
index 0000000..804ce98
--- /dev/null
+++ b/lib/libthr/thread/thr_info.c
@@ -0,0 +1,73 @@
+/*
+ * 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 "namespace.h"
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.h>
+#include <pthread_np.h>
+#include "un-namespace.h"
+
+#include "thr_private.h"
+
+__weak_reference(_pthread_set_name_np, pthread_set_name_np);
+
+/* Set the thread name for debug. */
+void
+_pthread_set_name_np(pthread_t thread, const char *name)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret = 0;
+
+ if (curthread == thread) {
+ if (thr_set_name(thread->tid, name))
+ ret = errno;
+ } else {
+ if (_thr_ref_add(curthread, thread, 0) == 0) {
+ THR_LOCK(thread);
+ if (thread->state != PS_DEAD) {
+ if (thr_set_name(thread->tid, name))
+ ret = errno;
+ }
+ THR_UNLOCK(thread);
+ _thr_ref_delete(curthread, thread);
+ } else {
+ ret = ESRCH;
+ }
+ }
+#if 0
+ /* XXX should return error code. */
+ return (ret);
+#endif
+}
diff --git a/lib/libthr/thread/thr_init.c b/lib/libthr/thread/thr_init.c
new file mode 100644
index 0000000..40365a0
--- /dev/null
+++ b/lib/libthr/thread/thr_init.c
@@ -0,0 +1,466 @@
+/*
+ * Copyright (c) 2003 Daniel M. Eischen <deischen@freebsd.org>
+ * 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 "namespace.h"
+#include <sys/types.h>
+#include <sys/signalvar.h>
+#include <sys/ioctl.h>
+#include <sys/sysctl.h>
+#include <sys/ttycom.h>
+#include <sys/mman.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <paths.h>
+#include <pthread.h>
+#include <pthread_np.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include "un-namespace.h"
+
+#include "libc_private.h"
+#include "thr_private.h"
+
+char *_usrstack;
+struct pthread *_thr_initial;
+int _thr_scope_system;
+int _libthr_debug;
+int _thread_event_mask;
+struct pthread *_thread_last_event;
+pthreadlist _thread_list = TAILQ_HEAD_INITIALIZER(_thread_list);
+pthreadlist _thread_gc_list = TAILQ_HEAD_INITIALIZER(_thread_gc_list);
+int _thread_active_threads = 1;
+atfork_head _thr_atfork_list = TAILQ_HEAD_INITIALIZER(_thr_atfork_list);
+umtx_t _thr_atfork_lock;
+
+/*
+ * XXX these values should be updated from kernel at startup,
+ * but current they are same.
+ */
+struct pthread_prio _thr_priorities[3] = {
+ {0, 31, 0}, /* FIF0 */
+ {-20, 20, 0}, /* OTHER */
+ {0, 31, 0} /* RR */
+};
+
+struct pthread_attr _pthread_attr_default = {
+ .sched_policy = SCHED_OTHER,
+ .sched_inherit = 0,
+ .prio = 0,
+ .suspend = THR_CREATE_RUNNING,
+ .flags = PTHREAD_SCOPE_SYSTEM,
+ .stackaddr_attr = NULL,
+ .stacksize_attr = THR_STACK_DEFAULT,
+ .guardsize_attr = 0
+};
+
+struct pthread_mutex_attr _pthread_mutexattr_default = {
+ .m_type = PTHREAD_MUTEX_DEFAULT,
+ .m_protocol = PTHREAD_PRIO_NONE,
+ .m_ceiling = 0,
+ .m_flags = 0
+};
+
+/* Default condition variable attributes: */
+struct pthread_cond_attr _pthread_condattr_default = {
+ .c_pshared = PTHREAD_PROCESS_PRIVATE,
+ .c_clockid = CLOCK_REALTIME
+};
+
+pid_t _thr_pid;
+size_t _thr_guard_default;
+size_t _thr_stack_default = THR_STACK_DEFAULT;
+size_t _thr_stack_initial = THR_STACK_INITIAL;
+int _thr_page_size;
+int _gc_count;
+umtx_t _mutex_static_lock;
+umtx_t _cond_static_lock;
+umtx_t _rwlock_static_lock;
+umtx_t _keytable_lock;
+umtx_t _thr_list_lock;
+umtx_t _thr_event_lock;
+
+int __pthread_cond_wait(pthread_cond_t *, pthread_mutex_t *);
+int __pthread_mutex_lock(pthread_mutex_t *);
+int __pthread_mutex_trylock(pthread_mutex_t *);
+void _thread_init_hack(void) __attribute__ ((constructor));
+
+static void init_private(void);
+static void init_main_thread(struct pthread *thread);
+
+/*
+ * All weak references used within libc should be in this table.
+ * This is so that static libraries will work.
+ */
+STATIC_LIB_REQUIRE(_accept);
+STATIC_LIB_REQUIRE(_close);
+STATIC_LIB_REQUIRE(_connect);
+STATIC_LIB_REQUIRE(_fcntl);
+STATIC_LIB_REQUIRE(_fsync);
+STATIC_LIB_REQUIRE(_nanosleep);
+STATIC_LIB_REQUIRE(_open);
+STATIC_LIB_REQUIRE(_pthread_getspecific);
+STATIC_LIB_REQUIRE(_pthread_key_create);
+STATIC_LIB_REQUIRE(_pthread_key_delete);
+STATIC_LIB_REQUIRE(_pthread_mutex_destroy);
+STATIC_LIB_REQUIRE(_pthread_mutex_init);
+STATIC_LIB_REQUIRE(_pthread_mutex_lock);
+STATIC_LIB_REQUIRE(_pthread_mutex_trylock);
+STATIC_LIB_REQUIRE(_pthread_mutex_unlock);
+STATIC_LIB_REQUIRE(_pthread_mutexattr_init);
+STATIC_LIB_REQUIRE(_pthread_mutexattr_destroy);
+STATIC_LIB_REQUIRE(_pthread_mutexattr_settype);
+STATIC_LIB_REQUIRE(_pthread_once);
+STATIC_LIB_REQUIRE(_pthread_setspecific);
+STATIC_LIB_REQUIRE(_read);
+STATIC_LIB_REQUIRE(_readv);
+STATIC_LIB_REQUIRE(_recvfrom);
+STATIC_LIB_REQUIRE(_recvmsg);
+STATIC_LIB_REQUIRE(_select);
+STATIC_LIB_REQUIRE(_sendmsg);
+STATIC_LIB_REQUIRE(_sendto);
+STATIC_LIB_REQUIRE(_sigaction);
+STATIC_LIB_REQUIRE(_sigprocmask);
+STATIC_LIB_REQUIRE(_sigsuspend);
+STATIC_LIB_REQUIRE(_socket);
+STATIC_LIB_REQUIRE(_socketpair);
+STATIC_LIB_REQUIRE(_thread_init_hack);
+STATIC_LIB_REQUIRE(_wait4);
+STATIC_LIB_REQUIRE(_write);
+STATIC_LIB_REQUIRE(_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_LIB_REQUIRE(_pthread_once);
+STATIC_LIB_REQUIRE(_pthread_key_create);
+STATIC_LIB_REQUIRE(_pthread_key_delete);
+STATIC_LIB_REQUIRE(_pthread_getspecific);
+STATIC_LIB_REQUIRE(_pthread_setspecific);
+STATIC_LIB_REQUIRE(_pthread_mutex_init);
+STATIC_LIB_REQUIRE(_pthread_mutex_destroy);
+STATIC_LIB_REQUIRE(_pthread_mutex_lock);
+STATIC_LIB_REQUIRE(_pthread_mutex_trylock);
+STATIC_LIB_REQUIRE(_pthread_mutex_unlock);
+STATIC_LIB_REQUIRE(_pthread_create);
+
+/* Pull in all symbols required by libthread_db */
+STATIC_LIB_REQUIRE(_thread_state_running);
+
+#define DUAL_ENTRY(entry) \
+ (pthread_func_t)entry, (pthread_func_t)entry
+
+static pthread_func_t jmp_table[][2] = {
+ {DUAL_ENTRY(_pthread_atfork)}, /* PJT_ATFORK */
+ {DUAL_ENTRY(_pthread_attr_destroy)}, /* PJT_ATTR_DESTROY */
+ {DUAL_ENTRY(_pthread_attr_getdetachstate)}, /* PJT_ATTR_GETDETACHSTATE */
+ {DUAL_ENTRY(_pthread_attr_getguardsize)}, /* PJT_ATTR_GETGUARDSIZE */
+ {DUAL_ENTRY(_pthread_attr_getinheritsched)}, /* PJT_ATTR_GETINHERITSCHED */
+ {DUAL_ENTRY(_pthread_attr_getschedparam)}, /* PJT_ATTR_GETSCHEDPARAM */
+ {DUAL_ENTRY(_pthread_attr_getschedpolicy)}, /* PJT_ATTR_GETSCHEDPOLICY */
+ {DUAL_ENTRY(_pthread_attr_getscope)}, /* PJT_ATTR_GETSCOPE */
+ {DUAL_ENTRY(_pthread_attr_getstackaddr)}, /* PJT_ATTR_GETSTACKADDR */
+ {DUAL_ENTRY(_pthread_attr_getstacksize)}, /* PJT_ATTR_GETSTACKSIZE */
+ {DUAL_ENTRY(_pthread_attr_init)}, /* PJT_ATTR_INIT */
+ {DUAL_ENTRY(_pthread_attr_setdetachstate)}, /* PJT_ATTR_SETDETACHSTATE */
+ {DUAL_ENTRY(_pthread_attr_setguardsize)}, /* PJT_ATTR_SETGUARDSIZE */
+ {DUAL_ENTRY(_pthread_attr_setinheritsched)}, /* PJT_ATTR_SETINHERITSCHED */
+ {DUAL_ENTRY(_pthread_attr_setschedparam)}, /* PJT_ATTR_SETSCHEDPARAM */
+ {DUAL_ENTRY(_pthread_attr_setschedpolicy)}, /* PJT_ATTR_SETSCHEDPOLICY */
+ {DUAL_ENTRY(_pthread_attr_setscope)}, /* PJT_ATTR_SETSCOPE */
+ {DUAL_ENTRY(_pthread_attr_setstackaddr)}, /* PJT_ATTR_SETSTACKADDR */
+ {DUAL_ENTRY(_pthread_attr_setstacksize)}, /* PJT_ATTR_SETSTACKSIZE */
+ {DUAL_ENTRY(_pthread_cancel)}, /* PJT_CANCEL */
+ {DUAL_ENTRY(_pthread_cleanup_pop)}, /* PJT_CLEANUP_POP */
+ {DUAL_ENTRY(_pthread_cleanup_push)}, /* PJT_CLEANUP_PUSH */
+ {DUAL_ENTRY(_pthread_cond_broadcast)}, /* PJT_COND_BROADCAST */
+ {DUAL_ENTRY(_pthread_cond_destroy)}, /* PJT_COND_DESTROY */
+ {DUAL_ENTRY(_pthread_cond_init)}, /* PJT_COND_INIT */
+ {DUAL_ENTRY(_pthread_cond_signal)}, /* PJT_COND_SIGNAL */
+ {DUAL_ENTRY(_pthread_cond_timedwait)}, /* PJT_COND_TIMEDWAIT */
+ {(pthread_func_t)__pthread_cond_wait,
+ (pthread_func_t)_pthread_cond_wait}, /* PJT_COND_WAIT */
+ {DUAL_ENTRY(_pthread_detach)}, /* PJT_DETACH */
+ {DUAL_ENTRY(_pthread_equal)}, /* PJT_EQUAL */
+ {DUAL_ENTRY(_pthread_exit)}, /* PJT_EXIT */
+ {DUAL_ENTRY(_pthread_getspecific)}, /* PJT_GETSPECIFIC */
+ {DUAL_ENTRY(_pthread_join)}, /* PJT_JOIN */
+ {DUAL_ENTRY(_pthread_key_create)}, /* PJT_KEY_CREATE */
+ {DUAL_ENTRY(_pthread_key_delete)}, /* PJT_KEY_DELETE*/
+ {DUAL_ENTRY(_pthread_kill)}, /* PJT_KILL */
+ {DUAL_ENTRY(_pthread_main_np)}, /* PJT_MAIN_NP */
+ {DUAL_ENTRY(_pthread_mutexattr_destroy)}, /* PJT_MUTEXATTR_DESTROY */
+ {DUAL_ENTRY(_pthread_mutexattr_init)}, /* PJT_MUTEXATTR_INIT */
+ {DUAL_ENTRY(_pthread_mutexattr_settype)}, /* PJT_MUTEXATTR_SETTYPE */
+ {DUAL_ENTRY(_pthread_mutex_destroy)}, /* PJT_MUTEX_DESTROY */
+ {DUAL_ENTRY(_pthread_mutex_init)}, /* PJT_MUTEX_INIT */
+ {(pthread_func_t)__pthread_mutex_lock,
+ (pthread_func_t)_pthread_mutex_lock}, /* PJT_MUTEX_LOCK */
+ {(pthread_func_t)__pthread_mutex_trylock,
+ (pthread_func_t)_pthread_mutex_trylock},/* PJT_MUTEX_TRYLOCK */
+ {DUAL_ENTRY(_pthread_mutex_unlock)}, /* PJT_MUTEX_UNLOCK */
+ {DUAL_ENTRY(_pthread_once)}, /* PJT_ONCE */
+ {DUAL_ENTRY(_pthread_rwlock_destroy)}, /* PJT_RWLOCK_DESTROY */
+ {DUAL_ENTRY(_pthread_rwlock_init)}, /* PJT_RWLOCK_INIT */
+ {DUAL_ENTRY(_pthread_rwlock_rdlock)}, /* PJT_RWLOCK_RDLOCK */
+ {DUAL_ENTRY(_pthread_rwlock_tryrdlock)},/* PJT_RWLOCK_TRYRDLOCK */
+ {DUAL_ENTRY(_pthread_rwlock_trywrlock)},/* PJT_RWLOCK_TRYWRLOCK */
+ {DUAL_ENTRY(_pthread_rwlock_unlock)}, /* PJT_RWLOCK_UNLOCK */
+ {DUAL_ENTRY(_pthread_rwlock_wrlock)}, /* PJT_RWLOCK_WRLOCK */
+ {DUAL_ENTRY(_pthread_self)}, /* PJT_SELF */
+ {DUAL_ENTRY(_pthread_setcancelstate)}, /* PJT_SETCANCELSTATE */
+ {DUAL_ENTRY(_pthread_setcanceltype)}, /* PJT_SETCANCELTYPE */
+ {DUAL_ENTRY(_pthread_setspecific)}, /* PJT_SETSPECIFIC */
+ {DUAL_ENTRY(_pthread_sigmask)}, /* PJT_SIGMASK */
+ {DUAL_ENTRY(_pthread_testcancel)} /* PJT_TESTCANCEL */
+};
+
+static int init_once = 0;
+
+/*
+ * 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;
+
+void
+_thread_init_hack(void)
+{
+
+ _libpthread_init(NULL);
+}
+
+
+/*
+ * Threaded process initialization.
+ *
+ * This is only called under two conditions:
+ *
+ * 1) Some thread routines have detected that the library hasn't yet
+ * been initialized (_thr_initial == NULL && curthread == NULL), or
+ *
+ * 2) An explicit call to reinitialize after a fork (indicated
+ * by curthread != NULL)
+ */
+void
+_libpthread_init(struct pthread *curthread)
+{
+ int fd, first = 0;
+ sigset_t sigset, oldset;
+
+ /* Check if this function has already been called: */
+ if ((_thr_initial != NULL) && (curthread == NULL))
+ /* Only initialize the threaded application once. */
+ return;
+
+ /*
+ * Check the size of the jump table to make sure it is preset
+ * with the correct number of entries.
+ */
+ if (sizeof(jmp_table) != (sizeof(pthread_func_t) * PJT_MAX * 2))
+ PANIC("Thread jump table not properly initialized");
+ memcpy(__thr_jtable, jmp_table, sizeof(jmp_table));
+
+ /*
+ * Check for the special case of this process running as
+ * or in place of init as pid = 1:
+ */
+ if ((_thr_pid = 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 (_ioctl(fd, TIOCSCTTY, (char *) NULL) == -1)
+ PANIC("Can't set controlling terminal");
+ }
+
+ /* Initialize pthread private data. */
+ init_private();
+
+ /* Set the initial thread. */
+ if (curthread == NULL) {
+ first = 1;
+ /* Create and initialize the initial thread. */
+ curthread = _thr_alloc(NULL);
+ if (curthread == NULL)
+ PANIC("Can't allocate initial thread");
+ init_main_thread(curthread);
+ }
+ /*
+ * Add the thread to the thread list queue.
+ */
+ THR_LIST_ADD(curthread);
+ _thread_active_threads = 1;
+
+ /* Setup the thread specific data */
+ _tcb_set(curthread->tcb);
+
+ if (first) {
+ SIGFILLSET(sigset);
+ SIGDELSET(sigset, SIGTRAP);
+ __sys_sigprocmask(SIG_SETMASK, &sigset, &oldset);
+ _thr_signal_init();
+ _thr_initial = curthread;
+ SIGDELSET(oldset, SIGCANCEL);
+ __sys_sigprocmask(SIG_SETMASK, &oldset, NULL);
+ if (_thread_event_mask & TD_CREATE)
+ _thr_report_creation(curthread, curthread);
+ }
+}
+
+/*
+ * This function and pthread_create() do a lot of the same things.
+ * It'd be nice to consolidate the common stuff in one place.
+ */
+static void
+init_main_thread(struct pthread *thread)
+{
+ /* Setup the thread attributes. */
+ thr_self(&thread->tid);
+ thread->attr = _pthread_attr_default;
+ /*
+ * Set up the thread stack.
+ *
+ * Create a red zone below the main stack. All other stacks
+ * are constrained to a maximum size by the parameters
+ * 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 - _thr_stack_initial -
+ _thr_guard_default, _thr_guard_default, 0, MAP_ANON,
+ -1, 0) == MAP_FAILED)
+ PANIC("Cannot allocate red zone for initial thread");
+
+ /*
+ * Mark the stack as an application supplied stack so that it
+ * isn't deallocated.
+ *
+ * XXX - I'm not sure it would hurt anything to deallocate
+ * the main thread stack because deallocation doesn't
+ * actually free() it; it just puts it in the free
+ * stack queue for later reuse.
+ */
+ thread->attr.stackaddr_attr = _usrstack - _thr_stack_initial;
+ thread->attr.stacksize_attr = _thr_stack_initial;
+ thread->attr.guardsize_attr = _thr_guard_default;
+ thread->attr.flags |= THR_STACK_USER;
+
+ /*
+ * Write a magic value to the thread structure
+ * to help identify valid ones:
+ */
+ thread->magic = THR_MAGIC;
+
+ thread->cancelflags = PTHREAD_CANCEL_ENABLE | PTHREAD_CANCEL_DEFERRED;
+ thr_set_name(thread->tid, "initial thread");
+
+ /* Default the priority of the initial thread: */
+ thread->base_priority = THR_DEF_PRIORITY;
+ thread->active_priority = THR_DEF_PRIORITY;
+ thread->inherited_priority = 0;
+
+ /* Initialize the mutex queue: */
+ TAILQ_INIT(&thread->mutexq);
+
+ thread->state = PS_RUNNING;
+
+ /* Others cleared to zero by thr_alloc() */
+}
+
+static void
+init_private(void)
+{
+ size_t len;
+ int mib[2];
+
+ _thr_umtx_init(&_mutex_static_lock);
+ _thr_umtx_init(&_cond_static_lock);
+ _thr_umtx_init(&_rwlock_static_lock);
+ _thr_umtx_init(&_keytable_lock);
+ _thr_umtx_init(&_thr_atfork_lock);
+ _thr_umtx_init(&_thr_event_lock);
+ _thr_once_init();
+ _thr_spinlock_init();
+ _thr_list_init();
+
+ /*
+ * Avoid reinitializing some things if they don't need to be,
+ * e.g. after a fork().
+ */
+ if (init_once == 0) {
+ /* Find the stack top */
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_USRSTACK;
+ len = sizeof (_usrstack);
+ if (sysctl(mib, 2, &_usrstack, &len, NULL, 0) == -1)
+ PANIC("Cannot get kern.usrstack from sysctl");
+ _thr_page_size = getpagesize();
+ _thr_guard_default = _thr_page_size;
+ _pthread_attr_default.guardsize_attr = _thr_guard_default;
+ _pthread_attr_default.stacksize_attr = _thr_stack_default;
+
+ TAILQ_INIT(&_thr_atfork_list);
+#ifdef SYSTEM_SCOPE_ONLY
+ _thr_scope_system = 1;
+#else
+ if (getenv("LIBPTHREAD_SYSTEM_SCOPE") != NULL)
+ _thr_scope_system = 1;
+ else if (getenv("LIBPTHREAD_PROCESS_SCOPE") != NULL)
+ _thr_scope_system = -1;
+#endif
+ }
+ init_once = 1;
+}
diff --git a/lib/libthr/thread/thr_join.c b/lib/libthr/thread/thr_join.c
new file mode 100644
index 0000000..de27074
--- /dev/null
+++ b/lib/libthr/thread/thr_join.c
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2005, David Xu <davidxu@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 "namespace.h"
+#include <errno.h>
+#include <pthread.h>
+#include "un-namespace.h"
+
+#include "thr_private.h"
+
+int _pthread_timedjoin_np(pthread_t pthread, void **thread_return,
+ const struct timespec *abstime);
+static int join_common(pthread_t, void **, const struct timespec *);
+
+__weak_reference(_pthread_join, pthread_join);
+__weak_reference(_pthread_timedjoin_np, pthread_timedjoin_np);
+
+static void backout_join(void *arg)
+{
+ struct pthread *curthread = _get_curthread();
+ struct pthread *pthread = (struct pthread *)arg;
+
+ THREAD_LIST_LOCK(curthread);
+ pthread->joiner = NULL;
+ THREAD_LIST_UNLOCK(curthread);
+}
+
+int
+_pthread_join(pthread_t pthread, void **thread_return)
+{
+ return (join_common(pthread, thread_return, NULL));
+}
+
+int
+_pthread_timedjoin_np(pthread_t pthread, void **thread_return,
+ const struct timespec *abstime)
+{
+ if (abstime == NULL || abstime->tv_sec < 0 || abstime->tv_nsec < 0 ||
+ abstime->tv_nsec >= 1000000000)
+ return (EINVAL);
+
+ return (join_common(pthread, thread_return, abstime));
+}
+
+static int
+join_common(pthread_t pthread, void **thread_return,
+ const struct timespec *abstime)
+{
+ struct pthread *curthread = _get_curthread();
+ struct timespec ts, ts2, *tsp;
+ void *tmp;
+ long tid;
+ int oldcancel;
+ int ret = 0;
+
+ if (pthread == NULL)
+ return (EINVAL);
+
+ if (pthread == curthread)
+ return (EDEADLK);
+
+ THREAD_LIST_LOCK(curthread);
+ if ((ret = _thr_find_thread(curthread, pthread, 1)) != 0) {
+ ret = ESRCH;
+ } else if ((pthread->tlflags & TLFLAGS_DETACHED) != 0) {
+ ret = ESRCH;
+ } else if (pthread->joiner != NULL) {
+ /* Multiple joiners are not supported. */
+ ret = ENOTSUP;
+ }
+ if (ret) {
+ THREAD_LIST_UNLOCK(curthread);
+ return (ret);
+ }
+ /* Set the running thread to be the joiner: */
+ pthread->joiner = curthread;
+
+ THREAD_LIST_UNLOCK(curthread);
+
+ THR_CLEANUP_PUSH(curthread, backout_join, pthread);
+ oldcancel = _thr_cancel_enter(curthread);
+
+ tid = pthread->tid;
+ while (pthread->tid != TID_TERMINATED) {
+ if (abstime != NULL) {
+ clock_gettime(CLOCK_REALTIME, &ts);
+ TIMESPEC_SUB(&ts2, abstime, &ts);
+ if (ts2.tv_sec < 0) {
+ ret = ETIMEDOUT;
+ break;
+ }
+ tsp = &ts2;
+ } else
+ tsp = NULL;
+ ret = _thr_umtx_wait(&pthread->tid, tid, tsp);
+ if (ret == ETIMEDOUT)
+ break;
+ }
+
+ _thr_cancel_leave(curthread, oldcancel);
+ THR_CLEANUP_POP(curthread, 0);
+
+ if (ret == ETIMEDOUT) {
+ THREAD_LIST_LOCK(curthread);
+ pthread->joiner = NULL;
+ THREAD_LIST_UNLOCK(curthread);
+ } else {
+ ret = 0;
+ tmp = pthread->ret;
+ THREAD_LIST_LOCK(curthread);
+ pthread->tlflags |= TLFLAGS_DETACHED;
+ pthread->joiner = NULL;
+ THR_GCLIST_ADD(pthread);
+ THREAD_LIST_UNLOCK(curthread);
+
+ if (thread_return != NULL)
+ *thread_return = tmp;
+ }
+ return (ret);
+}
diff --git a/lib/libthr/thread/thr_kern.c b/lib/libthr/thread/thr_kern.c
new file mode 100644
index 0000000..aa7dce6
--- /dev/null
+++ b/lib/libthr/thread/thr_kern.c
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2005 David Xu <davidxu@freebsd.org>
+ * Copyright (C) 2003 Daniel M. Eischen <deischen@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 <sys/signalvar.h>
+#include <pthread.h>
+
+#include "thr_private.h"
+
+/*#define DEBUG_THREAD_KERN */
+#ifdef DEBUG_THREAD_KERN
+#define DBG_MSG stdout_debug
+#else
+#define DBG_MSG(x...)
+#endif
+
+/*
+ * This is called when the first thread (other than the initial
+ * thread) is created.
+ */
+int
+_thr_setthreaded(int threaded)
+{
+ if (((threaded == 0) ^ (__isthreaded == 0)) == 0)
+ return (0);
+
+ __isthreaded = threaded;
+ if (threaded != 0) {
+ _thr_rtld_init();
+ } else {
+ _thr_rtld_fini();
+ }
+ return (0);
+}
+
+void
+_thr_signal_block(struct pthread *curthread)
+{
+ sigset_t set;
+
+ if (curthread->sigblock > 0) {
+ curthread->sigblock++;
+ return;
+ }
+ SIGFILLSET(set);
+ SIGDELSET(set, SIGBUS);
+ SIGDELSET(set, SIGILL);
+ SIGDELSET(set, SIGFPE);
+ SIGDELSET(set, SIGSEGV);
+ SIGDELSET(set, SIGTRAP);
+ __sys_sigprocmask(SIG_BLOCK, &set, &curthread->sigmask);
+ curthread->sigblock++;
+}
+
+void
+_thr_signal_unblock(struct pthread *curthread)
+{
+ if (--curthread->sigblock == 0)
+ __sys_sigprocmask(SIG_SETMASK, &curthread->sigmask, NULL);
+}
+
+int
+_thr_send_sig(struct pthread *thread, int sig)
+{
+ return thr_kill(thread->tid, sig);
+}
+
+void
+_thr_assert_lock_level()
+{
+ PANIC("locklevel <= 0");
+}
diff --git a/lib/libthr/thread/thr_kill.c b/lib/libthr/thread/thr_kill.c
new file mode 100644
index 0000000..e55681a
--- /dev/null
+++ b/lib/libthr/thread/thr_kill.c
@@ -0,0 +1,69 @@
+/*
+ * 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 "namespace.h"
+#include <errno.h>
+#include <signal.h>
+#include <pthread.h>
+#include "un-namespace.h"
+
+#include "thr_private.h"
+
+__weak_reference(_pthread_kill, pthread_kill);
+
+int
+_pthread_kill(pthread_t pthread, int sig)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret;
+
+ /* Check for invalid signal numbers: */
+ if (sig < 0 || sig > _SIG_MAXSIG)
+ /* Invalid signal: */
+ ret = EINVAL;
+ /*
+ * Ensure the thread is in the list of active threads, and the
+ * signal is valid (signal 0 specifies error checking only) and
+ * not being ignored:
+ */
+ else if ((ret = _thr_ref_add(curthread, pthread, /*include dead*/0))
+ == 0) {
+ if (sig > 0)
+ _thr_send_sig(pthread, sig);
+ _thr_ref_delete(curthread, pthread);
+ }
+
+ /* Return the completion status: */
+ return (ret);
+}
diff --git a/lib/libthr/thread/thr_list.c b/lib/libthr/thread/thr_list.c
new file mode 100644
index 0000000..d46b5ea
--- /dev/null
+++ b/lib/libthr/thread/thr_list.c
@@ -0,0 +1,343 @@
+/*
+ * Copyright (c) 2005 David Xu <davidxu@freebsd.org>
+ * Copyright (C) 2003 Daniel M. Eischen <deischen@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 <sys/queue.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.h>
+
+#include "thr_private.h"
+#include "libc_private.h"
+
+/*#define DEBUG_THREAD_LIST */
+#ifdef DEBUG_THREAD_LIST
+#define DBG_MSG stdout_debug
+#else
+#define DBG_MSG(x...)
+#endif
+
+#define MAX_THREADS 100000
+
+/*
+ * Define a high water mark for the maximum number of threads that
+ * will be cached. Once this level is reached, any extra threads
+ * will be free()'d.
+ */
+#define MAX_CACHED_THREADS 100
+
+/*
+ * We've got to keep track of everything that is allocated, not only
+ * to have a speedy free list, but also so they can be deallocated
+ * after a fork().
+ */
+static TAILQ_HEAD(, pthread) free_threadq;
+static umtx_t free_thread_lock;
+static umtx_t tcb_lock;
+static int free_thread_count = 0;
+static int inited = 0;
+static int total_threads;
+
+LIST_HEAD(thread_hash_head, pthread);
+#define HASH_QUEUES 128
+static struct thread_hash_head thr_hashtable[HASH_QUEUES];
+#define THREAD_HASH(thrd) (((unsigned long)thrd >> 8) % HASH_QUEUES)
+
+static void thr_destroy(struct pthread *curthread, struct pthread *thread);
+
+void
+_thr_list_init(void)
+{
+ int i;
+
+ _gc_count = 0;
+ total_threads = 1;
+ _thr_umtx_init(&_thr_list_lock);
+ TAILQ_INIT(&_thread_list);
+ TAILQ_INIT(&free_threadq);
+ _thr_umtx_init(&free_thread_lock);
+ _thr_umtx_init(&tcb_lock);
+ if (inited) {
+ for (i = 0; i < HASH_QUEUES; ++i)
+ LIST_INIT(&thr_hashtable[i]);
+ }
+ inited = 1;
+}
+
+void
+_thr_gc(struct pthread *curthread)
+{
+ struct pthread *td, *td_next;
+ TAILQ_HEAD(, pthread) worklist;
+
+ TAILQ_INIT(&worklist);
+ THREAD_LIST_LOCK(curthread);
+
+ /* Check the threads waiting for GC. */
+ for (td = TAILQ_FIRST(&_thread_gc_list); td != NULL; td = td_next) {
+ td_next = TAILQ_NEXT(td, gcle);
+ if (td->tid != TID_TERMINATED) {
+ /* make sure we are not still in userland */
+ continue;
+ }
+ _thr_stack_free(&td->attr);
+ if (((td->tlflags & TLFLAGS_DETACHED) != 0) &&
+ (td->refcount == 0)) {
+ THR_GCLIST_REMOVE(td);
+ /*
+ * The thread has detached and is no longer
+ * referenced. It is safe to remove all
+ * remnants of the thread.
+ */
+ THR_LIST_REMOVE(td);
+ TAILQ_INSERT_HEAD(&worklist, td, gcle);
+ }
+ }
+ THREAD_LIST_UNLOCK(curthread);
+
+ while ((td = TAILQ_FIRST(&worklist)) != NULL) {
+ TAILQ_REMOVE(&worklist, td, gcle);
+ /*
+ * XXX we don't free initial thread, because there might
+ * have some code referencing initial thread.
+ */
+ if (td == _thr_initial) {
+ DBG_MSG("Initial thread won't be freed\n");
+ continue;
+ }
+
+ _thr_free(curthread, td);
+ }
+}
+
+struct pthread *
+_thr_alloc(struct pthread *curthread)
+{
+ struct pthread *thread = NULL;
+ struct tcb *tcb;
+
+ if (curthread != NULL) {
+ if (GC_NEEDED())
+ _thr_gc(curthread);
+ if (free_thread_count > 0) {
+ THR_LOCK_ACQUIRE(curthread, &free_thread_lock);
+ if ((thread = TAILQ_FIRST(&free_threadq)) != NULL) {
+ TAILQ_REMOVE(&free_threadq, thread, tle);
+ free_thread_count--;
+ }
+ THR_LOCK_RELEASE(curthread, &free_thread_lock);
+ }
+ }
+ if (thread == NULL) {
+ if (total_threads > MAX_THREADS)
+ return (NULL);
+ atomic_fetchadd_int(&total_threads, 1);
+ thread = malloc(sizeof(struct pthread));
+ if (thread == NULL) {
+ atomic_fetchadd_int(&total_threads, -1);
+ return (NULL);
+ }
+ }
+ if (curthread != NULL) {
+ THR_LOCK_ACQUIRE(curthread, &tcb_lock);
+ tcb = _tcb_ctor(thread, 0 /* not initial tls */);
+ THR_LOCK_RELEASE(curthread, &tcb_lock);
+ } else {
+ tcb = _tcb_ctor(thread, 1 /* initial tls */);
+ }
+ if (tcb != NULL) {
+ memset(thread, 0, sizeof(*thread));
+ thread->tcb = tcb;
+ } else {
+ thr_destroy(curthread, thread);
+ atomic_fetchadd_int(&total_threads, -1);
+ thread = NULL;
+ }
+ return (thread);
+}
+
+void
+_thr_free(struct pthread *curthread, struct pthread *thread)
+{
+ DBG_MSG("Freeing thread %p\n", thread);
+
+ /*
+ * Always free tcb, as we only know it is part of RTLD TLS
+ * block, but don't know its detail and can not assume how
+ * it works, so better to avoid caching it here.
+ */
+ if (curthread != NULL) {
+ THR_LOCK_ACQUIRE(curthread, &tcb_lock);
+ _tcb_dtor(thread->tcb);
+ THR_LOCK_RELEASE(curthread, &tcb_lock);
+ } else {
+ _tcb_dtor(thread->tcb);
+ }
+ thread->tcb = NULL;
+ if ((curthread == NULL) || (free_thread_count >= MAX_CACHED_THREADS)) {
+ thr_destroy(curthread, thread);
+ atomic_fetchadd_int(&total_threads, -1);
+ } else {
+ /*
+ * Add the thread to the free thread list, this also avoids
+ * pthread id is reused too quickly, may help some buggy apps.
+ */
+ THR_LOCK_ACQUIRE(curthread, &free_thread_lock);
+ TAILQ_INSERT_TAIL(&free_threadq, thread, tle);
+ free_thread_count++;
+ THR_LOCK_RELEASE(curthread, &free_thread_lock);
+ }
+}
+
+static void
+thr_destroy(struct pthread *curthread __unused, struct pthread *thread)
+{
+ free(thread);
+}
+
+/*
+ * Add the thread to the list of all threads and increment
+ * number of active threads.
+ */
+void
+_thr_link(struct pthread *curthread, struct pthread *thread)
+{
+ THREAD_LIST_LOCK(curthread);
+ THR_LIST_ADD(thread);
+ _thread_active_threads++;
+ THREAD_LIST_UNLOCK(curthread);
+}
+
+/*
+ * Remove an active thread.
+ */
+void
+_thr_unlink(struct pthread *curthread, struct pthread *thread)
+{
+ THREAD_LIST_LOCK(curthread);
+ THR_LIST_REMOVE(thread);
+ _thread_active_threads--;
+ THREAD_LIST_UNLOCK(curthread);
+}
+
+void
+_thr_hash_add(struct pthread *thread)
+{
+ struct thread_hash_head *head;
+
+ head = &thr_hashtable[THREAD_HASH(thread)];
+ LIST_INSERT_HEAD(head, thread, hle);
+}
+
+void
+_thr_hash_remove(struct pthread *thread)
+{
+ LIST_REMOVE(thread, hle);
+}
+
+struct pthread *
+_thr_hash_find(struct pthread *thread)
+{
+ struct pthread *td;
+ struct thread_hash_head *head;
+
+ head = &thr_hashtable[THREAD_HASH(thread)];
+ LIST_FOREACH(td, head, hle) {
+ if (td == thread)
+ return (thread);
+ }
+ return (NULL);
+}
+
+/*
+ * Find a thread in the linked list of active threads and add a reference
+ * to it. Threads with positive reference counts will not be deallocated
+ * until all references are released.
+ */
+int
+_thr_ref_add(struct pthread *curthread, struct pthread *thread,
+ int include_dead)
+{
+ int ret;
+
+ if (thread == NULL)
+ /* Invalid thread: */
+ return (EINVAL);
+
+ THREAD_LIST_LOCK(curthread);
+ if ((ret = _thr_find_thread(curthread, thread, include_dead)) == 0) {
+ thread->refcount++;
+ }
+ THREAD_LIST_UNLOCK(curthread);
+
+ /* Return zero if the thread exists: */
+ return (ret);
+}
+
+void
+_thr_ref_delete(struct pthread *curthread, struct pthread *thread)
+{
+ THREAD_LIST_LOCK(curthread);
+ _thr_ref_delete_unlocked(curthread, thread);
+ THREAD_LIST_UNLOCK(curthread);
+}
+
+void
+_thr_ref_delete_unlocked(struct pthread *curthread __unused,
+ struct pthread *thread)
+{
+ if (thread != NULL) {
+ thread->refcount--;
+ if ((thread->refcount == 0) && thread->state == PS_DEAD &&
+ (thread->tlflags & TLFLAGS_DETACHED) != 0)
+ THR_GCLIST_ADD(thread);
+ }
+}
+
+int
+_thr_find_thread(struct pthread *curthread __unused, struct pthread *thread,
+ int include_dead)
+{
+ struct pthread *pthread;
+
+ if (thread == NULL)
+ /* Invalid thread: */
+ return (EINVAL);
+
+ pthread = _thr_hash_find(thread);
+ if (pthread) {
+ if (include_dead == 0 && pthread->state == PS_DEAD) {
+ pthread = NULL;
+ }
+ }
+
+ /* Return zero if the thread exists: */
+ return ((pthread != NULL) ? 0 : ESRCH);
+}
diff --git a/lib/libthr/thread/thr_main_np.c b/lib/libthr/thread/thr_main_np.c
new file mode 100644
index 0000000..bfa8b87
--- /dev/null
+++ b/lib/libthr/thread/thr_main_np.c
@@ -0,0 +1,50 @@
+/*
+ * 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 "namespace.h"
+#include <pthread.h>
+#include <pthread_np.h>
+#include "un-namespace.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 (!_thr_initial)
+ return (-1);
+ else
+ return (_pthread_equal(_pthread_self(), _thr_initial) ? 1 : 0);
+}
diff --git a/lib/libthr/thread/thr_multi_np.c b/lib/libthr/thread/thr_multi_np.c
new file mode 100644
index 0000000..3ea2cb4
--- /dev/null
+++ b/lib/libthr/thread/thr_multi_np.c
@@ -0,0 +1,53 @@
+/*
+ * 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 "namespace.h"
+#include <pthread.h>
+#include <pthread_np.h>
+#include "un-namespace.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..e79e014
--- /dev/null
+++ b/lib/libthr/thread/thr_mutex.c
@@ -0,0 +1,669 @@
+/*
+ * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>.
+ * Copyright (c) 2006 David Xu <davidxu@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 "namespace.h"
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <pthread.h>
+#include "un-namespace.h"
+
+#include "thr_private.h"
+
+#if defined(_PTHREADS_INVARIANTS)
+#define MUTEX_INIT_LINK(m) do { \
+ (m)->m_qe.tqe_prev = NULL; \
+ (m)->m_qe.tqe_next = NULL; \
+} while (0)
+#define MUTEX_ASSERT_IS_OWNED(m) do { \
+ if ((m)->m_qe.tqe_prev == NULL) \
+ PANIC("mutex is not on list"); \
+} while (0)
+#define MUTEX_ASSERT_NOT_OWNED(m) do { \
+ if (((m)->m_qe.tqe_prev != NULL) || \
+ ((m)->m_qe.tqe_next != NULL)) \
+ PANIC("mutex is on list"); \
+} while (0)
+#else
+#define MUTEX_INIT_LINK(m)
+#define MUTEX_ASSERT_IS_OWNED(m)
+#define MUTEX_ASSERT_NOT_OWNED(m)
+#endif
+
+/*
+ * Prototypes
+ */
+int __pthread_mutex_init(pthread_mutex_t *mutex,
+ const pthread_mutexattr_t *mutex_attr);
+int __pthread_mutex_trylock(pthread_mutex_t *mutex);
+int __pthread_mutex_lock(pthread_mutex_t *mutex);
+int __pthread_mutex_timedlock(pthread_mutex_t *mutex,
+ const struct timespec *abstime);
+
+static int mutex_self_trylock(pthread_mutex_t);
+static int mutex_self_lock(pthread_mutex_t,
+ const struct timespec *abstime);
+static int mutex_unlock_common(pthread_mutex_t *);
+
+__weak_reference(__pthread_mutex_init, pthread_mutex_init);
+__weak_reference(__pthread_mutex_lock, pthread_mutex_lock);
+__weak_reference(__pthread_mutex_timedlock, pthread_mutex_timedlock);
+__weak_reference(__pthread_mutex_trylock, pthread_mutex_trylock);
+
+/* Single underscore versions provided for libc internal usage: */
+/* No difference between libc and application usage of these: */
+__weak_reference(_pthread_mutex_destroy, pthread_mutex_destroy);
+__weak_reference(_pthread_mutex_unlock, pthread_mutex_unlock);
+
+__weak_reference(_pthread_mutex_getprioceiling, pthread_mutex_getprioceiling);
+__weak_reference(_pthread_mutex_setprioceiling, pthread_mutex_setprioceiling);
+
+static int
+mutex_init(pthread_mutex_t *mutex,
+ const pthread_mutexattr_t *mutex_attr, int private)
+{
+ const struct pthread_mutex_attr *attr;
+ struct pthread_mutex *pmutex;
+
+ if (mutex_attr == NULL) {
+ attr = &_pthread_mutexattr_default;
+ } else {
+ attr = *mutex_attr;
+ if (attr->m_type < PTHREAD_MUTEX_ERRORCHECK ||
+ attr->m_type >= PTHREAD_MUTEX_TYPE_MAX)
+ return (EINVAL);
+ if (attr->m_protocol < PTHREAD_PRIO_NONE ||
+ attr->m_protocol > PTHREAD_PRIO_PROTECT)
+ return (EINVAL);
+ }
+
+ if ((pmutex = (pthread_mutex_t)
+ malloc(sizeof(struct pthread_mutex))) == NULL)
+ return (ENOMEM);
+
+ _thr_umtx_init(&pmutex->m_lock);
+ pmutex->m_type = attr->m_type;
+ pmutex->m_protocol = attr->m_protocol;
+ TAILQ_INIT(&pmutex->m_queue);
+ pmutex->m_owner = NULL;
+ pmutex->m_flags = attr->m_flags | MUTEX_FLAGS_INITED;
+ if (private)
+ pmutex->m_flags |= MUTEX_FLAGS_PRIVATE;
+ pmutex->m_count = 0;
+ pmutex->m_refcount = 0;
+ if (attr->m_protocol == PTHREAD_PRIO_PROTECT)
+ pmutex->m_prio = attr->m_ceiling;
+ else
+ pmutex->m_prio = -1;
+ pmutex->m_saved_prio = 0;
+ MUTEX_INIT_LINK(pmutex);
+ *mutex = pmutex;
+ return (0);
+}
+
+static int
+init_static(struct pthread *thread, pthread_mutex_t *mutex)
+{
+ int ret;
+
+ THR_LOCK_ACQUIRE(thread, &_mutex_static_lock);
+
+ if (*mutex == NULL)
+ ret = mutex_init(mutex, NULL, 0);
+ else
+ ret = 0;
+
+ THR_LOCK_RELEASE(thread, &_mutex_static_lock);
+
+ return (ret);
+}
+
+static int
+init_static_private(struct pthread *thread, pthread_mutex_t *mutex)
+{
+ int ret;
+
+ THR_LOCK_ACQUIRE(thread, &_mutex_static_lock);
+
+ if (*mutex == NULL)
+ ret = mutex_init(mutex, NULL, 1);
+ else
+ ret = 0;
+
+ THR_LOCK_RELEASE(thread, &_mutex_static_lock);
+
+ return (ret);
+}
+
+int
+_pthread_mutex_init(pthread_mutex_t *mutex,
+ const pthread_mutexattr_t *mutex_attr)
+{
+ return mutex_init(mutex, mutex_attr, 1);
+}
+
+int
+__pthread_mutex_init(pthread_mutex_t *mutex,
+ const pthread_mutexattr_t *mutex_attr)
+{
+ return mutex_init(mutex, mutex_attr, 0);
+}
+
+int
+_mutex_reinit(pthread_mutex_t *mutex)
+{
+ _thr_umtx_init(&(*mutex)->m_lock);
+ TAILQ_INIT(&(*mutex)->m_queue);
+ MUTEX_INIT_LINK(*mutex);
+ (*mutex)->m_owner = NULL;
+ (*mutex)->m_count = 0;
+ (*mutex)->m_refcount = 0;
+ (*mutex)->m_prio = 0;
+ (*mutex)->m_saved_prio = 0;
+ return (0);
+}
+
+void
+_mutex_fork(struct pthread *curthread)
+{
+ struct pthread_mutex *m;
+
+ /*
+ * Fix mutex ownership for child process.
+ * note that process shared mutex should not
+ * be inherited because owner is forking thread
+ * which is in parent process, they should be
+ * removed from the owned mutex list, current,
+ * process shared mutex is not supported, so I
+ * am not worried.
+ */
+ TAILQ_FOREACH(m, &curthread->mutexq, m_qe)
+ m->m_lock = (umtx_t)curthread->tid;
+}
+
+int
+_pthread_mutex_destroy(pthread_mutex_t *mutex)
+{
+ struct pthread *curthread = _get_curthread();
+ pthread_mutex_t m;
+ int ret = 0;
+
+ if (__predict_false(*mutex == NULL))
+ ret = EINVAL;
+ else {
+ /*
+ * Try to lock the mutex structure, we only need to
+ * try once, if failed, the mutex is in used.
+ */
+ ret = THR_UMTX_TRYLOCK(curthread, &(*mutex)->m_lock);
+ if (ret)
+ return (ret);
+
+ /*
+ * Check mutex other fields to see if this mutex is
+ * in use. Mostly for prority mutex types, or there
+ * are condition variables referencing it.
+ */
+ if (((*mutex)->m_owner != NULL) ||
+ (TAILQ_FIRST(&(*mutex)->m_queue) != NULL) ||
+ ((*mutex)->m_refcount != 0)) {
+ THR_UMTX_UNLOCK(curthread, &(*mutex)->m_lock);
+ ret = EBUSY;
+ } else {
+ /*
+ * Save a pointer to the mutex so it can be free'd
+ * and set the caller's pointer to NULL.
+ */
+ m = *mutex;
+ *mutex = NULL;
+
+ THR_UMTX_UNLOCK(curthread, &m->m_lock);
+
+ MUTEX_ASSERT_NOT_OWNED(m);
+ free(m);
+ }
+ }
+
+ return (ret);
+}
+
+static int
+mutex_trylock_common(struct pthread *curthread, pthread_mutex_t *mutex)
+{
+ struct pthread_mutex *m;
+ int ret;
+
+ m = *mutex;
+ ret = THR_UMTX_TRYLOCK(curthread, &m->m_lock);
+ if (ret == 0) {
+ m->m_owner = curthread;
+ /* Add to the list of owned mutexes. */
+ MUTEX_ASSERT_NOT_OWNED(m);
+ TAILQ_INSERT_TAIL(&curthread->mutexq, m, m_qe);
+ } else if (m->m_owner == curthread) {
+ ret = mutex_self_trylock(m);
+ } /* else {} */
+
+ return (ret);
+}
+
+int
+__pthread_mutex_trylock(pthread_mutex_t *mutex)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret;
+
+ /*
+ * If the mutex is statically initialized, perform the dynamic
+ * initialization:
+ */
+ if (__predict_false(*mutex == NULL)) {
+ ret = init_static(curthread, mutex);
+ if (__predict_false(ret))
+ return (ret);
+ }
+ return (mutex_trylock_common(curthread, mutex));
+}
+
+int
+_pthread_mutex_trylock(pthread_mutex_t *mutex)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret;
+
+ /*
+ * If the mutex is statically initialized, perform the dynamic
+ * initialization marking the mutex private (delete safe):
+ */
+ if (__predict_false(*mutex == NULL)) {
+ ret = init_static_private(curthread, mutex);
+ if (__predict_false(ret))
+ return (ret);
+ }
+ return (mutex_trylock_common(curthread, mutex));
+}
+
+static int
+mutex_lock_common(struct pthread *curthread, pthread_mutex_t *mutex,
+ const struct timespec * abstime)
+{
+ struct timespec ts, ts2;
+ struct pthread_mutex *m;
+ int ret;
+
+ m = *mutex;
+ ret = THR_UMTX_TRYLOCK(curthread, &m->m_lock);
+ if (ret == 0) {
+ m->m_owner = curthread;
+ /* Add to the list of owned mutexes: */
+ MUTEX_ASSERT_NOT_OWNED(m);
+ TAILQ_INSERT_TAIL(&curthread->mutexq, m, m_qe);
+ } else if (m->m_owner == curthread) {
+ ret = mutex_self_lock(m, abstime);
+ } else {
+ if (abstime == NULL) {
+ THR_UMTX_LOCK(curthread, &m->m_lock);
+ ret = 0;
+ } else if (__predict_false(
+ abstime->tv_sec < 0 || abstime->tv_nsec < 0 ||
+ abstime->tv_nsec >= 1000000000)) {
+ ret = EINVAL;
+ } else {
+ clock_gettime(CLOCK_REALTIME, &ts);
+ TIMESPEC_SUB(&ts2, abstime, &ts);
+ ret = THR_UMTX_TIMEDLOCK(curthread, &m->m_lock, &ts2);
+ /*
+ * Timed out wait is not restarted if
+ * it was interrupted, not worth to do it.
+ */
+ if (ret == EINTR)
+ ret = ETIMEDOUT;
+ }
+ if (ret == 0) {
+ m->m_owner = curthread;
+ /* Add to the list of owned mutexes: */
+ MUTEX_ASSERT_NOT_OWNED(m);
+ TAILQ_INSERT_TAIL(&curthread->mutexq, m, m_qe);
+ }
+ }
+ return (ret);
+}
+
+int
+__pthread_mutex_lock(pthread_mutex_t *m)
+{
+ struct pthread *curthread;
+ int ret;
+
+ _thr_check_init();
+
+ curthread = _get_curthread();
+
+ /*
+ * If the mutex is statically initialized, perform the dynamic
+ * initialization:
+ */
+ if (__predict_false(*m == NULL)) {
+ ret = init_static(curthread, m);
+ if (__predict_false(ret))
+ return (ret);
+ }
+ return (mutex_lock_common(curthread, m, NULL));
+}
+
+int
+_pthread_mutex_lock(pthread_mutex_t *m)
+{
+ struct pthread *curthread;
+ int ret;
+
+ _thr_check_init();
+
+ curthread = _get_curthread();
+
+ /*
+ * If the mutex is statically initialized, perform the dynamic
+ * initialization marking it private (delete safe):
+ */
+ if (__predict_false(*m == NULL)) {
+ ret = init_static_private(curthread, m);
+ if (__predict_false(ret))
+ return (ret);
+ }
+ return (mutex_lock_common(curthread, m, NULL));
+}
+
+int
+__pthread_mutex_timedlock(pthread_mutex_t *m, const struct timespec *abstime)
+{
+ struct pthread *curthread;
+ int ret;
+
+ _thr_check_init();
+
+ curthread = _get_curthread();
+
+ /*
+ * If the mutex is statically initialized, perform the dynamic
+ * initialization:
+ */
+ if (__predict_false(*m == NULL)) {
+ ret = init_static(curthread, m);
+ if (__predict_false(ret))
+ return (ret);
+ }
+ return (mutex_lock_common(curthread, m, abstime));
+}
+
+int
+_pthread_mutex_timedlock(pthread_mutex_t *m, const struct timespec *abstime)
+{
+ struct pthread *curthread;
+ int ret;
+
+ _thr_check_init();
+
+ curthread = _get_curthread();
+
+ /*
+ * If the mutex is statically initialized, perform the dynamic
+ * initialization marking it private (delete safe):
+ */
+ if (__predict_false(*m == NULL)) {
+ ret = init_static_private(curthread, m);
+ if (__predict_false(ret))
+ return (ret);
+ }
+ return (mutex_lock_common(curthread, m, abstime));
+}
+
+int
+_pthread_mutex_unlock(pthread_mutex_t *m)
+{
+ return (mutex_unlock_common(m));
+}
+
+int
+_mutex_cv_lock(pthread_mutex_t *m, int count)
+{
+ int ret;
+
+ ret = mutex_lock_common(_get_curthread(), m, NULL);
+ if (ret == 0) {
+ (*m)->m_refcount--;
+ (*m)->m_count += count;
+ }
+ return (ret);
+}
+
+static int
+mutex_self_trylock(pthread_mutex_t m)
+{
+ int ret;
+
+ switch (m->m_type) {
+ case PTHREAD_MUTEX_ERRORCHECK:
+ case PTHREAD_MUTEX_NORMAL:
+ ret = EBUSY;
+ break;
+
+ case PTHREAD_MUTEX_RECURSIVE:
+ /* Increment the lock count: */
+ if (m->m_count + 1 > 0) {
+ m->m_count++;
+ ret = 0;
+ } else
+ ret = EAGAIN;
+ break;
+
+ default:
+ /* Trap invalid mutex types; */
+ ret = EINVAL;
+ }
+
+ return (ret);
+}
+
+static int
+mutex_self_lock(pthread_mutex_t m, const struct timespec *abstime)
+{
+ struct timespec ts1, ts2;
+ int ret;
+
+ switch (m->m_type) {
+ case PTHREAD_MUTEX_ERRORCHECK:
+ if (abstime) {
+ clock_gettime(CLOCK_REALTIME, &ts1);
+ TIMESPEC_SUB(&ts2, abstime, &ts1);
+ __sys_nanosleep(&ts2, NULL);
+ ret = ETIMEDOUT;
+ } else {
+ /*
+ * POSIX specifies that mutexes should return
+ * EDEADLK if a recursive lock is detected.
+ */
+ ret = EDEADLK;
+ }
+ break;
+
+ case PTHREAD_MUTEX_NORMAL:
+ /*
+ * What SS2 define as a 'normal' mutex. Intentionally
+ * deadlock on attempts to get a lock you already own.
+ */
+ ret = 0;
+ if (abstime) {
+ clock_gettime(CLOCK_REALTIME, &ts1);
+ TIMESPEC_SUB(&ts2, abstime, &ts1);
+ __sys_nanosleep(&ts2, NULL);
+ ret = ETIMEDOUT;
+ } else {
+ ts1.tv_sec = 30;
+ ts1.tv_nsec = 0;
+ for (;;)
+ __sys_nanosleep(&ts1, NULL);
+ }
+ break;
+
+ case PTHREAD_MUTEX_RECURSIVE:
+ /* Increment the lock count: */
+ if (m->m_count + 1 > 0) {
+ m->m_count++;
+ ret = 0;
+ } else
+ ret = EAGAIN;
+ break;
+
+ default:
+ /* Trap invalid mutex types; */
+ ret = EINVAL;
+ }
+
+ return (ret);
+}
+
+static int
+mutex_unlock_common(pthread_mutex_t *mutex)
+{
+ struct pthread *curthread = _get_curthread();
+ struct pthread_mutex *m;
+
+ if (__predict_false((m = *mutex) == NULL))
+ return (EINVAL);
+
+ /*
+ * Check if the running thread is not the owner of the mutex.
+ */
+ if (__predict_false(m->m_owner != curthread))
+ return (EPERM);
+
+ if (__predict_false(
+ m->m_type == PTHREAD_MUTEX_RECURSIVE &&
+ m->m_count > 0)) {
+ m->m_count--;
+ } else {
+ m->m_owner = NULL;
+ /* Remove the mutex from the threads queue. */
+ MUTEX_ASSERT_IS_OWNED(m);
+ TAILQ_REMOVE(&curthread->mutexq, m, m_qe);
+ MUTEX_INIT_LINK(m);
+ THR_UMTX_UNLOCK(curthread, &m->m_lock);
+ }
+ return (0);
+}
+
+int
+_mutex_cv_unlock(pthread_mutex_t *mutex, int *count)
+{
+ struct pthread *curthread = _get_curthread();
+ struct pthread_mutex *m;
+
+ if (__predict_false((m = *mutex) == NULL))
+ return (EINVAL);
+
+ /*
+ * Check if the running thread is not the owner of the mutex.
+ */
+ if (__predict_false(m->m_owner != curthread))
+ return (EPERM);
+
+ /*
+ * Clear the count in case this is a recursive mutex.
+ */
+ *count = m->m_count;
+ m->m_refcount++;
+ m->m_count = 0;
+ m->m_owner = NULL;
+ /* Remove the mutex from the threads queue. */
+ MUTEX_ASSERT_IS_OWNED(m);
+ TAILQ_REMOVE(&curthread->mutexq, m, m_qe);
+ MUTEX_INIT_LINK(m);
+ THR_UMTX_UNLOCK(curthread, &m->m_lock);
+ return (0);
+}
+
+void
+_mutex_unlock_private(pthread_t pthread)
+{
+ struct pthread_mutex *m, *m_next;
+
+ for (m = TAILQ_FIRST(&pthread->mutexq); m != NULL; m = m_next) {
+ m_next = TAILQ_NEXT(m, m_qe);
+ if ((m->m_flags & MUTEX_FLAGS_PRIVATE) != 0)
+ _pthread_mutex_unlock(&m);
+ }
+}
+
+int
+_pthread_mutex_getprioceiling(pthread_mutex_t *mutex,
+ int *prioceiling)
+{
+ int ret;
+
+ if (*mutex == NULL)
+ ret = EINVAL;
+ else if ((*mutex)->m_protocol != PTHREAD_PRIO_PROTECT)
+ ret = EINVAL;
+ else {
+ *prioceiling = (*mutex)->m_prio;
+ ret = 0;
+ }
+
+ return(ret);
+}
+
+int
+_pthread_mutex_setprioceiling(pthread_mutex_t *mutex,
+ int prioceiling, int *old_ceiling)
+{
+ int ret = 0;
+ int tmp;
+
+ if (*mutex == NULL)
+ ret = EINVAL;
+ else if ((*mutex)->m_protocol != PTHREAD_PRIO_PROTECT)
+ ret = EINVAL;
+ else if ((ret = _pthread_mutex_lock(mutex)) == 0) {
+ tmp = (*mutex)->m_prio;
+ (*mutex)->m_prio = prioceiling;
+ ret = _pthread_mutex_unlock(mutex);
+
+ /* Return the old ceiling. */
+ *old_ceiling = tmp;
+ }
+ return(ret);
+}
diff --git a/lib/libthr/thread/thr_mutex_prioceiling.c b/lib/libthr/thread/thr_mutex_prioceiling.c
new file mode 100644
index 0000000..edea124
--- /dev/null
+++ b/lib/libthr/thread/thr_mutex_prioceiling.c
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 1998 Daniel Eischen <eischen@vigrid.com>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Daniel Eischen.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY DANIEL EISCHEN AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <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)
+{
+ int ret = 0;
+
+ if ((mattr == NULL) || (*mattr == NULL))
+ ret = EINVAL;
+ else if ((*mattr)->m_protocol != PTHREAD_PRIO_PROTECT)
+ ret = EINVAL;
+ else
+ (*mattr)->m_ceiling = prioceiling;
+
+ return(ret);
+}
+
+int
+_pthread_mutex_getprioceiling(pthread_mutex_t *mutex,
+ int *prioceiling)
+{
+ int ret;
+
+ if ((mutex == NULL) || (*mutex == NULL))
+ ret = EINVAL;
+ else if ((*mutex)->m_protocol != PTHREAD_PRIO_PROTECT)
+ ret = EINVAL;
+ else
+ ret = (*mutex)->m_prio;
+
+ return(ret);
+}
+
+int
+_pthread_mutex_setprioceiling(pthread_mutex_t *mutex,
+ int prioceiling, int *old_ceiling)
+{
+ int ret = 0;
+ int tmp;
+
+ if ((mutex == NULL) || (*mutex == NULL))
+ ret = EINVAL;
+ else if ((*mutex)->m_protocol != PTHREAD_PRIO_PROTECT)
+ ret = EINVAL;
+ /* Lock the mutex: */
+ else if ((ret = pthread_mutex_lock(mutex)) == 0) {
+ tmp = (*mutex)->m_prio;
+ /* Set the new ceiling: */
+ (*mutex)->m_prio = prioceiling;
+
+ /* Unlock the mutex: */
+ ret = pthread_mutex_unlock(mutex);
+
+ /* Return the old ceiling: */
+ *old_ceiling = tmp;
+ }
+ return(ret);
+}
diff --git a/lib/libthr/thread/thr_mutex_protocol.c b/lib/libthr/thread/thr_mutex_protocol.c
new file mode 100644
index 0000000..526cbe0
--- /dev/null
+++ b/lib/libthr/thread/thr_mutex_protocol.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 1998 Daniel Eischen <eischen@vigrid.com>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Daniel Eischen.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY DANIEL EISCHEN AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <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 = THR_MAX_PRIORITY;
+ }
+ return(ret);
+}
+
diff --git a/lib/libthr/thread/thr_mutexattr.c b/lib/libthr/thread/thr_mutexattr.c
new file mode 100644
index 0000000..7244c58
--- /dev/null
+++ b/lib/libthr/thread/thr_mutexattr.c
@@ -0,0 +1,262 @@
+/*
+ * 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$
+ */
+
+/*
+ * 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.
+ *
+ */
+
+#include "namespace.h"
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <pthread.h>
+#include <pthread_np.h>
+#include "un-namespace.h"
+
+#include "thr_private.h"
+
+__weak_reference(_pthread_mutexattr_init, pthread_mutexattr_init);
+__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);
+__weak_reference(_pthread_mutexattr_destroy, pthread_mutexattr_destroy);
+__weak_reference(_pthread_mutexattr_getpshared, pthread_mutexattr_getpshared);
+__weak_reference(_pthread_mutexattr_setpshared, pthread_mutexattr_setpshared);
+__weak_reference(_pthread_mutexattr_getprotocol, pthread_mutexattr_getprotocol);
+__weak_reference(_pthread_mutexattr_setprotocol, pthread_mutexattr_setprotocol);
+__weak_reference(_pthread_mutexattr_getprioceiling, pthread_mutexattr_getprioceiling);
+__weak_reference(_pthread_mutexattr_setprioceiling, pthread_mutexattr_setprioceiling);
+
+int
+_pthread_mutexattr_init(pthread_mutexattr_t *attr)
+{
+ int ret;
+ pthread_mutexattr_t pattr;
+
+ if ((pattr = (pthread_mutexattr_t)
+ malloc(sizeof(struct pthread_mutex_attr))) == NULL) {
+ ret = ENOMEM;
+ } else {
+ memcpy(pattr, &_pthread_mutexattr_default,
+ sizeof(struct pthread_mutex_attr));
+ *attr = pattr;
+ ret = 0;
+ }
+ return (ret);
+}
+
+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 >= PTHREAD_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 >=
+ PTHREAD_MUTEX_TYPE_MAX) {
+ ret = EINVAL;
+ } else {
+ *type = (*attr)->m_type;
+ ret = 0;
+ }
+ return ret;
+}
+
+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);
+}
+
+int
+_pthread_mutexattr_getpshared(const pthread_mutexattr_t *attr,
+ int *pshared)
+{
+
+ if (attr == NULL || *attr == NULL)
+ return (EINVAL);
+
+ *pshared = PTHREAD_PROCESS_PRIVATE;
+ return (0);
+}
+
+int
+_pthread_mutexattr_setpshared(pthread_mutexattr_t *attr, int pshared)
+{
+
+ if (attr == NULL || *attr == NULL)
+ return (EINVAL);
+
+ /* Only PTHREAD_PROCESS_PRIVATE is supported. */
+ if (pshared != PTHREAD_PROCESS_PRIVATE)
+ return (EINVAL);
+
+ return (0);
+}
+
+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 = THR_MAX_RR_PRIORITY;
+ }
+ return(ret);
+}
+
+int
+_pthread_mutexattr_getprioceiling(pthread_mutexattr_t *mattr, int *prioceiling)
+{
+ int ret = 0;
+
+ if ((mattr == NULL) || (*mattr == NULL))
+ ret = EINVAL;
+ else if ((*mattr)->m_protocol != PTHREAD_PRIO_PROTECT)
+ ret = EINVAL;
+ else
+ *prioceiling = (*mattr)->m_ceiling;
+
+ return(ret);
+}
+
+int
+_pthread_mutexattr_setprioceiling(pthread_mutexattr_t *mattr, int prioceiling)
+{
+ int ret = 0;
+
+ if ((mattr == NULL) || (*mattr == NULL))
+ ret = EINVAL;
+ else if ((*mattr)->m_protocol != PTHREAD_PRIO_PROTECT)
+ ret = EINVAL;
+ else
+ (*mattr)->m_ceiling = prioceiling;
+
+ return(ret);
+}
+
diff --git a/lib/libthr/thread/thr_once.c b/lib/libthr/thread/thr_once.c
new file mode 100644
index 0000000..4fe392c
--- /dev/null
+++ b/lib/libthr/thread/thr_once.c
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2005, David Xu <davidxu@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 "namespace.h"
+#include <pthread.h>
+#include "un-namespace.h"
+
+#include "thr_private.h"
+
+__weak_reference(_pthread_once, pthread_once);
+
+#define ONCE_NEVER_DONE PTHREAD_NEEDS_INIT
+#define ONCE_DONE PTHREAD_DONE_INIT
+#define ONCE_IN_PROGRESS 0x02
+#define ONCE_MASK 0x03
+
+static pthread_mutex_t _thr_once_lock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t _thr_once_cv = PTHREAD_COND_INITIALIZER;
+
+/*
+ * POSIX:
+ * The pthread_once() function is not a cancellation point. However,
+ * if init_routine is a cancellation point and is canceled, the effect
+ * on once_control shall be as if pthread_once() was never called.
+ */
+
+static void
+once_cancel_handler(void *arg)
+{
+ pthread_once_t *once_control = arg;
+
+ _pthread_mutex_lock(&_thr_once_lock);
+ once_control->state = ONCE_NEVER_DONE;
+ _pthread_mutex_unlock(&_thr_once_lock);
+ _pthread_cond_broadcast(&_thr_once_cv);
+}
+
+int
+_pthread_once(pthread_once_t *once_control, void (*init_routine) (void))
+{
+ int wakeup = 0;
+
+ if (once_control->state == ONCE_DONE)
+ return (0);
+ _pthread_mutex_lock(&_thr_once_lock);
+ while (*(volatile int *)&(once_control->state) == ONCE_IN_PROGRESS)
+ _pthread_cond_wait(&_thr_once_cv, &_thr_once_lock);
+ /*
+ * If previous thread was canceled, then the state still
+ * could be ONCE_NEVER_DONE, we need to check it again.
+ */
+ if (*(volatile int *)&(once_control->state) == ONCE_NEVER_DONE) {
+ once_control->state = ONCE_IN_PROGRESS;
+ _pthread_mutex_unlock(&_thr_once_lock);
+ _pthread_cleanup_push(once_cancel_handler, once_control);
+ init_routine();
+ _pthread_cleanup_pop(0);
+ _pthread_mutex_lock(&_thr_once_lock);
+ once_control->state = ONCE_DONE;
+ wakeup = 1;
+ }
+ _pthread_mutex_unlock(&_thr_once_lock);
+ if (wakeup)
+ _pthread_cond_broadcast(&_thr_once_cv);
+ return (0);
+}
+
+void
+_thr_once_init()
+{
+ _thr_once_lock = PTHREAD_MUTEX_INITIALIZER;
+ _thr_once_cv = PTHREAD_COND_INITIALIZER;
+}
diff --git a/lib/libthr/thread/thr_printf.c b/lib/libthr/thread/thr_printf.c
new file mode 100644
index 0000000..7d32ae7
--- /dev/null
+++ b/lib/libthr/thread/thr_printf.c
@@ -0,0 +1,135 @@
+/*-
+ * 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 <stdarg.h>
+#include <string.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[20];
+ char *s;
+ unsigned long r, u;
+ int c;
+ long d;
+ int islong;
+
+ va_start(ap, fmt);
+ while ((c = *fmt++)) {
+ islong = 0;
+ if (c == '%') {
+next: c = *fmt++;
+ if (c == '\0')
+ goto out;
+ switch (c) {
+ case 'c':
+ pchar(fd, va_arg(ap, int));
+ continue;
+ case 's':
+ pstr(fd, va_arg(ap, char *));
+ continue;
+ case 'l':
+ islong = 1;
+ goto next;
+ case 'p':
+ islong = 1;
+ case 'd':
+ case 'u':
+ case 'x':
+ r = ((c == 'u') || (c == 'd')) ? 10 : 16;
+ if (c == 'd') {
+ if (islong)
+ d = va_arg(ap, unsigned long);
+ else
+ d = va_arg(ap, unsigned);
+ if (d < 0) {
+ pchar(fd, '-');
+ u = (unsigned long)(d * -1);
+ } else
+ u = (unsigned long)d;
+ } else {
+ if (islong)
+ u = va_arg(ap, unsigned long);
+ 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);
+ }
+out:
+ va_end(ap);
+}
+
+/*
+ * Write a single character to stdout, in a thread-safe manner.
+ */
+static void
+pchar(int fd, char c)
+{
+
+ __sys_write(fd, &c, 1);
+}
+
+/*
+ * Write a string to stdout, in a thread-safe manner.
+ */
+static void
+pstr(int fd, const char *s)
+{
+
+ __sys_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..0453864
--- /dev/null
+++ b/lib/libthr/thread/thr_private.h
@@ -0,0 +1,741 @@
+/*
+ * Copyright (C) 2005 Daniel M. Eischen <deischen@freebsd.org>
+ * Copyright (c) 2005 David Xu <davidxu@freebsd.org>
+ * 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 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$
+ */
+
+#ifndef _THR_PRIVATE_H
+#define _THR_PRIVATE_H
+
+/*
+ * Include files.
+ */
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/cdefs.h>
+#include <sys/queue.h>
+#include <machine/atomic.h>
+#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <ucontext.h>
+#include <sys/thr.h>
+#include <pthread.h>
+
+#ifndef __hidden
+#define __hidden __attribute__((visibility("hidden")))
+#endif
+
+#include "pthread_md.h"
+#include "thr_umtx.h"
+#include "thread_db.h"
+
+typedef TAILQ_HEAD(pthreadlist, pthread) pthreadlist;
+typedef TAILQ_HEAD(atfork_head, pthread_atfork) atfork_head;
+
+/* Signal to do cancellation */
+#define SIGCANCEL 32
+
+/*
+ * 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)
+
+#ifdef _PTHREADS_INVARIANTS
+#define THR_ASSERT(cond, msg) do { \
+ if (__predict_false(!(cond))) \
+ PANIC(msg); \
+} while (0)
+#else
+#define THR_ASSERT(cond, msg)
+#endif
+
+#ifdef PIC
+# define STATIC_LIB_REQUIRE(name)
+#else
+# define STATIC_LIB_REQUIRE(name) __asm (".globl " #name)
+#endif
+
+#define TIMESPEC_ADD(dst, src, val) \
+ do { \
+ (dst)->tv_sec = (src)->tv_sec + (val)->tv_sec; \
+ (dst)->tv_nsec = (src)->tv_nsec + (val)->tv_nsec; \
+ if ((dst)->tv_nsec >= 1000000000) { \
+ (dst)->tv_sec++; \
+ (dst)->tv_nsec -= 1000000000; \
+ } \
+ } while (0)
+
+#define TIMESPEC_SUB(dst, src, val) \
+ do { \
+ (dst)->tv_sec = (src)->tv_sec - (val)->tv_sec; \
+ (dst)->tv_nsec = (src)->tv_nsec - (val)->tv_nsec; \
+ if ((dst)->tv_nsec < 0) { \
+ (dst)->tv_sec--; \
+ (dst)->tv_nsec += 1000000000; \
+ } \
+ } while (0)
+
+struct pthread_mutex {
+ /*
+ * Lock for accesses to this structure.
+ */
+ volatile umtx_t m_lock;
+ enum pthread_mutextype m_type;
+ int m_protocol;
+ TAILQ_HEAD(mutex_head, pthread) m_queue;
+ struct pthread *m_owner;
+ int m_flags;
+ int m_count;
+ int m_refcount;
+
+ /*
+ * Used for priority inheritence and protection.
+ *
+ * m_prio - For priority inheritence, the highest active
+ * priority (threads locking the mutex inherit
+ * this priority). For priority protection, the
+ * ceiling priority of this mutex.
+ * m_saved_prio - mutex owners inherited priority before
+ * taking the mutex, restored when the owner
+ * unlocks the mutex.
+ */
+ int m_prio;
+ int m_saved_prio;
+
+ /*
+ * Link for list of all mutexes a thread currently owns.
+ */
+ TAILQ_ENTRY(pthread_mutex) m_qe;
+};
+
+/*
+ * Flags for mutexes.
+ */
+#define MUTEX_FLAGS_PRIVATE 0x01
+#define MUTEX_FLAGS_INITED 0x02
+#define MUTEX_FLAGS_BUSY 0x04
+
+struct pthread_mutex_attr {
+ enum pthread_mutextype m_type;
+ int m_protocol;
+ int m_ceiling;
+ int m_flags;
+};
+
+#define PTHREAD_MUTEXATTR_STATIC_INITIALIZER \
+ { PTHREAD_MUTEX_DEFAULT, PTHREAD_PRIO_NONE, 0, MUTEX_FLAGS_PRIVATE }
+
+struct pthread_cond {
+ /*
+ * Lock for accesses to this structure.
+ */
+ volatile umtx_t c_lock;
+ volatile umtx_t c_seqno;
+ volatile int c_waiters;
+ volatile int c_wakeups;
+ int c_pshared;
+ int c_clockid;
+};
+
+struct pthread_cond_attr {
+ int c_pshared;
+ int c_clockid;
+};
+
+struct pthread_barrier {
+ volatile umtx_t b_lock;
+ volatile umtx_t b_cycle;
+ volatile int b_count;
+ volatile int b_waiters;
+};
+
+struct pthread_barrierattr {
+ int pshared;
+};
+
+struct pthread_spinlock {
+ volatile umtx_t s_lock;
+};
+
+/*
+ * Flags for condition variables.
+ */
+#define COND_FLAGS_PRIVATE 0x01
+#define COND_FLAGS_INITED 0x02
+#define COND_FLAGS_BUSY 0x04
+
+/*
+ * Cleanup definitions.
+ */
+struct pthread_cleanup {
+ struct pthread_cleanup *next;
+ void (*routine)(void *args);
+ void *routine_arg;
+ int onstack;
+};
+
+#define THR_CLEANUP_PUSH(td, func, arg) { \
+ struct pthread_cleanup __cup; \
+ \
+ __cup.routine = func; \
+ __cup.routine_arg = arg; \
+ __cup.onstack = 1; \
+ __cup.next = (td)->cleanup; \
+ (td)->cleanup = &__cup;
+
+#define THR_CLEANUP_POP(td, exec) \
+ (td)->cleanup = __cup.next; \
+ if ((exec) != 0) \
+ __cup.routine(__cup.routine_arg); \
+}
+
+struct pthread_atfork {
+ TAILQ_ENTRY(pthread_atfork) qe;
+ void (*prepare)(void);
+ void (*parent)(void);
+ void (*child)(void);
+};
+
+struct pthread_attr {
+ int sched_policy;
+ int sched_inherit;
+ int prio;
+ int suspend;
+#define THR_STACK_USER 0x100 /* 0xFF reserved for <pthread.h> */
+ int flags;
+ void *stackaddr_attr;
+ size_t stacksize_attr;
+ size_t guardsize_attr;
+};
+
+/*
+ * Thread creation state attributes.
+ */
+#define THR_CREATE_RUNNING 0
+#define THR_CREATE_SUSPENDED 1
+
+/*
+ * Miscellaneous definitions.
+ */
+#define THR_STACK_DEFAULT (sizeof(void *) / 4 * 1024 * 1024)
+
+/*
+ * 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 THR_STACK_INITIAL (THR_STACK_DEFAULT * 2)
+
+/*
+ * Define priorities returned by kernel.
+ */
+#define THR_MIN_PRIORITY (_thr_priorities[SCHED_OTHER-1].pri_min)
+#define THR_MAX_PRIORITY (_thr_priorities[SCHED_OTHER-1].pri_min)
+#define THR_DEF_PRIORITY (_thr_priorities[SCHED_OTHER-1].pri_default)
+
+#define THR_MIN_RR_PRIORITY (_thr_priorities[SCHED_RR-1].pri_min)
+#define THR_MAX_RR_PRIORITY (_thr_priorities[SCHED_RR-1].pri_max)
+#define THR_DEF_RR_PRIORITY (_thr_priorities[SCHED_RR-1].pri_default)
+
+/* XXX The SCHED_FIFO should have same priority range as SCHED_RR */
+#define THR_MIN_FIFO_PRIORITY (_thr_priorities[SCHED_FIFO_1].pri_min)
+#define THR_MAX_FIFO_PRIORITY (_thr_priorities[SCHED_FIFO-1].pri_min)
+#define THR_DEF_FIFO_PRIORITY (_thr_priorities[SCHED_FIFO-1].pri_default)
+
+struct pthread_prio {
+ int pri_min;
+ int pri_max;
+ int pri_default;
+};
+
+struct pthread_rwlockattr {
+ int pshared;
+};
+
+struct pthread_rwlock {
+ pthread_mutex_t lock; /* monitor lock */
+ pthread_cond_t read_signal;
+ pthread_cond_t write_signal;
+ int state; /* 0 = idle >0 = # of readers -1 = writer */
+ int blocked_writers;
+};
+
+/*
+ * Thread states.
+ */
+enum pthread_state {
+ PS_RUNNING,
+ PS_DEAD
+};
+
+struct pthread_specific_elem {
+ const void *data;
+ int seqno;
+};
+
+struct pthread_key {
+ volatile int allocated;
+ volatile int count;
+ int seqno;
+ void (*destructor)(void *);
+};
+
+/*
+ * Thread structure.
+ */
+struct pthread {
+ /* Kernel thread id. */
+ long tid;
+#define TID_TERMINATED 1
+
+ /*
+ * Lock for accesses to this thread structure.
+ */
+ umtx_t lock;
+
+ /* Internal condition variable cycle number. */
+ umtx_t cycle;
+
+ /* How many low level locks the thread held. */
+ int locklevel;
+
+ /*
+ * Set to non-zero when this thread has entered a critical
+ * region. We allow for recursive entries into critical regions.
+ */
+ int critical_count;
+
+ /* Signal blocked counter. */
+ int sigblock;
+
+ /* Queue entry for list of all threads. */
+ TAILQ_ENTRY(pthread) tle; /* link for all threads in process */
+
+ /* Queue entry for GC lists. */
+ TAILQ_ENTRY(pthread) gcle;
+
+ /* Hash queue entry. */
+ LIST_ENTRY(pthread) hle;
+
+ /* Threads reference count. */
+ int refcount;
+
+ /*
+ * Thread start routine, argument, stack pointer and thread
+ * attributes.
+ */
+ void *(*start_routine)(void *);
+ void *arg;
+ struct pthread_attr attr;
+
+ /*
+ * Cancelability flags
+ */
+#define THR_CANCEL_DISABLE 0x0001
+#define THR_CANCEL_EXITING 0x0002
+#define THR_CANCEL_AT_POINT 0x0004
+#define THR_CANCEL_NEEDED 0x0008
+#define SHOULD_CANCEL(val) \
+ (((val) & (THR_CANCEL_DISABLE | THR_CANCEL_EXITING | \
+ THR_CANCEL_NEEDED)) == THR_CANCEL_NEEDED)
+
+#define SHOULD_ASYNC_CANCEL(val) \
+ (((val) & (THR_CANCEL_DISABLE | THR_CANCEL_EXITING | \
+ THR_CANCEL_NEEDED | THR_CANCEL_AT_POINT)) == \
+ (THR_CANCEL_NEEDED | THR_CANCEL_AT_POINT))
+ int cancelflags;
+
+ /* Thread temporary signal mask. */
+ sigset_t sigmask;
+
+ /* Thread state: */
+ umtx_t 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;
+
+ /*
+ * The current thread can belong to a priority mutex queue.
+ * This is the synchronization queue link.
+ */
+ TAILQ_ENTRY(pthread) sqe;
+
+ /* Miscellaneous flags; only set with scheduling lock held. */
+ int flags;
+#define THR_FLAGS_PRIVATE 0x0001
+#define THR_FLAGS_NEED_SUSPEND 0x0002 /* thread should be suspended */
+#define THR_FLAGS_SUSPENDED 0x0004 /* thread is suspended */
+
+ /* Thread list flags; only set with thread list lock held. */
+ int tlflags;
+#define TLFLAGS_GC_SAFE 0x0001 /* thread safe for cleaning */
+#define TLFLAGS_IN_TDLIST 0x0002 /* thread in all thread list */
+#define TLFLAGS_IN_GCLIST 0x0004 /* thread in gc list */
+#define TLFLAGS_DETACHED 0x0008 /* thread is detached */
+
+ /*
+ * 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;
+
+ /* Queue of currently owned simple type mutexes. */
+ TAILQ_HEAD(, pthread_mutex) mutexq;
+
+ void *ret;
+ struct pthread_specific_elem *specific;
+ int specific_data_count;
+
+ /* Number rwlocks rdlocks held. */
+ int rdlock_count;
+
+ /*
+ * Current locks bitmap for rtld. */
+ int rtld_bits;
+
+ /* Thread control block */
+ struct tcb *tcb;
+
+ /* Cleanup handlers Link List */
+ struct pthread_cleanup *cleanup;
+
+ /*
+ * Magic value to help recognize a valid thread structure
+ * from an invalid one:
+ */
+#define THR_MAGIC ((u_int32_t) 0xd09ba115)
+ u_int32_t magic;
+
+ /* Enable event reporting */
+ int report_events;
+
+ /* Event mask */
+ int event_mask;
+
+ /* Event */
+ td_event_msg_t event_buf;
+};
+
+#define THR_IN_CRITICAL(thrd) \
+ (((thrd)->locklevel > 0) || \
+ ((thrd)->critical_count > 0))
+
+#define THR_CRITICAL_ENTER(thrd) \
+ (thrd)->critical_count++
+
+#define THR_CRITICAL_LEAVE(thrd) \
+ (thrd)->critical_count--; \
+ _thr_ast(thrd);
+
+#define THR_UMTX_TRYLOCK(thrd, lck) \
+ _thr_umtx_trylock((lck), (thrd)->tid)
+
+#define THR_UMTX_LOCK(thrd, lck) \
+ _thr_umtx_lock((lck), (thrd)->tid)
+
+#define THR_UMTX_TIMEDLOCK(thrd, lck, timo) \
+ _thr_umtx_timedlock((lck), (thrd)->tid, (timo))
+
+#define THR_UMTX_UNLOCK(thrd, lck) \
+ _thr_umtx_unlock((lck), (thrd)->tid)
+
+#define THR_LOCK_ACQUIRE(thrd, lck) \
+do { \
+ (thrd)->locklevel++; \
+ _thr_umtx_lock(lck, (thrd)->tid); \
+} while (0)
+
+#ifdef _PTHREADS_INVARIANTS
+#define THR_ASSERT_LOCKLEVEL(thrd) \
+do { \
+ if (__predict_false((thrd)->locklevel <= 0)) \
+ _thr_assert_lock_level(); \
+} while (0)
+#else
+#define THR_ASSERT_LOCKLEVEL(thrd)
+#endif
+
+#define THR_LOCK_RELEASE(thrd, lck) \
+do { \
+ THR_ASSERT_LOCKLEVEL(thrd); \
+ _thr_umtx_unlock((lck), (thrd)->tid); \
+ (thrd)->locklevel--; \
+ _thr_ast(thrd); \
+} while (0)
+
+#define THR_LOCK(curthrd) THR_LOCK_ACQUIRE(curthrd, &(curthrd)->lock)
+#define THR_UNLOCK(curthrd) THR_LOCK_RELEASE(curthrd, &(curthrd)->lock)
+#define THR_THREAD_LOCK(curthrd, thr) THR_LOCK_ACQUIRE(curthrd, &(thr)->lock)
+#define THR_THREAD_UNLOCK(curthrd, thr) THR_LOCK_RELEASE(curthrd, &(thr)->lock)
+
+#define THREAD_LIST_LOCK(curthrd) \
+do { \
+ THR_LOCK_ACQUIRE((curthrd), &_thr_list_lock); \
+} while (0)
+
+#define THREAD_LIST_UNLOCK(curthrd) \
+do { \
+ THR_LOCK_RELEASE((curthrd), &_thr_list_lock); \
+} while (0)
+
+/*
+ * Macros to insert/remove threads to the all thread list and
+ * the gc list.
+ */
+#define THR_LIST_ADD(thrd) do { \
+ if (((thrd)->tlflags & TLFLAGS_IN_TDLIST) == 0) { \
+ TAILQ_INSERT_HEAD(&_thread_list, thrd, tle); \
+ _thr_hash_add(thrd); \
+ (thrd)->tlflags |= TLFLAGS_IN_TDLIST; \
+ } \
+} while (0)
+#define THR_LIST_REMOVE(thrd) do { \
+ if (((thrd)->tlflags & TLFLAGS_IN_TDLIST) != 0) { \
+ TAILQ_REMOVE(&_thread_list, thrd, tle); \
+ _thr_hash_remove(thrd); \
+ (thrd)->tlflags &= ~TLFLAGS_IN_TDLIST; \
+ } \
+} while (0)
+#define THR_GCLIST_ADD(thrd) do { \
+ if (((thrd)->tlflags & TLFLAGS_IN_GCLIST) == 0) { \
+ TAILQ_INSERT_HEAD(&_thread_gc_list, thrd, gcle);\
+ (thrd)->tlflags |= TLFLAGS_IN_GCLIST; \
+ _gc_count++; \
+ } \
+} while (0)
+#define THR_GCLIST_REMOVE(thrd) do { \
+ if (((thrd)->tlflags & TLFLAGS_IN_GCLIST) != 0) { \
+ TAILQ_REMOVE(&_thread_gc_list, thrd, gcle); \
+ (thrd)->tlflags &= ~TLFLAGS_IN_GCLIST; \
+ _gc_count--; \
+ } \
+} while (0)
+
+#define GC_NEEDED() (_gc_count >= 5)
+
+#define SHOULD_REPORT_EVENT(curthr, e) \
+ (curthr->report_events && \
+ (((curthr)->event_mask | _thread_event_mask ) & e) != 0)
+
+extern int __isthreaded;
+
+/*
+ * Global variables for the pthread kernel.
+ */
+
+extern char *_usrstack __hidden;
+extern struct pthread *_thr_initial __hidden;
+extern int _thr_scope_system __hidden;
+
+/* For debugger */
+extern int _libthr_debug;
+extern int _thread_event_mask;
+extern struct pthread *_thread_last_event;
+
+/* List of all threads: */
+extern pthreadlist _thread_list;
+
+/* List of threads needing GC: */
+extern pthreadlist _thread_gc_list __hidden;
+
+extern int _thread_active_threads;
+extern atfork_head _thr_atfork_list __hidden;
+extern umtx_t _thr_atfork_lock __hidden;
+
+/* Default thread attributes: */
+extern struct pthread_attr _pthread_attr_default __hidden;
+
+/* Default mutex attributes: */
+extern struct pthread_mutex_attr _pthread_mutexattr_default __hidden;
+
+/* Default condition variable attributes: */
+extern struct pthread_cond_attr _pthread_condattr_default __hidden;
+
+extern struct pthread_prio _thr_priorities[] __hidden;
+
+extern pid_t _thr_pid __hidden;
+extern size_t _thr_guard_default __hidden;
+extern size_t _thr_stack_default __hidden;
+extern size_t _thr_stack_initial __hidden;
+extern int _thr_page_size __hidden;
+/* Garbage thread count. */
+extern int _gc_count __hidden;
+
+extern umtx_t _mutex_static_lock __hidden;
+extern umtx_t _cond_static_lock __hidden;
+extern umtx_t _rwlock_static_lock __hidden;
+extern umtx_t _keytable_lock __hidden;
+extern umtx_t _thr_list_lock __hidden;
+extern umtx_t _thr_event_lock __hidden;
+
+/*
+ * Function prototype definitions.
+ */
+__BEGIN_DECLS
+int _thr_setthreaded(int) __hidden;
+int _mutex_cv_lock(pthread_mutex_t *, int count) __hidden;
+int _mutex_cv_unlock(pthread_mutex_t *, int *count) __hidden;
+int _mutex_reinit(pthread_mutex_t *) __hidden;
+void _mutex_fork(struct pthread *curthread) __hidden;
+void _mutex_unlock_private(struct pthread *) __hidden;
+void _libpthread_init(struct pthread *) __hidden;
+struct pthread *_thr_alloc(struct pthread *) __hidden;
+void _thread_exit(const char *, int, const char *) __hidden __dead2;
+void _thr_exit_cleanup(void) __hidden;
+int _thr_ref_add(struct pthread *, struct pthread *, int) __hidden;
+void _thr_ref_delete(struct pthread *, struct pthread *) __hidden;
+void _thr_ref_delete_unlocked(struct pthread *, struct pthread *) __hidden;
+int _thr_find_thread(struct pthread *, struct pthread *, int) __hidden;
+void _thr_rtld_init(void) __hidden;
+void _thr_rtld_fini(void) __hidden;
+int _thr_stack_alloc(struct pthread_attr *) __hidden;
+void _thr_stack_free(struct pthread_attr *) __hidden;
+void _thr_free(struct pthread *, struct pthread *) __hidden;
+void _thr_gc(struct pthread *) __hidden;
+void _thread_cleanupspecific(void) __hidden;
+void _thread_dump_info(void) __hidden;
+void _thread_printf(int, const char *, ...) __hidden;
+void _thr_spinlock_init(void) __hidden;
+int _thr_cancel_enter(struct pthread *) __hidden;
+void _thr_cancel_leave(struct pthread *, int) __hidden;
+void _thr_signal_block(struct pthread *) __hidden;
+void _thr_signal_unblock(struct pthread *) __hidden;
+void _thr_signal_init(void) __hidden;
+void _thr_signal_deinit(void) __hidden;
+int _thr_send_sig(struct pthread *, int sig) __hidden;
+void _thr_list_init(void) __hidden;
+void _thr_hash_add(struct pthread *) __hidden;
+void _thr_hash_remove(struct pthread *) __hidden;
+struct pthread *_thr_hash_find(struct pthread *) __hidden;
+void _thr_link(struct pthread *, struct pthread *) __hidden;
+void _thr_unlink(struct pthread *, struct pthread *) __hidden;
+void _thr_suspend_check(struct pthread *) __hidden;
+void _thr_assert_lock_level(void) __hidden __dead2;
+void _thr_ast(struct pthread *) __hidden;
+void _thr_once_init(void) __hidden;
+void _thr_report_creation(struct pthread *curthread,
+ struct pthread *newthread) __hidden;
+void _thr_report_death(struct pthread *curthread) __hidden;
+void _thread_bp_create(void);
+void _thread_bp_death(void);
+
+/* #include <fcntl.h> */
+#ifdef _SYS_FCNTL_H_
+int __sys_fcntl(int, int, ...);
+int __sys_open(const char *, int, ...);
+#endif
+
+/* #include <signal.h> */
+#ifdef _SIGNAL_H_
+int __sys_kill(pid_t, int);
+int __sys_sigaction(int, const struct sigaction *, struct sigaction *);
+int __sys_sigpending(sigset_t *);
+int __sys_sigprocmask(int, const sigset_t *, sigset_t *);
+int __sys_sigsuspend(const sigset_t *);
+int __sys_sigreturn(ucontext_t *);
+int __sys_sigaltstack(const struct sigaltstack *, struct sigaltstack *);
+int __sys_sigwait(const sigset_t *, int *);
+int __sys_sigtimedwait(const sigset_t *, siginfo_t *,
+ const struct timespec *);
+int __sys_sigwaitinfo(const sigset_t *set, siginfo_t *info);
+#endif
+
+/* #include <time.h> */
+#ifdef _TIME_H_
+int __sys_nanosleep(const struct timespec *, struct timespec *);
+#endif
+
+/* #include <unistd.h> */
+#ifdef _UNISTD_H_
+int __sys_close(int);
+int __sys_fork(void);
+pid_t __sys_getpid(void);
+ssize_t __sys_read(int, void *, size_t);
+ssize_t __sys_write(int, const void *, size_t);
+void __sys_exit(int);
+#endif
+
+static inline int
+_thr_isthreaded(void)
+{
+ return (__isthreaded != 0);
+}
+
+static inline int
+_thr_is_inited(void)
+{
+ return (_thr_initial != NULL);
+}
+
+static inline void
+_thr_check_init(void)
+{
+ if (_thr_initial == NULL)
+ _libpthread_init(NULL);
+}
+
+__END_DECLS
+
+#endif /* !_THR_PRIVATE_H */
diff --git a/lib/libthr/thread/thr_pspinlock.c b/lib/libthr/thread/thr_pspinlock.c
new file mode 100644
index 0000000..ec3d68b
--- /dev/null
+++ b/lib/libthr/thread/thr_pspinlock.c
@@ -0,0 +1,136 @@
+/*-
+ * Copyright (c) 2003 David Xu <davidxu@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 "namespace.h"
+#include <errno.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include "un-namespace.h"
+
+#include "thr_private.h"
+
+#define SPIN_COUNT 100000
+
+__weak_reference(_pthread_spin_init, pthread_spin_init);
+__weak_reference(_pthread_spin_destroy, pthread_spin_destroy);
+__weak_reference(_pthread_spin_trylock, pthread_spin_trylock);
+__weak_reference(_pthread_spin_lock, pthread_spin_lock);
+__weak_reference(_pthread_spin_unlock, pthread_spin_unlock);
+
+int
+_pthread_spin_init(pthread_spinlock_t *lock, int pshared)
+{
+ struct pthread_spinlock *lck;
+ int ret;
+
+ if (lock == NULL || pshared != PTHREAD_PROCESS_PRIVATE)
+ ret = EINVAL;
+ else if ((lck = malloc(sizeof(struct pthread_spinlock))) == NULL)
+ ret = ENOMEM;
+ else {
+ _thr_umtx_init(&lck->s_lock);
+ *lock = lck;
+ ret = 0;
+ }
+
+ return (ret);
+}
+
+int
+_pthread_spin_destroy(pthread_spinlock_t *lock)
+{
+ int ret;
+
+ if (lock == NULL || *lock == NULL)
+ ret = EINVAL;
+ else {
+ free(*lock);
+ *lock = NULL;
+ ret = 0;
+ }
+
+ return (ret);
+}
+
+int
+_pthread_spin_trylock(pthread_spinlock_t *lock)
+{
+ struct pthread *curthread = _get_curthread();
+ struct pthread_spinlock *lck;
+ int ret;
+
+ if (lock == NULL || (lck = *lock) == NULL)
+ ret = EINVAL;
+ else
+ ret = THR_UMTX_TRYLOCK(curthread, &lck->s_lock);
+ return (ret);
+}
+
+int
+_pthread_spin_lock(pthread_spinlock_t *lock)
+{
+ struct pthread *curthread = _get_curthread();
+ struct pthread_spinlock *lck;
+ int ret, count;
+
+ if (lock == NULL || (lck = *lock) == NULL)
+ ret = EINVAL;
+ else {
+ count = SPIN_COUNT;
+ while ((ret = THR_UMTX_TRYLOCK(curthread, &lck->s_lock)) != 0) {
+ while (lck->s_lock) {
+#ifdef __i386__
+ /* tell cpu we are spinning */
+ __asm __volatile("pause");
+#endif
+ if (--count <= 0) {
+ count = SPIN_COUNT;
+ _pthread_yield();
+ }
+ }
+ }
+ ret = 0;
+ }
+
+ return (ret);
+}
+
+int
+_pthread_spin_unlock(pthread_spinlock_t *lock)
+{
+ struct pthread *curthread = _get_curthread();
+ struct pthread_spinlock *lck;
+ int ret;
+
+ if (lock == NULL || (lck = *lock) == NULL)
+ ret = EINVAL;
+ else {
+ ret = THR_UMTX_UNLOCK(curthread, &lck->s_lock);
+ }
+ return (ret);
+}
diff --git a/lib/libthr/thread/thr_resume_np.c b/lib/libthr/thread/thr_resume_np.c
new file mode 100644
index 0000000..7fd3733
--- /dev/null
+++ b/lib/libthr/thread/thr_resume_np.c
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include "namespace.h"
+#include <errno.h>
+#include <pthread.h>
+#include <pthread_np.h>
+#include "un-namespace.h"
+
+#include "thr_private.h"
+
+__weak_reference(_pthread_resume_np, pthread_resume_np);
+__weak_reference(_pthread_resume_all_np, pthread_resume_all_np);
+
+static void resume_common(struct pthread *thread);
+
+/* Resume a thread: */
+int
+_pthread_resume_np(pthread_t thread)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret;
+
+ /* Add a reference to the thread: */
+ if ((ret = _thr_ref_add(curthread, thread, /*include dead*/0)) == 0) {
+ /* Lock the threads scheduling queue: */
+ THR_THREAD_LOCK(curthread, thread);
+ resume_common(thread);
+ THR_THREAD_UNLOCK(curthread, thread);
+ _thr_ref_delete(curthread, thread);
+ }
+ return (ret);
+}
+
+void
+_pthread_resume_all_np(void)
+{
+ struct pthread *curthread = _get_curthread();
+ struct pthread *thread;
+
+ /* Take the thread list lock: */
+ THREAD_LIST_LOCK(curthread);
+
+ TAILQ_FOREACH(thread, &_thread_list, tle) {
+ if (thread != curthread) {
+ THR_THREAD_LOCK(curthread, thread);
+ resume_common(thread);
+ THR_THREAD_UNLOCK(curthread, thread);
+ }
+ }
+
+ /* Release the thread list lock: */
+ THREAD_LIST_UNLOCK(curthread);
+}
+
+static void
+resume_common(struct pthread *thread)
+{
+ /* Clear the suspend flag: */
+ thread->flags &= ~THR_FLAGS_NEED_SUSPEND;
+ thread->cycle++;
+ _thr_umtx_wake(&thread->cycle, 1);
+}
diff --git a/lib/libthr/thread/thr_rtld.c b/lib/libthr/thread/thr_rtld.c
new file mode 100644
index 0000000..827b962
--- /dev/null
+++ b/lib/libthr/thread/thr_rtld.c
@@ -0,0 +1,219 @@
+/*
+ * Copyright (c) 2006, David Xu <davidxu@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$
+ *
+ */
+
+ /*
+ * A lockless rwlock for rtld.
+ */
+#include <sys/cdefs.h>
+#include <stdlib.h>
+
+#include "rtld_lock.h"
+#include "thr_private.h"
+
+#define CACHE_LINE_SIZE 64
+#define WAFLAG 0x1
+#define RC_INCR 0x2
+
+static int _thr_rtld_clr_flag(int);
+static void *_thr_rtld_lock_create(void);
+static void _thr_rtld_lock_destroy(void *);
+static void _thr_rtld_lock_release(void *);
+static void _thr_rtld_rlock_acquire(void *);
+static int _thr_rtld_set_flag(int);
+static void _thr_rtld_wlock_acquire(void *);
+
+struct rtld_lock {
+ volatile int lock;
+ volatile int rd_waiters;
+ volatile int wr_waiters;
+ volatile umtx_t rd_cv;
+ volatile umtx_t wr_cv;
+ void *base;
+};
+
+static void *
+_thr_rtld_lock_create(void)
+{
+ void *base;
+ char *p;
+ uintptr_t r;
+ struct rtld_lock *l;
+
+ THR_ASSERT(sizeof(struct rtld_lock) <= CACHE_LINE_SIZE,
+ "rtld_lock too large");
+ base = calloc(1, CACHE_LINE_SIZE);
+ p = (char *)base;
+ if ((uintptr_t)p % CACHE_LINE_SIZE != 0) {
+ free(base);
+ base = calloc(1, 2 * CACHE_LINE_SIZE);
+ p = (char *)base;
+ if ((r = (uintptr_t)p % CACHE_LINE_SIZE) != 0)
+ p += CACHE_LINE_SIZE - r;
+ }
+ l = (struct rtld_lock *)p;
+ l->base = base;
+ return (l);
+}
+
+static void
+_thr_rtld_lock_destroy(void *lock)
+{
+ struct rtld_lock *l = (struct rtld_lock *)lock;
+ free(l->base);
+}
+
+static void
+_thr_rtld_rlock_acquire(void *lock)
+{
+ struct pthread *curthread;
+ struct rtld_lock *l;
+ umtx_t v;
+
+ curthread = _get_curthread();
+ l = (struct rtld_lock *)lock;
+
+ THR_CRITICAL_ENTER(curthread);
+ atomic_add_acq_int(&l->lock, RC_INCR);
+ if (!(l->lock & WAFLAG))
+ return;
+ v = l->rd_cv;
+ atomic_add_int(&l->rd_waiters, 1);
+ while (l->lock & WAFLAG) {
+ _thr_umtx_wait(&l->rd_cv, v, NULL);
+ v = l->rd_cv;
+ }
+ atomic_add_int(&l->rd_waiters, -1);
+}
+
+static void
+_thr_rtld_wlock_acquire(void *lock)
+{
+ struct pthread *curthread;
+ struct rtld_lock *l;
+ umtx_t v;
+
+ curthread = _get_curthread();
+ l = (struct rtld_lock *)lock;
+
+ _thr_signal_block(curthread);
+ for (;;) {
+ if (atomic_cmpset_acq_int(&l->lock, 0, WAFLAG))
+ return;
+ v = l->wr_cv;
+ atomic_add_int(&l->wr_waiters, 1);
+ while (l->lock != 0) {
+ _thr_umtx_wait(&l->wr_cv, v, NULL);
+ v = l->wr_cv;
+ }
+ atomic_add_int(&l->wr_waiters, -1);
+ }
+}
+
+static void
+_thr_rtld_lock_release(void *lock)
+{
+ struct pthread *curthread;
+ struct rtld_lock *l;
+
+ curthread = _get_curthread();
+ l = (struct rtld_lock *)lock;
+
+ if ((l->lock & WAFLAG) == 0) {
+ atomic_add_rel_int(&l->lock, -RC_INCR);
+ if (l->lock == 0 && l->wr_waiters) {
+ atomic_add_long(&l->wr_cv, 1);
+ _thr_umtx_wake(&l->wr_cv, l->wr_waiters);
+ }
+ THR_CRITICAL_LEAVE(curthread);
+ } else {
+ atomic_add_rel_int(&l->lock, -WAFLAG);
+ if (l->lock == 0 && l->wr_waiters) {
+ atomic_add_long(&l->wr_cv, 1);
+ _thr_umtx_wake(&l->wr_cv, l->wr_waiters);
+ } else if (l->rd_waiters) {
+ atomic_add_long(&l->rd_cv, 1);
+ _thr_umtx_wake(&l->rd_cv, l->rd_waiters);
+ }
+ _thr_signal_unblock(curthread);
+ }
+}
+
+static int
+_thr_rtld_set_flag(int mask __unused)
+{
+ /*
+ * The caller's code in rtld-elf is broken, it is not signal safe,
+ * just return zero to fool it.
+ */
+ return (0);
+}
+
+static int
+_thr_rtld_clr_flag(int mask __unused)
+{
+ return (0);
+}
+
+void
+_thr_rtld_init(void)
+{
+ struct RtldLockInfo li;
+ struct pthread *curthread;
+ umtx_t dummy;
+
+ curthread = _get_curthread();
+
+ /* force to resolve _umtx_op PLT */
+ _umtx_op((struct umtx *)&dummy, UMTX_OP_WAKE, 1, 0, 0);
+
+ li.lock_create = _thr_rtld_lock_create;
+ li.lock_destroy = _thr_rtld_lock_destroy;
+ li.rlock_acquire = _thr_rtld_rlock_acquire;
+ li.wlock_acquire = _thr_rtld_wlock_acquire;
+ li.lock_release = _thr_rtld_lock_release;
+ li.thread_set_flag = _thr_rtld_set_flag;
+ li.thread_clr_flag = _thr_rtld_clr_flag;
+ li.at_fork = NULL;
+
+ /* mask signals, also force to resolve __sys_sigprocmask PLT */
+ _thr_signal_block(curthread);
+ _rtld_thread_init(&li);
+ _thr_signal_unblock(curthread);
+}
+
+void
+_thr_rtld_fini(void)
+{
+ struct pthread *curthread;
+
+ curthread = _get_curthread();
+ _thr_signal_block(curthread);
+ _rtld_thread_init(NULL);
+ _thr_signal_unblock(curthread);
+}
diff --git a/lib/libthr/thread/thr_rwlock.c b/lib/libthr/thread/thr_rwlock.c
new file mode 100644
index 0000000..81d1459
--- /dev/null
+++ b/lib/libthr/thread/thr_rwlock.c
@@ -0,0 +1,417 @@
+/*-
+ * 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 "namespace.h"
+#include <pthread.h>
+#include "un-namespace.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_timedrdlock, pthread_rwlock_timedrdlock);
+__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);
+__weak_reference(_pthread_rwlock_timedwrlock, pthread_rwlock_timedwrlock);
+
+/*
+ * Prototypes
+ */
+
+static int
+rwlock_init(pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr __unused)
+{
+ 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_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);
+}
+
+static int
+init_static(struct pthread *thread, pthread_rwlock_t *rwlock)
+{
+ int ret;
+
+ THR_LOCK_ACQUIRE(thread, &_rwlock_static_lock);
+
+ if (*rwlock == NULL)
+ ret = rwlock_init(rwlock, NULL);
+ else
+ ret = 0;
+
+ THR_LOCK_RELEASE(thread, &_rwlock_static_lock);
+
+ return (ret);
+}
+
+int
+_pthread_rwlock_init (pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr)
+{
+ *rwlock = NULL;
+ return (rwlock_init(rwlock, attr));
+}
+
+static int
+rwlock_rdlock_common (pthread_rwlock_t *rwlock, const struct timespec *abstime)
+{
+ struct pthread *curthread = _get_curthread();
+ pthread_rwlock_t prwlock;
+ int ret;
+
+ if (rwlock == NULL)
+ return (EINVAL);
+
+ prwlock = *rwlock;
+
+ /* check for static initialization */
+ if (prwlock == NULL) {
+ if ((ret = init_static(curthread, rwlock)) != 0)
+ return (ret);
+
+ prwlock = *rwlock;
+ }
+
+ /* grab the monitor lock */
+ if ((ret = _pthread_mutex_lock(&prwlock->lock)) != 0)
+ return (ret);
+
+ /* check lock count */
+ if (prwlock->state == MAX_READ_LOCKS) {
+ _pthread_mutex_unlock(&prwlock->lock);
+ return (EAGAIN);
+ }
+
+ if ((curthread->rdlock_count > 0) && (prwlock->state > 0)) {
+ /*
+ * To avoid having to track all the rdlocks held by
+ * a thread or all of the threads that hold a rdlock,
+ * we keep a simple count of all the rdlocks held by
+ * a thread. If a thread holds any rdlocks it is
+ * possible that it is attempting to take a recursive
+ * rdlock. If there are blocked writers and precedence
+ * is given to them, then that would result in the thread
+ * deadlocking. So allowing a thread to take the rdlock
+ * when it already has one or more rdlocks avoids the
+ * deadlock. I hope the reader can follow that logic ;-)
+ */
+ ; /* nothing needed */
+ } else {
+ /* give writers priority over readers */
+ while (prwlock->blocked_writers || prwlock->state < 0) {
+ if (abstime)
+ ret = _pthread_cond_timedwait
+ (&prwlock->read_signal,
+ &prwlock->lock, abstime);
+ else
+ 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);
+ }
+ }
+ }
+
+ curthread->rdlock_count++;
+ 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_rdlock (pthread_rwlock_t *rwlock)
+{
+ return (rwlock_rdlock_common(rwlock, NULL));
+}
+
+int
+_pthread_rwlock_timedrdlock (pthread_rwlock_t *rwlock,
+ const struct timespec *abstime)
+{
+ return (rwlock_rdlock_common(rwlock, abstime));
+}
+
+int
+_pthread_rwlock_tryrdlock (pthread_rwlock_t *rwlock)
+{
+ struct pthread *curthread = _get_curthread();
+ pthread_rwlock_t prwlock;
+ int ret;
+
+ if (rwlock == NULL)
+ return (EINVAL);
+
+ prwlock = *rwlock;
+
+ /* check for static initialization */
+ if (prwlock == NULL) {
+ if ((ret = init_static(curthread, rwlock)) != 0)
+ return (ret);
+
+ prwlock = *rwlock;
+ }
+
+ /* grab the monitor lock */
+ if ((ret = _pthread_mutex_lock(&prwlock->lock)) != 0)
+ return (ret);
+
+ if (prwlock->state == MAX_READ_LOCKS)
+ ret = EAGAIN;
+ else if ((curthread->rdlock_count > 0) && (prwlock->state > 0)) {
+ /* see comment for pthread_rwlock_rdlock() */
+ curthread->rdlock_count++;
+ prwlock->state++;
+ }
+ /* give writers priority over readers */
+ else if (prwlock->blocked_writers || prwlock->state < 0)
+ ret = EBUSY;
+ else {
+ curthread->rdlock_count++;
+ 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)
+{
+ struct pthread *curthread = _get_curthread();
+ pthread_rwlock_t prwlock;
+ int ret;
+
+ if (rwlock == NULL)
+ return (EINVAL);
+
+ prwlock = *rwlock;
+
+ /* check for static initialization */
+ if (prwlock == NULL) {
+ if ((ret = init_static(curthread, 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)
+{
+ struct pthread *curthread = _get_curthread();
+ 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) {
+ curthread->rdlock_count--;
+ prwlock->state--;
+ 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);
+}
+
+static int
+rwlock_wrlock_common (pthread_rwlock_t *rwlock, const struct timespec *abstime)
+{
+ struct pthread *curthread = _get_curthread();
+ pthread_rwlock_t prwlock;
+ int ret;
+
+ if (rwlock == NULL)
+ return (EINVAL);
+
+ prwlock = *rwlock;
+
+ /* check for static initialization */
+ if (prwlock == NULL) {
+ if ((ret = init_static(curthread, 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++;
+
+ if (abstime != NULL)
+ ret = _pthread_cond_timedwait(&prwlock->write_signal,
+ &prwlock->lock, abstime);
+ else
+ 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);
+}
+
+int
+_pthread_rwlock_wrlock (pthread_rwlock_t *rwlock)
+{
+ return (rwlock_wrlock_common (rwlock, NULL));
+}
+
+int
+_pthread_rwlock_timedwrlock (pthread_rwlock_t *rwlock,
+ const struct timespec *abstime)
+{
+ return (rwlock_wrlock_common (rwlock, abstime));
+}
diff --git a/lib/libthr/thread/thr_rwlockattr.c b/lib/libthr/thread/thr_rwlockattr.c
new file mode 100644
index 0000000..b47d167
--- /dev/null
+++ b/lib/libthr/thread/thr_rwlockattr.c
@@ -0,0 +1,100 @@
+/*-
+ * 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 "namespace.h"
+#include <errno.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include "un-namespace.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..85fb54e
--- /dev/null
+++ b/lib/libthr/thread/thr_self.c
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE 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 "namespace.h"
+#include <pthread.h>
+#include "un-namespace.h"
+
+#include "thr_private.h"
+
+__weak_reference(_pthread_self, pthread_self);
+
+pthread_t
+_pthread_self(void)
+{
+ _thr_check_init();
+
+ /* 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..88a3cbd
--- /dev/null
+++ b/lib/libthr/thread/thr_sem.c
@@ -0,0 +1,271 @@
+/*
+ * Copyright (C) 2005 David Xu <davidxu@freebsd.org>.
+ * 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 "namespace.h"
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <semaphore.h>
+#include <stdlib.h>
+#include <time.h>
+#include <_semaphore.h>
+#include "un-namespace.h"
+
+#include "thr_private.h"
+
+
+__weak_reference(_sem_init, sem_init);
+__weak_reference(_sem_destroy, sem_destroy);
+__weak_reference(_sem_getvalue, sem_getvalue);
+__weak_reference(_sem_trywait, sem_trywait);
+__weak_reference(_sem_wait, sem_wait);
+__weak_reference(_sem_timedwait, sem_timedwait);
+__weak_reference(_sem_post, sem_post);
+
+
+static inline int
+sem_check_validity(sem_t *sem)
+{
+
+ if ((sem != NULL) && ((*sem)->magic == SEM_MAGIC))
+ return (0);
+ else {
+ errno = EINVAL;
+ return (-1);
+ }
+}
+
+static sem_t
+sem_alloc(unsigned int value, semid_t semid, int system_sem)
+{
+ sem_t sem;
+
+ if (value > SEM_VALUE_MAX) {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ sem = (sem_t)malloc(sizeof(struct sem));
+ if (sem == NULL) {
+ errno = ENOSPC;
+ return (NULL);
+ }
+ _thr_umtx_init((umtx_t *)&sem->lock);
+ /*
+ * Fortunatly count and nwaiters are adjacency, so we can
+ * use umtx_wait to wait on it, umtx_wait needs an address
+ * can be accessed as a long interger.
+ */
+ sem->count = (u_int32_t)value;
+ sem->nwaiters = 0;
+ sem->magic = SEM_MAGIC;
+ sem->semid = semid;
+ sem->syssem = system_sem;
+ return (sem);
+}
+
+int
+_sem_init(sem_t *sem, int pshared, unsigned int value)
+{
+ semid_t semid;
+
+ semid = (semid_t)SEM_USER;
+ if ((pshared != 0) && (ksem_init(&semid, value) != 0))
+ return (-1);
+
+ (*sem) = sem_alloc(value, semid, pshared);
+ if ((*sem) == NULL) {
+ if (pshared != 0)
+ ksem_destroy(semid);
+ return (-1);
+ }
+ return (0);
+}
+
+int
+_sem_destroy(sem_t *sem)
+{
+ int retval;
+
+ if (sem_check_validity(sem) != 0)
+ return (-1);
+
+ /*
+ * If this is a system semaphore let the kernel track it otherwise
+ * make sure there are no waiters.
+ */
+ if ((*sem)->syssem != 0)
+ retval = ksem_destroy((*sem)->semid);
+ else {
+ retval = 0;
+ (*sem)->magic = 0;
+ }
+ if (retval == 0)
+ free(*sem);
+ return (retval);
+}
+
+int
+_sem_getvalue(sem_t * __restrict sem, int * __restrict sval)
+{
+ int retval;
+
+ if (sem_check_validity(sem) != 0)
+ return (-1);
+
+ if ((*sem)->syssem != 0)
+ retval = ksem_getvalue((*sem)->semid, sval);
+ else {
+ *sval = (int)(*sem)->count;
+ retval = 0;
+ }
+ return (retval);
+}
+
+int
+_sem_trywait(sem_t *sem)
+{
+ int val;
+
+ if (sem_check_validity(sem) != 0)
+ return (-1);
+
+ if ((*sem)->syssem != 0)
+ return (ksem_trywait((*sem)->semid));
+
+ while ((val = (*sem)->count) > 0) {
+ if (atomic_cmpset_acq_int(&(*sem)->count, val, val - 1))
+ return (0);
+ }
+ errno = EAGAIN;
+ return (-1);
+}
+
+int
+_sem_wait(sem_t *sem)
+{
+ struct pthread *curthread;
+ int val, oldcancel, retval;
+
+ if (sem_check_validity(sem) != 0)
+ return (-1);
+
+ curthread = _get_curthread();
+ if ((*sem)->syssem != 0) {
+ oldcancel = _thr_cancel_enter(curthread);
+ retval = ksem_wait((*sem)->semid);
+ _thr_cancel_leave(curthread, oldcancel);
+ return (retval);
+ }
+
+ _pthread_testcancel();
+ do {
+ while ((val = (*sem)->count) > 0) {
+ if (atomic_cmpset_acq_int(&(*sem)->count, val, val - 1))
+ return (0);
+ }
+ oldcancel = _thr_cancel_enter(curthread);
+ retval = _thr_umtx_wait((umtx_t *)&(*sem)->count, 0, NULL);
+ _thr_cancel_leave(curthread, oldcancel);
+ } while (retval == 0);
+ errno = retval;
+ return (-1);
+}
+
+int
+_sem_timedwait(sem_t * __restrict sem,
+ const struct timespec * __restrict abstime)
+{
+ struct timespec ts, ts2;
+ struct pthread *curthread;
+ int val, oldcancel, retval;
+
+ if (sem_check_validity(sem) != 0)
+ return (-1);
+
+ curthread = _get_curthread();
+ if ((*sem)->syssem != 0) {
+ oldcancel = _thr_cancel_enter(curthread);
+ retval = ksem_timedwait((*sem)->semid, abstime);
+ _thr_cancel_leave(curthread, oldcancel);
+ return (retval);
+ }
+
+ /*
+ * The timeout argument is only supposed to
+ * be checked if the thread would have blocked.
+ */
+ _pthread_testcancel();
+ do {
+ while ((val = (*sem)->count) > 0) {
+ if (atomic_cmpset_acq_int(&(*sem)->count, val, val - 1))
+ return (0);
+ }
+ if (abstime == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+ clock_gettime(CLOCK_REALTIME, &ts);
+ TIMESPEC_SUB(&ts2, abstime, &ts);
+ oldcancel = _thr_cancel_enter(curthread);
+ retval = _thr_umtx_wait((umtx_t *)&(*sem)->count, 0, &ts2);
+ _thr_cancel_leave(curthread, oldcancel);
+ } while (retval == 0);
+ errno = retval;
+ return (-1);
+}
+
+int
+_sem_post(sem_t *sem)
+{
+ int val, retval;
+
+ if (sem_check_validity(sem) != 0)
+ return (-1);
+
+ if ((*sem)->syssem != 0)
+ return (ksem_post((*sem)->semid));
+
+ /*
+ * sem_post() is required to be safe to call from within
+ * signal handlers, these code should work as that.
+ */
+ do {
+ val = (*sem)->count;
+ } while (!atomic_cmpset_acq_int(&(*sem)->count, val, val + 1));
+ retval = _thr_umtx_wake((umtx_t *)&(*sem)->count, val + 1);
+ if (retval > 0)
+ retval = 0;
+ return (retval);
+}
diff --git a/lib/libthr/thread/thr_seterrno.c b/lib/libthr/thread/thr_seterrno.c
new file mode 100644
index 0000000..f481799
--- /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.
+ */
+#undef errno
+extern int errno;
+
+void
+_thread_seterrno(pthread_t thread, int error)
+{
+ /* Check for the initial thread: */
+ if (thread == NULL || thread == _thr_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..bb9a9bf
--- /dev/null
+++ b/lib/libthr/thread/thr_setprio.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 "namespace.h"
+#include <pthread.h>
+#include "un-namespace.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..eba5017
--- /dev/null
+++ b/lib/libthr/thread/thr_setschedparam.c
@@ -0,0 +1,95 @@
+/*
+ * 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 "namespace.h"
+#include <sys/param.h>
+#include <errno.h>
+#include <pthread.h>
+#include "un-namespace.h"
+
+#include "thr_private.h"
+
+__weak_reference(_pthread_setschedparam, pthread_setschedparam);
+
+/*
+ * Set a thread's scheduling parameters, this should be done
+ * in kernel, doing it in userland is no-op.
+ */
+int
+_pthread_setschedparam(pthread_t pthread, int policy,
+ const struct sched_param *param)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret = 0;
+
+ if ((param == NULL) || (policy < SCHED_FIFO) || (policy > SCHED_RR)) {
+ ret = EINVAL;
+ } else if (param->sched_priority < _thr_priorities[policy-1].pri_min ||
+ param->sched_priority > _thr_priorities[policy-1].pri_max) {
+ ret = ENOTSUP;
+ } else if ((ret = _thr_ref_add(curthread, pthread, /*include dead*/0))
+ == 0) {
+ /*
+ * Lock the threads scheduling queue while we change
+ * its priority:
+ */
+ THR_THREAD_LOCK(curthread, pthread);
+ if (pthread->state == PS_DEAD) {
+ THR_THREAD_UNLOCK(curthread, pthread);
+ _thr_ref_delete(curthread, pthread);
+ return (ESRCH);
+ }
+
+ /* Set the scheduling policy: */
+ pthread->attr.sched_policy = policy;
+
+ if (param->sched_priority == pthread->base_priority)
+ /*
+ * There is nothing to do; unlock the threads
+ * scheduling queue.
+ */
+ THR_THREAD_UNLOCK(curthread, pthread);
+ else {
+ pthread->base_priority = param->sched_priority;
+
+ /* Recalculate the active priority: */
+ pthread->active_priority = MAX(pthread->base_priority,
+ pthread->inherited_priority);
+
+ THR_THREAD_UNLOCK(curthread, pthread);
+ }
+ _thr_ref_delete(curthread, pthread);
+ }
+ return (ret);
+}
diff --git a/lib/libthr/thread/thr_sig.c b/lib/libthr/thread/thr_sig.c
new file mode 100644
index 0000000..865fb72
--- /dev/null
+++ b/lib/libthr/thread/thr_sig.c
@@ -0,0 +1,284 @@
+/*
+ * Copyright (c) 2005, David Xu <davidxu@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 "namespace.h"
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/signalvar.h>
+#include <signal.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <pthread.h>
+#include "un-namespace.h"
+
+#include "thr_private.h"
+
+/* #define DEBUG_SIGNAL */
+#ifdef DEBUG_SIGNAL
+#define DBG_MSG stdout_debug
+#else
+#define DBG_MSG(x...)
+#endif
+
+int __sigtimedwait(const sigset_t *set, siginfo_t *info,
+ const struct timespec * timeout);
+int __sigwaitinfo(const sigset_t *set, siginfo_t *info);
+int __sigwait(const sigset_t *set, int *sig);
+
+static void
+sigcancel_handler(int sig __unused,
+ siginfo_t *info __unused, ucontext_t *ucp __unused)
+{
+ struct pthread *curthread = _get_curthread();
+
+ _thr_ast(curthread);
+}
+
+void
+_thr_ast(struct pthread *curthread)
+{
+ if (!THR_IN_CRITICAL(curthread)) {
+ if (__predict_false(
+ SHOULD_ASYNC_CANCEL(curthread->cancelflags)))
+ _pthread_testcancel();
+ if (__predict_false((curthread->flags &
+ (THR_FLAGS_NEED_SUSPEND | THR_FLAGS_SUSPENDED))
+ == THR_FLAGS_NEED_SUSPEND))
+ _thr_suspend_check(curthread);
+ }
+}
+
+void
+_thr_suspend_check(struct pthread *curthread)
+{
+ umtx_t cycle;
+ int err;
+
+ err = errno;
+ /*
+ * Blocks SIGCANCEL which other threads must send.
+ */
+ _thr_signal_block(curthread);
+
+ /*
+ * Increase critical_count, here we don't use THR_LOCK/UNLOCK
+ * because we are leaf code, we don't want to recursively call
+ * ourself.
+ */
+ curthread->critical_count++;
+ THR_UMTX_LOCK(curthread, &(curthread)->lock);
+ while ((curthread->flags & (THR_FLAGS_NEED_SUSPEND |
+ THR_FLAGS_SUSPENDED)) == THR_FLAGS_NEED_SUSPEND) {
+ curthread->cycle++;
+ cycle = curthread->cycle;
+
+ /* Wake the thread suspending us. */
+ _thr_umtx_wake(&curthread->cycle, INT_MAX);
+
+ /*
+ * if we are from pthread_exit, we don't want to
+ * suspend, just go and die.
+ */
+ if (curthread->state == PS_DEAD)
+ break;
+ curthread->flags |= THR_FLAGS_SUSPENDED;
+ THR_UMTX_UNLOCK(curthread, &(curthread)->lock);
+ _thr_umtx_wait(&curthread->cycle, cycle, NULL);
+ THR_UMTX_LOCK(curthread, &(curthread)->lock);
+ curthread->flags &= ~THR_FLAGS_SUSPENDED;
+ }
+ THR_UMTX_UNLOCK(curthread, &(curthread)->lock);
+ curthread->critical_count--;
+
+ /*
+ * Unblocks SIGCANCEL, it is possible a new SIGCANCEL is ready and
+ * a new signal frame will nest us, this seems a problem because
+ * stack will grow and overflow, but because kernel will automatically
+ * mask the SIGCANCEL when delivering the signal, so we at most only
+ * have one nesting signal frame, this should be fine.
+ */
+ _thr_signal_unblock(curthread);
+ errno = err;
+}
+
+void
+_thr_signal_init(void)
+{
+ struct sigaction act;
+
+ /* Install cancel handler. */
+ SIGEMPTYSET(act.sa_mask);
+ act.sa_flags = SA_SIGINFO | SA_RESTART;
+ act.sa_sigaction = (__siginfohandler_t *)&sigcancel_handler;
+ __sys_sigaction(SIGCANCEL, &act, NULL);
+}
+
+void
+_thr_signal_deinit(void)
+{
+}
+
+__weak_reference(_sigaction, sigaction);
+
+int
+_sigaction(int sig, const struct sigaction * act, struct sigaction * oact)
+{
+ /* Check if the signal number is out of range: */
+ if (sig < 1 || sig > _SIG_MAXSIG || sig == SIGCANCEL) {
+ /* Return an invalid argument: */
+ errno = EINVAL;
+ return (-1);
+ }
+
+ return __sys_sigaction(sig, act, oact);
+}
+
+__weak_reference(_sigprocmask, sigprocmask);
+
+int
+_sigprocmask(int how, const sigset_t *set, sigset_t *oset)
+{
+ const sigset_t *p = set;
+ sigset_t newset;
+
+ if (how != SIG_UNBLOCK) {
+ if (set != NULL) {
+ newset = *set;
+ SIGDELSET(newset, SIGCANCEL);
+ p = &newset;
+ }
+ }
+ return (__sys_sigprocmask(how, p, oset));
+}
+
+__weak_reference(_pthread_sigmask, pthread_sigmask);
+
+int
+_pthread_sigmask(int how, const sigset_t *set, sigset_t *oset)
+{
+ if (_sigprocmask(how, set, oset))
+ return (errno);
+ return (0);
+}
+
+__weak_reference(_sigsuspend, sigsuspend);
+
+int
+_sigsuspend(const sigset_t * set)
+{
+ struct pthread *curthread = _get_curthread();
+ sigset_t newset;
+ const sigset_t *pset;
+ int oldcancel;
+ int ret;
+
+ if (SIGISMEMBER(*set, SIGCANCEL)) {
+ newset = *set;
+ SIGDELSET(newset, SIGCANCEL);
+ pset = &newset;
+ } else
+ pset = set;
+
+ oldcancel = _thr_cancel_enter(curthread);
+ ret = __sys_sigsuspend(pset);
+ _thr_cancel_leave(curthread, oldcancel);
+
+ return (ret);
+}
+
+__weak_reference(__sigwait, sigwait);
+__weak_reference(__sigtimedwait, sigtimedwait);
+__weak_reference(__sigwaitinfo, sigwaitinfo);
+
+int
+__sigtimedwait(const sigset_t *set, siginfo_t *info,
+ const struct timespec * timeout)
+{
+ struct pthread *curthread = _get_curthread();
+ sigset_t newset;
+ const sigset_t *pset;
+ int oldcancel;
+ int ret;
+
+ if (SIGISMEMBER(*set, SIGCANCEL)) {
+ newset = *set;
+ SIGDELSET(newset, SIGCANCEL);
+ pset = &newset;
+ } else
+ pset = set;
+ oldcancel = _thr_cancel_enter(curthread);
+ ret = __sys_sigtimedwait(pset, info, timeout);
+ _thr_cancel_leave(curthread, oldcancel);
+ return (ret);
+}
+
+int
+__sigwaitinfo(const sigset_t *set, siginfo_t *info)
+{
+ struct pthread *curthread = _get_curthread();
+ sigset_t newset;
+ const sigset_t *pset;
+ int oldcancel;
+ int ret;
+
+ if (SIGISMEMBER(*set, SIGCANCEL)) {
+ newset = *set;
+ SIGDELSET(newset, SIGCANCEL);
+ pset = &newset;
+ } else
+ pset = set;
+
+ oldcancel = _thr_cancel_enter(curthread);
+ ret = __sys_sigwaitinfo(pset, info);
+ _thr_cancel_leave(curthread, oldcancel);
+ return (ret);
+}
+
+int
+__sigwait(const sigset_t *set, int *sig)
+{
+ struct pthread *curthread = _get_curthread();
+ sigset_t newset;
+ const sigset_t *pset;
+ int oldcancel;
+ int ret;
+
+ if (SIGISMEMBER(*set, SIGCANCEL)) {
+ newset = *set;
+ SIGDELSET(newset, SIGCANCEL);
+ pset = &newset;
+ } else
+ pset = set;
+
+ oldcancel = _thr_cancel_enter(curthread);
+ ret = __sys_sigwait(pset, sig);
+ _thr_cancel_leave(curthread, oldcancel);
+ return (ret);
+}
diff --git a/lib/libthr/thread/thr_sigmask.c b/lib/libthr/thread/thr_sigmask.c
new file mode 100644
index 0000000..2024cc0
--- /dev/null
+++ b/lib/libthr/thread/thr_sigmask.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 1997 John Birrell <jb@cimlogic.com.au>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <errno.h>
+#include <signal.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+__weak_reference(_pthread_sigmask, pthread_sigmask);
+
+extern int
+_sigprocmask(int how, const sigset_t *set, sigset_t *oset);
+
+int
+_pthread_sigmask(int how, const sigset_t *set, sigset_t *oset)
+{
+ /* use our overridden verion of _sigprocmask */
+ if (_sigprocmask(how, set, oset))
+ return (errno);
+ return (0);
+}
diff --git a/lib/libthr/thread/thr_single_np.c b/lib/libthr/thread/thr_single_np.c
new file mode 100644
index 0000000..c74fc55
--- /dev/null
+++ b/lib/libthr/thread/thr_single_np.c
@@ -0,0 +1,52 @@
+/*
+ * 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 "namespace.h"
+#include <pthread.h>
+#include <pthread_np.h>
+#include "un-namespace.h"
+
+__weak_reference(_pthread_single_np, pthread_single_np);
+
+int _pthread_single_np()
+{
+
+ /* Enter single-threaded (non-POSIX) scheduling mode: */
+ _pthread_suspend_all_np();
+ /*
+ * XXX - Do we want to do this?
+ * __is_threaded = 0;
+ */
+ return (0);
+}
diff --git a/lib/libthr/thread/thr_spec.c b/lib/libthr/thread/thr_spec.c
new file mode 100644
index 0000000..cd4d49f
--- /dev/null
+++ b/lib/libthr/thread/thr_spec.c
@@ -0,0 +1,230 @@
+/*
+ * 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 "namespace.h"
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <pthread.h>
+#include "un-namespace.h"
+
+#include "thr_private.h"
+
+/* Static variables: */
+struct pthread_key _thread_keytable[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 *))
+{
+ struct pthread *curthread = _get_curthread();
+ int i;
+
+ /* Lock the key table: */
+ THR_LOCK_ACQUIRE(curthread, &_keytable_lock);
+ for (i = 0; i < PTHREAD_KEYS_MAX; i++) {
+
+ if (_thread_keytable[i].allocated == 0) {
+ _thread_keytable[i].allocated = 1;
+ _thread_keytable[i].destructor = destructor;
+ _thread_keytable[i].seqno++;
+
+ /* Unlock the key table: */
+ THR_LOCK_RELEASE(curthread, &_keytable_lock);
+ *key = i;
+ return (0);
+ }
+
+ }
+ /* Unlock the key table: */
+ THR_LOCK_RELEASE(curthread, &_keytable_lock);
+ return (EAGAIN);
+}
+
+int
+_pthread_key_delete(pthread_key_t key)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret = 0;
+
+ if ((unsigned int)key < PTHREAD_KEYS_MAX) {
+ /* Lock the key table: */
+ THR_LOCK_ACQUIRE(curthread, &_keytable_lock);
+
+ if (_thread_keytable[key].allocated)
+ _thread_keytable[key].allocated = 0;
+ else
+ ret = EINVAL;
+
+ /* Unlock the key table: */
+ THR_LOCK_RELEASE(curthread, &_keytable_lock);
+ } else
+ ret = EINVAL;
+ return (ret);
+}
+
+void
+_thread_cleanupspecific(void)
+{
+ struct pthread *curthread = _get_curthread();
+ void (*destructor)( void *);
+ const void *data = NULL;
+ int key;
+ int i;
+
+ if (curthread->specific == NULL)
+ return;
+
+ /* Lock the key table: */
+ THR_LOCK_ACQUIRE(curthread, &_keytable_lock);
+ for (i = 0; (i < PTHREAD_DESTRUCTOR_ITERATIONS) &&
+ (curthread->specific_data_count > 0); i++) {
+ for (key = 0; (key < PTHREAD_KEYS_MAX) &&
+ (curthread->specific_data_count > 0); key++) {
+ destructor = NULL;
+
+ if (_thread_keytable[key].allocated &&
+ (curthread->specific[key].data != NULL)) {
+ if (curthread->specific[key].seqno ==
+ _thread_keytable[key].seqno) {
+ data = curthread->specific[key].data;
+ destructor = _thread_keytable[key].destructor;
+ }
+ curthread->specific[key].data = NULL;
+ curthread->specific_data_count--;
+ }
+
+ /*
+ * If there is a destructore, call it
+ * with the key table entry unlocked:
+ */
+ if (destructor != NULL) {
+ /*
+ * Don't hold the lock while calling the
+ * destructor:
+ */
+ THR_LOCK_RELEASE(curthread, &_keytable_lock);
+ destructor(__DECONST(void *, data));
+ THR_LOCK_ACQUIRE(curthread, &_keytable_lock);
+ }
+ }
+ }
+ THR_LOCK_RELEASE(curthread, &_keytable_lock);
+ free(curthread->specific);
+ curthread->specific = NULL;
+ if (curthread->specific_data_count > 0)
+ stderr_debug("Thread %p has exited with leftover "
+ "thread-specific data after %d destructor iterations\n",
+ curthread, PTHREAD_DESTRUCTOR_ITERATIONS);
+}
+
+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 ((unsigned int)key < PTHREAD_KEYS_MAX) {
+ if (_thread_keytable[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 =
+ _thread_keytable[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;
+ const void *data;
+
+ /* Point to the running thread: */
+ pthread = _get_curthread();
+
+ /* Check if there is specific data: */
+ if (pthread->specific != NULL && (unsigned int)key < PTHREAD_KEYS_MAX) {
+ /* Check if this key has been used before: */
+ if (_thread_keytable[key].allocated &&
+ (pthread->specific[key].seqno == _thread_keytable[key].seqno)) {
+ /* Return the value: */
+ data = 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 (__DECONST(void *, data));
+}
diff --git a/lib/libthr/thread/thr_spinlock.c b/lib/libthr/thread/thr_spinlock.c
new file mode 100644
index 0000000..b9d2279
--- /dev/null
+++ b/lib/libthr/thread/thr_spinlock.c
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 1997 John Birrell <jb@cimlogic.com.au>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ *
+ */
+
+#include <sys/types.h>
+#include <pthread.h>
+#include <libc_private.h>
+#include <spinlock.h>
+
+#include "thr_private.h"
+
+#define MAX_SPINLOCKS 72
+
+/*
+ * These data structures are used to trace all spinlocks
+ * in libc.
+ */
+struct spinlock_extra {
+ spinlock_t *owner;
+};
+
+static umtx_t spinlock_static_lock;
+static struct spinlock_extra extra[MAX_SPINLOCKS];
+static int spinlock_count;
+static int initialized;
+
+static void init_spinlock(spinlock_t *lck);
+
+/*
+ * These are for compatability only. Spinlocks of this type
+ * are deprecated.
+ */
+
+void
+_spinunlock(spinlock_t *lck)
+{
+ THR_UMTX_UNLOCK(_get_curthread(), (volatile umtx_t *)&lck->access_lock);
+}
+
+void
+_spinlock(spinlock_t *lck)
+{
+ if (!__isthreaded)
+ PANIC("Spinlock called when not threaded.");
+ if (!initialized)
+ PANIC("Spinlocks not initialized.");
+ if (lck->fname == NULL)
+ init_spinlock(lck);
+ THR_UMTX_LOCK(_get_curthread(), (volatile umtx_t *)&lck->access_lock);
+}
+
+void
+_spinlock_debug(spinlock_t *lck, char *fname __unused, int lineno __unused)
+{
+ _spinlock(lck);
+}
+
+static void
+init_spinlock(spinlock_t *lck)
+{
+ static int count = 0;
+
+ THR_UMTX_LOCK(_get_curthread(), &spinlock_static_lock);
+ if ((lck->fname == NULL) && (spinlock_count < MAX_SPINLOCKS)) {
+ lck->fname = (char *)&extra[spinlock_count];
+ extra[spinlock_count].owner = lck;
+ spinlock_count++;
+ }
+ THR_UMTX_UNLOCK(_get_curthread(), &spinlock_static_lock);
+ if (lck->fname == NULL && ++count < 5)
+ stderr_debug("Warning: exceeded max spinlocks");
+}
+
+void
+_thr_spinlock_init(void)
+{
+ int i;
+
+ _thr_umtx_init(&spinlock_static_lock);
+ if (initialized != 0) {
+ /*
+ * called after fork() to reset state of libc spin locks,
+ * it is not quite right since libc may be in inconsistent
+ * state, resetting the locks to allow current thread to be
+ * able to hold them may not help things too much, but
+ * anyway, we do our best.
+ * it is better to do pthread_atfork in libc.
+ */
+ for (i = 0; i < spinlock_count; i++)
+ _thr_umtx_init((volatile umtx_t *)
+ &extra[i].owner->access_lock);
+ } else {
+ initialized = 1;
+ }
+}
diff --git a/lib/libthr/thread/thr_stack.c b/lib/libthr/thread/thr_stack.c
new file mode 100644
index 0000000..9376086
--- /dev/null
+++ b/lib/libthr/thread/thr_stack.c
@@ -0,0 +1,256 @@
+/*
+ * 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/queue.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 mapped with PROT_NONE) 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 - _thr_stack_default | top of 2nd thread stack
+ * | |
+ * | |
+ * | |
+ * | |
+ * | stack 2 |
+ * +-----------------------------------+ <-- start of 2nd thread stack
+ * | |
+ * | Red Zone | red zone for 1st thread
+ * | |
+ * +-----------------------------------+
+ * | stack 1 - _thr_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 - _thr_stack_initial | top of main thread stack
+ * | | ^
+ * | | |
+ * | | |
+ * | | | stack growth
+ * | |
+ * +-----------------------------------+ <-- start of main thread stack
+ * (USRSTACK)
+ * high memory
+ *
+ */
+static char *last_stack = NULL;
+
+/*
+ * Round size up to the nearest multiple of
+ * _thr_page_size.
+ */
+static inline size_t
+round_up(size_t size)
+{
+ if (size % _thr_page_size != 0)
+ size = ((size / _thr_page_size) + 1) *
+ _thr_page_size;
+ return size;
+}
+
+int
+_thr_stack_alloc(struct pthread_attr *attr)
+{
+ struct pthread *curthread = _get_curthread();
+ struct stack *spare_stack;
+ size_t stacksize;
+ size_t guardsize;
+ char *stackaddr;
+
+ /*
+ * Round up stack size to nearest multiple of _thr_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.
+ */
+ stacksize = round_up(attr->stacksize_attr);
+ guardsize = round_up(attr->guardsize_attr);
+
+ attr->stackaddr_attr = NULL;
+ attr->flags &= ~THR_STACK_USER;
+
+ /*
+ * Use the garbage collector lock for synchronization of the
+ * spare stack lists and allocations from usrstack.
+ */
+ THREAD_LIST_LOCK(curthread);
+ /*
+ * If the stack and guard sizes are default, try to allocate a stack
+ * from the default-size stack cache:
+ */
+ if ((stacksize == THR_STACK_DEFAULT) &&
+ (guardsize == _thr_guard_default)) {
+ if ((spare_stack = LIST_FIRST(&dstackq)) != NULL) {
+ /* Use the spare stack. */
+ LIST_REMOVE(spare_stack, qe);
+ attr->stackaddr_attr = spare_stack->stackaddr;
+ }
+ }
+ /*
+ * 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 {
+ LIST_FOREACH(spare_stack, &mstackq, qe) {
+ if (spare_stack->stacksize == stacksize &&
+ spare_stack->guardsize == guardsize) {
+ LIST_REMOVE(spare_stack, qe);
+ attr->stackaddr_attr = spare_stack->stackaddr;
+ break;
+ }
+ }
+ }
+ if (attr->stackaddr_attr != NULL) {
+ /* A cached stack was found. Release the lock. */
+ THREAD_LIST_UNLOCK(curthread);
+ }
+ else {
+ /* Allocate a stack from usrstack. */
+ if (last_stack == NULL)
+ last_stack = _usrstack - _thr_stack_initial -
+ _thr_guard_default;
+
+ /* Allocate a new stack. */
+ stackaddr = last_stack - stacksize - guardsize;
+
+ /*
+ * 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 -= (stacksize + guardsize);
+
+ /* Release the lock before mmap'ing it. */
+ THREAD_LIST_UNLOCK(curthread);
+
+ /* Map the stack and guard page together, and split guard
+ page from allocated space: */
+ if ((stackaddr = mmap(stackaddr, stacksize+guardsize,
+ PROT_READ | PROT_WRITE, MAP_STACK,
+ -1, 0)) != MAP_FAILED &&
+ (guardsize == 0 ||
+ mprotect(stackaddr, guardsize, PROT_NONE) == 0)) {
+ stackaddr += guardsize;
+ } else {
+ if (stackaddr != MAP_FAILED)
+ munmap(stackaddr, stacksize + guardsize);
+ stackaddr = NULL;
+ }
+ attr->stackaddr_attr = stackaddr;
+ }
+ if (attr->stackaddr_attr != NULL)
+ return (0);
+ else
+ return (-1);
+}
+
+/* This function must be called with _thread_list_lock held. */
+void
+_thr_stack_free(struct pthread_attr *attr)
+{
+ struct stack *spare_stack;
+
+ if ((attr != NULL) && ((attr->flags & THR_STACK_USER) == 0)
+ && (attr->stackaddr_attr != NULL)) {
+ spare_stack = (struct stack *)
+ ((char *)attr->stackaddr_attr +
+ attr->stacksize_attr - sizeof(struct stack));
+ spare_stack->stacksize = round_up(attr->stacksize_attr);
+ spare_stack->guardsize = round_up(attr->guardsize_attr);
+ spare_stack->stackaddr = attr->stackaddr_attr;
+
+ if (spare_stack->stacksize == THR_STACK_DEFAULT &&
+ spare_stack->guardsize == _thr_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);
+ }
+ attr->stackaddr_attr = NULL;
+ }
+}
diff --git a/lib/libthr/thread/thr_suspend_np.c b/lib/libthr/thread/thr_suspend_np.c
new file mode 100644
index 0000000..ec34029
--- /dev/null
+++ b/lib/libthr/thread/thr_suspend_np.c
@@ -0,0 +1,145 @@
+/*
+ * 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 "namespace.h"
+#include <errno.h>
+#include <pthread.h>
+#include <pthread_np.h>
+#include "un-namespace.h"
+
+#include "thr_private.h"
+
+static int suspend_common(struct pthread *, struct pthread *,
+ int);
+
+__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)
+{
+ struct pthread *curthread = _get_curthread();
+ int ret;
+
+ /* Suspending the current thread doesn't make sense. */
+ if (thread == _get_curthread())
+ ret = EDEADLK;
+
+ /* Add a reference to the thread: */
+ else if ((ret = _thr_ref_add(curthread, thread, /*include dead*/0))
+ == 0) {
+ /* Lock the threads scheduling queue: */
+ THR_THREAD_LOCK(curthread, thread);
+ suspend_common(curthread, thread, 1);
+ /* Unlock the threads scheduling queue: */
+ THR_THREAD_UNLOCK(curthread, thread);
+
+ /* Don't forget to remove the reference: */
+ _thr_ref_delete(curthread, thread);
+ }
+ return (ret);
+}
+
+void
+_pthread_suspend_all_np(void)
+{
+ struct pthread *curthread = _get_curthread();
+ struct pthread *thread;
+ int ret;
+
+ THREAD_LIST_LOCK(curthread);
+
+ TAILQ_FOREACH(thread, &_thread_list, tle) {
+ if (thread != curthread) {
+ THR_THREAD_LOCK(curthread, thread);
+ if (thread->state != PS_DEAD &&
+ !(thread->flags & THR_FLAGS_SUSPENDED))
+ thread->flags |= THR_FLAGS_NEED_SUSPEND;
+ THR_THREAD_UNLOCK(curthread, thread);
+ }
+ }
+ thr_kill(-1, SIGCANCEL);
+
+restart:
+ TAILQ_FOREACH(thread, &_thread_list, tle) {
+ if (thread != curthread) {
+ /* First try to suspend the thread without waiting */
+ THR_THREAD_LOCK(curthread, thread);
+ ret = suspend_common(curthread, thread, 0);
+ if (ret == 0) {
+ /* Can not suspend, try to wait */
+ thread->refcount++;
+ THREAD_LIST_UNLOCK(curthread);
+ suspend_common(curthread, thread, 1);
+ THR_THREAD_UNLOCK(curthread, thread);
+ THREAD_LIST_LOCK(curthread);
+ _thr_ref_delete_unlocked(curthread, thread);
+ /*
+ * Because we were blocked, things may have
+ * been changed, we have to restart the
+ * process.
+ */
+ goto restart;
+ }
+ THR_THREAD_UNLOCK(curthread, thread);
+ }
+ }
+
+ THREAD_LIST_UNLOCK(curthread);
+}
+
+static int
+suspend_common(struct pthread *curthread, struct pthread *thread,
+ int waitok)
+{
+ umtx_t tmp;
+
+ while (thread->state != PS_DEAD &&
+ !(thread->flags & THR_FLAGS_SUSPENDED)) {
+ thread->flags |= THR_FLAGS_NEED_SUSPEND;
+ tmp = thread->cycle;
+ THR_THREAD_UNLOCK(curthread, thread);
+ _thr_send_sig(thread, SIGCANCEL);
+ if (waitok) {
+ _thr_umtx_wait(&thread->cycle, tmp, NULL);
+ THR_THREAD_LOCK(curthread, thread);
+ } else {
+ THR_THREAD_LOCK(curthread, thread);
+ return (0);
+ }
+ }
+
+ return (1);
+}
diff --git a/lib/libthr/thread/thr_switch_np.c b/lib/libthr/thread/thr_switch_np.c
new file mode 100644
index 0000000..f6ffb07
--- /dev/null
+++ b/lib/libthr/thread/thr_switch_np.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 1998 Daniel Eischen <eischen@vigrid.com>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Daniel Eischen.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY DANIEL EISCHEN AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include "namespace.h"
+#include <errno.h>
+#include <pthread.h>
+#include <pthread_np.h>
+#include "un-namespace.h"
+
+#include "thr_private.h"
+
+
+__weak_reference(_pthread_switch_add_np, pthread_switch_add_np);
+__weak_reference(_pthread_switch_delete_np, pthread_switch_delete_np);
+
+int
+_pthread_switch_add_np(pthread_switch_routine_t routine __unused)
+{
+ return (ENOTSUP);
+}
+
+int
+_pthread_switch_delete_np(pthread_switch_routine_t routine __unused)
+{
+ return (ENOTSUP);
+}
diff --git a/lib/libthr/thread/thr_symbols.c b/lib/libthr/thread/thr_symbols.c
new file mode 100644
index 0000000..ca6606a
--- /dev/null
+++ b/lib/libthr/thread/thr_symbols.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2004 David Xu <davidxu@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 <sys/types.h>
+#include <stddef.h>
+#include <pthread.h>
+#include <rtld.h>
+
+#include "thr_private.h"
+
+/* A collection of symbols needed by debugger */
+
+/* int _libthr_debug */
+int _thread_off_tcb = offsetof(struct pthread, tcb);
+int _thread_off_tid = offsetof(struct pthread, tid);
+int _thread_off_next = offsetof(struct pthread, tle.tqe_next);
+int _thread_off_attr_flags = offsetof(struct pthread, attr.flags);
+int _thread_off_linkmap = offsetof(Obj_Entry, linkmap);
+int _thread_off_tlsindex = offsetof(Obj_Entry, tlsindex);
+int _thread_off_report_events = offsetof(struct pthread, report_events);
+int _thread_off_event_mask = offsetof(struct pthread, event_mask);
+int _thread_off_event_buf = offsetof(struct pthread, event_buf);
+int _thread_size_key = sizeof(struct pthread_key);
+int _thread_off_key_allocated = offsetof(struct pthread_key, allocated);
+int _thread_off_key_destructor = offsetof(struct pthread_key, destructor);
+int _thread_max_keys = PTHREAD_KEYS_MAX;
+int _thread_off_dtv = DTV_OFFSET;
+int _thread_off_state = offsetof(struct pthread, state);
+int _thread_state_running = PS_RUNNING;
+int _thread_state_zoombie = PS_DEAD;
diff --git a/lib/libthr/thread/thr_syscalls.c b/lib/libthr/thread/thr_syscalls.c
new file mode 100644
index 0000000..a36849a
--- /dev/null
+++ b/lib/libthr/thread/thr_syscalls.c
@@ -0,0 +1,675 @@
+/*
+ * Copyright (C) 2005 David Xu <davidxu@freebsd.org>.
+ * Copyright (c) 2003 Daniel Eischen <deischen@freebsd.org>.
+ * 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$
+ */
+
+/*
+ * 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 "namespace.h"
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/param.h>
+#include <sys/select.h>
+#include <sys/signalvar.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/time.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 <signal.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+#include <pthread.h>
+#include "un-namespace.h"
+
+#include "thr_private.h"
+
+extern int __creat(const char *, mode_t);
+extern int __pause(void);
+extern int __pselect(int, fd_set *, fd_set *, fd_set *,
+ const struct timespec *, const sigset_t *);
+extern unsigned __sleep(unsigned int);
+extern int __system(const char *);
+extern int __tcdrain(int);
+extern int __usleep(useconds_t);
+extern pid_t __wait(int *);
+extern pid_t __waitpid(pid_t, int *, int);
+extern int __sys_aio_suspend(const struct aiocb * const[], int,
+ const struct timespec *);
+extern int __sys_accept(int, struct sockaddr *, socklen_t *);
+extern int __sys_connect(int, const struct sockaddr *, socklen_t);
+extern int __sys_fsync(int);
+extern int __sys_msync(void *, size_t, int);
+extern int __sys_poll(struct pollfd *, unsigned, int);
+extern ssize_t __sys_recv(int, void *, size_t, int);
+extern ssize_t __sys_recvfrom(int, void *, size_t, int, struct sockaddr *, socklen_t *);
+extern ssize_t __sys_recvmsg(int, struct msghdr *, int);
+extern int __sys_select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
+extern int __sys_sendfile(int, int, off_t, size_t, struct sf_hdtr *,
+ off_t *, int);
+extern ssize_t __sys_sendmsg(int, const struct msghdr *, int);
+extern ssize_t __sys_sendto(int, const void *,size_t, int, const struct sockaddr *, socklen_t);
+extern ssize_t __sys_readv(int, const struct iovec *, int);
+extern pid_t __sys_wait4(pid_t, int *, int, struct rusage *);
+extern ssize_t __sys_writev(int, const struct iovec *, int);
+
+int ___creat(const char *, mode_t);
+int __accept(int, struct sockaddr *, socklen_t *);
+int __close(int);
+int __connect(int, const struct sockaddr *, socklen_t);
+int __fcntl(int, int,...);
+int __fsync(int);
+int __msync(void *, size_t, int);
+int __nanosleep(const struct timespec *, struct timespec *);
+int __open(const char *, int,...);
+int __poll(struct pollfd *, unsigned int, int);
+ssize_t __read(int, void *buf, size_t);
+ssize_t __readv(int, const struct iovec *, int);
+ssize_t __recvfrom(int, void *, size_t, int f, struct sockaddr *, socklen_t *);
+ssize_t __recvmsg(int, struct msghdr *, int);
+int __select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
+ssize_t __sendmsg(int, const struct msghdr *, int);
+ssize_t __sendto(int, const void *, size_t, int,
+ const struct sockaddr *, socklen_t);
+pid_t __wait4(pid_t, int *, int, struct rusage *);
+ssize_t __write(int, const void *, size_t);
+ssize_t __writev(int, const struct iovec *, int);
+int _aio_suspend(const struct aiocb * const iocbs[], int,
+ const struct timespec *);
+int _pause(void);
+int _pselect(int, fd_set *, fd_set *, fd_set *,
+ const struct timespec *, const sigset_t *);
+int _raise(int);
+unsigned _sleep(unsigned);
+int _system(const char *);
+int _tcdrain(int);
+int _vfork(void);
+pid_t _wait(int *);
+
+
+__weak_reference(__accept, accept);
+
+int
+__accept(int s, struct sockaddr *addr, socklen_t *addrlen)
+{
+ struct pthread *curthread;
+ int oldcancel;
+ int ret;
+
+ curthread = _get_curthread();
+ oldcancel = _thr_cancel_enter(curthread);
+ ret = __sys_accept(s, addr, addrlen);
+ _thr_cancel_leave(curthread, oldcancel);
+
+ return (ret);
+}
+
+__weak_reference(_aio_suspend, aio_suspend);
+
+int
+_aio_suspend(const struct aiocb * const iocbs[], int niocb, const struct
+ timespec *timeout)
+{
+ struct pthread *curthread = _get_curthread();
+ int oldcancel;
+ int ret;
+
+ oldcancel = _thr_cancel_enter(curthread);
+ ret = __sys_aio_suspend(iocbs, niocb, timeout);
+ _thr_cancel_leave(curthread, oldcancel);
+
+ return (ret);
+}
+
+__weak_reference(__close, close);
+
+int
+__close(int fd)
+{
+ struct pthread *curthread = _get_curthread();
+ int oldcancel;
+ int ret;
+
+ oldcancel = _thr_cancel_enter(curthread);
+ ret = __sys_close(fd);
+ _thr_cancel_leave(curthread, oldcancel);
+
+ return (ret);
+}
+
+__weak_reference(__connect, connect);
+
+int
+__connect(int fd, const struct sockaddr *name, socklen_t namelen)
+{
+ struct pthread *curthread = _get_curthread();
+ int oldcancel;
+ int ret;
+
+ oldcancel = _thr_cancel_enter(curthread);
+ ret = __sys_connect(fd, name, namelen);
+ _thr_cancel_leave(curthread, oldcancel);
+
+ return (ret);
+}
+
+__weak_reference(___creat, creat);
+
+int
+___creat(const char *path, mode_t mode)
+{
+ struct pthread *curthread = _get_curthread();
+ int oldcancel;
+ int ret;
+
+ oldcancel = _thr_cancel_enter(curthread);
+ ret = __creat(path, mode);
+ _thr_cancel_leave(curthread, oldcancel);
+
+ return ret;
+}
+
+__weak_reference(__fcntl, fcntl);
+
+int
+__fcntl(int fd, int cmd,...)
+{
+ struct pthread *curthread = _get_curthread();
+ int oldcancel;
+ int ret;
+ va_list ap;
+
+ oldcancel = _thr_cancel_enter(curthread);
+
+ va_start(ap, cmd);
+ switch (cmd) {
+ case F_DUPFD:
+ ret = __sys_fcntl(fd, cmd, va_arg(ap, int));
+ break;
+ 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);
+
+ _thr_cancel_leave(curthread, oldcancel);
+
+ return (ret);
+}
+
+__weak_reference(__fsync, fsync);
+
+int
+__fsync(int fd)
+{
+ struct pthread *curthread = _get_curthread();
+ int oldcancel;
+ int ret;
+
+ oldcancel = _thr_cancel_enter(curthread);
+ ret = __sys_fsync(fd);
+ _thr_cancel_leave(curthread, oldcancel);
+
+ return (ret);
+}
+
+__weak_reference(__msync, msync);
+
+int
+__msync(void *addr, size_t len, int flags)
+{
+ struct pthread *curthread = _get_curthread();
+ int oldcancel;
+ int ret;
+
+ oldcancel = _thr_cancel_enter(curthread);
+ ret = __sys_msync(addr, len, flags);
+ _thr_cancel_leave(curthread, oldcancel);
+
+ return ret;
+}
+
+__weak_reference(__nanosleep, nanosleep);
+
+int
+__nanosleep(const struct timespec *time_to_sleep,
+ struct timespec *time_remaining)
+{
+ struct pthread *curthread = _get_curthread();
+ int oldcancel;
+ int ret;
+
+ oldcancel = _thr_cancel_enter(curthread);
+ ret = __sys_nanosleep(time_to_sleep, time_remaining);
+ _thr_cancel_leave(curthread, oldcancel);
+
+ return (ret);
+}
+
+__weak_reference(__open, open);
+
+int
+__open(const char *path, int flags,...)
+{
+ struct pthread *curthread = _get_curthread();
+ int oldcancel;
+ int ret;
+ int mode = 0;
+ va_list ap;
+
+ oldcancel = _thr_cancel_enter(curthread);
+
+ /* 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);
+
+ _thr_cancel_leave(curthread, oldcancel);
+
+ return ret;
+}
+
+__weak_reference(_pause, pause);
+
+int
+_pause(void)
+{
+ struct pthread *curthread = _get_curthread();
+ int oldcancel;
+ int ret;
+
+ oldcancel = _thr_cancel_enter(curthread);
+ ret = __pause();
+ _thr_cancel_leave(curthread, oldcancel);
+
+ return ret;
+}
+
+__weak_reference(__poll, poll);
+
+int
+__poll(struct pollfd *fds, unsigned int nfds, int timeout)
+{
+ struct pthread *curthread = _get_curthread();
+ int oldcancel;
+ int ret;
+
+ oldcancel = _thr_cancel_enter(curthread);
+ ret = __sys_poll(fds, nfds, timeout);
+ _thr_cancel_leave(curthread, oldcancel);
+
+ return ret;
+}
+
+__weak_reference(_pselect, pselect);
+
+int
+_pselect(int count, fd_set *rfds, fd_set *wfds, fd_set *efds,
+ const struct timespec *timo, const sigset_t *mask)
+{
+ struct pthread *curthread = _get_curthread();
+ int oldcancel;
+ int ret;
+
+ oldcancel = _thr_cancel_enter(curthread);
+ ret = __pselect(count, rfds, wfds, efds, timo, mask);
+ _thr_cancel_leave(curthread, oldcancel);
+
+ return (ret);
+}
+
+__weak_reference(_raise, raise);
+
+int
+_raise(int sig)
+{
+ int ret;
+
+ if (!_thr_isthreaded())
+ ret = kill(getpid(), sig);
+ else
+ ret = _thr_send_sig(_get_curthread(), sig);
+ return (ret);
+}
+
+__weak_reference(__read, read);
+
+ssize_t
+__read(int fd, void *buf, size_t nbytes)
+{
+ struct pthread *curthread = _get_curthread();
+ int oldcancel;
+ ssize_t ret;
+
+ oldcancel = _thr_cancel_enter(curthread);
+ ret = __sys_read(fd, buf, nbytes);
+ _thr_cancel_leave(curthread, oldcancel);
+
+ return ret;
+}
+
+__weak_reference(__readv, readv);
+
+ssize_t
+__readv(int fd, const struct iovec *iov, int iovcnt)
+{
+ struct pthread *curthread = _get_curthread();
+ int oldcancel;
+ ssize_t ret;
+
+ oldcancel = _thr_cancel_enter(curthread);
+ ret = __sys_readv(fd, iov, iovcnt);
+ _thr_cancel_leave(curthread, oldcancel);
+
+ return ret;
+}
+
+__weak_reference(__recvfrom, recvfrom);
+
+ssize_t
+__recvfrom(int s, void *b, size_t l, int f, struct sockaddr *from,
+ socklen_t *fl)
+{
+ struct pthread *curthread = _get_curthread();
+ int oldcancel;
+ ssize_t ret;
+
+ oldcancel = _thr_cancel_enter(curthread);
+ ret = __sys_recvfrom(s, b, l, f, from, fl);
+ _thr_cancel_leave(curthread, oldcancel);
+ return (ret);
+}
+
+__weak_reference(__recvmsg, recvmsg);
+
+ssize_t
+__recvmsg(int s, struct msghdr *m, int f)
+{
+ struct pthread *curthread = _get_curthread();
+ ssize_t ret;
+ int oldcancel;
+
+ oldcancel = _thr_cancel_enter(curthread);
+ ret = __sys_recvmsg(s, m, f);
+ _thr_cancel_leave(curthread, oldcancel);
+ return (ret);
+}
+
+__weak_reference(__select, select);
+
+int
+__select(int numfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
+ struct timeval *timeout)
+{
+ struct pthread *curthread = _get_curthread();
+ int oldcancel;
+ int ret;
+
+ oldcancel = _thr_cancel_enter(curthread);
+ ret = __sys_select(numfds, readfds, writefds, exceptfds, timeout);
+ _thr_cancel_leave(curthread, oldcancel);
+ return ret;
+}
+
+__weak_reference(__sendmsg, sendmsg);
+
+ssize_t
+__sendmsg(int s, const struct msghdr *m, int f)
+{
+ struct pthread *curthread = _get_curthread();
+ ssize_t ret;
+ int oldcancel;
+
+ oldcancel = _thr_cancel_enter(curthread);
+ ret = __sys_sendmsg(s, m, f);
+ _thr_cancel_leave(curthread, oldcancel);
+ return (ret);
+}
+
+__weak_reference(__sendto, sendto);
+
+ssize_t
+__sendto(int s, const void *m, size_t l, int f, const struct sockaddr *t,
+ socklen_t tl)
+{
+ struct pthread *curthread = _get_curthread();
+ ssize_t ret;
+ int oldcancel;
+
+ oldcancel = _thr_cancel_enter(curthread);
+ ret = __sys_sendto(s, m, l, f, t, tl);
+ _thr_cancel_leave(curthread, oldcancel);
+ return (ret);
+}
+
+__weak_reference(_sleep, sleep);
+
+unsigned int
+_sleep(unsigned int seconds)
+{
+ struct pthread *curthread = _get_curthread();
+ int oldcancel;
+ unsigned int ret;
+
+ oldcancel = _thr_cancel_enter(curthread);
+ ret = __sleep(seconds);
+ _thr_cancel_leave(curthread, oldcancel);
+
+ return (ret);
+}
+
+__weak_reference(_system, system);
+
+int
+_system(const char *string)
+{
+ struct pthread *curthread = _get_curthread();
+ int oldcancel;
+ int ret;
+
+ oldcancel = _thr_cancel_enter(curthread);
+ ret = __system(string);
+ _thr_cancel_leave(curthread, oldcancel);
+
+ return ret;
+}
+
+__weak_reference(_tcdrain, tcdrain);
+
+int
+_tcdrain(int fd)
+{
+ struct pthread *curthread = _get_curthread();
+ int oldcancel;
+ int ret;
+
+ oldcancel = _thr_cancel_enter(curthread);
+ ret = __tcdrain(fd);
+ _thr_cancel_leave(curthread, oldcancel);
+
+ return (ret);
+}
+
+__weak_reference(_usleep, usleep);
+
+int
+_usleep(useconds_t useconds)
+{
+ struct pthread *curthread = _get_curthread();
+ int oldcancel;
+ int ret;
+
+ oldcancel = _thr_cancel_enter(curthread);
+ ret = __usleep(useconds);
+ _thr_cancel_leave(curthread, oldcancel);
+
+ return (ret);
+}
+
+__weak_reference(_vfork, vfork);
+
+int
+_vfork(void)
+{
+ return (fork());
+}
+
+__weak_reference(_wait, wait);
+
+pid_t
+_wait(int *istat)
+{
+ struct pthread *curthread = _get_curthread();
+ int oldcancel;
+ pid_t ret;
+
+ oldcancel = _thr_cancel_enter(curthread);
+ ret = __wait(istat);
+ _thr_cancel_leave(curthread, oldcancel);
+
+ return ret;
+}
+
+__weak_reference(__wait4, wait4);
+
+pid_t
+__wait4(pid_t pid, int *istat, int options, struct rusage *rusage)
+{
+ struct pthread *curthread = _get_curthread();
+ int oldcancel;
+ pid_t ret;
+
+ oldcancel = _thr_cancel_enter(curthread);
+ ret = __sys_wait4(pid, istat, options, rusage);
+ _thr_cancel_leave(curthread, oldcancel);
+
+ return ret;
+}
+
+__weak_reference(_waitpid, waitpid);
+
+pid_t
+_waitpid(pid_t wpid, int *status, int options)
+{
+ struct pthread *curthread = _get_curthread();
+ int oldcancel;
+ pid_t ret;
+
+ oldcancel = _thr_cancel_enter(curthread);
+ ret = __waitpid(wpid, status, options);
+ _thr_cancel_leave(curthread, oldcancel);
+
+ return ret;
+}
+
+__weak_reference(__write, write);
+
+ssize_t
+__write(int fd, const void *buf, size_t nbytes)
+{
+ struct pthread *curthread = _get_curthread();
+ int oldcancel;
+ ssize_t ret;
+
+ oldcancel = _thr_cancel_enter(curthread);
+ ret = __sys_write(fd, buf, nbytes);
+ _thr_cancel_leave(curthread, oldcancel);
+
+ return ret;
+}
+
+__weak_reference(__writev, writev);
+
+ssize_t
+__writev(int fd, const struct iovec *iov, int iovcnt)
+{
+ struct pthread *curthread = _get_curthread();
+ int oldcancel;
+ ssize_t ret;
+
+ oldcancel = _thr_cancel_enter(curthread);
+ ret = __sys_writev(fd, iov, iovcnt);
+ _thr_cancel_leave(curthread, oldcancel);
+
+ return ret;
+}
diff --git a/lib/libthr/thread/thr_umtx.c b/lib/libthr/thread/thr_umtx.c
new file mode 100644
index 0000000..cba6942
--- /dev/null
+++ b/lib/libthr/thread/thr_umtx.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2005 David Xu <davidxu@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 "thr_private.h"
+#include "thr_umtx.h"
+
+int
+__thr_umtx_lock(volatile umtx_t *mtx, long id)
+{
+ while (_umtx_op(__DEVOLATILE(struct umtx *, mtx),
+ UMTX_OP_LOCK, id, 0, 0))
+ ;
+ return (0);
+}
+
+int
+__thr_umtx_timedlock(volatile umtx_t *mtx, long id,
+ const struct timespec *timeout)
+{
+ if (timeout && (timeout->tv_sec < 0 || (timeout->tv_sec == 0 &&
+ timeout->tv_nsec <= 0)))
+ return (ETIMEDOUT);
+ if (_umtx_op(__DEVOLATILE(struct umtx *, mtx), UMTX_OP_LOCK, id, 0,
+ __DECONST(void *, timeout)) == 0)
+ return (0);
+ return (errno);
+}
+
+int
+__thr_umtx_unlock(volatile umtx_t *mtx, long id)
+{
+ if (_umtx_op(__DEVOLATILE(struct umtx *, mtx), UMTX_OP_UNLOCK,
+ id, 0, 0) == 0)
+ return (0);
+ return (errno);
+}
+
+int
+_thr_umtx_wait(volatile umtx_t *mtx, long id, const struct timespec *timeout)
+{
+ if (timeout && (timeout->tv_sec < 0 || (timeout->tv_sec == 0 &&
+ timeout->tv_nsec <= 0)))
+ return (ETIMEDOUT);
+ if (_umtx_op(__DEVOLATILE(struct umtx *, mtx), UMTX_OP_WAIT, id, 0,
+ __DECONST(void*, timeout)) == 0)
+ return (0);
+ return (errno);
+}
+
+int
+_thr_umtx_wake(volatile umtx_t *mtx, int nr_wakeup)
+{
+ if (_umtx_op(__DEVOLATILE(struct umtx *, mtx), UMTX_OP_WAKE,
+ nr_wakeup, 0, 0) == 0)
+ return (0);
+ return (errno);
+}
diff --git a/lib/libthr/thread/thr_umtx.h b/lib/libthr/thread/thr_umtx.h
new file mode 100644
index 0000000..1fbf534
--- /dev/null
+++ b/lib/libthr/thread/thr_umtx.h
@@ -0,0 +1,87 @@
+/*-
+ * Copyright (c) 2005 David Xu <davidxu@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$
+ */
+
+#ifndef _THR_FBSD_UMTX_H_
+#define _THR_FBSD_UMTX_H_
+
+#include <sys/umtx.h>
+
+typedef long umtx_t;
+
+int __thr_umtx_lock(volatile umtx_t *mtx, long id) __hidden;
+int __thr_umtx_timedlock(volatile umtx_t *mtx, long id,
+ const struct timespec *timeout) __hidden;
+int __thr_umtx_unlock(volatile umtx_t *mtx, long id) __hidden;
+
+static inline void
+_thr_umtx_init(volatile umtx_t *mtx)
+{
+ *mtx = 0;
+}
+
+static inline int
+_thr_umtx_trylock(volatile umtx_t *mtx, long id)
+{
+ if (atomic_cmpset_acq_ptr((volatile uintptr_t *)mtx,
+ (uintptr_t)UMTX_UNOWNED, (uintptr_t)id))
+ return (0);
+ return (EBUSY);
+}
+
+static inline int
+_thr_umtx_lock(volatile umtx_t *mtx, long id)
+{
+ if (atomic_cmpset_acq_ptr((volatile uintptr_t *)mtx,
+ (uintptr_t)UMTX_UNOWNED, (uintptr_t)id))
+ return (0);
+ return (__thr_umtx_lock(mtx, id));
+}
+
+static inline int
+_thr_umtx_timedlock(volatile umtx_t *mtx, long id,
+ const struct timespec *timeout)
+{
+ if (atomic_cmpset_acq_ptr((volatile uintptr_t *)mtx,
+ (uintptr_t)UMTX_UNOWNED, (uintptr_t)id))
+ return (0);
+ return (__thr_umtx_timedlock(mtx, id, timeout));
+}
+
+static inline int
+_thr_umtx_unlock(volatile umtx_t *mtx, long id)
+{
+ if (atomic_cmpset_rel_ptr((volatile uintptr_t *)mtx,
+ (uintptr_t)id, (uintptr_t)UMTX_UNOWNED))
+ return (0);
+ return __thr_umtx_unlock(mtx, id);
+}
+
+int _thr_umtx_wait(volatile umtx_t *mtx, umtx_t exp,
+ const struct timespec *timeout) __hidden;
+int _thr_umtx_wake(volatile umtx_t *mtx, int count) __hidden;
+#endif
diff --git a/lib/libthr/thread/thr_yield.c b/lib/libthr/thread/thr_yield.c
new file mode 100644
index 0000000..300504b
--- /dev/null
+++ b/lib/libthr/thread/thr_yield.c
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include "namespace.h"
+#include <pthread.h>
+#include <sched.h>
+#include "un-namespace.h"
+
+__weak_reference(_pthread_yield, pthread_yield);
+
+/* Draft 4 yield */
+void
+_pthread_yield(void)
+{
+
+ sched_yield();
+}
OpenPOWER on IntegriCloud