Import initial version of 1:1 pthread library.
authorDavid Xu <davidxu@dragonflybsd.org>
Tue, 1 Feb 2005 12:38:27 +0000 (12:38 +0000)
committerDavid Xu <davidxu@dragonflybsd.org>
Tue, 1 Feb 2005 12:38:27 +0000 (12:38 +0000)
67 files changed:
lib/libthread_xu/Makefile [new file with mode: 0644]
lib/libthread_xu/arch/Makefile.inc [new file with mode: 0644]
lib/libthread_xu/arch/alpha/Makefile.inc [new file with mode: 0644]
lib/libthread_xu/arch/alpha/alpha/pthread_md.c [new file with mode: 0644]
lib/libthread_xu/arch/alpha/include/pthread_md.h [new file with mode: 0644]
lib/libthread_xu/arch/amd64/Makefile.inc [new file with mode: 0644]
lib/libthread_xu/arch/amd64/amd64/pthread_md.c [new file with mode: 0644]
lib/libthread_xu/arch/amd64/include/pthread_md.h [new file with mode: 0644]
lib/libthread_xu/arch/i386/Makefile.inc [new file with mode: 0644]
lib/libthread_xu/arch/i386/i386/pthread_md.c [new file with mode: 0644]
lib/libthread_xu/arch/i386/include/pthread_md.h [new file with mode: 0644]
lib/libthread_xu/pthread.map [new file with mode: 0644]
lib/libthread_xu/sys/Makefile.inc [new file with mode: 0644]
lib/libthread_xu/sys/thr_error.c [new file with mode: 0644]
lib/libthread_xu/thread/Makefile.inc [new file with mode: 0644]
lib/libthread_xu/thread/thr_attr.c [new file with mode: 0644]
lib/libthread_xu/thread/thr_barrier.c [new file with mode: 0644]
lib/libthread_xu/thread/thr_barrierattr.c [new file with mode: 0644]
lib/libthread_xu/thread/thr_cancel.c [new file with mode: 0644]
lib/libthread_xu/thread/thr_clean.c [new file with mode: 0644]
lib/libthread_xu/thread/thr_concurrency.c [new file with mode: 0644]
lib/libthread_xu/thread/thr_cond.c [new file with mode: 0644]
lib/libthread_xu/thread/thr_condattr.c [new file with mode: 0644]
lib/libthread_xu/thread/thr_create.c [new file with mode: 0644]
lib/libthread_xu/thread/thr_detach.c [new file with mode: 0644]
lib/libthread_xu/thread/thr_equal.c [new file with mode: 0644]
lib/libthread_xu/thread/thr_exit.c [new file with mode: 0644]
lib/libthread_xu/thread/thr_fork.c [new file with mode: 0644]
lib/libthread_xu/thread/thr_getprio.c [new file with mode: 0644]
lib/libthread_xu/thread/thr_getschedparam.c [new file with mode: 0644]
lib/libthread_xu/thread/thr_info.c [new file with mode: 0644]
lib/libthread_xu/thread/thr_init.c [new file with mode: 0644]
lib/libthread_xu/thread/thr_join.c [new file with mode: 0644]
lib/libthread_xu/thread/thr_kern.c [new file with mode: 0644]
lib/libthread_xu/thread/thr_kill.c [new file with mode: 0644]
lib/libthread_xu/thread/thr_list.c [new file with mode: 0644]
lib/libthread_xu/thread/thr_main_np.c [new file with mode: 0644]
lib/libthread_xu/thread/thr_multi_np.c [new file with mode: 0644]
lib/libthread_xu/thread/thr_mutex.c [new file with mode: 0644]
lib/libthread_xu/thread/thr_mutex_prioceiling.c [new file with mode: 0644]
lib/libthread_xu/thread/thr_mutex_protocol.c [new file with mode: 0644]
lib/libthread_xu/thread/thr_mutexattr.c [new file with mode: 0644]
lib/libthread_xu/thread/thr_once.c [new file with mode: 0644]
lib/libthread_xu/thread/thr_printf.c [new file with mode: 0644]
lib/libthread_xu/thread/thr_private.h [new file with mode: 0644]
lib/libthread_xu/thread/thr_pspinlock.c [new file with mode: 0644]
lib/libthread_xu/thread/thr_resume_np.c [new file with mode: 0644]
lib/libthread_xu/thread/thr_rtld.c [new file with mode: 0644]
lib/libthread_xu/thread/thr_rwlock.c [new file with mode: 0644]
lib/libthread_xu/thread/thr_rwlockattr.c [new file with mode: 0644]
lib/libthread_xu/thread/thr_self.c [new file with mode: 0644]
lib/libthread_xu/thread/thr_sem.c [new file with mode: 0644]
lib/libthread_xu/thread/thr_seterrno.c [new file with mode: 0644]
lib/libthread_xu/thread/thr_setprio.c [new file with mode: 0644]
lib/libthread_xu/thread/thr_setschedparam.c [new file with mode: 0644]
lib/libthread_xu/thread/thr_sig.c [new file with mode: 0644]
lib/libthread_xu/thread/thr_single_np.c [new file with mode: 0644]
lib/libthread_xu/thread/thr_spec.c [new file with mode: 0644]
lib/libthread_xu/thread/thr_spinlock.c [new file with mode: 0644]
lib/libthread_xu/thread/thr_stack.c [new file with mode: 0644]
lib/libthread_xu/thread/thr_suspend_np.c [new file with mode: 0644]
lib/libthread_xu/thread/thr_switch_np.c [new file with mode: 0644]
lib/libthread_xu/thread/thr_symbols.c [new file with mode: 0644]
lib/libthread_xu/thread/thr_syscalls.c [new file with mode: 0644]
lib/libthread_xu/thread/thr_umtx.c [new file with mode: 0644]
lib/libthread_xu/thread/thr_umtx.h [new file with mode: 0644]
lib/libthread_xu/thread/thr_yield.c [new file with mode: 0644]

diff --git a/lib/libthread_xu/Makefile b/lib/libthread_xu/Makefile
new file mode 100644 (file)
index 0000000..554043f
--- /dev/null
@@ -0,0 +1,38 @@
+# $FreeBSD: src/lib/libpthread/Makefile,v 1.53 2004/10/24 15:32:32 ru Exp $
+# $DragonFly: src/lib/libthread_xu/Makefile,v 1.1 2005/02/01 12:38:26 davidxu Exp $
+#
+# All library objects contain FreeBSD revision strings by default; they may be
+# excluded as a space-saving measure.  To produce a library that does
+# not contain these strings, add -DSTRIP_FBSDID (see <sys/cdefs.h>) to CFLAGS
+# below.  Note, there are no IDs for syscall stubs whose sources are generated.
+# To included legacy CSRG sccsid strings, add -DLIBC_SCCS and -DSYSLIBC_SCCS
+# (for system call stubs) to CFLAGS below.  -DSYSLIBC_SCCS affects just the
+# system call stubs.
+LIB=thread_xu
+SHLIB_MAJOR= 1
+SHLIB_MINOR= 0
+CFLAGS+=-DPTHREAD_KERNEL -D_THREAD_SAFE
+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+=-Winline
+
+CFLAGS+= -g
+
+# CFLAGS+=-DSYSTEM_SCOPE_ONLY
+
+LDFLAGS=--version-script=${.CURDIR}/pthread.map
+
+# enable extra internal consistancy checks
+CFLAGS+=-D_PTHREADS_INVARIANTS -Wall
+
+PRECIOUSLIB=   yes
+
+.include "${.CURDIR}/arch/${MACHINE_ARCH}/Makefile.inc"
+.include "${.CURDIR}/sys/Makefile.inc"
+.include "${.CURDIR}/thread/Makefile.inc"
+
+.include <bsd.lib.mk>
diff --git a/lib/libthread_xu/arch/Makefile.inc b/lib/libthread_xu/arch/Makefile.inc
new file mode 100644 (file)
index 0000000..9fa3c0d
--- /dev/null
@@ -0,0 +1,5 @@
+# $DragonFly: src/lib/libthread_xu/arch/Makefile.inc,v 1.1 2005/02/01 12:38:26 davidxu Exp $
+
+.PATH: ${.CURDIR}/arch/${MACHINE_ARCH}/${MACHINE_ARCH}
+
+SRCS+= pthread_md.c
diff --git a/lib/libthread_xu/arch/alpha/Makefile.inc b/lib/libthread_xu/arch/alpha/Makefile.inc
new file mode 100644 (file)
index 0000000..1c67f14
--- /dev/null
@@ -0,0 +1,5 @@
+# $DragonFly: src/lib/libthread_xu/arch/alpha/Attic/Makefile.inc,v 1.1 2005/02/01 12:38:27 davidxu Exp $
+
+.PATH: ${.CURDIR}/arch/${MACHINE_ARCH}/${MACHINE_ARCH}
+
+SRCS+= pthread_md.c
diff --git a/lib/libthread_xu/arch/alpha/alpha/pthread_md.c b/lib/libthread_xu/arch/alpha/alpha/pthread_md.c
new file mode 100644 (file)
index 0000000..39ca9fd
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ *
+ * $DragonFly: src/lib/libthread_xu/arch/alpha/alpha/Attic/pthread_md.c,v 1.1 2005/02/01 12:38:27 davidxu Exp $
+ */
+
+#include <sys/cdefs.h>
+#include <stdlib.h>
+#include <strings.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) {
+               tcb->tcb_thread = thread;
+       }
+       return (tcb);
+}
+
+void
+_tcb_dtor(struct tcb *tcb)
+{
+       free(tcb);
+}
diff --git a/lib/libthread_xu/arch/alpha/include/pthread_md.h b/lib/libthread_xu/arch/alpha/include/pthread_md.h
new file mode 100644 (file)
index 0000000..ee82b60
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * 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: src/lib/libpthread/arch/alpha/include/pthread_md.h,v 1.7 2004/08/16 14:07:38 davidxu Exp $
+ * $DragonFly: src/lib/libthread_xu/arch/alpha/include/Attic/pthread_md.h,v 1.1 2005/02/01 12:38:27 davidxu Exp $
+ */
+
+#ifndef _PTHREAD_MD_H_
+#define        _PTHREAD_MD_H_
+
+#include <stddef.h>
+
+#define        DTV_OFFSET              offsetof(struct tcb, tcb_tdv)
+
+struct pthread;
+struct tcb;
+struct tdv;    /* We don't know what this is yet? */
+
+struct tcb {
+       struct tdv              *tcb_tdv;       /* dynamic TLS */
+       struct pthread          *tcb_thread;
+};
+
+#define        _tp     __builtin_thread_pointer()
+#define        _tcb    ((struct tcb*)((char*)(_tp)))
+
+/*
+ * The 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)
+{
+       /* There is no thread yet; use the fake tcb. */
+       __builtin_set_thread_pointer(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/libthread_xu/arch/amd64/Makefile.inc b/lib/libthread_xu/arch/amd64/Makefile.inc
new file mode 100644 (file)
index 0000000..c641b7b
--- /dev/null
@@ -0,0 +1,5 @@
+# $DragonFly: src/lib/libthread_xu/arch/amd64/Makefile.inc,v 1.1 2005/02/01 12:38:27 davidxu Exp $
+
+.PATH: ${.CURDIR}/arch/${MACHINE_ARCH}/${MACHINE_ARCH}
+
+SRCS+= pthread_md.c
diff --git a/lib/libthread_xu/arch/amd64/amd64/pthread_md.c b/lib/libthread_xu/arch/amd64/amd64/pthread_md.c
new file mode 100644 (file)
index 0000000..a9e1207
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * 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: src/lib/libpthread/arch/amd64/amd64/pthread_md.c,v 1.4 2004/11/06 03:33:19 peter Exp $
+ * $DragonFly: src/lib/libthread_xu/arch/amd64/amd64/pthread_md.c,v 1.1 2005/02/01 12:38:27 davidxu Exp $
+ */
+
+#include <stdlib.h>
+#include <strings.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) {
+               __asm __volatile("movq %%fs:0, %0" : "=r" (oldtls));
+       } 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/libthread_xu/arch/amd64/include/pthread_md.h b/lib/libthread_xu/arch/amd64/include/pthread_md.h
new file mode 100644 (file)
index 0000000..a3ea5d4
--- /dev/null
@@ -0,0 +1,114 @@
+/*-
+ * 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: src/lib/libpthread/arch/amd64/include/pthread_md.h,v 1.10 2004/08/25 23:42:40 davidxu Exp $
+ * $DragonFly: src/lib/libthread_xu/arch/amd64/include/pthread_md.h,v 1.1 2005/02/01 12:38:27 davidxu Exp $
+ */
+
+/*
+ * Machine-dependent thread prototypes/definitions for the thread kernel.
+ */
+#ifndef _PTHREAD_MD_H_
+#define        _PTHREAD_MD_H_
+
+#include <stddef.h>
+#include <sys/types.h>
+#include <sys/kse.h>
+#include <machine/sysarch.h>
+#include <ucontext.h>
+
+#define        DTV_OFFSET              offsetof(struct tcb, tcb_dtv)
+
+struct pthread;
+struct tdv;
+
+/*
+ * %fs points to a struct tcb.
+ */
+
+struct tcb {
+       struct tcb              *tcb_self;      /* required by rtld */
+       void                    *tcb_dtv;       /* required by rtld */
+       struct pthread          *tcb_thread;
+       void                    *tcb_spare[1];  /* align tcb_tmbx to 16 bytes */
+};
+
+/*
+ * Evaluates to the byte offset of the per-kse variable name.
+ */
+#define        __tcb_offset(name)      __offsetof(struct tcb, name)
+
+/*
+ * Evaluates to the type of the per-kse variable name.
+ */
+#define        __tcb_type(name)        __typeof(((struct tcb *)0)->name)
+
+/*
+ * Evaluates to the value of the per-kse 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;                                               \
+})
+
+/*
+ * The constructors.
+ */
+struct tcb     *_tcb_ctor(struct pthread *, int);
+void           _tcb_dtor(struct tcb *tcb);
+
+/* Called from the KSE to set its private data. */
+static __inline void
+_tcb_set(struct tcb *tcb)
+{
+       amd64_set_fsbase(tcb);
+}
+
+/* Get the current kcb. */
+static __inline struct tcb *
+_tcb_get(void)
+{
+       return (TCB_GET64(tcb_self));
+}
+
+extern struct pthread *_thr_initial;
+
+/* Get the current thread. */
+static __inline struct pthread *
+_get_curthread(void)
+{
+       if (_thr_initial)
+               return (TCB_GET64(tcb_thread));
+       return (NULL);
+}
+#endif
diff --git a/lib/libthread_xu/arch/i386/Makefile.inc b/lib/libthread_xu/arch/i386/Makefile.inc
new file mode 100644 (file)
index 0000000..cea024c
--- /dev/null
@@ -0,0 +1,5 @@
+# $DragonFly: src/lib/libthread_xu/arch/i386/Makefile.inc,v 1.1 2005/02/01 12:38:27 davidxu Exp $
+
+.PATH: ${.CURDIR}/arch/${MACHINE_ARCH}/${MACHINE_ARCH}
+
+SRCS+= pthread_md.c
diff --git a/lib/libthread_xu/arch/i386/i386/pthread_md.c b/lib/libthread_xu/arch/i386/i386/pthread_md.c
new file mode 100644 (file)
index 0000000..c9adc20
--- /dev/null
@@ -0,0 +1,181 @@
+/*-
+ * 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.
+ *
+ * $DragonFly: src/lib/libthread_xu/arch/i386/i386/pthread_md.c,v 1.1 2005/02/01 12:38:27 davidxu Exp $
+ */
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+#include <machine/cpufunc.h>
+#include <machine/segments.h>
+#include <machine/sysarch.h>
+
+#include <unistd.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef __DragonFly__
+#include "rtld_tls.h"
+#endif
+
+#include "pthread_md.h"
+
+#ifdef __DragonFly__
+
+#define LDT_ENTRIES 8192
+#define LDT_WORDS   (8192/sizeof(unsigned int))
+#define LDT_RESERVED NLDT
+
+static unsigned int ldt_mask[LDT_WORDS];
+static int initialized = 0;
+
+static void    initialize(void);
+
+static void
+initialize(void)
+{
+       int i, j;
+
+       memset(ldt_mask, 0xFF, sizeof(ldt_mask));
+       /* Reserve system predefined LDT entries */
+       for (i = 0; i < LDT_RESERVED; ++i) {
+               j = i / 32;
+               ldt_mask[j] &= ~(1 << (i % 32));
+       }
+       initialized = 1;
+}
+
+static u_int
+alloc_ldt_entry(void)
+{
+       u_int i, j, index;
+       
+       index = 0;
+       for (i = 0; i < LDT_WORDS; ++i) {
+               if (ldt_mask[i] != 0) {
+                       j = bsfl(ldt_mask[i]);
+                       ldt_mask[i] &= ~(1 << j);
+                       index = i * 32 + j;
+                       break;
+               }
+       }
+       return (index);
+}
+
+static void
+free_ldt_entry(u_int index)
+{
+       u_int i, j;
+
+       if (index < LDT_RESERVED || index >= LDT_ENTRIES)
+               return;
+       i = index / 32;
+       j = index % 32;
+       ldt_mask[i] |= (1 << j);
+}
+
+#endif
+
+struct tcb *
+_tcb_ctor(struct pthread *thread, int initial)
+{
+#ifndef COMPAT_32BIT
+       union descriptor ldt;
+#endif
+       struct tcb *tcb;
+
+#ifndef __DragonFly__
+       void *oldtls;
+
+       if (initial)
+               __asm __volatile("movl %%gs:0, %0" : "=r" (oldtls));
+       else
+               oldtls = NULL;
+
+       tcb = _rtld_allocate_tls(oldtls, sizeof(struct tcb), 16);
+#else
+       if (!initialized)
+               initialize();
+       if ((tcb = malloc(sizeof(struct tcb))) == NULL)
+               return (NULL);
+       /* tcb_self and tcb_dtv should assigned by rtld tls code. */
+       tcb->tcb_self = tcb;
+       tcb->tcb_dtv = NULL;
+       if ((tcb->tcb_ldt = alloc_ldt_entry()) == 0) {
+               free(tcb);
+               return (NULL);
+       }
+#endif
+
+       if (tcb) {
+               tcb->tcb_thread = thread;
+#ifndef COMPAT_32BIT
+               ldt.sd.sd_hibase = (unsigned int)tcb >> 24;
+               ldt.sd.sd_lobase = (unsigned int)tcb & 0xFFFFFF;
+               ldt.sd.sd_hilimit = (sizeof(struct tcb) >> 16) & 0xF;
+               ldt.sd.sd_lolimit = sizeof(struct tcb) & 0xFFFF;
+               ldt.sd.sd_type = SDT_MEMRWA;
+               ldt.sd.sd_dpl = SEL_UPL;
+               ldt.sd.sd_p = 1;
+               ldt.sd.sd_xx = 0;
+               ldt.sd.sd_def32 = 1;
+               ldt.sd.sd_gran = 0;     /* no more than 1M */
+
+#ifdef __DragonFly__
+               if (i386_set_ldt(tcb->tcb_ldt, &ldt, 1) == -1) { 
+                       free_ldt_entry(tcb->tcb_ldt);
+                       free(tcb);
+                       tcb = NULL;
+               }
+#else
+               tcb->tcb_ldt = i386_set_ldt(LDT_AUTO_ALLOC, &ldt, 1);
+               if (tcb->tcb_ldt < 0) {
+                       free(tcb);
+                       tcb = NULL;
+               }
+#endif
+#endif
+       }
+       return (tcb);
+}
+
+void
+_tcb_dtor(struct tcb *tcb)
+{
+#ifdef __DragonFly__
+       if (tcb->tcb_ldt > 0) {
+               free_ldt_entry(tcb->tcb_ldt);
+               free(tcb);      
+       }
+#else
+#ifndef COMPAT_32BIT
+       if (tcb->tcb_ldt > 0)
+               i386_set_ldt(tcb->tcb_ldt, NULL, 1);
+#endif
+       _rtld_free_tls(tcb, sizeof(struct tcb), 16);
+#endif
+}
diff --git a/lib/libthread_xu/arch/i386/include/pthread_md.h b/lib/libthread_xu/arch/i386/include/pthread_md.h
new file mode 100644 (file)
index 0000000..3398f8a
--- /dev/null
@@ -0,0 +1,141 @@
+/*-
+ * 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: src/lib/libpthread/arch/i386/include/pthread_md.h,v 1.13 2004/11/06 03:35:51 peter Exp $
+ * $DragonFly: src/lib/libthread_xu/arch/i386/include/pthread_md.h,v 1.1 2005/02/01 12:38:27 davidxu Exp $
+ */
+
+/*
+ * Machine-dependent thread prototypes/definitions for the thread kernel.
+ */
+#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)
+
+struct pthread;
+
+/*
+ * %gs points to a struct tcb.
+ */
+struct tcb {
+       struct tcb              *tcb_self;      /* required by rtld */
+       void                    *tcb_dtv;       /* required by rtld */
+       struct pthread          *tcb_thread;
+       int                     tcb_ldt;
+};
+
+/*
+ * Evaluates to the byte offset of the per-thread variable name.
+ */
+#define        __tcb_offset(name)      __offsetof(struct tcb, name)
+
+/*
+ * Evaluates to the type of the per-thread variable name.
+ */
+#define        __tcb_type(name)        __typeof(((struct tcb *)0)->name)
+
+/*
+ * Evaluates to the value of the per-kse 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;                                               \
+})
+
+#ifdef __DragonFly__
+static __inline int
+atomic_cmpset_int(volatile int *dst, int exp, int src)
+{
+       int res = exp;
+
+       __asm __volatile (
+       "       lock cmpxchgl %1,%2 ;   "
+       "       setz    %%al ;          "
+       "       movzbl  %%al,%0 ;       "
+       "1:                             "
+       "# atomic_cmpset_int"
+       : "+a" (res)                    /* 0 (result) */
+       : "r" (src),                    /* 1 */
+         "m" (*(dst))                  /* 2 */
+       : "memory");                             
+
+       return (res);
+}
+
+#define atomic_cmpset_acq_int  atomic_cmpset_int
+#endif
+
+/*
+ * 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)
+{
+#ifndef COMPAT_32BIT
+       int val;
+
+       val = (tcb->tcb_ldt << 3) | 7;
+       __asm __volatile("movl %0, %%gs" : : "r" (val));
+#else
+       _amd64_set_gsbase(tcb);
+#endif
+
+}
+
+/* Get the current kcb. */
+static __inline struct tcb *
+_tcb_get(void)
+{
+       return (TCB_GET32(tcb_self));
+}
+
+extern struct pthread *_thr_initial;
+
+/* Get the current thread. */
+static __inline struct pthread *
+_get_curthread(void)
+{
+       if (_thr_initial)
+               return (TCB_GET32(tcb_thread));
+       return (NULL);
+}
+#endif
diff --git a/lib/libthread_xu/pthread.map b/lib/libthread_xu/pthread.map
new file mode 100644 (file)
index 0000000..b561c78
--- /dev/null
@@ -0,0 +1,372 @@
+# $FreeBSD: src/lib/libpthread/pthread.map,v 1.13 2004/09/26 06:50:14 deischen Exp $
+# $DragonFly: src/lib/libthread_xu/pthread.map,v 1.1 2005/02/01 12:38:26 davidxu Exp $
+
+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_trylock;
+       __pthread_mutex_timedlock;
+       __read;
+       __readv;
+       __recvfrom;
+       __recvmsg;
+       __select;
+       __sendmsg;
+       __sendto;
+       __sigsuspend;
+       __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_default;
+       _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_default;
+       _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_default;
+       _pthread_mutexattr_destroy;
+       _pthread_mutexattr_getkind_np;
+       _pthread_mutexattr_getprioceiling;
+       _pthread_mutexattr_getprotocol;
+       _pthread_mutexattr_gettype;
+       _pthread_mutexattr_init;
+       _pthread_mutexattr_setkind_np;
+       _pthread_mutexattr_setprioceiling;
+       _pthread_mutexattr_setprotocol;
+       _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_yield;
+       _raise;
+       _sem_close;
+       _sem_destroy;
+       _sem_getvalue;
+       _sem_init;
+       _sem_open;
+       _sem_post;
+       _sem_timedwait;
+       _sem_trywait;
+       _sem_unlink;
+       _sem_wait;
+       _sigaction;
+       _sigprocmask;
+       _sigsuspend;
+       _sigwait;
+       _sigtimedwait;
+       _sigwaitinfo;
+       _sleep;
+       _spinlock;
+       _spinlock_debug;
+       _spinunlock;
+       _system;
+       _tcdrain;
+       _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_getprotocol;
+       pthread_mutexattr_gettype;
+       pthread_mutexattr_init;
+       pthread_mutexattr_setkind_np;
+       pthread_mutexattr_setprioceiling;
+       pthread_mutexattr_setprotocol;
+       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_yield;
+       raise;
+       read;
+       readv;
+       recvfrom;
+       recvmsg;
+       select;
+       sem_close;
+       sem_destroy;
+       sem_getvalue;
+       sem_init;
+       sem_open;
+       sem_post;
+       sem_timedwait;
+       sem_trywait;
+       sem_unlink;
+       sem_wait;
+       sendmsg;
+       sendto;
+       sigaction;
+       sigaltstack;
+       sigpending;
+       sigprocmask;
+       sigsuspend;
+       sigwait;
+       sigwaitinfo;
+       sigtimedwait;
+       sleep;
+       system;
+       tcdrain;
+       vfork;
+       wait;
+       wait4;
+       waitpid;
+       write;
+       writev;
+
+       # Debugger needs these.
+       _libthread_xu_debug;
+       _thread_inited;
+       _thread_active_threads;
+       _thread_keytable;
+       _thread_list;
+       _thread_max_keys;
+       _thread_off_attr_flags;
+       _thread_off_dtv;
+       _thread_off_linkmap;
+       _thread_off_next;
+       _thread_off_tcb;
+       _thread_off_tid;
+       _thread_off_key_allocated;
+       _thread_off_key_destructor;
+       _thread_off_state;
+       _thread_off_thr_locklevel;
+       _thread_off_tlsindex;
+       _thread_off_isdead;
+       _thread_size_key;
+       _thread_state_running;
+       _thread_state_zoombie;
+local:
+       *;
+};
diff --git a/lib/libthread_xu/sys/Makefile.inc b/lib/libthread_xu/sys/Makefile.inc
new file mode 100644 (file)
index 0000000..712fbb1
--- /dev/null
@@ -0,0 +1,5 @@
+# $DragonFly: src/lib/libthread_xu/sys/Attic/Makefile.inc,v 1.1 2005/02/01 12:38:27 davidxu Exp $
+
+.PATH:  ${.CURDIR}/sys
+
+SRCS+= thr_error.c
diff --git a/lib/libthread_xu/sys/thr_error.c b/lib/libthread_xu/sys/thr_error.c
new file mode 100644 (file)
index 0000000..87a571a
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * 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: src/lib/libpthread/sys/thr_error.c,v 1.7 2003/04/23 21:46:50 deischen Exp $
+ * $DragonFly: src/lib/libthread_xu/sys/Attic/thr_error.c,v 1.1 2005/02/01 12:38:27 davidxu Exp $
+ */
+#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/libthread_xu/thread/Makefile.inc b/lib/libthread_xu/thread/Makefile.inc
new file mode 100644 (file)
index 0000000..4c3e7db
--- /dev/null
@@ -0,0 +1,51 @@
+# $DragonFly: src/lib/libthread_xu/thread/Makefile.inc,v 1.1 2005/02/01 12:38:27 davidxu Exp $
+
+# thr sources
+.PATH: ${.CURDIR}/thread
+
+SRCS+= \
+       thr_attr.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_exit.c \
+       thr_fork.c \
+       thr_getprio.c \
+       thr_getschedparam.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_mutex_prioceiling.c \
+       thr_mutex_protocol.c \
+       thr_once.c \
+       thr_printf.c \
+       thr_resume_np.c \
+       thr_rwlock.c \
+       thr_rwlockattr.c \
+       thr_self.c \
+       thr_sem.c \
+       thr_seterrno.c \
+       thr_setprio.c \
+       thr_setschedparam.c \
+       thr_sig.c \
+       thr_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/libthread_xu/thread/thr_attr.c b/lib/libthread_xu/thread/thr_attr.c
new file mode 100644 (file)
index 0000000..8ffb748
--- /dev/null
@@ -0,0 +1,532 @@
+/*
+ * 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.
+ *
+ * $DragonFly: src/lib/libthread_xu/thread/thr_attr.c,v 1.1 2005/02/01 12:38:27 davidxu Exp $
+ */
+
+#include <errno.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pthread_np.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;
+       _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;
+
+       /* 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));
+               pattr->guardsize_attr = _thr_guard_default;
+
+               /* 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 ret = 0;
+
+       if ((attr == NULL) || (*attr == NULL))
+               ret = EINVAL;
+       else if (param == NULL) {
+               ret = ENOTSUP;
+       } else if ((param->sched_priority < THR_MIN_PRIORITY) ||
+           (param->sched_priority > THR_MAX_PRIORITY)) {
+               /* Return an unsupported value error. */
+               ret = ENOTSUP;
+       } else
+               (*attr)->prio = param->sched_priority;
+
+       return(ret);
+}
+
+__weak_reference(_pthread_attr_setschedpolicy, pthread_attr_setschedpolicy);
+
+int
+_pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy)
+{
+       int ret = 0;
+
+       if ((attr == NULL) || (*attr == NULL))
+               ret = EINVAL;
+       else if ((policy < SCHED_FIFO) || (policy > SCHED_RR)) {
+               ret = ENOTSUP;
+       } else
+               (*attr)->sched_policy = policy;
+
+       return(ret);
+}
+
+__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/libthread_xu/thread/thr_barrier.c b/lib/libthread_xu/thread/thr_barrier.c
new file mode 100644 (file)
index 0000000..2f70271
--- /dev/null
@@ -0,0 +1,108 @@
+/*-
+ * 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: src/lib/libpthread/thread/thr_barrier.c,v 1.1 2003/09/04 14:06:43 davidxu Exp $
+ * $DragonFly: src/lib/libthread_xu/thread/thr_barrier.c,v 1.1 2005/02/01 12:38:27 davidxu Exp $
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <pthread.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, int count)
+{
+       pthread_barrier_t       bar;
+
+       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, INT_MAX);
+               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/libthread_xu/thread/thr_barrierattr.c b/lib/libthread_xu/thread/thr_barrierattr.c
new file mode 100644 (file)
index 0000000..70256ac
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * 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: src/lib/libpthread/thread/thr_barrierattr.c,v 1.1 2003/09/04 14:06:43 davidxu Exp $
+ * $DragonFly: src/lib/libthread_xu/thread/thr_barrierattr.c,v 1.1 2005/02/01 12:38:27 davidxu Exp $
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <pthread.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/libthread_xu/thread/thr_cancel.c b/lib/libthread_xu/thread/thr_cancel.c
new file mode 100644 (file)
index 0000000..c5a1e40
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+ * 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.
+ *
+ * $DragonFly: src/lib/libthread_xu/thread/thr_cancel.c,v 1.1 2005/02/01 12:38:27 davidxu Exp $
+ */
+
+#include <pthread.h>
+#include "thr_private.h"
+
+__weak_reference(_pthread_cancel, pthread_cancel);
+__weak_reference(_pthread_setcancelstate, pthread_setcancelstate);
+__weak_reference(_pthread_setcanceltype, pthread_setcanceltype);
+__weak_reference(_pthread_testcancel, pthread_testcancel);
+
+int _pthread_setcanceltype(int type, int *oldtype);
+
+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))
+               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/libthread_xu/thread/thr_clean.c b/lib/libthread_xu/thread/thr_clean.c
new file mode 100644 (file)
index 0000000..3e0d221
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * 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: src/lib/libpthread/thread/thr_clean.c,v 1.9 2004/12/18 18:07:37 deischen Exp $
+ * $DragonFly: src/lib/libthread_xu/thread/thr_clean.c,v 1.1 2005/02/01 12:38:27 davidxu Exp $
+ */
+#include <signal.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+__weak_reference(_pthread_cleanup_push, pthread_cleanup_push);
+__weak_reference(_pthread_cleanup_pop, pthread_cleanup_pop);
+
+void
+_pthread_cleanup_push(void (*routine) (void *), void *routine_arg)
+{
+       struct pthread  *curthread = _get_curthread();
+       struct pthread_cleanup *new;
+
+       if ((new = (struct pthread_cleanup *)
+           malloc(sizeof(struct pthread_cleanup))) != NULL) {
+               new->routine = routine;
+               new->routine_arg = routine_arg;
+               new->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/libthread_xu/thread/thr_concurrency.c b/lib/libthread_xu/thread/thr_concurrency.c
new file mode 100644 (file)
index 0000000..be668b3
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2003 Daniel M. Eischen <deischen@freebsd.org>
+ * 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. Neither the name of the author nor the names of any 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/lib/libpthread/thread/thr_concurrency.c,v 1.8 2004/03/14 05:24:27 bde Exp $
+ * $DragonFly: src/lib/libthread_xu/thread/thr_concurrency.c,v 1.1 2005/02/01 12:38:27 davidxu Exp $
+ */
+#include <errno.h>
+#include <pthread.h>
+#include <sys/types.h>
+#include <sys/sysctl.h>
+
+#include "thr_private.h"
+
+/*#define DEBUG_CONCURRENCY */
+#ifdef DEBUG_CONCURRENCY
+#define DBG_MSG                stdout_debug
+#else
+#define        DBG_MSG(x...)
+#endif
+
+static int level = 0;
+
+__weak_reference(_pthread_getconcurrency, pthread_getconcurrency);
+__weak_reference(_pthread_setconcurrency, pthread_setconcurrency);
+
+int
+_pthread_getconcurrency(void)
+{
+       return (level);
+}
+
+int
+_pthread_setconcurrency(int new_level)
+{
+       if (new_level < 0)
+               return (EINVAL);
+       level = new_level;
+       return 0;
+}
diff --git a/lib/libthread_xu/thread/thr_cond.c b/lib/libthread_xu/thread/thr_cond.c
new file mode 100644 (file)
index 0000000..6c33b70
--- /dev/null
@@ -0,0 +1,347 @@
+/*
+ * 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.
+ *
+ * $DragonFly: src/lib/libthread_xu/thread/thr_cond.c,v 1.1 2005/02/01 12:38:27 davidxu Exp $
+ */
+
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <pthread.h>
+#include <limits.h>
+
+#include "thr_private.h"
+
+/*
+ * Prototypes
+ */
+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;
+};
+
+static void
+cond_cancel_handler(void *arg)
+{
+       struct pthread *curthread = _get_curthread();
+       struct cond_cancel_info *cci = (struct cond_cancel_info *)arg;
+       pthread_cond_t cv;
+
+       cv = *(cci->cond);
+       THR_LOCK_ACQUIRE(curthread, &cv->c_lock);
+       if (cv->c_seqno != cci->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(cci->mutex);
+}
+
+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 cci;
+       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);
+       if (ret) {
+               THR_LOCK_RELEASE(curthread, &cv->c_lock);
+               return (ret);
+       }
+       oldseq = seq = cv->c_seqno;
+       cci.mutex = mutex;
+       cci.cond  = cond;
+       cci.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, &cci);
+                       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);
+       return (ret);
+}
+
+int
+_pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
+{
+       return cond_wait_common(cond, mutex, NULL, 0);
+}
+
+__strong_reference(_pthread_cond_wait, _thr_cond_wait);
+
+int
+__pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
+{
+       int ret;
+
+       ret = cond_wait_common(cond, mutex, NULL, 1);
+       return (ret);
+}
+
+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);
+}
+
+__strong_reference(_pthread_cond_timedwait, _thr_cond_timedwait);
+
+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;
+
+       /*
+        * 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 {
+                       cv->c_wakeups += cv->c_waiters;
+                       cv->c_waiters = 0;
+                       cv->c_seqno++;
+                       _thr_umtx_wake(&cv->c_seqno, INT_MAX);
+               }
+       }
+       THR_LOCK_RELEASE(curthread, &cv->c_lock);
+       return (ret);
+}
+
+int
+_pthread_cond_signal(pthread_cond_t * cond)
+{
+       return cond_signal_common(cond, 0);
+}
+
+__strong_reference(_pthread_cond_signal, _thr_cond_signal);
+
+int
+_pthread_cond_broadcast(pthread_cond_t * cond)
+{
+       return cond_signal_common(cond, 1);
+}
+
+__strong_reference(_pthread_cond_broadcast, _thr_cond_broadcast);
diff --git a/lib/libthread_xu/thread/thr_condattr.c b/lib/libthread_xu/thread/thr_condattr.c
new file mode 100644 (file)
index 0000000..b4fe7ed
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * 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.
+ *
+ * $DragonFly: src/lib/libthread_xu/thread/thr_condattr.c,v 1.1 2005/02/01 12:38:27 davidxu Exp $
+ */
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <pthread.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(const pthread_condattr_t *attr,
+       clockid_t clock_id)
+{
+       if (attr == NULL || *attr == NULL)
+               return (EINVAL);
+       if (clock_id != CLOCK_REALTIME)
+               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/libthread_xu/thread/thr_create.c b/lib/libthread_xu/thread/thr_create.c
new file mode 100644 (file)
index 0000000..09198c5
--- /dev/null
@@ -0,0 +1,252 @@
+/*
+ * Copyright (c) 2005 David Xu <davidxu@freebsd.org>
+ * Copyright (c) 2003 Daniel M. Eischen <deischen@gdeb.com>
+ * 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: src/lib/libpthread/thread/thr_create.c,v 1.58 2004/10/23 23:28:36 davidxu Exp $
+ * $DragonFly: src/lib/libthread_xu/thread/thr_create.c,v 1.1 2005/02/01 12:38:27 davidxu Exp $
+ */
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stddef.h>
+#include <sys/time.h>
+#include <machine/reg.h>
+#include <pthread.h>
+#include <sys/signalvar.h>
+
+#include "thr_private.h"
+#include "libc_private.h"
+
+struct start_arg {
+       struct pthread  *thread;
+       volatile umtx_t started;
+};
+
+static void free_thread(struct pthread *curthread, struct pthread *thread);
+static int  create_stack(struct pthread_attr *pattr);
+static void free_stack(struct pthread *curthread, struct pthread_attr *pattr);
+static void thread_start(void *);
+
+__weak_reference(_pthread_create, pthread_create);
+
+int
+_pthread_create(pthread_t * thread, const pthread_attr_t * attr,
+              void *(*start_routine) (void *), void *arg)
+{
+       struct start_arg start_arg;
+       void *stack;
+       sigset_t sigmask, oldsigmask;
+       struct pthread *curthread, *new_thread;
+       int ret = 0;
+
+       _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);
+
+       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 (_thread_scope_system > 0)
+               new_thread->attr.flags |= PTHREAD_SCOPE_SYSTEM;
+       else if (_thread_scope_system < 0)
+               new_thread->attr.flags &= ~PTHREAD_SCOPE_SYSTEM;
+
+       if (create_stack(&new_thread->attr) != 0) {
+               /* Insufficient memory to create a stack: */
+               new_thread->terminated = 1;
+               _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);
+       TAILQ_INIT(&new_thread->pri_mutexq);
+
+       /* Initialise hooks in the thread structure: */
+       if (new_thread->attr.suspend == THR_CREATE_SUSPENDED)
+               new_thread->flags = THR_FLAGS_SUSPENDED;
+       new_thread->state = PS_RUNNING;
+       /*
+        * Thread created by thr_create() inherits currrent thread
+        * sigmask, however, before new thread setup itself correctly,
+        * it can not handle signal, so we should masks all signals here.
+        */
+       SIGFILLSET(sigmask);
+       __sys_sigprocmask(SIG_SETMASK, &sigmask, &oldsigmask);
+       new_thread->sigmask = oldsigmask;
+       /* Add the new thread. */
+       _thr_link(curthread, new_thread);
+       /* Return thread pointer eariler so that new thread can use it. */
+       (*thread) = new_thread;
+       /* Schedule the new thread. */
+       stack = (char *)new_thread->attr.stackaddr_attr +
+                       new_thread->attr.stacksize_attr;
+       start_arg.thread  = new_thread;
+       start_arg.started = 0;
+       ret = rfork_thread(RFPROC | RFNOWAIT | RFMEM | RFSIGSHARE, stack,
+                          (int (*)(void *))thread_start, &start_arg);
+       __sys_sigprocmask(SIG_SETMASK, &oldsigmask, NULL);
+       if (ret >= 0) {
+               /*
+                * Wait until new thread get its thread id, so we can
+                * send signal to it immediately after we return.
+                */
+               while (start_arg.started == 0)
+                       _thr_umtx_wait(&start_arg.started, 0, 0);
+               ret = 0;
+       } else {
+               ret = EAGAIN;
+       }
+       if (ret != 0) {
+               _thr_unlink(curthread, new_thread);
+               free_thread(curthread, new_thread);
+               (*thread) = 0;
+               ret = EAGAIN;
+       }
+       return (ret);
+}
+
+static void
+free_thread(struct pthread *curthread, struct pthread *thread)
+{
+       free_stack(curthread, &thread->attr);
+       curthread->terminated = 1;
+       _thr_free(curthread, thread);
+}
+
+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
+free_stack(struct pthread *curthread, struct pthread_attr *pattr)
+{
+       if ((pattr->flags & THR_STACK_USER) == 0) {
+               THREAD_LIST_LOCK(curthread);
+               /* Stack routines don't use malloc/free. */
+               _thr_stack_free(pattr);
+               THREAD_LIST_UNLOCK(curthread);
+       }
+}
+
+static void
+thread_start(void *arg)
+{
+       struct pthread *curthread;
+       struct start_arg *start_arg = arg;
+
+       curthread = start_arg->thread;
+       curthread->tid = _thr_get_tid();
+       _tcb_set(curthread->tcb);
+       start_arg->started = 1;
+       _thr_umtx_wake(&start_arg->started, 1);
+
+       /* Thread was created with all signals blocked, unblock them. */
+       __sys_sigprocmask(SIG_SETMASK, &curthread->sigmask, NULL);
+
+       if (curthread->flags & THR_FLAGS_NEED_SUSPEND)
+               _thr_suspend_check(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/libthread_xu/thread/thr_detach.c b/lib/libthread_xu/thread/thr_detach.c
new file mode 100644 (file)
index 0000000..6f32310
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * 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: src/lib/libpthread/thread/thr_detach.c,v 1.23 2003/07/23 02:11:07 deischen Exp $
+ * $DragonFly: src/lib/libthread_xu/thread/thr_detach.c,v 1.1 2005/02/01 12:38:27 davidxu Exp $
+ */
+#include <sys/types.h>
+#include <machine/atomic.h>
+#include <errno.h>
+#include <pthread.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/libthread_xu/thread/thr_equal.c b/lib/libthread_xu/thread/thr_equal.c
new file mode 100644 (file)
index 0000000..2f3d577
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by John Birrell.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/lib/libpthread/thread/thr_equal.c,v 1.6 2002/09/16 08:45:34 mini Exp $
+ * $DragonFly: src/lib/libthread_xu/thread/thr_equal.c,v 1.1 2005/02/01 12:38:27 davidxu Exp $
+ */
+#include <pthread.h>
+#include "thr_private.h"
+
+__weak_reference(_pthread_equal, pthread_equal);
+
+int
+_pthread_equal(pthread_t t1, pthread_t t2)
+{
+       /* Compare the two thread pointers: */
+       return (t1 == t2);
+}
diff --git a/lib/libthread_xu/thread/thr_exit.c b/lib/libthread_xu/thread/thr_exit.c
new file mode 100644 (file)
index 0000000..6c5b293
--- /dev/null
@@ -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: src/lib/libpthread/thread/thr_exit.c,v 1.39 2004/10/23 23:37:54 davidxu Exp $
+ * $DragonFly: src/lib/libthread_xu/thread/thr_exit.c,v 1.1 2005/02/01 12:38:27 davidxu Exp $
+ */
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+void   _pthread_exit(void *status);
+
+__weak_reference(_pthread_exit, pthread_exit);
+
+void
+_thread_exit(char *fname, int lineno, 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);
+       }
+       if (curthread->attr.cleanup_attr != NULL) {
+               curthread->attr.cleanup_attr(curthread->attr.arg_attr);
+       }
+       /* Check if there is thread specific data: */
+       if (curthread->specific != NULL) {
+               /* Run the thread-specific data destructors: */
+               _thread_cleanupspecific();
+       }
+
+       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! */
+       }
+       if (curthread->tlflags & TLFLAGS_DETACHED)
+               THR_GCLIST_ADD(curthread);
+       curthread->state = PS_DEAD;
+       THREAD_LIST_UNLOCK(curthread);
+       if (curthread->joiner)
+               _thr_umtx_wake(&curthread->state, INT_MAX);
+       /* XXX
+        * All the code is incorrect on DragonFly.
+        * DragonFly has race condition here. it should provide
+        * an interface to tell userland that a thread is now
+        * in kernel, and userland stack can be safely recycled
+        * by userland GC code.
+        */
+       curthread->terminated = 1;
+       _exit(0);
+       PANIC("thr_exit() returned");
+       /* Never reach! */
+}
diff --git a/lib/libthread_xu/thread/thr_fork.c b/lib/libthread_xu/thread/thr_fork.c
new file mode 100644 (file)
index 0000000..9a58bc2
--- /dev/null
@@ -0,0 +1,228 @@
+/*
+ * 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: src/lib/libpthread/thread/thr_atfork.c,v 1.1 2003/11/05 03:42:10 davidxu Exp $
+ */
+
+/*
+ * 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: src/lib/libpthread/thread/thr_fork.c,v 1.34 2003/11/05 18:18:45 deischen Exp $
+ * $DragonFly: src/lib/libthread_xu/thread/thr_fork.c,v 1.1 2005/02/01 12:38:27 davidxu Exp $
+ */
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <spinlock.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);
+}
+
+/*
+ * For a while, allow libpthread to work with a libc that doesn't
+ * export the malloc lock.
+ */
+#pragma weak __malloc_lock
+
+__weak_reference(_fork, fork);
+
+pid_t
+_fork(void)
+{
+       static umtx_t inprogress;
+       static int waiters;
+       umtx_t tmp;
+
+       struct pthread *curthread;
+       struct pthread_atfork *af;
+       pid_t ret;
+       int errsave;
+#ifndef __DragonFly__
+       int unlock_malloc;
+#endif
+
+       if (!_thr_is_inited())
+               return (__sys_fork());
+
+       curthread = _get_curthread();
+
+       THR_UMTX_LOCK(curthread, &_thr_atfork_lock);
+       tmp = inprogress;
+       while (tmp) {
+               waiters++;
+               THR_UMTX_UNLOCK(curthread, &_thr_atfork_lock);
+               _thr_umtx_wait(&inprogress, tmp, NULL);
+               THR_UMTX_LOCK(curthread, &_thr_atfork_lock);
+               waiters--;
+               tmp = inprogress;
+       }
+       inprogress = 1;
+       THR_UMTX_UNLOCK(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();
+       }
+
+#ifndef __DragonFly__
+       /*
+        * 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) && (__malloc_lock != NULL)) {
+               unlock_malloc = 1;
+               _spinlock(__malloc_lock);
+       } else {
+               unlock_malloc = 0;
+       }
+#endif
+
+       /*
+        * 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;
+               inprogress = 0;
+               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. */
+               curthread->tid = _thr_get_tid();
+
+               /* clear other threads locked us. */
+               _thr_umtx_init(&curthread->lock);
+               _thr_umtx_init(&_thr_atfork_lock);
+               _thr_setthreaded(0);
+
+               /* reinitialize libc spinlocks, this includes __malloc_lock. */
+               _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;
+
+#ifndef __DragonFly__
+               if (unlock_malloc)
+                       _spinunlock(__malloc_lock);
+#endif
+
+               /* Ready to continue, unblock signals. */ 
+               _thr_signal_unblock(curthread);
+
+               /* Run down atfork parent handlers. */
+               TAILQ_FOREACH(af, &_thr_atfork_list, qe) {
+                       if (af->parent != NULL)
+                               af->parent();
+               }
+
+               THR_UMTX_LOCK(curthread, &_thr_atfork_lock);
+               inprogress = 0;
+               if (waiters)
+                       _thr_umtx_wake(&inprogress, waiters);
+               THR_UMTX_UNLOCK(curthread, &_thr_atfork_lock);
+       }
+       errno = errsave;
+
+       /* Return the process ID: */
+       return (ret);
+}
diff --git a/lib/libthread_xu/thread/thr_getprio.c b/lib/libthread_xu/thread/thr_getprio.c
new file mode 100644 (file)
index 0000000..6778a1f
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * 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: src/lib/libpthread/thread/thr_getprio.c,v 1.9 2002/09/16 08:45:34 mini Exp $
+ * $DragonFly: src/lib/libthread_xu/thread/thr_getprio.c,v 1.1 2005/02/01 12:38:27 davidxu Exp $
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+__weak_reference(_pthread_getprio, pthread_getprio);
+
+int
+_pthread_getprio(pthread_t pthread)
+{
+       int policy, ret;
+       struct sched_param param;
+
+       if ((ret = pthread_getschedparam(pthread, &policy, &param)) == 0)
+               ret = param.sched_priority;
+       else {
+               /* Invalid thread: */
+               errno = ret;
+               ret = -1;
+       }
+
+       /* Return the thread priority or an error status: */
+       return (ret);
+}
diff --git a/lib/libthread_xu/thread/thr_getschedparam.c b/lib/libthread_xu/thread/thr_getschedparam.c
new file mode 100644 (file)
index 0000000..8bdd28c
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * 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: src/lib/libpthread/thread/thr_getschedparam.c,v 1.10 2003/07/07 04:28:23 davidxu Exp $
+ * $DragonFly: src/lib/libthread_xu/thread/thr_getschedparam.c,v 1.1 2005/02/01 12:38:27 davidxu Exp $
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+__weak_reference(_pthread_getschedparam, pthread_getschedparam);
+
+int
+_pthread_getschedparam(pthread_t pthread, int *policy, 
+       struct sched_param *param)
+{
+       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 =
+                   THR_BASE_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 =
+                   THR_BASE_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/libthread_xu/thread/thr_info.c b/lib/libthread_xu/thread/thr_info.c
new file mode 100644 (file)
index 0000000..01b6300
--- /dev/null
@@ -0,0 +1,200 @@
+/*
+ * 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: src/lib/libpthread/thread/thr_info.c,v 1.27 2003/09/22 00:40:23 davidxu Exp $
+ * $DragonFly: src/lib/libthread_xu/thread/thr_info.c,v 1.1 2005/02/01 12:38:27 davidxu Exp $
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <errno.h>
+#include "thr_private.h"
+
+#ifndef NELEMENTS
+#define NELEMENTS(arr) (sizeof(arr) / sizeof(arr[0]))
+#endif
+
+static void    dump_thread(int fd, pthread_t pthread, int long_version);
+
+__weak_reference(_pthread_set_name_np, pthread_set_name_np);
+
+struct s_thread_info {
+       enum pthread_state state;
+       char           *name;
+};
+
+/* Static variables: */
+static const struct s_thread_info thread_info[] = {
+       {PS_RUNNING     , "Running"},
+       {PS_MUTEX_WAIT  , "Waiting on a mutex"},
+       {PS_JOIN        , "Waiting to join"},
+       {PS_SUSPENDED   , "Suspended"},
+       {PS_DEAD        , "Dead"},
+       {PS_DEADLOCK    , "Deadlocked"},
+       {PS_STATE_MAX   , "Not a real state!"}
+};
+
+void
+_thread_dump_info(void)
+{
+       char s[512], tmpfile[128];
+       pthread_t pthread;
+       int fd, i;
+
+       for (i = 0; i < 100000; i++) {
+               snprintf(tmpfile, sizeof(tmpfile), "/tmp/pthread.dump.%u.%i",
+                       getpid(), i);
+               /* Open the dump file for append and create it if necessary: */
+               if ((fd = __sys_open(tmpfile, O_RDWR | O_CREAT | O_EXCL,
+                       0666)) < 0) {
+                               /* Can't open the dump file. */
+                               if (errno == EEXIST)
+                                       continue;
+                               /*
+                                * We only need to continue in case of
+                                * EEXIT error. Most other error
+                                * codes means that we will fail all
+                                * the times.
+                                */
+                               return;
+               } else {
+                       break;
+               }
+       }
+       if (i==100000) {
+               /* all 100000 possibilities are in use :( */
+               return;
+       } else {
+               /* Dump the active threads. */
+               strcpy(s, "\n\n========\nACTIVE THREADS\n\n");
+               __sys_write(fd, s, strlen(s));
+
+               /* Enter a loop to report each thread in the global list: */
+               TAILQ_FOREACH(pthread, &_thread_list, tle) {
+                       if (pthread->state != PS_DEAD)
+                               dump_thread(fd, pthread, /*long_verson*/ 1);
+               }
+
+               /*
+                * Dump the ready threads.
+                * XXX - We can't easily do this because the run queues
+                *       are per-KSEG.
+                */
+               strcpy(s, "\n\n========\nREADY THREADS - unimplemented\n\n");
+               __sys_write(fd, s, strlen(s));
+
+
+               /*
+                * Dump the waiting threads.
+                * XXX - We can't easily do this because the wait queues
+                *       are per-KSEG.
+                */
+               strcpy(s, "\n\n========\nWAITING THREADS - unimplemented\n\n");
+               __sys_write(fd, s, strlen(s));
+
+               /* Close the dump file. */
+               __sys_close(fd);
+       }
+}
+
+static void
+dump_thread(int fd, pthread_t pthread, int long_version)
+{
+       struct pthread *curthread = _get_curthread();
+       char s[512];
+       int i;
+
+       /* Find the state: */
+       for (i = 0; i < NELEMENTS(thread_info) - 1; i++)
+               if (thread_info[i].state == pthread->state)
+                       break;
+
+       /* Output a record for the thread: */
+       snprintf(s, sizeof(s),
+           "--------------------\n"
+           "Thread %p (%s), scope %s, prio %3d, state %s [%s:%d]\n",
+           pthread, (pthread->name == NULL) ? "" : pthread->name,
+           pthread->attr.flags & PTHREAD_SCOPE_SYSTEM ? "system" : "process",
+           pthread->active_priority,
+           thread_info[i].name, pthread->fname, pthread->lineno);
+       __sys_write(fd, s, strlen(s));
+
+       if (long_version != 0) {
+               /* Check if this is the running thread: */
+               if (pthread == curthread) {
+                       /* Output a record for the running thread: */
+                       strcpy(s, "This is the running thread\n");
+                       __sys_write(fd, s, strlen(s));
+               }
+               /* Check if this is the initial thread: */
+               if (pthread == _thr_initial) {
+                       /* Output a record for the initial thread: */
+                       strcpy(s, "This is the initial thread\n");
+                       __sys_write(fd, s, strlen(s));
+               }
+       
+               /* Process according to thread state: */
+               switch (pthread->state) {
+               /*
+                * Trap other states that are not explicitly
+                * coded to dump information:
+                */
+               default:
+                       snprintf(s, sizeof(s), "sigmask (hi) ");
+                       __sys_write(fd, s, strlen(s));
+                       for (i = _SIG_WORDS - 1; i >= 0; i--) {
+                               snprintf(s, sizeof(s), "%08x ",
+                                   pthread->sigmask.__bits[i]);
+                               __sys_write(fd, s, strlen(s));
+                       }
+                       snprintf(s, sizeof(s), "(lo)\n");
+                       __sys_write(fd, s, strlen(s));
+                       break;
+               }
+       }
+}
+
+/* Set the thread name for debug: */
+void
+_pthread_set_name_np(pthread_t thread, char *name)
+{
+       /* Check if the caller has specified a valid thread: */
+       if (thread != NULL && thread->magic == THR_MAGIC) {
+               if (thread->name != NULL) {
+                       /* Free space for previous name. */
+                       free(thread->name);
+               }
+               thread->name = strdup(name);
+       }
+}
diff --git a/lib/libthread_xu/thread/thr_init.c b/lib/libthread_xu/thread/thr_init.c
new file mode 100644 (file)
index 0000000..9710cd6
--- /dev/null
@@ -0,0 +1,415 @@
+/*
+ * 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: src/lib/libpthread/thread/thr_init.c,v 1.66 2004/08/21 11:49:19 davidxu Exp $
+ * $DragonFly: src/lib/libthread_xu/thread/thr_init.c,v 1.1 2005/02/01 12:38:27 davidxu Exp $
+ */
+
+/* Allocate space for global thread variables here: */
+#define GLOBAL_PTHREAD_PRIVATE
+
+#include "namespace.h"
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/signalvar.h>
+#include <machine/reg.h>
+
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/uio.h>
+#include <sys/socket.h>
+#include <sys/event.h>
+#include <sys/stat.h>
+#include <sys/sysctl.h>
+#include <sys/time.h>
+#include <sys/ttycom.h>
+#include <sys/wait.h>
+#include <sys/mman.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <paths.h>
+#include <pthread.h>
+#include <pthread_np.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "un-namespace.h"
+
+#include "libc_private.h"
+#include "thr_private.h"
+
+extern int _thread_state_running;
+
+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(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 void *references[] = {
+       &_accept,
+       &_bind,
+       &_close,
+       &_connect,
+       &_dup,
+       &_dup2,
+       &_execve,
+       &_fcntl,
+       &_flock,
+       &_flockfile,
+       &_fstat,
+       &_fstatfs,
+       &_fsync,
+       &_funlockfile,
+       &_getdirentries,
+       &_getlogin,
+       &_getpeername,
+       &_getsockname,
+       &_getsockopt,
+       &_ioctl,
+       &_kevent,
+       &_listen,
+       &_nanosleep,
+       &_open,
+       &_pthread_getspecific,
+       &_pthread_key_create,
+       &_pthread_key_delete,
+       &_pthread_mutex_destroy,
+       &_pthread_mutex_init,
+       &_pthread_mutex_lock,
+       &_pthread_mutex_trylock,
+       &_pthread_mutex_unlock,
+       &_pthread_mutexattr_init,
+       &_pthread_mutexattr_destroy,
+       &_pthread_mutexattr_settype,
+       &_pthread_once,
+       &_pthread_setspecific,
+       &_read,
+       &_readv,
+       &_recvfrom,
+       &_recvmsg,
+       &_select,
+       &_sendmsg,
+       &_sendto,
+       &_setsockopt,
+       &_sigaction,
+       &_sigprocmask,
+       &_sigsuspend,
+       &_socket,
+       &_socketpair,
+       &_thread_init,
+       &_wait4,
+       &_write,
+       &_writev
+};
+
+/*
+ * These are needed when linking statically.  All references within
+ * libgcc (and in the future libc) to these routines are weak, but
+ * if they are not (strongly) referenced by the application or other
+ * libraries, then the actual functions will not be loaded.
+ */
+static void *libgcc_references[] = {
+       &_pthread_once,
+       &_pthread_key_create,
+       &_pthread_key_delete,
+       &_pthread_getspecific,
+       &_pthread_setspecific,
+       &_pthread_mutex_init,
+       &_pthread_mutex_destroy,
+       &_pthread_mutex_lock,
+       &_pthread_mutex_trylock,
+       &_pthread_mutex_unlock,
+       &_pthread_cond_init,
+       &_pthread_cond_destroy,
+       &_pthread_cond_wait,
+       &_pthread_cond_timedwait,
+       &_pthread_cond_signal,
+       &_pthread_cond_broadcast
+};
+
+#if 0
+#define        DUAL_ENTRY(entry)       \
+       (pthread_func_t)entry, (pthread_func_t)entry
+
+static pthread_func_t jmp_table[][2] = {
+       {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 */
+       {(pthread_func_t)__pthread_cond_wait,
+        (pthread_func_t)_pthread_cond_wait},   /* PJT_COND_WAIT */
+       {DUAL_ENTRY(_pthread_getspecific)},     /* PJT_GETSPECIFIC */
+       {DUAL_ENTRY(_pthread_key_create)},      /* PJT_KEY_CREATE */
+       {DUAL_ENTRY(_pthread_key_delete)},      /* PJT_KEY_DELETE*/
+       {DUAL_ENTRY(_pthread_main_np)},         /* PJT_MAIN_NP */
+       {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_mutexattr_destroy)}, /* PJT_MUTEXATTR_DESTROY */
+       {DUAL_ENTRY(_pthread_mutexattr_init)},  /* PJT_MUTEXATTR_INIT */
+       {DUAL_ENTRY(_pthread_mutexattr_settype)}, /* PJT_MUTEXATTR_SETTYPE */
+       {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_setspecific)},     /* PJT_SETSPECIFIC */
+       {DUAL_ENTRY(_pthread_sigmask)}          /* PJT_SIGMASK */
+};
+#endif
+
+static int     init_once = 0;
+
+/*
+ * 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;
+
+       /*
+        * Make gcc quiescent about {,libgcc_}references not being
+        * referenced:
+        */
+       if ((references[0] == NULL) || (libgcc_references[0] == NULL))
+               PANIC("Failed loading mandatory references in _thread_init");
+
+       /* Pull debug symbols in for static binary */
+       _thread_state_running = PS_RUNNING;
+
+#if 0
+       /*
+        * 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));
+#endif
+       /*
+        * 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 (__sys_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);
+               __sys_sigprocmask(SIG_SETMASK, &sigset, &oldset);
+               _thr_signal_init();
+               _thr_initial = curthread;
+               SIGDELSET(oldset, SIGCANCEL);
+               __sys_sigprocmask(SIG_SETMASK, &oldset, NULL);
+       }
+}
+
+/*
+ * 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. */
+       thread->tid = _thr_get_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((void *)_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 = (void *)_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;
+       thread->name = strdup("initial thread");
+
+       /* Default the priority of the initial thread: */
+       thread->base_priority = THR_DEFAULT_PRIORITY;
+       thread->active_priority = THR_DEFAULT_PRIORITY;
+       thread->inherited_priority = 0;
+
+       /* Initialize the mutex queue: */
+       TAILQ_INIT(&thread->mutexq);
+       TAILQ_INIT(&thread->pri_mutexq);
+
+       thread->state = PS_RUNNING;
+       thread->uniqueid = 0;
+
+       /* 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_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;
+               
+               TAILQ_INIT(&_thr_atfork_list);
+#ifdef SYSTEM_SCOPE_ONLY
+               _thread_scope_system = 1;
+#else
+               if (getenv("LIBPTHREAD_SYSTEM_SCOPE") != NULL)
+                       _thread_scope_system = 1;
+               else if (getenv("LIBPTHREAD_PROCESS_SCOPE") != NULL)
+                       _thread_scope_system = -1;
+#endif
+       }
+       init_once = 1;
+}
+
+void
+_thread_init(void)
+{
+       _libpthread_init(NULL);
+}
+
+extern int _thread_autoinit_dummy_decl;
+int _thread_autoinit_dummy_decl = 0;
diff --git a/lib/libthread_xu/thread/thr_join.c b/lib/libthread_xu/thread/thr_join.c
new file mode 100644 (file)
index 0000000..626b0d3
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * 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: src/lib/libpthread/thread/thr_join.c,v 1.28 2003/12/09 02:20:56 davidxu Exp $
+ * $DragonFly: src/lib/libthread_xu/thread/thr_join.c,v 1.1 2005/02/01 12:38:27 davidxu Exp $
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+__weak_reference(_pthread_join, pthread_join);
+
+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)
+{
+       struct pthread *curthread = _get_curthread();
+       void *tmp;
+       long state;
+       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);
+
+       while ((state = pthread->state) != PS_DEAD) {
+               _thr_umtx_wait(&pthread->state, state, NULL);
+       }
+
+       _thr_cancel_leave(curthread, oldcancel);
+       THR_CLEANUP_POP(curthread, 0);
+
+       tmp = pthread->ret;
+       THREAD_LIST_LOCK(curthread);
+       pthread->tlflags |= TLFLAGS_DETACHED;
+       THR_GCLIST_ADD(pthread);
+       THREAD_LIST_UNLOCK(curthread);
+
+       if (thread_return != NULL)
+               *thread_return = tmp;
+
+       return (ret);
+}
diff --git a/lib/libthread_xu/thread/thr_kern.c b/lib/libthread_xu/thread/thr_kern.c
new file mode 100644 (file)
index 0000000..5c29c80
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * 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.
+ *
+ * $DragonFly: src/lib/libthread_xu/thread/thr_kern.c,v 1.1 2005/02/01 12:38:27 davidxu Exp $
+ */
+
+#include <sys/cdefs.h>
+#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 0
+       if (threaded != 0) {
+               _thr_rtld_init();
+       } else {
+               _thr_rtld_fini();
+       }
+#endif
+       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);
+}
+
+void
+_thr_assert_lock_level()
+{
+       PANIC("locklevel <= 0");
+}
+
+int
+_thr_send_sig(struct pthread *thread, int sig)
+{
+       return (kill(thread->tid, sig));
+}
+
+int
+_thr_get_tid()
+{
+       return (getpid());
+}
diff --git a/lib/libthread_xu/thread/thr_kill.c b/lib/libthread_xu/thread/thr_kill.c
new file mode 100644 (file)
index 0000000..2902a0b
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * 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: src/lib/libpthread/thread/thr_kill.c,v 1.16 2003/06/28 09:55:02 davidxu Exp $
+ * $DragonFly: src/lib/libthread_xu/thread/thr_kill.c,v 1.1 2005/02/01 12:38:27 davidxu Exp $
+ */
+#include <errno.h>
+#include <signal.h>
+#include <pthread.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/libthread_xu/thread/thr_list.c b/lib/libthread_xu/thread/thr_list.c
new file mode 100644 (file)
index 0000000..0483717
--- /dev/null
@@ -0,0 +1,334 @@
+/*
+ * 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.
+ *
+ * $DragonFly: src/lib/libthread_xu/thread/thr_list.c,v 1.1 2005/02/01 12:38:27 davidxu Exp $
+ */
+
+#include <sys/cdefs.h>
+#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 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 u_int64_t               next_uniqueid = 1;
+
+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 >> 12) % HASH_QUEUES)
+
+static void thr_destroy(struct pthread *curthread, struct pthread *thread);
+
+void
+_thr_list_init(void)
+{
+       int i;
+
+       _gc_count = 0;
+       _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->terminated == 0) {
+                       /* 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;
+               }
+
+               DBG_MSG("Freeing thread %p\n", td);
+               _thr_free(curthread, td);
+       }
+}
+
+struct pthread *
+_thr_alloc(struct pthread *curthread)
+{
+       struct pthread  *thread = NULL;
+       struct tcb      *tcb = NULL;
+
+       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);
+                               tcb = thread->tcb;
+                               free_thread_count--;
+                       }
+                       THR_LOCK_RELEASE(curthread, &free_thread_lock);
+               }
+       }
+       if ((thread == NULL) &&
+           ((thread = malloc(sizeof(struct pthread))) != NULL)) {
+               if (curthread) {
+                       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) {
+                       free(thread);
+                       thread = NULL;
+               }
+       }
+       if (thread) {
+               memset(thread, 0, sizeof(*thread));
+               thread->tcb = tcb;
+       }
+       return (thread);
+}
+
+void
+_thr_free(struct pthread *curthread, struct pthread *thread)
+{
+       DBG_MSG("Freeing thread %p\n", thread);
+       if (thread->name) {
+               free(thread->name);
+               thread->name = NULL;
+       }
+       if ((curthread == NULL) || (free_thread_count >= MAX_CACHED_THREADS)) {
+               thr_destroy(curthread, thread);
+       } else {
+               /* Add the thread to the free thread list. */
+               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, struct pthread *thread)
+{
+       if (curthread) {
+               THR_LOCK_ACQUIRE(curthread, &tcb_lock);
+               _tcb_dtor(thread->tcb);
+               THR_LOCK_RELEASE(curthread, &tcb_lock);
+       } else {
+               _tcb_dtor(thread->tcb);
+       }
+       free(thread);
+}
+
+/*
+ * Add an active thread:
+ *
+ *   o Assign the thread a unique id (which GDB uses to track
+ *     threads.
+ *   o 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);
+       /*
+        * Initialize the unique id (which GDB uses to track
+        * threads), add the thread to the list of all threads,
+        * and
+        */
+       thread->uniqueid = next_uniqueid++;
+       THR_LIST_ADD(thread);
+       if (thread->attr.flags & PTHREAD_DETACHED)
+               thread->tlflags |= TLFLAGS_DETACHED;
+       _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)
+{
+       if (thread != NULL) {
+               THREAD_LIST_LOCK(curthread);
+               thread->refcount--;
+               if ((thread->refcount == 0) &&
+                   (thread->tlflags & TLFLAGS_GC_SAFE) != 0)
+                       THR_GCLIST_ADD(thread);
+               THREAD_LIST_UNLOCK(curthread);
+       }
+}
+
+int
+_thr_find_thread(struct pthread *curthread, 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/libthread_xu/thread/thr_main_np.c b/lib/libthread_xu/thread/thr_main_np.c
new file mode 100644 (file)
index 0000000..9f9da3f
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * 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: src/lib/libpthread/thread/thr_main_np.c,v 1.5 2003/04/18 05:04:16 deischen Exp $
+ * $DragonFly: src/lib/libthread_xu/thread/thr_main_np.c,v 1.1 2005/02/01 12:38:27 davidxu Exp $
+ */
+
+#include <pthread.h>
+#include <pthread_np.h>
+#include "thr_private.h"
+
+__weak_reference(_pthread_main_np, pthread_main_np);
+
+/*
+ * Provide the equivelant to Solaris thr_main() function
+ */
+int
+_pthread_main_np()
+{
+
+       if (!_thr_initial)
+               return (-1);
+       else
+               return (pthread_equal(pthread_self(), _thr_initial) ? 1 : 0);
+}
diff --git a/lib/libthread_xu/thread/thr_multi_np.c b/lib/libthread_xu/thread/thr_multi_np.c
new file mode 100644 (file)
index 0000000..2d6192a
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * 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: src/lib/libpthread/thread/thr_multi_np.c,v 1.7 2002/05/24 04:32:28 deischen Exp $
+ * $DragonFly: src/lib/libthread_xu/thread/thr_multi_np.c,v 1.1 2005/02/01 12:38:27 davidxu Exp $
+ */
+#include <pthread.h>
+#include <pthread_np.h>
+
+__weak_reference(_pthread_multi_np, pthread_multi_np);
+
+int
+_pthread_multi_np()
+{
+
+       /* Return to multi-threaded scheduling mode: */
+       /*
+        * XXX - Do we want to do this?
+        * __is_threaded = 1;
+        */
+       pthread_resume_all_np();
+       return (0);
+}
diff --git a/lib/libthread_xu/thread/thr_mutex.c b/lib/libthread_xu/thread/thr_mutex.c
new file mode 100644 (file)
index 0000000..7cbde9a
--- /dev/null
@@ -0,0 +1,1676 @@
+/*
+ * 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: src/lib/libpthread/thread/thr_mutex.c,v 1.46 2004/10/31 05:03:50 green Exp $
+ * $DragonFly: src/lib/libthread_xu/thread/thr_mutex.c,v 1.1 2005/02/01 12:38:27 davidxu Exp $
+ */
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <pthread.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)
+#define        THR_ASSERT_NOT_IN_SYNCQ(thr)    do {            \
+       THR_ASSERT(((thr)->sflags & THR_FLAGS_IN_SYNCQ) == 0, \
+           "thread in syncq when it shouldn't be.");   \
+} while (0);
+#else
+#define MUTEX_INIT_LINK(m)
+#define MUTEX_ASSERT_IS_OWNED(m)
+#define MUTEX_ASSERT_NOT_OWNED(m)
+#define        THR_ASSERT_NOT_IN_SYNCQ(thr)
+#endif
+
+#define THR_IN_MUTEXQ(thr)     (((thr)->sflags & THR_FLAGS_IN_SYNCQ) != 0)
+#define        MUTEX_DESTROY(m) do {           \
+       free(m);                        \
+} while (0)
+
+
+/*
+ * Prototypes
+ */
+static long            mutex_handoff(struct pthread *, struct pthread_mutex *);
+static int             mutex_self_trylock(struct pthread *, pthread_mutex_t);
+static int             mutex_self_lock(struct pthread *, pthread_mutex_t,
+                               const struct timespec *abstime);
+static int             mutex_unlock_common(pthread_mutex_t *, int);
+static void            mutex_priority_adjust(struct pthread *, pthread_mutex_t);
+static void            mutex_rescan_owned (struct pthread *, struct pthread *,
+                           struct pthread_mutex *);
+#if 0
+static pthread_t       mutex_queue_deq(pthread_mutex_t);
+#endif
+static void            mutex_queue_remove(pthread_mutex_t, pthread_t);
+static void            mutex_queue_enq(pthread_mutex_t, pthread_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);
+
+static int
+mutex_init(pthread_mutex_t *mutex,
+    const pthread_mutexattr_t *mutex_attr, int private)
+{
+       struct pthread_mutex *pmutex;
+       enum pthread_mutextype type;
+       int             protocol;
+       int             ceiling;
+       int             flags;
+       int             ret = 0;
+
+       /* Check if default mutex attributes: */
+       if (mutex_attr == NULL || *mutex_attr == NULL) {
+               /* Default to a (error checking) POSIX mutex: */
+               type = PTHREAD_MUTEX_ERRORCHECK;
+               protocol = PTHREAD_PRIO_NONE;
+               ceiling = THR_MAX_PRIORITY;
+               flags = 0;
+       }
+
+       /* Check mutex type: */
+       else if (((*mutex_attr)->m_type < PTHREAD_MUTEX_ERRORCHECK) ||
+           ((*mutex_attr)->m_type >= MUTEX_TYPE_MAX))
+               /* Return an invalid argument error: */
+               ret = EINVAL;
+
+       /* Check mutex protocol: */
+       else if (((*mutex_attr)->m_protocol < PTHREAD_PRIO_NONE) ||
+           ((*mutex_attr)->m_protocol > PTHREAD_PRIO_PROTECT))
+               /* Return an invalid argument error: */
+               ret = EINVAL;
+
+       else {
+               /* Use the requested mutex type and protocol: */
+               type = (*mutex_attr)->m_type;
+               protocol = (*mutex_attr)->m_protocol;
+               ceiling = (*mutex_attr)->m_ceiling;
+               flags = (*mutex_attr)->m_flags;
+       }
+
+       /* Check no errors so far: */
+       if (ret == 0) {
+               if ((pmutex = (pthread_mutex_t)
+                   malloc(sizeof(struct pthread_mutex))) == NULL) {
+                       ret = ENOMEM;
+               } else {
+                       _thr_umtx_init(&pmutex->m_lock);
+                       /* Set the mutex flags: */
+                       pmutex->m_flags = flags;
+
+                       /* Process according to mutex type: */
+                       switch (type) {
+                       /* case PTHREAD_MUTEX_DEFAULT: */
+                       case PTHREAD_MUTEX_ERRORCHECK:
+                       case PTHREAD_MUTEX_NORMAL:
+                               /* Nothing to do here. */
+                               break;
+
+                       /* Single UNIX Spec 2 recursive mutex: */
+                       case PTHREAD_MUTEX_RECURSIVE:
+                               /* Reset the mutex count: */
+                               pmutex->m_count = 0;
+                               break;
+
+                       /* Trap invalid mutex types: */
+                       default:
+                               /* Return an invalid argument error: */
+                               ret = EINVAL;
+                               break;
+                       }
+                       if (ret == 0) {
+                               /* Initialise the rest of the mutex: */
+                               TAILQ_INIT(&pmutex->m_queue);
+                               pmutex->m_flags |= MUTEX_FLAGS_INITED;
+                               if (private)
+                                       pmutex->m_flags |= MUTEX_FLAGS_PRIVATE;
+                               pmutex->m_owner = NULL;
+                               pmutex->m_type = type;
+                               pmutex->m_protocol = protocol;
+                               pmutex->m_refcount = 0;
+                               if (protocol == PTHREAD_PRIO_PROTECT)
+                                       pmutex->m_prio = ceiling;
+                               else
+                                       pmutex->m_prio = -1;
+                               pmutex->m_saved_prio = 0;
+                               MUTEX_INIT_LINK(pmutex);
+                               *mutex = pmutex;
+                       } else {
+                               /* Free the mutex lock structure: */
+                               MUTEX_DESTROY(pmutex);
+                               *mutex = NULL;
+                       }
+               }
+       }
+       /* Return the completion status: */
+       return (ret);
+}
+
+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;
+
+       TAILQ_FOREACH(m, &curthread->mutexq, m_qe)
+               m->m_lock = UMTX_LOCKED;
+
+       /* Clear contender for priority mutexes */
+       TAILQ_FOREACH(m, &curthread->pri_mutexq, m_qe) {
+               /* clear another thread locked us */
+               _thr_umtx_init(&m->m_lock);
+               TAILQ_INIT(&m->m_queue);
+       }
+}
+
+int
+_pthread_mutex_destroy(pthread_mutex_t *mutex)
+{
+       struct pthread *curthread = _get_curthread();
+       pthread_mutex_t m;
+       int ret = 0;
+
+       if (mutex == NULL || *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;
+
+                       /* Unlock the mutex structure: */
+                       _thr_umtx_unlock(&m->m_lock, curthread->tid);
+
+                       /*
+                        * Free the memory allocated for the mutex
+                        * structure:
+                        */
+                       MUTEX_ASSERT_NOT_OWNED(m);
+                       MUTEX_DESTROY(m);
+               }
+       }
+
+       /* Return the completion status: */
+       return (ret);
+}
+
+static int
+mutex_trylock_common(struct pthread *curthread, pthread_mutex_t *mutex)
+{
+       int ret = 0;
+
+       THR_ASSERT((mutex != NULL) && (*mutex != NULL),
+           "Uninitialized mutex in mutex_trylock_common");
+
+       /* Short cut for simple mutex. */
+       if ((*mutex)->m_protocol == PTHREAD_PRIO_NONE) {
+               ret = THR_UMTX_TRYLOCK(curthread, &(*mutex)->m_lock);
+               if (ret == 0) {
+                       (*mutex)->m_owner = curthread;
+                       /* Add to the list of owned mutexes: */
+                       MUTEX_ASSERT_NOT_OWNED(*mutex);
+                       TAILQ_INSERT_TAIL(&curthread->mutexq,
+                           (*mutex), m_qe);
+               } else if ((*mutex)->m_owner == curthread) {
+                       ret = mutex_self_trylock(curthread, *mutex);
+               } /* else {} */
+
+               return (ret);
+       }
+
+       /* Code for priority mutex */
+
+       /* Lock the mutex structure: */
+       THR_LOCK_ACQUIRE(curthread, &(*mutex)->m_lock);
+
+       /*
+        * If the mutex was statically allocated, properly
+        * initialize the tail queue.
+        */
+       if (((*mutex)->m_flags & MUTEX_FLAGS_INITED) == 0) {
+               TAILQ_INIT(&(*mutex)->m_queue);
+               MUTEX_INIT_LINK(*mutex);
+               (*mutex)->m_flags |= MUTEX_FLAGS_INITED;
+       }
+
+       /* Process according to mutex type: */
+       switch ((*mutex)->m_protocol) {
+       /* POSIX priority inheritence mutex: */
+       case PTHREAD_PRIO_INHERIT:
+               /* Check if this mutex is not locked: */
+               if ((*mutex)->m_owner == NULL) {
+                       /* Lock the mutex for the running thread: */
+                       (*mutex)->m_owner = curthread;
+
+                       THR_LOCK(curthread);
+                       /* Track number of priority mutexes owned: */
+                       curthread->priority_mutex_count++;
+
+                       /*
+                        * The mutex takes on the attributes of the
+                        * running thread when there are no waiters.
+                        */
+                       (*mutex)->m_prio = curthread->active_priority;
+                       (*mutex)->m_saved_prio =
+                           curthread->inherited_priority;
+                       curthread->inherited_priority = (*mutex)->m_prio;
+                       THR_UNLOCK(curthread);
+
+                       /* Add to the list of owned mutexes: */
+                       MUTEX_ASSERT_NOT_OWNED(*mutex);
+                       TAILQ_INSERT_TAIL(&curthread->pri_mutexq,
+                           (*mutex), m_qe);
+               } else if ((*mutex)->m_owner == curthread)
+                       ret = mutex_self_trylock(curthread, *mutex);
+               else
+                       /* Return a busy error: */
+                       ret = EBUSY;
+               break;
+
+       /* POSIX priority protection mutex: */
+       case PTHREAD_PRIO_PROTECT:
+               /* Check for a priority ceiling violation: */
+               if (curthread->active_priority > (*mutex)->m_prio)
+                       ret = EINVAL;
+
+               /* Check if this mutex is not locked: */
+               else if ((*mutex)->m_owner == NULL) {
+                       /* Lock the mutex for the running thread: */
+                       (*mutex)->m_owner = curthread;
+
+                       THR_LOCK(curthread);
+                       /* Track number of priority mutexes owned: */
+                       curthread->priority_mutex_count++;
+
+                       /*
+                        * The running thread inherits the ceiling
+                        * priority of the mutex and executes at that
+                        * priority.
+                        */
+                       curthread->active_priority = (*mutex)->m_prio;
+                       (*mutex)->m_saved_prio =
+                           curthread->inherited_priority;
+                       curthread->inherited_priority =
+                           (*mutex)->m_prio;
+                       THR_UNLOCK(curthread);
+                       /* Add to the list of owned mutexes: */
+                       MUTEX_ASSERT_NOT_OWNED(*mutex);
+                       TAILQ_INSERT_TAIL(&curthread->pri_mutexq,
+                           (*mutex), m_qe);
+               } else if ((*mutex)->m_owner == curthread)
+                       ret = mutex_self_trylock(curthread, *mutex);
+               else
+                       /* Return a busy error: */
+                       ret = EBUSY;
+               break;
+
+       /* Trap invalid mutex types: */
+       default:
+               /* Return an invalid argument error: */
+               ret = EINVAL;
+               break;
+       }
+
+       /* Unlock the mutex structure: */
+       THR_LOCK_RELEASE(curthread, &(*mutex)->m_lock);
+
+       /* Return the completion status: */
+       return (ret);
+}
+
+int
+__pthread_mutex_trylock(pthread_mutex_t *mutex)
+{
+       struct pthread *curthread = _get_curthread();
+       int ret = 0;
+
+       /*
+        * If the mutex is statically initialized, perform the dynamic
+        * initialization:
+        */
+       if ((*mutex != NULL) ||
+           ((ret = init_static(curthread, mutex)) == 0))
+               ret = mutex_trylock_common(curthread, mutex);
+
+       return (ret);
+}
+
+int
+_pthread_mutex_trylock(pthread_mutex_t *mutex)
+{
+       struct pthread  *curthread = _get_curthread();
+       int     ret = 0;
+
+       /*
+        * If the mutex is statically initialized, perform the dynamic
+        * initialization marking the mutex private (delete safe):
+        */
+       if ((*mutex != NULL) ||
+           ((ret = init_static_private(curthread, mutex)) == 0))
+               ret = mutex_trylock_common(curthread, mutex);
+
+       return (ret);
+}
+
+static int
+mutex_lock_common(struct pthread *curthread, pthread_mutex_t *m,
+       const struct timespec * abstime)
+{
+       struct  timespec ts, ts2;
+       long    cycle;
+       int     ret = 0;
+
+       THR_ASSERT((m != NULL) && (*m != NULL),
+           "Uninitialized mutex in mutex_lock_common");
+
+       if (abstime != NULL && (abstime->tv_sec < 0 || abstime->tv_nsec < 0 ||
+           abstime->tv_nsec >= 1000000000))
+               return (EINVAL);
+
+       /* Short cut for simple mutex. */
+
+       if ((*m)->m_protocol == PTHREAD_PRIO_NONE) {
+               /* Default POSIX 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(curthread, *m, abstime);
+               } else {
+                       if (abstime == NULL) {
+                               THR_UMTX_LOCK(curthread, &(*m)->m_lock);
+                               ret = 0;
+                       } 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);
+       }
+
+       /* Code for priority mutex */
+
+       /*
+        * Enter a loop waiting to become the mutex owner.  We need a
+        * loop in case the waiting thread is interrupted by a signal
+        * to execute a signal handler.  It is not (currently) possible
+        * to remain in the waiting queue while running a handler.
+        * Instead, the thread is interrupted and backed out of the
+        * waiting queue prior to executing the signal handler.
+        */
+       do {
+               /* Lock the mutex structure: */
+               THR_LOCK_ACQUIRE(curthread, &(*m)->m_lock);
+
+               /*
+                * If the mutex was statically allocated, properly
+                * initialize the tail queue.
+                */
+               if (((*m)->m_flags & MUTEX_FLAGS_INITED) == 0) {
+                       TAILQ_INIT(&(*m)->m_queue);
+                       (*m)->m_flags |= MUTEX_FLAGS_INITED;
+                       MUTEX_INIT_LINK(*m);
+               }
+
+               /* Process according to mutex type: */
+               switch ((*m)->m_protocol) {
+               /* POSIX priority inheritence mutex: */
+               case PTHREAD_PRIO_INHERIT:
+                       /* Check if this mutex is not locked: */
+                       if ((*m)->m_owner == NULL) {
+                               /* Lock the mutex for this thread: */
+                               (*m)->m_owner = curthread;
+
+                               THR_LOCK(curthread);
+                               /* Track number of priority mutexes owned: */
+                               curthread->priority_mutex_count++;
+
+                               /*
+                                * The mutex takes on attributes of the
+                                * running thread when there are no waiters.
+                                * Make sure the thread's scheduling lock is
+                                * held while priorities are adjusted.
+                                */
+                               (*m)->m_prio = curthread->active_priority;
+                               (*m)->m_saved_prio =
+                                   curthread->inherited_priority;
+                               curthread->inherited_priority = (*m)->m_prio;
+                               THR_UNLOCK(curthread);
+
+                               /* Add to the list of owned mutexes: */
+                               MUTEX_ASSERT_NOT_OWNED(*m);
+                               TAILQ_INSERT_TAIL(&curthread->pri_mutexq,
+                                   (*m), m_qe);
+
+                               /* Unlock the mutex structure: */
+                               THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
+                       } else if ((*m)->m_owner == curthread) {
+                               ret = mutex_self_lock(curthread, *m, abstime);
+
+                               /* Unlock the mutex structure: */
+                               THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
+                       } else {
+                               /*
+                                * Join the queue of threads waiting to lock
+                                * the mutex and save a pointer to the mutex.
+                                */
+                               mutex_queue_enq(*m, curthread);
+                               curthread->data.mutex = *m;
+
+                               if (curthread->active_priority > (*m)->m_prio)
+                                       /* Adjust priorities: */
+                                       mutex_priority_adjust(curthread, *m);
+
+                               THR_LOCK(curthread);
+                               cycle = curthread->cycle;
+                               THR_UNLOCK(curthread);
+
+                               /* Unlock the mutex structure: */
+                               THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
+
+                               clock_gettime(CLOCK_REALTIME, &ts);
+                               TIMESPEC_SUB(&ts2, abstime, &ts);
+                               ret = _thr_umtx_wait(&curthread->cycle, cycle,
+                                        &ts2);
+                               if (ret == EINTR)
+                                       ret = 0;
+
+                               if (THR_IN_MUTEXQ(curthread)) {
+                                       THR_LOCK_ACQUIRE(curthread, &(*m)->m_lock);
+                                       mutex_queue_remove(*m, curthread);
+                                       THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
+                               }
+                               /*
+                                * Only clear these after assuring the
+                                * thread is dequeued.
+                                */
+                               curthread->data.mutex = NULL;
+                       }
+                       break;
+
+               /* POSIX priority protection mutex: */
+               case PTHREAD_PRIO_PROTECT:
+                       /* Check for a priority ceiling violation: */
+                       if (curthread->active_priority > (*m)->m_prio) {
+                               /* Unlock the mutex structure: */
+                               THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
+                               ret = EINVAL;
+                       }
+                       /* Check if this mutex is not locked: */
+                       else if ((*m)->m_owner == NULL) {
+                               /*
+                                * Lock the mutex for the running
+                                * thread:
+                                */
+                               (*m)->m_owner = curthread;
+
+                               THR_LOCK(curthread);
+                               /* Track number of priority mutexes owned: */
+                               curthread->priority_mutex_count++;
+
+                               /*
+                                * The running thread inherits the ceiling
+                                * priority of the mutex and executes at that
+                                * priority.  Make sure the thread's
+                                * scheduling lock is held while priorities
+                                * are adjusted.
+                                */
+                               curthread->active_priority = (*m)->m_prio;
+                               (*m)->m_saved_prio =
+                                   curthread->inherited_priority;
+                               curthread->inherited_priority = (*m)->m_prio;
+                               THR_UNLOCK(curthread);
+
+                               /* Add to the list of owned mutexes: */
+                               MUTEX_ASSERT_NOT_OWNED(*m);
+                               TAILQ_INSERT_TAIL(&curthread->pri_mutexq,
+                                   (*m), m_qe);
+
+                               /* Unlock the mutex structure: */
+                               THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
+                       } else if ((*m)->m_owner == curthread) {
+                               ret = mutex_self_lock(curthread, *m, abstime);
+
+                               /* Unlock the mutex structure: */
+                               THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
+                       } else {
+                               /*
+                                * Join the queue of threads waiting to lock
+                                * the mutex and save a pointer to the mutex.
+                                */
+                               mutex_queue_enq(*m, curthread);
+                               curthread->data.mutex = *m;
+
+                               /* Clear any previous error: */
+                               curthread->error = 0;
+
+                               THR_LOCK(curthread);
+                               cycle = curthread->cycle;
+                               THR_UNLOCK(curthread);
+
+                               /* Unlock the mutex structure: */
+                               THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
+
+                               clock_gettime(CLOCK_REALTIME, &ts);
+                               TIMESPEC_SUB(&ts2, abstime, &ts);
+                               ret = _thr_umtx_wait(&curthread->cycle, cycle,
+                                       &ts2);
+                               if (ret == EINTR)
+                                       ret = 0;
+
+                               curthread->data.mutex = NULL;
+                               if (THR_IN_MUTEXQ(curthread)) {
+                                       THR_LOCK_ACQUIRE(curthread, &(*m)->m_lock);
+                                       mutex_queue_remove(*m, curthread);
+                                       THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
+                               }
+                               /*
+                                * Only clear these after assuring the
+                                * thread is dequeued.
+                                */
+                               curthread->data.mutex = NULL;
+
+                               /*
+                                * The threads priority may have changed while
+                                * waiting for the mutex causing a ceiling
+                                * violation.
+                                */
+                               ret = curthread->error;
+                               curthread->error = 0;
+                       }
+                       break;
+
+               /* Trap invalid mutex types: */
+               default:
+                       /* Unlock the mutex structure: */
+                       THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
+
+                       /* Return an invalid argument error: */
+                       ret = EINVAL;
+                       break;
+               }
+
+       } while (((*m)->m_owner != curthread) && (ret == 0));
+
+       /* Return the completion status: */
+       return (ret);
+}
+
+int
+__pthread_mutex_lock(pthread_mutex_t *m)
+{
+       struct pthread *curthread;
+       int     ret = 0;
+
+       _thr_check_init();
+
+       curthread = _get_curthread();
+
+       /*
+        * If the mutex is statically initialized, perform the dynamic
+        * initialization:
+        */
+       if ((*m != NULL) || ((ret = init_static(curthread, m)) == 0))
+               ret = mutex_lock_common(curthread, m, NULL);
+
+       return (ret);
+}
+
+__strong_reference(__pthread_mutex_lock, _thr_mutex_lock);
+
+int
+_pthread_mutex_lock(pthread_mutex_t *m)
+{
+       struct pthread *curthread;
+       int     ret = 0;
+
+       _thr_check_init();
+
+       curthread = _get_curthread();
+
+       /*
+        * If the mutex is statically initialized, perform the dynamic
+        * initialization marking it private (delete safe):
+        */
+       if ((*m != NULL) ||
+           ((ret = init_static_private(curthread, m)) == 0))
+               ret = mutex_lock_common(curthread, m, NULL);
+
+       return (ret);
+}
+
+int
+__pthread_mutex_timedlock(pthread_mutex_t *m,
+       const struct timespec *abs_timeout)
+{
+       struct pthread *curthread;
+       int     ret = 0;
+
+       _thr_check_init();
+
+       curthread = _get_curthread();
+
+       /*
+        * If the mutex is statically initialized, perform the dynamic
+        * initialization:
+        */
+       if ((*m != NULL) || ((ret = init_static(curthread, m)) == 0))
+               ret = mutex_lock_common(curthread, m, abs_timeout);
+
+       return (ret);
+}
+
+int
+_pthread_mutex_timedlock(pthread_mutex_t *m,
+       const struct timespec *abs_timeout)
+{
+       struct pthread *curthread;
+       int     ret = 0;
+
+       _thr_check_init();
+
+       curthread = _get_curthread();
+
+       /*
+        * If the mutex is statically initialized, perform the dynamic
+        * initialization marking it private (delete safe):
+        */
+       if ((*m != NULL) ||
+           ((ret = init_static_private(curthread, m)) == 0))
+               ret = mutex_lock_common(curthread, m, abs_timeout);
+
+       return (ret);
+}
+
+int
+_pthread_mutex_unlock(pthread_mutex_t *m)
+{
+       return (mutex_unlock_common(m, /* add reference */ 0));
+}
+
+__strong_reference(_pthread_mutex_unlock, _thr_mutex_unlock);
+
+int
+_mutex_cv_unlock(pthread_mutex_t *m)
+{
+       return (mutex_unlock_common(m, /* add reference */ 1));
+}
+
+int
+_mutex_cv_lock(pthread_mutex_t *m)
+{
+       struct  pthread *curthread;
+       int     ret;
+
+       curthread = _get_curthread();
+       if ((ret = _pthread_mutex_lock(m)) == 0)
+               (*m)->m_refcount--;
+       return (ret);
+}
+
+static int
+mutex_self_trylock(struct pthread *curthread, pthread_mutex_t m)
+{
+       int     ret;
+
+       switch (m->m_type) {
+       /* case PTHREAD_MUTEX_DEFAULT: */
+       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(struct pthread *curthread, pthread_mutex_t m,
+       const struct timespec *abstime)
+{
+       struct timespec ts1, ts2;
+       int ret;
+
+       switch (m->m_type) {
+       /* case PTHREAD_MUTEX_DEFAULT: */
+       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 (m->m_protocol != PTHREAD_PRIO_NONE) {
+                       /* Unlock the mutex structure: */
+                       THR_LOCK_RELEASE(curthread, &m->m_lock);
+               }
+               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 *m, int add_reference)
+{
+       struct pthread *curthread = _get_curthread();
+       long tid = -1;
+       int ret = 0;
+
+       if (m == NULL || *m == NULL)
+               ret = EINVAL;
+       else {
+               /* Short cut for simple mutex. */
+
+               if ((*m)->m_protocol == PTHREAD_PRIO_NONE) {
+                       /*
+                        * Check if the running thread is not the owner of the
+                        * mutex:
+                        */
+                       if (__predict_false((*m)->m_owner != curthread)) {
+                               ret = EPERM;
+                       } else if (__predict_false(
+                                 (*m)->m_type == PTHREAD_MUTEX_RECURSIVE &&
+                                 (*m)->m_count > 0)) {
+                               /* Decrement the count: */
+                               (*m)->m_count--;
+                               if (add_reference)
+                                       (*m)->m_refcount++;
+                       } else {
+                               /*
+                                * Clear the count in case this is a recursive
+                                * mutex.
+                                */
+                               (*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);
+                               if (add_reference)
+                                       (*m)->m_refcount++;
+                               /*
+                                * Hand off the mutex to the next waiting
+                                * thread.
+                                */
+                               _thr_umtx_unlock(&(*m)->m_lock, curthread->tid);
+                       }
+                       return (ret);
+               }
+
+               /* Code for priority mutex */
+
+               /* Lock the mutex structure: */
+               THR_LOCK_ACQUIRE(curthread, &(*m)->m_lock);
+
+               /* Process according to mutex type: */
+               switch ((*m)->m_protocol) {
+               /* POSIX priority inheritence mutex: */
+               case PTHREAD_PRIO_INHERIT:
+                       /*
+                        * Check if the running thread is not the owner of the
+                        * mutex:
+                        */
+                       if ((*m)->m_owner != curthread)
+                               ret = EPERM;
+                       else if (((*m)->m_type == PTHREAD_MUTEX_RECURSIVE) &&
+                           ((*m)->m_count > 0))
+                               /* Decrement the count: */
+                               (*m)->m_count--;
+                       else {
+                               /*
+                                * Clear the count in case this is recursive
+                                * mutex.
+                                */
+                               (*m)->m_count = 0;
+
+                               /*
+                                * Restore the threads inherited priority and
+                                * recompute the active priority (being careful
+                                * not to override changes in the threads base
+                                * priority subsequent to locking the mutex).
+                                */
+                               THR_LOCK(curthread);
+                               curthread->inherited_priority =
+                                       (*m)->m_saved_prio;
+                               curthread->active_priority =
+                                   MAX(curthread->inherited_priority,
+                                   curthread->base_priority);
+
+                               /*
+                                * This thread now owns one less priority mutex.
+                                */
+                               curthread->priority_mutex_count--;
+                               THR_UNLOCK(curthread);
+
+                               /* Remove the mutex from the threads queue. */
+                               MUTEX_ASSERT_IS_OWNED(*m);
+                               TAILQ_REMOVE(&(*m)->m_owner->pri_mutexq,
+                                   (*m), m_qe);
+                               MUTEX_INIT_LINK(*m);
+
+                               /*
+                                * Hand off the mutex to the next waiting
+                                * thread:
+                                */
+                               tid = mutex_handoff(curthread, *m);
+                       }
+                       break;
+
+               /* POSIX priority ceiling mutex: */
+               case PTHREAD_PRIO_PROTECT:
+                       /*
+                        * Check if the running thread is not the owner of the
+                        * mutex:
+                        */
+                       if ((*m)->m_owner != curthread)
+                               ret = EPERM;
+                       else if (((*m)->m_type == PTHREAD_MUTEX_RECURSIVE) &&
+                           ((*m)->m_count > 0))
+                               /* Decrement the count: */
+                               (*m)->m_count--;
+                       else {
+                               /*
+                                * Clear the count in case this is a recursive
+                                * mutex.
+                                */
+                               (*m)->m_count = 0;
+
+                               /*
+                                * Restore the threads inherited priority and
+                                * recompute the active priority (being careful
+                                * not to override changes in the threads base
+                                * priority subsequent to locking the mutex).
+                                */
+                               THR_LOCK(curthread);
+                               curthread->inherited_priority =
+                                       (*m)->m_saved_prio;
+                               curthread->active_priority =
+                                   MAX(curthread->inherited_priority,
+                                   curthread->base_priority);
+
+                               /*
+                                * This thread now owns one less priority mutex.
+                                */
+                               curthread->priority_mutex_count--;
+                               THR_UNLOCK(curthread);
+
+                               /* Remove the mutex from the threads queue. */
+                               MUTEX_ASSERT_IS_OWNED(*m);
+                               TAILQ_REMOVE(&(*m)->m_owner->pri_mutexq,
+                                   (*m), m_qe);
+                               MUTEX_INIT_LINK(*m);
+
+                               /*
+                                * Hand off the mutex to the next waiting
+                                * thread:
+                                */
+                               tid = mutex_handoff(curthread, *m);
+                       }
+                       break;
+
+               /* Trap invalid mutex types: */
+               default:
+                       /* Return an invalid argument error: */
+                       ret = EINVAL;
+                       break;
+               }
+
+               if ((ret == 0) && (add_reference != 0))
+                       /* Increment the reference count: */
+                       (*m)->m_refcount++;
+
+               /* Unlock the mutex structure: */
+               THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
+       }
+
+       /* Return the completion status: */
+       return (ret);
+}
+
+
+/*
+ * This function is called when a change in base priority occurs for
+ * a thread that is holding or waiting for a priority protection or
+ * inheritence mutex.  A change in a threads base priority can effect
+ * changes to active priorities of other threads and to the ordering
+ * of mutex locking by waiting threads.
+ *
+ * This must be called without the target thread's scheduling lock held.
+ */
+void
+_mutex_notify_priochange(struct pthread *curthread, struct pthread *pthread,
+    int propagate_prio)
+{
+       struct pthread_mutex *m;
+
+       /* Adjust the priorites of any owned priority mutexes: */
+       if (pthread->priority_mutex_count > 0) {
+               /*
+                * Rescan the mutexes owned by this thread and correct
+                * their priorities to account for this threads change
+                * in priority.  This has the side effect of changing
+                * the threads active priority.
+                *
+                * Be sure to lock the first mutex in the list of owned
+                * mutexes.  This acts as a barrier against another
+                * simultaneous call to change the threads priority
+                * and from the owning thread releasing the mutex.
+                */
+               m = TAILQ_FIRST(&pthread->pri_mutexq);
+               if (m != NULL) {
+                       THR_LOCK_ACQUIRE(curthread, &m->m_lock);
+                       /*
+                        * Make sure the thread still owns the lock.
+                        */
+                       if (m == TAILQ_FIRST(&pthread->pri_mutexq))
+                               mutex_rescan_owned(curthread, pthread,
+                                   /* rescan all owned */ NULL);
+                       THR_LOCK_RELEASE(curthread, &m->m_lock);
+               }
+       }
+
+       /*
+        * If this thread is waiting on a priority inheritence mutex,
+        * check for priority adjustments.  A change in priority can
+        * also cause a ceiling violation(*) for a thread waiting on
+        * a priority protection mutex; we don't perform the check here
+        * as it is done in pthread_mutex_unlock.
+        *
+        * (*) It should be noted that a priority change to a thread
+        *     _after_ taking and owning a priority ceiling mutex
+        *     does not affect ownership of that mutex; the ceiling
+        *     priority is only checked before mutex ownership occurs.
+        */
+       if (propagate_prio != 0) {
+               /*
+                * Lock the thread's scheduling queue.  This is a bit
+                * convoluted; the "in synchronization queue flag" can
+                * only be cleared with both the thread's scheduling and
+                * mutex locks held.  The thread's pointer to the wanted
+                * mutex is guaranteed to be valid during this time.
+                */
+               THR_THREAD_LOCK(curthread, pthread);
+
+               if (((pthread->sflags & THR_FLAGS_IN_SYNCQ) == 0) ||
+                   ((m = pthread->data.mutex) == NULL))
+                       THR_THREAD_UNLOCK(curthread, pthread);
+               else {
+                       /*
+                        * This thread is currently waiting on a mutex; unlock
+                        * the scheduling queue lock and lock the mutex.  We
+                        * can't hold both at the same time because the locking
+                        * order could cause a deadlock.
+                        */
+                       THR_THREAD_UNLOCK(curthread, pthread);
+                       THR_LOCK_ACQUIRE(curthread, &m->m_lock);
+
+                       /*
+                        * Check to make sure this thread is still in the
+                        * same state (the lock above can yield the CPU to
+                        * another thread or the thread may be running on
+                        * another CPU).
+                        */
+                       if (((pthread->sflags & THR_FLAGS_IN_SYNCQ) != 0) &&
+                           (pthread->data.mutex == m)) {
+                               /*
+                                * Remove and reinsert this thread into
+                                * the list of waiting threads to preserve
+                                * decreasing priority order.
+                                */
+                               mutex_queue_remove(m, pthread);
+                               mutex_queue_enq(m, pthread);
+
+                               if (m->m_protocol == PTHREAD_PRIO_INHERIT)
+                                       /* Adjust priorities: */
+                                       mutex_priority_adjust(curthread, m);
+                       }
+
+                       /* Unlock the mutex structure: */
+                       THR_LOCK_RELEASE(curthread, &m->m_lock);
+               }
+       }
+}
+
+/*
+ * Called when a new thread is added to the mutex waiting queue or
+ * when a threads priority changes that is already in the mutex
+ * waiting queue.
+ *
+ * This must be called with the mutex locked by the current thread.
+ */
+static void
+mutex_priority_adjust(struct pthread *curthread, pthread_mutex_t mutex)
+{
+       pthread_mutex_t m = mutex;
+       struct pthread  *pthread_next, *pthread = mutex->m_owner;
+       int             done, temp_prio;
+
+       /*
+        * Calculate the mutex priority as the maximum of the highest
+        * active priority of any waiting threads and the owning threads
+        * active priority(*).
+        *
+        * (*) Because the owning threads current active priority may
+        *     reflect priority inherited from this mutex (and the mutex
+        *     priority may have changed) we must recalculate the active
+        *     priority based on the threads saved inherited priority
+        *     and its base priority.
+        */
+       pthread_next = TAILQ_FIRST(&m->m_queue);  /* should never be NULL */
+       temp_prio = MAX(pthread_next->active_priority,
+           MAX(m->m_saved_prio, pthread->base_priority));
+
+       /* See if this mutex really needs adjusting: */
+       if (temp_prio == m->m_prio)
+               /* No need to propagate the priority: */
+               return;
+
+       /* Set new priority of the mutex: */
+       m->m_prio = temp_prio;
+
+       /*
+        * Don't unlock the mutex passed in as an argument.  It is
+        * expected to be locked and unlocked by the caller.
+        */
+       done = 1;
+       do {
+               /*
+                * Save the threads priority before rescanning the
+                * owned mutexes:
+                */
+               temp_prio = pthread->active_priority;
+
+               /*
+                * Fix the priorities for all mutexes held by the owning
+                * thread since taking this mutex.  This also has a
+                * potential side-effect of changing the threads priority.
+                *
+                * At this point the mutex is locked by the current thread.
+                * The owning thread can't release the mutex until it is
+                * unlocked, so we should be able to safely walk its list
+                * of owned mutexes.
+                */
+               mutex_rescan_owned(curthread, pthread, m);
+
+               /*
+                * If this isn't the first time through the loop,
+                * the current mutex needs to be unlocked.
+                */
+               if (done == 0)
+                       THR_LOCK_RELEASE(curthread, &m->m_lock);
+
+               /* Assume we're done unless told otherwise: */
+               done = 1;
+
+               /*
+                * If the thread is currently waiting on a mutex, check
+                * to see if the threads new priority has affected the
+                * priority of the mutex.
+                */
+               if ((temp_prio != pthread->active_priority) &&
+                   ((pthread->sflags & THR_FLAGS_IN_SYNCQ) != 0) &&
+                   ((m = pthread->data.mutex) != NULL) &&
+                   (m->m_protocol == PTHREAD_PRIO_INHERIT)) {
+                       /* Lock the mutex structure: */
+                       THR_LOCK_ACQUIRE(curthread, &m->m_lock);
+
+                       /*
+                        * Make sure the thread is still waiting on the
+                        * mutex:
+                        */
+                       if (((pthread->sflags & THR_FLAGS_IN_SYNCQ) != 0) &&
+                           (m == pthread->data.mutex)) {
+                               /*
+                                * The priority for this thread has changed.
+                                * Remove and reinsert this thread into the
+                                * list of waiting threads to preserve
+                                * decreasing priority order.
+                                */
+                               mutex_queue_remove(m, pthread);
+                               mutex_queue_enq(m, pthread);
+
+                               /*
+                                * Grab the waiting thread with highest
+                                * priority:
+                                */
+                               pthread_next = TAILQ_FIRST(&m->m_queue);
+
+                               /*
+                                * Calculate the mutex priority as the maximum
+                                * of the highest active priority of any
+                                * waiting threads and the owning threads
+                                * active priority.
+                                */
+                               temp_prio = MAX(pthread_next->active_priority,
+                                   MAX(m->m_saved_prio,
+                                   m->m_owner->base_priority));
+
+                               if (temp_prio != m->m_prio) {
+                                       /*
+                                        * The priority needs to be propagated
+                                        * to the mutex this thread is waiting
+                                        * on and up to the owner of that mutex.
+                                        */
+                                       m->m_prio = temp_prio;
+                                       pthread = m->m_owner;
+
+                                       /* We're not done yet: */
+                                       done = 0;
+                               }
+                       }
+                       /* Only release the mutex if we're done: */
+                       if (done != 0)
+                               THR_LOCK_RELEASE(curthread, &m->m_lock);
+               }
+       } while (done == 0);
+}
+
+static void
+mutex_rescan_owned(struct pthread *curthread, struct pthread *pthread,
+    struct pthread_mutex *mutex)
+{
+       struct pthread_mutex    *m;
+       struct pthread          *pthread_next;
+       int                     active_prio, inherited_prio;
+
+       /*
+        * Start walking the mutexes the thread has taken since
+        * taking this mutex.
+        */
+       if (mutex == NULL) {
+               /*
+                * A null mutex means start at the beginning of the owned
+                * mutex list.
+                */
+               m = TAILQ_FIRST(&pthread->pri_mutexq);
+
+               /* There is no inherited priority yet. */
+               inherited_prio = 0;
+       } else {
+               /*
+                * The caller wants to start after a specific mutex.  It
+                * is assumed that this mutex is a priority inheritence
+                * mutex and that its priority has been correctly
+                * calculated.
+                */
+               m = TAILQ_NEXT(mutex, m_qe);
+
+               /* Start inheriting priority from the specified mutex. */
+               inherited_prio = mutex->m_prio;
+       }
+       active_prio = MAX(inherited_prio, pthread->base_priority);
+
+       for (; m != NULL; m = TAILQ_NEXT(m, m_qe)) {
+               /*
+                * We only want to deal with priority inheritence
+                * mutexes.  This might be optimized by only placing
+                * priority inheritence mutexes into the owned mutex
+                * list, but it may prove to be useful having all
+                * owned mutexes in this list.  Consider a thread
+                * exiting while holding mutexes...
+                */
+               if (m->m_protocol == PTHREAD_PRIO_INHERIT) {
+                       /*
+                        * Fix the owners saved (inherited) priority to
+                        * reflect the priority of the previous mutex.
+                        */
+                       m->m_saved_prio = inherited_prio;
+
+                       if ((pthread_next = TAILQ_FIRST(&m->m_queue)) != NULL)
+                               /* Recalculate the priority of the mutex: */
+                               m->m_prio = MAX(active_prio,
+                                    pthread_next->active_priority);
+                       else
+                               m->m_prio = active_prio;
+
+                       /* Recalculate new inherited and active priorities: */
+                       inherited_prio = m->m_prio;
+                       active_prio = MAX(m->m_prio, pthread->base_priority);
+               }
+       }
+
+       /*
+        * Fix the threads inherited priority and recalculate its
+        * active priority.
+        */
+       pthread->inherited_priority = inherited_prio;
+       active_prio = MAX(inherited_prio, pthread->base_priority);
+
+       if (active_prio != pthread->active_priority) {
+               /* Lock the thread's scheduling queue: */
+               THR_THREAD_LOCK(curthread, pthread);
+
+               /* if ((pthread->flags & THR_FLAGS_IN_RUNQ) == 0) */
+               if (1) {
+                       /*
+                        * This thread is not in a run queue.  Just set
+                        * its active priority.
+                        */
+                       pthread->active_priority = active_prio;
+               }
+               else {
+                       /*
+                        * This thread is in a run queue.  Remove it from
+                        * the queue before changing its priority:
+                        */
+                       /* THR_RUNQ_REMOVE(pthread);*/
+                       /*
+                        * POSIX states that if the priority is being
+                        * lowered, the thread must be inserted at the
+                        * head of the queue for its priority if it owns
+                        * any priority protection or inheritence mutexes.
+                        */
+                       if ((active_prio < pthread->active_priority) &&
+                           (pthread->priority_mutex_count > 0)) {
+                               /* Set the new active priority. */
+                               pthread->active_priority = active_prio;
+                               /* THR_RUNQ_INSERT_HEAD(pthread); */
+                       } else {
+                               /* Set the new active priority. */
+                               pthread->active_priority = active_prio;
+                               /* THR_RUNQ_INSERT_TAIL(pthread);*/
+                       }
+               }
+               THR_THREAD_UNLOCK(curthread, pthread);
+       }
+}
+
+void
+_mutex_unlock_private(pthread_t pthread)
+{
+       struct pthread_mutex    *m, *m_next;
+
+       for (m = TAILQ_FIRST(&pthread->pri_mutexq); m != NULL; m = m_next) {
+               m_next = TAILQ_NEXT(m, m_qe);
+               if ((m->m_flags & MUTEX_FLAGS_PRIVATE) != 0)
+                       pthread_mutex_unlock(&m);
+       }
+}
+
+/*
+ * Dequeue a waiting thread from the head of a mutex queue in descending
+ * priority order.
+ *
+ * In order to properly dequeue a thread from the mutex queue and
+ * make it runnable without the possibility of errant wakeups, it
+ * is necessary to lock the thread's scheduling queue while also
+ * holding the mutex lock.
+ */
+static long
+mutex_handoff(struct pthread *curthread, struct pthread_mutex *mutex)
+{
+       struct pthread *pthread;
+       long tid = -1;
+
+       /* Keep dequeueing until we find a valid thread: */
+       mutex->m_owner = NULL;
+       pthread = TAILQ_FIRST(&mutex->m_queue);
+       while (pthread != NULL) {
+               /* Take the thread's scheduling lock: */
+               THR_THREAD_LOCK(curthread, pthread);
+
+               /* Remove the thread from the mutex queue: */
+               TAILQ_REMOVE(&mutex->m_queue, pthread, sqe);
+               pthread->sflags &= ~THR_FLAGS_IN_SYNCQ;
+
+               /*
+                * Only exit the loop if the thread hasn't been
+                * cancelled.
+                */
+               switch (mutex->m_protocol) {
+               case PTHREAD_PRIO_NONE:
+                       /*
+                        * Assign the new owner and add the mutex to the
+                        * thread's list of owned mutexes.
+                        */
+                       mutex->m_owner = pthread;
+                       TAILQ_INSERT_TAIL(&pthread->pri_mutexq, mutex, m_qe);
+                       break;
+
+               case PTHREAD_PRIO_INHERIT:
+                       /*
+                        * Assign the new owner and add the mutex to the
+                        * thread's list of owned mutexes.
+                        */
+                       mutex->m_owner = pthread;
+                       TAILQ_INSERT_TAIL(&pthread->pri_mutexq, mutex, m_qe);
+
+                       /* Track number of priority mutexes owned: */
+                       pthread->priority_mutex_count++;
+
+                       /*
+                        * Set the priority of the mutex.  Since our waiting
+                        * threads are in descending priority order, the
+                        * priority of the mutex becomes the active priority
+                        * of the thread we just dequeued.
+                        */
+                       mutex->m_prio = pthread->active_priority;
+
+                       /* Save the owning threads inherited priority: */
+                       mutex->m_saved_prio = pthread->inherited_priority;
+
+                       /*
+                        * The owning threads inherited priority now becomes
+                        * his active priority (the priority of the mutex).
+                        */
+                       pthread->inherited_priority = mutex->m_prio;
+                       break;
+
+               case PTHREAD_PRIO_PROTECT:
+                       if (pthread->active_priority > mutex->m_prio) {
+                               /*
+                                * Either the mutex ceiling priority has
+                                * been lowered and/or this threads priority
+                                * has been raised subsequent to the thread
+                                * being queued on the waiting list.
+                                */
+                               pthread->error = EINVAL;
+                       }
+                       else {
+                               /*
+                                * Assign the new owner and add the mutex
+                                * to the thread's list of owned mutexes.
+                                */
+                               mutex->m_owner = pthread;
+                               TAILQ_INSERT_TAIL(&pthread->pri_mutexq,
+                                   mutex, m_qe);
+
+                               /* Track number of priority mutexes owned: */
+                               pthread->priority_mutex_count++;
+
+                               /*
+                                * Save the owning threads inherited
+                                * priority:
+                                */
+                               mutex->m_saved_prio =
+                                   pthread->inherited_priority;
+
+                               /*
+                                * The owning thread inherits the ceiling
+                                * priority of the mutex and executes at
+                                * that priority:
+                                */
+                               pthread->inherited_priority = mutex->m_prio;
+                               pthread->active_priority = mutex->m_prio;
+
+                       }
+                       break;
+               }
+
+               /* Make the thread runnable and unlock the scheduling queue: */
+               pthread->cycle++;
+               _thr_umtx_wake(&pthread->cycle, 1);
+
+               THR_THREAD_UNLOCK(curthread, pthread);
+               if (mutex->m_owner == pthread)
+                       /* We're done; a valid owner was found. */
+                       break;
+               else
+                       /* Get the next thread from the waiting queue: */
+                       pthread = TAILQ_NEXT(pthread, sqe);
+       }
+
+       if ((pthread == NULL) && (mutex->m_protocol == PTHREAD_PRIO_INHERIT))
+               /* This mutex has no priority: */
+               mutex->m_prio = 0;
+       return (tid);
+}
+
+#if 0
+/*
+ * Dequeue a waiting thread from the head of a mutex queue in descending
+ * priority order.
+ */
+static pthread_t
+mutex_queue_deq(struct pthread_mutex *mutex)
+{
+       pthread_t pthread;
+
+       while ((pthread = TAILQ_FIRST(&mutex->m_queue)) != NULL) {
+               TAILQ_REMOVE(&mutex->m_queue, pthread, sqe);
+               pthread->sflags &= ~THR_FLAGS_IN_SYNCQ;
+       }
+
+       return (pthread);
+}
+#endif
+
+/*
+ * Remove a waiting thread from a mutex queue in descending priority order.
+ */
+static void
+mutex_queue_remove(pthread_mutex_t mutex, pthread_t pthread)
+{
+       if ((pthread->sflags & THR_FLAGS_IN_SYNCQ) != 0) {
+               TAILQ_REMOVE(&mutex->m_queue, pthread, sqe);
+               pthread->sflags &= ~THR_FLAGS_IN_SYNCQ;
+       }
+}
+
+/*
+ * Enqueue a waiting thread to a queue in descending priority order.
+ */
+static void
+mutex_queue_enq(pthread_mutex_t mutex, pthread_t pthread)
+{
+       pthread_t tid = TAILQ_LAST(&mutex->m_queue, mutex_head);
+
+       THR_ASSERT_NOT_IN_SYNCQ(pthread);
+       /*
+        * For the common case of all threads having equal priority,
+        * we perform a quick check against the priority of the thread
+        * at the tail of the queue.
+        */
+       if ((tid == NULL) || (pthread->active_priority <= tid->active_priority))
+               TAILQ_INSERT_TAIL(&mutex->m_queue, pthread, sqe);
+       else {
+               tid = TAILQ_FIRST(&mutex->m_queue);
+               while (pthread->active_priority <= tid->active_priority)
+                       tid = TAILQ_NEXT(tid, sqe);
+               TAILQ_INSERT_BEFORE(tid, pthread, sqe);
+       }
+       pthread->sflags |= THR_FLAGS_IN_SYNCQ;
+}
diff --git a/lib/libthread_xu/thread/thr_mutex_prioceiling.c b/lib/libthread_xu/thread/thr_mutex_prioceiling.c
new file mode 100644 (file)
index 0000000..b847e7c
--- /dev/null
@@ -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: src/lib/libpthread/thread/thr_mutex_prioceiling.c,v 1.8 2003/07/07 04:28:23 davidxu Exp $
+ * $DragonFly: src/lib/libthread_xu/thread/thr_mutex_prioceiling.c,v 1.1 2005/02/01 12:38:27 davidxu Exp $
+ */
+#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/libthread_xu/thread/thr_mutex_protocol.c b/lib/libthread_xu/thread/thr_mutex_protocol.c
new file mode 100644 (file)
index 0000000..d6a8314
--- /dev/null
@@ -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: src/lib/libpthread/thread/thr_mutex_protocol.c,v 1.7 2003/04/18 05:04:16 deischen Exp $
+ * $DragonFly: src/lib/libthread_xu/thread/thr_mutex_protocol.c,v 1.1 2005/02/01 12:38:27 davidxu Exp $
+ */
+#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/libthread_xu/thread/thr_mutexattr.c b/lib/libthread_xu/thread/thr_mutexattr.c
new file mode 100644 (file)
index 0000000..07d5c52
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * 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.
+ *
+ * $DragonFly: src/lib/libthread_xu/thread/thr_mutexattr.c,v 1.1 2005/02/01 12:38:27 davidxu Exp $
+ */
+
+/*
+ * Copyright (c) 1997 John Birrell <jb@cimlogic.com.au>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by John Birrell.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+__weak_reference(_pthread_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);
+
+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 >= MUTEX_TYPE_MAX) {
+               errno = EINVAL;
+               ret = -1;
+       } else {
+               (*attr)->m_type = type;
+               ret = 0;
+       }
+       return(ret);
+}
+
+int
+_pthread_mutexattr_gettype(pthread_mutexattr_t *attr, int *type)
+{
+       int     ret;
+
+       if (attr == NULL || *attr == NULL || (*attr)->m_type >=
+           MUTEX_TYPE_MAX) {
+               ret = EINVAL;
+       } else {
+               *type = (*attr)->m_type;
+               ret = 0;
+       }
+       return ret;
+}
+
+int
+_pthread_mutexattr_destroy(pthread_mutexattr_t *attr)
+{
+       int     ret;
+       if (attr == NULL || *attr == NULL) {
+               ret = EINVAL;
+       } else {
+               free(*attr);
+               *attr = NULL;
+               ret = 0;
+       }
+       return(ret);
+}
diff --git a/lib/libthread_xu/thread/thr_once.c b/lib/libthread_xu/thread/thr_once.c
new file mode 100644 (file)
index 0000000..92c9e1b
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by John Birrell.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/lib/libpthread/thread/thr_once.c,v 1.9 2003/09/09 22:38:12 davidxu Exp $
+ * $DragonFly: src/lib/libthread_xu/thread/thr_once.c,v 1.1 2005/02/01 12:38:27 davidxu Exp $
+ */
+
+#include <pthread.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         once_lock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t          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(&once_lock);
+       once_control->state = ONCE_NEVER_DONE;
+       _pthread_mutex_unlock(&once_lock);
+       _pthread_cond_broadcast(&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(&once_lock);
+       while (*(volatile int *)&(once_control->state) == ONCE_IN_PROGRESS)
+               _pthread_cond_wait(&once_cv, &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(&once_lock);
+               _pthread_cleanup_push(once_cancel_handler, once_control);
+               init_routine();
+               _pthread_cleanup_pop(0);
+               _pthread_mutex_lock(&once_lock);
+               once_control->state = ONCE_DONE;
+               wakeup = 1;
+       }
+       _pthread_mutex_unlock(&once_lock);
+       if (wakeup)
+               _pthread_cond_broadcast(&once_cv);
+       return (0);
+}
+
diff --git a/lib/libthread_xu/thread/thr_printf.c b/lib/libthread_xu/thread/thr_printf.c
new file mode 100644 (file)
index 0000000..07e49f8
--- /dev/null
@@ -0,0 +1,136 @@
+/*-
+ * 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.
+ *
+ * $DragonFly: src/lib/libthread_xu/thread/thr_printf.c,v 1.1 2005/02/01 12:38:27 davidxu Exp $
+ */
+
+#include <sys/cdefs.h>
+#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/libthread_xu/thread/thr_private.h b/lib/libthread_xu/thread/thr_private.h
new file mode 100644 (file)
index 0000000..b52fe04
--- /dev/null
@@ -0,0 +1,850 @@
+/*
+ * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by John Birrell.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Private thread definitions for the uthread kernel.
+ *
+ * $FreeBSD: src/lib/libpthread/thread/thr_private.h,v 1.120 2004/11/01 10:49:34 davidxu Exp $
+ * $DragonFly: src/lib/libthread_xu/thread/thr_private.h,v 1.1 2005/02/01 12:38:27 davidxu Exp $
+ */
+
+#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 <stdio.h>
+#include <sched.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <pthread_np.h>
+
+#include "pthread_md.h"
+#include "thr_umtx.h"
+
+/*
+ * Evaluate the storage class specifier.
+ */
+#ifdef GLOBAL_PTHREAD_PRIVATE
+#define SCLASS
+#define SCLASS_PRESET(x...)    = x
+#else
+#define SCLASS                 extern
+#define SCLASS_PRESET(x...)
+#endif
+
+/* 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 __DragonFly__
+#define __predict_true(exp)    (exp)
+#define        __predict_false(exp)    (exp)
+#endif
+
+#ifdef _PTHREADS_INVARIANTS
+#define THR_ASSERT(cond, msg) do {     \
+       if (__predict_false(!(cond)))   \
+               PANIC(msg);             \
+} while (0)
+#else
+#define THR_ASSERT(cond, msg)
+#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;
+       long                            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;
+};
+
+#define TAILQ_INITIALIZER      { NULL, NULL }
+
+#define PTHREAD_MUTEX_STATIC_INITIALIZER   \
+       {0, PTHREAD_MUTEX_DEFAULT, PTHREAD_PRIO_NONE, TAILQ_INITIALIZER, \
+       NULL, { NULL }, MUTEX_FLAGS_PRIVATE, 0, 0, 0, TAILQ_INITIALIZER }
+/*
+ * 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;
+       long                    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                    *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     sched_interval;
+       int     prio;
+       int     suspend;
+#define        THR_STACK_USER          0x100   /* 0xFF reserved for <pthread.h> */
+       int     flags;
+       void    *arg_attr;
+       void    (*cleanup_attr)();
+       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                      0x100000
+
+/*
+ * 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                      0x200000
+
+/*
+ * Define the different priority ranges.  All applications have thread
+ * priorities constrained within 0-31.  The threads library raises the
+ * priority when delivering signals in order to ensure that signal
+ * delivery happens (from the POSIX spec) "as soon as possible".
+ * In the future, the threads library will also be able to map specific
+ * threads into real-time (cooperating) processes or kernel threads.
+ * The RT and SIGNAL priorities will be used internally and added to
+ * thread base priorities so that the scheduling queue can handle both
+ * normal and RT priority threads with and without signal handling.
+ *
+ * The approach taken is that, within each class, signal delivery
+ * always has priority over thread execution.
+ */
+#define THR_DEFAULT_PRIORITY                   15
+#define THR_MIN_PRIORITY                       0
+#define THR_MAX_PRIORITY                       31      /* 0x1F */
+#define THR_SIGNAL_PRIORITY                    32      /* 0x20 */
+#define THR_RT_PRIORITY                                64      /* 0x40 */
+#define THR_FIRST_PRIORITY                     THR_MIN_PRIORITY
+#define THR_LAST_PRIORITY      \
+       (THR_MAX_PRIORITY + THR_SIGNAL_PRIORITY + THR_RT_PRIORITY)
+#define THR_BASE_PRIORITY(prio)        ((prio) & THR_MAX_PRIORITY)
+
+/*
+ * Time slice period in microseconds.
+ */
+#define TIMESLICE_USEC                         20000
+
+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
+};
+
+union pthread_wait_data {
+       pthread_mutex_t mutex;
+};
+
+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 {
+       /*
+        * Magic value to help recognize a valid thread structure
+        * from an invalid one:
+        */
+#define        THR_MAGIC               ((u_int32_t) 0xd09ba115)
+       u_int32_t               magic;
+       char                    *name;
+       u_int64_t               uniqueid; /* for gdb */
+
+       /*
+        * Lock for accesses to this thread structure.
+        */
+       umtx_t                  lock;
+
+       /* Thread is terminated in kernel, written by kernel. */
+       long                    terminated;
+
+       /* Kernel thread id. */
+       long                    tid;
+
+       /* Internal condition variable cycle number. */
+       umtx_t                  cycle;
+
+       /* How many low level locks the thread held. */
+       int                     locklevel;
+
+       /* 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;
+
+       /* Wait data. */
+       union pthread_wait_data data;
+
+       int                     sflags;
+#define THR_FLAGS_IN_SYNCQ     0x0001
+
+       /* 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;
+
+       /* Number of priority ceiling or protection mutexes owned. */
+       int                     priority_mutex_count;
+
+       /* Queue of currently owned simple type mutexes. */
+       TAILQ_HEAD(, pthread_mutex)     mutexq;
+
+       /* Queue of currently owned priority type mutexs. */
+       TAILQ_HEAD(, pthread_mutex)     pri_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;
+};
+
+#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)
+
+#define        THR_LOCK_RELEASE(thrd, lck)                     \
+do {                                                   \
+       if ((thrd)->locklevel > 0) {                    \
+               _thr_umtx_unlock((lck), (thrd)->tid);   \
+               (thrd)->locklevel--;                    \
+       } else {                                        \
+               _thr_assert_lock_level();               \
+       }                                               \
+} 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        THR_IN_SYNCQ(thrd)      (((thrd)->sflags & THR_FLAGS_IN_SYNCQ) != 0)
+
+extern int __isthreaded;
+
+/*
+ * Global variables for the pthread kernel.
+ */
+
+SCLASS void            *_usrstack      SCLASS_PRESET(NULL);
+SCLASS struct pthread  *_thr_initial   SCLASS_PRESET(NULL);
+/* For debugger */
+SCLASS int             _libthread_xu_debug     SCLASS_PRESET(0);
+SCLASS int             _thread_scope_system    SCLASS_PRESET(0);
+
+/* List of all threads: */
+SCLASS TAILQ_HEAD(, pthread)   _thread_list
+    SCLASS_PRESET(TAILQ_HEAD_INITIALIZER(_thread_list));
+
+/* List of threads needing GC: */
+SCLASS TAILQ_HEAD(, pthread)   _thread_gc_list
+    SCLASS_PRESET(TAILQ_HEAD_INITIALIZER(_thread_gc_list));
+
+SCLASS int     _thread_active_threads  SCLASS_PRESET(1);
+
+SCLASS TAILQ_HEAD(atfork_head, pthread_atfork) _thr_atfork_list;
+SCLASS umtx_t  _thr_atfork_lock;
+
+/* Default thread attributes: */
+SCLASS struct pthread_attr _pthread_attr_default
+    SCLASS_PRESET({
+       .sched_policy = SCHED_RR,
+       .sched_inherit = 0,
+       .sched_interval = TIMESLICE_USEC,
+       .prio = THR_DEFAULT_PRIORITY,
+       .suspend = THR_CREATE_RUNNING,
+       .flags = 0,
+       .arg_attr = NULL,
+       .cleanup_attr = NULL,
+       .stackaddr_attr = NULL,
+       .stacksize_attr = THR_STACK_DEFAULT,
+       .guardsize_attr = 0
+    });
+
+/* Default mutex attributes: */
+SCLASS struct pthread_mutex_attr _pthread_mutexattr_default
+    SCLASS_PRESET({
+       .m_type = PTHREAD_MUTEX_DEFAULT,
+       .m_protocol = PTHREAD_PRIO_NONE,
+       .m_ceiling = 0,
+       .m_flags = 0
+    });
+
+/* Default condition variable attributes: */
+SCLASS struct pthread_cond_attr _pthread_condattr_default
+    SCLASS_PRESET({
+       .c_pshared = PTHREAD_PROCESS_PRIVATE,
+       .c_clockid = CLOCK_REALTIME
+    });
+
+SCLASS pid_t           _thr_pid                SCLASS_PRESET(0);
+SCLASS int             _thr_guard_default;
+SCLASS int             _thr_page_size;
+/* Garbage thread count. */
+SCLASS int              _gc_count               SCLASS_PRESET(0);
+
+SCLASS umtx_t          _mutex_static_lock;
+SCLASS umtx_t          _cond_static_lock;
+SCLASS umtx_t          _rwlock_static_lock;
+SCLASS umtx_t          _keytable_lock;
+SCLASS umtx_t          _thr_list_lock;
+
+/* Undefine the storage class and preset specifiers: */
+#undef  SCLASS
+#undef SCLASS_PRESET
+
+/*
+ * Function prototype definitions.
+ */
+__BEGIN_DECLS
+int    _thr_setthreaded(int);
+int    _mutex_cv_lock(pthread_mutex_t *);
+int    _mutex_cv_unlock(pthread_mutex_t *);
+void   _mutex_notify_priochange(struct pthread *, struct pthread *, int);
+int    _mutex_reinit(pthread_mutex_t *);
+void   _mutex_fork(struct pthread *curthread);
+void   _mutex_unlock_private(struct pthread *);
+void   _libpthread_init(struct pthread *);
+void   *_pthread_getspecific(pthread_key_t);
+int    _pthread_cond_init(pthread_cond_t *, const pthread_condattr_t *);
+int    _pthread_cond_destroy(pthread_cond_t *);
+int    _pthread_cond_wait(pthread_cond_t *, pthread_mutex_t *);
+int    _pthread_cond_timedwait(pthread_cond_t *, pthread_mutex_t *,
+           const struct timespec *);
+int    _pthread_cond_signal(pthread_cond_t *);
+int    _pthread_cond_broadcast(pthread_cond_t *);
+int    _pthread_key_create(pthread_key_t *, void (*) (void *));
+int    _pthread_key_delete(pthread_key_t);
+int    _pthread_mutex_destroy(pthread_mutex_t *);
+int    _pthread_mutex_init(pthread_mutex_t *, const pthread_mutexattr_t *);
+int    _pthread_mutex_lock(pthread_mutex_t *);
+int    _pthread_mutex_trylock(pthread_mutex_t *);
+int    _pthread_mutex_unlock(pthread_mutex_t *);
+int    _pthread_mutexattr_init(pthread_mutexattr_t *);
+int    _pthread_mutexattr_destroy(pthread_mutexattr_t *);
+int    _pthread_mutexattr_settype(pthread_mutexattr_t *, int);
+int    _pthread_once(pthread_once_t *, void (*) (void));
+int    _pthread_rwlock_init(pthread_rwlock_t *, const pthread_rwlockattr_t *);
+int    _pthread_rwlock_destroy (pthread_rwlock_t *);
+struct pthread *_pthread_self(void);
+int    _pthread_setspecific(pthread_key_t, const void *);
+void   _pthread_testcancel(void);
+void   _pthread_yield(void);
+void   _pthread_cleanup_push(void (*routine) (void *), void *routine_arg);
+void   _pthread_cleanup_pop(int execute);
+struct pthread *_thr_alloc(struct pthread *);
+void   _thread_exit(char *, int, char *) __dead2;
+void   _thr_exit_cleanup(void);
+int    _thr_ref_add(struct pthread *, struct pthread *, int);
+void   _thr_ref_delete(struct pthread *, struct pthread *);
+int    _thr_find_thread(struct pthread *, struct pthread *, int);
+void   _thr_rtld_init(void);
+void   _thr_rtld_fini(void);
+int    _thr_stack_alloc(struct pthread_attr *);
+void   _thr_stack_free(struct pthread_attr *);
+void   _thr_free(struct pthread *, struct pthread *);
+void   _thr_gc(struct pthread *);
+void    _thread_cleanupspecific(void);
+void    _thread_dump_info(void);
+void   _thread_printf(int, const char *, ...);
+void   _thr_spinlock_init(void);
+int    _thr_cancel_enter(struct pthread *);
+void   _thr_cancel_leave(struct pthread *, int);
+void   _thr_signal_block(struct pthread *);
+void   _thr_signal_unblock(struct pthread *);
+void   _thr_signal_init(void);
+void   _thr_signal_deinit(void);
+int    _thr_send_sig(struct pthread *, int sig);
+void   _thr_list_init();
+void   _thr_hash_add(struct pthread *);
+void   _thr_hash_remove(struct pthread *);
+struct pthread *_thr_hash_find(struct pthread *);
+void   _thr_link(struct pthread *curthread, struct pthread *thread);
+void   _thr_unlink(struct pthread *curthread, struct pthread *thread);
+void   _thr_suspend_check(struct pthread *curthread);
+void   _thr_assert_lock_level() __dead2;
+int    _thr_get_tid(void);
+
+/*
+ * Aliases for _pthread functions. Should be called instead of
+ * originals if PLT replocation is unwanted at runtme.
+ */
+int    _thr_cond_broadcast(pthread_cond_t *);
+int    _thr_cond_signal(pthread_cond_t *);
+int    _thr_cond_wait(pthread_cond_t *, pthread_mutex_t *);
+int    _thr_mutex_lock(pthread_mutex_t *);
+int    _thr_mutex_unlock(pthread_mutex_t *);
+int    _thr_rwlock_rdlock(pthread_rwlock_t *);
+int    _thr_rwlock_wrlock(pthread_rwlock_t *);
+int    _thr_rwlock_unlock(pthread_rwlock_t *);
+
+/* #include <sys/aio.h> */
+#ifdef _SYS_AIO_H_
+int    __sys_aio_suspend(const struct aiocb * const[], int, const struct timespec *);
+#endif
+
+/* #include <fcntl.h> */
+#ifdef  _SYS_FCNTL_H_
+int     __sys_fcntl(int, int, ...);
+int     __sys_open(const char *, int, ...);
+#endif
+
+/* #include <sys/ioctl.h> */
+#ifdef _SYS_IOCTL_H_
+int    __sys_ioctl(int, unsigned long, ...);
+#endif
+
+/* #inclde <sched.h> */
+#ifdef _SCHED_H_
+int    __sys_sched_yield(void);
+#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 *);
+#endif
+
+/* #include <sys/socket.h> */
+#ifdef _SYS_SOCKET_H_
+int    __sys_accept(int, struct sockaddr *, socklen_t *);
+int    __sys_connect(int, const struct sockaddr *, socklen_t);
+ssize_t __sys_recv(int, void *, size_t, int);
+ssize_t __sys_recvfrom(int, void *, size_t, int, struct sockaddr *, socklen_t *);
+ssize_t __sys_recvmsg(int, struct msghdr *, int);
+int    __sys_sendfile(int, int, off_t, size_t, struct sf_hdtr *,
+           off_t *, int);
+ssize_t __sys_sendmsg(int, const struct msghdr *, int);
+ssize_t __sys_sendto(int, const void *,size_t, int, const struct sockaddr *, socklen_t);
+#endif
+
+/* #include <sys/uio.h> */
+#ifdef  _SYS_UIO_H_
+ssize_t __sys_readv(int, const struct iovec *, int);
+ssize_t __sys_writev(int, const struct iovec *, int);
+#endif
+
+/* #include <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_execve(const char *, char * const *, char * const *);
+int    __sys_fork(void);
+int    __sys_fsync(int);
+pid_t  __sys_getpid(void);
+int     __sys_select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
+ssize_t __sys_read(int, void *, size_t);
+ssize_t __sys_write(int, const void *, size_t);
+void   __sys_exit(int);
+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 <poll.h> */
+#ifdef _SYS_POLL_H_
+int    __sys_poll(struct pollfd *, unsigned, int);
+#endif
+
+/* #include <sys/mman.h> */
+#ifdef _SYS_MMAN_H_
+int    __sys_msync(void *, size_t, int);
+#endif
+
+static inline int
+_thr_isthreaded(void)
+{
+       return (__isthreaded != 0);
+}
+
+static inline int
+_thr_is_inited(void)
+{
+       return (_thr_initial != 0);
+}
+
+static inline void
+_thr_check_init(void)
+{
+       if (_thr_initial == 0)
+               _libpthread_init(0);
+}
+
+__END_DECLS
+
+#endif  /* !_THR_PRIVATE_H */
diff --git a/lib/libthread_xu/thread/thr_pspinlock.c b/lib/libthread_xu/thread/thr_pspinlock.c
new file mode 100644 (file)
index 0000000..0d53fc1
--- /dev/null
@@ -0,0 +1,134 @@
+/*-
+ * 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: src/lib/libpthread/thread/thr_pspinlock.c,v 1.2 2003/11/04 19:56:12 deischen Exp $
+ * $DragonFly: src/lib/libthread_xu/thread/thr_pspinlock.c,v 1.1 2005/02/01 12:38:27 davidxu Exp $
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <pthread.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/libthread_xu/thread/thr_resume_np.c b/lib/libthread_xu/thread/thr_resume_np.c
new file mode 100644 (file)
index 0000000..c865ea2
--- /dev/null
+++ b/