[Midnightbsd-cvs] src: src/lib: Move libpthread to libkse.

laffer1 at midnightbsd.org laffer1 at midnightbsd.org
Wed Oct 1 22:02:00 EDT 2008


Log Message:
-----------
Move libpthread to libkse.  Prepare to set libthr as the default threading library.

Move libncurses to ncurses.  Prepare to import a newer version of ncurses.

Modified Files:
--------------
    src/lib:
        Makefile (r1.5 -> r1.6)
    src/lib/libthr:
        Makefile (r1.3 -> r1.4)
        libthr.3 (r1.1.1.1 -> r1.2)
        pthread.map (r1.1.1.2 -> r1.2)

Added Files:
-----------
    src/lib/libkse:
        Makefile (r1.1)
        kse.map (r1.1)
    src/lib/libkse/arch/amd64:
        Makefile.inc (r1.1)
    src/lib/libkse/arch/amd64/amd64:
        context.S (r1.1)
        enter_uts.S (r1.1)
        pthread_md.c (r1.1)
    src/lib/libkse/arch/amd64/include:
        atomic_ops.h (r1.1)
        pthread_md.h (r1.1)
    src/lib/libkse/arch/i386:
        Makefile.inc (r1.1)
    src/lib/libkse/arch/i386/i386:
        pthread_md.c (r1.1)
        thr_enter_uts.S (r1.1)
        thr_getcontext.S (r1.1)
    src/lib/libkse/arch/i386/include:
        atomic_ops.h (r1.1)
        pthread_md.h (r1.1)
    src/lib/libkse/arch/sparc64:
        Makefile.inc (r1.1)
    src/lib/libkse/arch/sparc64/include:
        atomic_ops.h (r1.1)
        pthread_md.h (r1.1)
    src/lib/libkse/arch/sparc64/sparc64:
        assym.s (r1.1)
        pthread_md.c (r1.1)
        thr_getcontext.S (r1.1)
    src/lib/libkse/support:
        Makefile.inc (r1.1)
        thr_support.c (r1.1)
    src/lib/libkse/sys:
        Makefile.inc (r1.1)
        lock.c (r1.1)
        lock.h (r1.1)
        thr_error.c (r1.1)
    src/lib/libkse/test:
        Makefile (r1.1)
        README (r1.1)
        guard_b.c (r1.1)
        guard_b.exp (r1.1)
        guard_s.pl (r1.1)
        hello_b.c (r1.1)
        hello_d.c (r1.1)
        hello_d.exp (r1.1)
        hello_s.c (r1.1)
        join_leak_d.c (r1.1)
        join_leak_d.exp (r1.1)
        mutex_d.c (r1.1)
        mutex_d.exp (r1.1)
        propagate_s.pl (r1.1)
        sem_d.c (r1.1)
        sem_d.exp (r1.1)
        sigsuspend_d.c (r1.1)
        sigsuspend_d.exp (r1.1)
        sigwait_d.c (r1.1)
        sigwait_d.exp (r1.1)
        verify (r1.1)
    src/lib/libkse/thread:
        Makefile.inc (r1.1)
        thr_accept.c (r1.1)
        thr_aio_suspend.c (r1.1)
        thr_atfork.c (r1.1)
        thr_attr_destroy.c (r1.1)
        thr_attr_get_np.c (r1.1)
        thr_attr_getdetachstate.c (r1.1)
        thr_attr_getguardsize.c (r1.1)
        thr_attr_getinheritsched.c (r1.1)
        thr_attr_getschedparam.c (r1.1)
        thr_attr_getschedpolicy.c (r1.1)
        thr_attr_getscope.c (r1.1)
        thr_attr_getstack.c (r1.1)
        thr_attr_getstackaddr.c (r1.1)
        thr_attr_getstacksize.c (r1.1)
        thr_attr_init.c (r1.1)
        thr_attr_setcreatesuspend_np.c (r1.1)
        thr_attr_setdetachstate.c (r1.1)
        thr_attr_setguardsize.c (r1.1)
        thr_attr_setinheritsched.c (r1.1)
        thr_attr_setschedparam.c (r1.1)
        thr_attr_setschedpolicy.c (r1.1)
        thr_attr_setscope.c (r1.1)
        thr_attr_setstack.c (r1.1)
        thr_attr_setstackaddr.c (r1.1)
        thr_attr_setstacksize.c (r1.1)
        thr_autoinit.c (r1.1)
        thr_barrier.c (r1.1)
        thr_barrierattr.c (r1.1)
        thr_cancel.c (r1.1)
        thr_clean.c (r1.1)
        thr_close.c (r1.1)
        thr_concurrency.c (r1.1)
        thr_cond.c (r1.1)
        thr_condattr_destroy.c (r1.1)
        thr_condattr_init.c (r1.1)
        thr_condattr_pshared.c (r1.1)
        thr_connect.c (r1.1)
        thr_creat.c (r1.1)
        thr_create.c (r1.1)
        thr_detach.c (r1.1)
        thr_equal.c (r1.1)
        thr_execve.c (r1.1)
        thr_exit.c (r1.1)
        thr_fcntl.c (r1.1)
        thr_find_thread.c (r1.1)
        thr_fork.c (r1.1)
        thr_fsync.c (r1.1)
        thr_getprio.c (r1.1)
        thr_getschedparam.c (r1.1)
        thr_info.c (r1.1)
        thr_init.c (r1.1)
        thr_join.c (r1.1)
        thr_kern.c (r1.1)
        thr_kill.c (r1.1)
        thr_main_np.c (r1.1)
        thr_mattr_init.c (r1.1)
        thr_mattr_kind_np.c (r1.1)
        thr_mattr_pshared.c (r1.1)
        thr_msync.c (r1.1)
        thr_multi_np.c (r1.1)
        thr_mutex.c (r1.1)
        thr_mutex_prioceiling.c (r1.1)
        thr_mutex_protocol.c (r1.1)
        thr_mutexattr_destroy.c (r1.1)
        thr_nanosleep.c (r1.1)
        thr_once.c (r1.1)
        thr_open.c (r1.1)
        thr_pause.c (r1.1)
        thr_poll.c (r1.1)
        thr_printf.c (r1.1)
        thr_priority_queue.c (r1.1)
        thr_private.h (r1.1)
        thr_pselect.c (r1.1)
        thr_pspinlock.c (r1.1)
        thr_raise.c (r1.1)
        thr_read.c (r1.1)
        thr_readv.c (r1.1)
        thr_resume_np.c (r1.1)
        thr_rtld.c (r1.1)
        thr_rwlock.c (r1.1)
        thr_rwlockattr.c (r1.1)
        thr_select.c (r1.1)
        thr_self.c (r1.1)
        thr_sem.c (r1.1)
        thr_seterrno.c (r1.1)
        thr_setprio.c (r1.1)
        thr_setschedparam.c (r1.1)
        thr_sig.c (r1.1)
        thr_sigaction.c (r1.1)
        thr_sigaltstack.c (r1.1)
        thr_sigmask.c (r1.1)
        thr_sigpending.c (r1.1)
        thr_sigprocmask.c (r1.1)
        thr_sigsuspend.c (r1.1)
        thr_sigwait.c (r1.1)
        thr_single_np.c (r1.1)
        thr_sleep.c (r1.1)
        thr_spec.c (r1.1)
        thr_spinlock.c (r1.1)
        thr_stack.c (r1.1)
        thr_suspend_np.c (r1.1)
        thr_switch_np.c (r1.1)
        thr_symbols.c (r1.1)
        thr_system.c (r1.1)
        thr_tcdrain.c (r1.1)
        thr_vfork.c (r1.1)
        thr_wait.c (r1.1)
        thr_wait4.c (r1.1)
        thr_waitpid.c (r1.1)
        thr_write.c (r1.1)
        thr_writev.c (r1.1)
        thr_yield.c (r1.1)
    src/lib/ncurses:
        Makefile (r1.1)
        Makefile.inc (r1.1)
        config.mk (r1.1)
    src/lib/ncurses/form:
        Makefile (r1.1)
    src/lib/ncurses/formw:
        Makefile (r1.1)
    src/lib/ncurses/menu:
        Makefile (r1.1)
    src/lib/ncurses/menuw:
        Makefile (r1.1)
    src/lib/ncurses/ncurses:
        Makefile (r1.1)
        ncurses_cfg.h (r1.1)
        pathnames.h (r1.1)
        termcap.c (r1.1)
    src/lib/ncurses/ncursesw:
        Makefile (r1.1)
    src/lib/ncurses/panel:
        Makefile (r1.1)
    src/lib/ncurses/panelw:
        Makefile (r1.1)

Removed Files:
-------------
    src/lib/libncurses:
        Makefile
        ncurses_cfg.h
        pathnames.h
        termcap.c

-------------- next part --------------
--- /dev/null
+++ lib/libkse/sys/thr_error.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 1995 John Birrell <jb at cimlogic.com.au>.
+ * Copyright (c) 1994 by Chris Provenzano, proven at 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/libkse/sys/thr_error.c,v 1.10 2007/10/09 13:42:26 obrien Exp $
+ */
+#include <pthread.h>
+#include "libc_private.h"
+#include "thr_private.h"
+
+#undef errno
+extern	int	errno;
+
+LT10_COMPAT_DEFAULT(__error);
+
+int *
+__error(void)
+{
+	struct pthread *curthread;
+
+	if (__isthreaded == 0)
+		return (&errno);
+	else if (_kse_in_critical())
+		return &(_get_curkse()->k_error);
+	else {
+		curthread = _get_curthread();
+		if ((curthread == NULL) || (curthread == _thr_initial))
+			return (&errno);
+		else
+			return (&curthread->error);
+	}
+}
--- /dev/null
+++ lib/libkse/sys/Makefile.inc
@@ -0,0 +1,5 @@
+# $FreeBSD: src/lib/libkse/sys/Makefile.inc,v 1.16 2007/10/09 13:42:26 obrien Exp $
+
+.PATH:	 ${.CURDIR}/sys
+
+SRCS+=	lock.c thr_error.c
--- /dev/null
+++ lib/libkse/sys/lock.c
@@ -0,0 +1,360 @@
+/*-
+ * Copyright (c) 2001, 2003 Daniel Eischen <deischen at freebsd.org>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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/libkse/sys/lock.c,v 1.11.4.1 2008/02/04 20:03:36 julian Exp $
+ */
+
+#include <sys/types.h>
+#include <machine/atomic.h>
+#include <assert.h>
+#include <stdlib.h>
+
+#include "atomic_ops.h"
+#include "lock.h"
+
+#ifdef _LOCK_DEBUG
+#define	LCK_ASSERT(e)	assert(e)
+#else
+#define LCK_ASSERT(e)
+#endif
+
+#define	MAX_SPINS	500
+
+void
+_lock_destroy(struct lock *lck)
+{
+	if ((lck != NULL) && (lck->l_head != NULL)) {
+		free(lck->l_head);
+		lck->l_head = NULL;
+		lck->l_tail = NULL;
+	}
+}
+
+int
+_lock_init(struct lock *lck, enum lock_type ltype,
+    lock_handler_t *waitfunc, lock_handler_t *wakeupfunc)
+{
+	if (lck == NULL)
+		return (-1);
+	else if ((lck->l_head = malloc(sizeof(struct lockreq))) == NULL)
+		return (-1);
+	else {
+		lck->l_type = ltype;
+		lck->l_wait = waitfunc;
+		lck->l_wakeup = wakeupfunc;
+		lck->l_head->lr_locked = 0;
+		lck->l_head->lr_watcher = NULL;
+		lck->l_head->lr_owner = NULL;
+		lck->l_head->lr_active = 1;
+		lck->l_tail = lck->l_head;
+	}
+	return (0);
+}
+
+int
+_lock_reinit(struct lock *lck, enum lock_type ltype,
+    lock_handler_t *waitfunc, lock_handler_t *wakeupfunc)
+{
+	if (lck == NULL)
+		return (-1);
+	else if (lck->l_head == NULL)
+		return (_lock_init(lck, ltype, waitfunc, wakeupfunc));
+	else {
+		lck->l_head->lr_locked = 0;
+		lck->l_head->lr_watcher = NULL;
+		lck->l_head->lr_owner = NULL;
+		lck->l_head->lr_active = 1;
+		lck->l_tail = lck->l_head;
+	}
+	return (0);
+}
+
+int
+_lockuser_init(struct lockuser *lu, void *priv)
+{
+	if (lu == NULL)
+		return (-1);
+	else if ((lu->lu_myreq == NULL) &&
+	    ((lu->lu_myreq = malloc(sizeof(struct lockreq))) == NULL))
+		return (-1);
+	else {
+		lu->lu_myreq->lr_locked = 1;
+		lu->lu_myreq->lr_watcher = NULL;
+		lu->lu_myreq->lr_owner = lu;
+		lu->lu_myreq->lr_active = 0;
+		lu->lu_watchreq = NULL;
+		lu->lu_priority = 0;
+		lu->lu_private = priv;
+		lu->lu_private2 = NULL;
+	}
+	return (0);
+}
+
+int
+_lockuser_reinit(struct lockuser *lu, void *priv)
+{
+	if (lu == NULL)
+		return (-1);
+
+	if (lu->lu_watchreq != NULL) {
+		/*
+		 * In this case the lock is active.  All lockusers
+		 * keep their watch request and drop their own
+		 * (lu_myreq) request.  Their own request is either
+		 * some other lockuser's watch request or is the
+		 * head of the lock.
+		 */
+		lu->lu_myreq = lu->lu_watchreq;
+		lu->lu_watchreq = NULL;
+       }
+       if (lu->lu_myreq == NULL)
+		/*
+		 * Oops, something isn't quite right.  Try to
+		 * allocate one.
+		 */
+		return (_lockuser_init(lu, priv));
+	else {
+		lu->lu_myreq->lr_locked = 1;
+		lu->lu_myreq->lr_watcher = NULL;
+		lu->lu_myreq->lr_owner = lu;
+		lu->lu_myreq->lr_active = 0;
+		lu->lu_watchreq = NULL;
+		lu->lu_priority = 0;
+		lu->lu_private = priv;
+		lu->lu_private2 = NULL;
+	}
+	return (0);
+}
+
+void
+_lockuser_destroy(struct lockuser *lu)
+{
+	if ((lu != NULL) && (lu->lu_myreq != NULL))
+		free(lu->lu_myreq);
+}
+
+/*
+ * Acquire a lock waiting (spin or sleep) for it to become available.
+ */
+void
+_lock_acquire(struct lock *lck, struct lockuser *lu, int prio)
+{
+	int i;
+	int lval;
+
+	/**
+	 * XXX - We probably want to remove these checks to optimize
+	 *       performance.  It is also a bug if any one of the 
+	 *       checks fail, so it's probably better to just let it
+	 *       SEGV and fix it.
+	 */
+#if 0
+	if (lck == NULL || lu == NULL || lck->l_head == NULL)
+		return;
+#endif
+	if ((lck->l_type & LCK_PRIORITY) != 0) {
+		LCK_ASSERT(lu->lu_myreq->lr_locked == 1);
+		LCK_ASSERT(lu->lu_myreq->lr_watcher == NULL);
+		LCK_ASSERT(lu->lu_myreq->lr_owner == lu);
+		LCK_ASSERT(lu->lu_watchreq == NULL);
+
+		lu->lu_priority = prio;
+	}
+	/*
+	 * Atomically swap the head of the lock request with
+	 * this request.
+	 */
+	atomic_swap_ptr(&lck->l_head, lu->lu_myreq, &lu->lu_watchreq);
+
+	if (lu->lu_watchreq->lr_locked != 0) {
+		atomic_store_rel_ptr
+		    ((volatile uintptr_t *)&lu->lu_watchreq->lr_watcher,
+		    (uintptr_t)lu);
+		if ((lck->l_wait == NULL) ||
+		    ((lck->l_type & LCK_ADAPTIVE) == 0)) {
+			while (lu->lu_watchreq->lr_locked != 0)
+				;	/* spin, then yield? */
+		} else {
+			/*
+			 * Spin for a bit before invoking the wait function.
+			 *
+			 * We should be a little smarter here.  If we're
+			 * running on a single processor, then the lock
+			 * owner got preempted and spinning will accomplish
+			 * nothing but waste time.  If we're running on
+			 * multiple processors, the owner could be running
+			 * on another CPU and we might acquire the lock if
+			 * we spin for a bit.
+			 *
+			 * The other thing to keep in mind is that threads
+			 * acquiring these locks are considered to be in
+			 * critical regions; they will not be preempted by
+			 * the _UTS_ until they release the lock.  It is
+			 * therefore safe to assume that if a lock can't
+			 * be acquired, it is currently held by a thread
+			 * running in another KSE.
+			 */
+			for (i = 0; i < MAX_SPINS; i++) {
+				if (lu->lu_watchreq->lr_locked == 0)
+					return;
+				if (lu->lu_watchreq->lr_active == 0)
+					break;
+			}
+			atomic_swap_int((int *)&lu->lu_watchreq->lr_locked,
+			    2, &lval);
+			if (lval == 0)
+				lu->lu_watchreq->lr_locked = 0;
+			else
+				lck->l_wait(lck, lu);
+
+		}
+	}
+	lu->lu_myreq->lr_active = 1;
+}
+
+/*
+ * Release a lock.
+ */
+void
+_lock_release(struct lock *lck, struct lockuser *lu)
+{
+	struct lockuser *lu_tmp, *lu_h;
+	struct lockreq *myreq;
+	int prio_h;
+	int lval;
+
+	/**
+	 * XXX - We probably want to remove these checks to optimize
+	 *       performance.  It is also a bug if any one of the 
+	 *       checks fail, so it's probably better to just let it
+	 *       SEGV and fix it.
+	 */
+#if 0
+	if ((lck == NULL) || (lu == NULL))
+		return;
+#endif
+	if ((lck->l_type & LCK_PRIORITY) != 0) {
+		prio_h = 0;
+		lu_h = NULL;
+
+		/* Update tail if our request is last. */
+		if (lu->lu_watchreq->lr_owner == NULL) {
+			atomic_store_rel_ptr((volatile uintptr_t *)&lck->l_tail,
+			    (uintptr_t)lu->lu_myreq);
+			atomic_store_rel_ptr
+			    ((volatile uintptr_t *)&lu->lu_myreq->lr_owner,
+			    (uintptr_t)NULL);
+		} else {
+			/* Remove ourselves from the list. */
+			atomic_store_rel_ptr((volatile uintptr_t *)
+			    &lu->lu_myreq->lr_owner,
+			    (uintptr_t)lu->lu_watchreq->lr_owner);
+			atomic_store_rel_ptr((volatile uintptr_t *)
+			    &lu->lu_watchreq->lr_owner->lu_myreq,
+			    (uintptr_t)lu->lu_myreq);
+		}
+		/*
+		 * The watch request now becomes our own because we've
+		 * traded away our previous request.  Save our previous
+		 * request so that we can grant the lock.
+		 */
+		myreq = lu->lu_myreq;
+		lu->lu_myreq = lu->lu_watchreq;
+		lu->lu_watchreq = NULL;
+		lu->lu_myreq->lr_locked = 1;
+		lu->lu_myreq->lr_owner = lu;
+		lu->lu_myreq->lr_watcher = NULL;
+		/*
+		 * Traverse the list of lock requests in reverse order
+		 * looking for the user with the highest priority.
+		 */
+		for (lu_tmp = lck->l_tail->lr_watcher; lu_tmp != NULL;
+		     lu_tmp = lu_tmp->lu_myreq->lr_watcher) {
+			if (lu_tmp->lu_priority > prio_h) {
+				lu_h = lu_tmp;
+				prio_h = lu_tmp->lu_priority;
+			}
+		}
+		if (lu_h != NULL) {
+			/* Give the lock to the highest priority user. */
+			if (lck->l_wakeup != NULL) {
+				atomic_swap_int(
+				    (int *)&lu_h->lu_watchreq->lr_locked,
+				    0, &lval);
+				if (lval == 2)
+					/* Notify the sleeper */
+					lck->l_wakeup(lck,
+					    lu_h->lu_myreq->lr_watcher);
+			}
+			else
+				atomic_store_rel_int(
+				    &lu_h->lu_watchreq->lr_locked, 0);
+		} else {
+			if (lck->l_wakeup != NULL) {
+				atomic_swap_int((int *)&myreq->lr_locked,
+				    0, &lval);
+				if (lval == 2)
+					/* Notify the sleeper */
+					lck->l_wakeup(lck, myreq->lr_watcher);
+			}
+			else
+				/* Give the lock to the previous request. */
+				atomic_store_rel_int(&myreq->lr_locked, 0);
+		}
+	} else {
+		/*
+		 * The watch request now becomes our own because we've
+		 * traded away our previous request.  Save our previous
+		 * request so that we can grant the lock.
+		 */
+		myreq = lu->lu_myreq;
+		lu->lu_myreq = lu->lu_watchreq;
+		lu->lu_watchreq = NULL;
+		lu->lu_myreq->lr_locked = 1;
+		if (lck->l_wakeup) {
+			atomic_swap_int((int *)&myreq->lr_locked, 0, &lval);
+			if (lval == 2)
+				/* Notify the sleeper */
+				lck->l_wakeup(lck, myreq->lr_watcher);
+		}
+		else
+			/* Give the lock to the previous request. */
+			atomic_store_rel_int(&myreq->lr_locked, 0);
+	}
+	lu->lu_myreq->lr_active = 0;
+}
+
+void
+_lock_grant(struct lock *lck /* unused */, struct lockuser *lu)
+{
+	atomic_store_rel_int(&lu->lu_watchreq->lr_locked, 3);
+}
+
+void
+_lockuser_setactive(struct lockuser *lu, int active)
+{
+	lu->lu_myreq->lr_active = active;
+}
+
--- /dev/null
+++ lib/libkse/sys/lock.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2001, 2003 Daniel Eischen <deischen at freebsd.org>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING 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/libkse/sys/lock.h,v 1.8 2007/10/09 13:42:26 obrien Exp $
+ */
+
+#ifndef _LOCK_H_
+#define	_LOCK_H_
+
+struct lockreq;
+struct lockuser;
+struct lock;
+
+enum lock_type {
+	LCK_DEFAULT	= 0x0000,	/* default is FIFO spin locks */
+	LCK_PRIORITY	= 0x0001,
+	LCK_ADAPTIVE 	= 0x0002	/* call user-supplied handlers */
+};
+
+typedef void lock_handler_t(struct lock *, struct lockuser *);
+
+struct lock {
+	struct lockreq	*l_head;
+	struct lockreq	*l_tail;	/* only used for priority locks */
+	enum lock_type	l_type;
+	lock_handler_t	*l_wait;	/* only used for adaptive locks */
+	lock_handler_t	*l_wakeup;	/* only used for adaptive locks */
+};
+
+/* Try to make this >= CACHELINESIZE */
+struct lockreq {
+	struct lockuser	*lr_watcher;	/* only used for priority locks */
+	struct lockuser	*lr_owner;	/* only used for priority locks */
+	volatile int	lr_locked;	/* lock granted = 0, busy otherwise */
+	volatile int	lr_active;	/* non-zero if the lock is last lock for thread */
+};
+
+struct lockuser {
+	struct lockreq	*lu_myreq;	/* request to give up/trade */
+	struct lockreq	*lu_watchreq;	/* watch this request */
+	int		lu_priority;	/* only used for priority locks */
+	void		*lu_private1;	/* private{1,2} are initialized to */
+	void		*lu_private2;	/*   NULL and can be used by caller */
+#define	lu_private	lu_private1
+};
+
+#define	_LCK_INITIALIZER(lck_req)	{ &lck_req, NULL, LCK_DEFAULT, \
+					  NULL, NULL }
+#define	_LCK_REQUEST_INITIALIZER	{ 0, NULL, NULL, 0 }
+
+#define	_LCK_BUSY(lu)			((lu)->lu_watchreq->lr_locked != 0)
+#define	_LCK_ACTIVE(lu)			((lu)->lu_watchreq->lr_active != 0)
+#define	_LCK_GRANTED(lu)		((lu)->lu_watchreq->lr_locked == 3)
+
+#define	_LCK_SET_PRIVATE(lu, p)		(lu)->lu_private = (void *)(p)
+#define	_LCK_GET_PRIVATE(lu)		(lu)->lu_private
+#define	_LCK_SET_PRIVATE2(lu, p)	(lu)->lu_private2 = (void *)(p)
+#define	_LCK_GET_PRIVATE2(lu)		(lu)->lu_private2
+
+void	_lock_acquire(struct lock *, struct lockuser *, int);
+void	_lock_destroy(struct lock *);
+void	_lock_grant(struct lock *, struct lockuser *);
+int	_lock_init(struct lock *, enum lock_type,
+	    lock_handler_t *, lock_handler_t *);
+int	_lock_reinit(struct lock *, enum lock_type,
+	    lock_handler_t *, lock_handler_t *);
+void	_lock_release(struct lock *, struct lockuser *);
+int	_lockuser_init(struct lockuser *lu, void *priv);
+void	_lockuser_destroy(struct lockuser *lu);
+int	_lockuser_reinit(struct lockuser *lu, void *priv);
+void	_lockuser_setactive(struct lockuser *lu, int active);
+
+#endif
--- /dev/null
+++ lib/libkse/arch/amd64/amd64/context.S
@@ -0,0 +1,217 @@
+/*
+ * Copyright (c) 2003 Daniel Eischen <deischen at 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 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.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD: src/lib/libkse/arch/amd64/amd64/context.S,v 1.9 2007/10/09 13:42:22 obrien Exp $");
+
+/*
+ * The following notes ("cheat sheet") was provided by Peter Wemm.
+ *
+ *   scratch:
+ *   rax     (1st return)
+ *   rcx     (4th arg)
+ *   rdx     (3rd arg, 2nd return)
+ *   rsi     (2nd arg)
+ *   rdi     (1st arg)
+ *   r8      (5th arg)
+ *   r9      (6th arg)
+ *   r10     (temp, static chain?)
+ *   r11     (temp)
+ * 
+ *   preserved:
+ *   rbx     (base pointer)
+ *   rsp     (stack)
+ *   rbp     (frame)
+ *   r12-r15 (general)
+ * 
+ *   calls:
+ *   rdi     1
+ *   rsi     2
+ *   rdx     3
+ *   rcx     4
+ *   r8      5
+ *   r9      6
+ * 
+ *   return:
+ *   rax     1
+ *   rdx     2
+ * 
+ *   This means:
+ *   arg1 goes in %rdi, arg2 in %rsi, etc. return value is %rax (and
+ *   secondary return, eg: pipe(2), in %rdx) %rcx,%rsi,%rdi etc are
+ *   trashed by making a call to something. %rbx,%rbp,%r12-15 are the
+ *   only registers preserved across a call. Note that unlike i386,
+ *   %rsi and %rdi are scratch rather than preserved. FPU is
+ *   different, args are in SSE registers rather than the x87 stack.
+ * 
+ *   Aside from the register calling conventions, amd64 can be treated
+ *   very much like i386.  Things like setjmp/longjmp etc were literal
+ *   translations from i386 but with the register names updated, etc. 
+ *   The main gotcha is that FPU save/restore is in SSE format, which
+ *   means a sparse 512 byte FPU context.
+ */
+
+
+/*
+ * Where do we define these?
+ */
+#define	MC_SIZE			800	/* sizeof mcontext_t */
+#define	MC_LEN_OFFSET		(25*8)	/* offset to mc_len from mcontext */
+#define	MC_FPFMT_OFFSET		(26*8)	/* offset to mc_fpformat from mcontext */
+#define	MC_FPFMT_NODEV		0x10000
+#define	MC_OWNEDFP_OFFSET	(27*8)	/* offset to mc_ownedfp from mcontext */
+#define	MC_OWNEDFP_NONE 	0x20000
+#define	MC_OWNEDFP_FPU		0x20001
+#define	MC_OWNEDFP_PCB		0x20002
+#define	MC_FPREGS_OFFSET	(28*8)	/* offset to FP registers */
+#define	MC_FP_CW_OFFSET		(28*8)	/* offset to FP control word */
+
+#define	MC_RDI		(1 * 8)
+#define	MC_RSI		(2 * 8)
+#define	MC_RDX		(3 * 8)
+#define	MC_RCX		(4 * 8)
+#define	MC_R8		(5 * 8)
+#define	MC_R9		(6 * 8)
+#define	MC_RAX		(7 * 8)
+#define	MC_RBX		(8 * 8)
+#define	MC_RBP		(9 * 8)
+#define	MC_R10		(10 * 8)
+#define	MC_R11		(11 * 8)
+#define	MC_R12		(12 * 8)
+#define	MC_R13		(13 * 8)
+#define	MC_R14		(14 * 8)
+#define	MC_R15		(15 * 8)
+#define	MC_FLAGS	(18 * 8)
+#define	MC_RIP		(20 * 8)
+#define	MC_CS		(21 * 8)
+#define	MC_RFLAGS	(22 * 8)
+#define	MC_RSP		(23 * 8)
+#define	MC_SS		(24 * 8)
+
+#define	REDZONE		128		/* size of the red zone */
+
+/*
+ * _amd64_ctx_save(mcontext_t *mcp)
+ *
+ * No values are saved to mc_trapno, mc_addr, mc_err and mc_cs.
+ * For the FPU state, only the floating point control word is stored.
+ */
+ENTRY(_amd64_save_context)
+	cmpq	$0, %rdi		/* check for null pointer */
+	jne	1f
+	movq	$-1, %rax
+	jmp	2f
+1:	movq	%rdi, MC_RDI(%rdi)
+	movq	%rsi, MC_RSI(%rdi)
+	movq	%rdx, MC_RDX(%rdi)
+	movq	%rcx, MC_RCX(%rdi)
+	movq	%r8, MC_R8(%rdi)
+	movq	%r9, MC_R9(%rdi)
+	movq	$1, MC_RAX(%rdi)	/* return 1 when restored */
+	movq	%rbx, MC_RBX(%rdi)
+	movq	%rbp, MC_RBP(%rdi)
+	movq	%r10, MC_R10(%rdi)
+	movq	%r11, MC_R11(%rdi)
+	movq	%r12, MC_R12(%rdi)
+	movq	%r13, MC_R13(%rdi)
+	movq	%r14, MC_R14(%rdi)
+	movq	%r15, MC_R15(%rdi)
+	movq	(%rsp), %rax		/* get return address */
+	movq	%rax, MC_RIP(%rdi)	/* save return address (%rip) */
+	pushfq				/* get flags */
+	popq	%rax
+	movq	%rax, MC_RFLAGS(%rdi)	/* save flags */
+	movq	%rsp, %rax		/* setcontext pushes the return */
+	addq	$8, %rax		/*   address onto the stack; */
+	movq	%rax, MC_RSP(%rdi)	/*   account for this -- ???. */
+	movw	%ss, MC_SS(%rdi)
+	fnstcw	MC_FP_CW_OFFSET(%rdi)	/* save FPU control word */
+	movq	$MC_OWNEDFP_NONE, MC_OWNEDFP_OFFSET(%rdi) /* no FP */
+	movq	$MC_FPFMT_NODEV, MC_FPFMT_OFFSET(%rdi)
+	movq	$MC_SIZE, MC_LEN_OFFSET(%rdi)
+	xorq	%rax, %rax		/* return 0 */
+2:	ret
+
+/*
+ * _amd64_ctx_restore(mcontext_t *mcp, intptr_t val, intptr_t *loc);
+ */
+ENTRY(_amd64_restore_context)
+	cmpq	$0, %rdi		/* check for null pointer */
+	jne	1f
+	movq	$-1, %rax
+	jmp	2f
+1:	cmpq	$MC_SIZE, MC_LEN_OFFSET(%rdi)	/* is context valid? */
+	je	2f
+	movq	$-1, %rax		/* bzzzt, invalid context */
+	ret
+2:	movq	MC_RCX(%rdi), %rcx
+	movq	MC_R8(%rdi), %r8
+	movq	MC_R9(%rdi), %r9
+	movq	MC_RBX(%rdi), %rbx
+	movq	MC_RBP(%rdi), %rbp
+	movq	MC_R10(%rdi), %r10
+	movq	MC_R11(%rdi), %r11
+	movq	MC_R12(%rdi), %r12
+	movq	MC_R13(%rdi), %r13
+	movq	MC_R14(%rdi), %r14
+	movq	MC_R15(%rdi), %r15
+	/*
+	 * if (mc_fpowned == MC_OWNEDFP_FPU || mc_fpowned == MC_OWNEDFP_PCB)
+	 *    restore XMM/SSE FP register format
+	 */
+	cmpq	$MC_OWNEDFP_NONE, MC_OWNEDFP_OFFSET(%rdi)
+	je	4f
+	cmpq	$MC_OWNEDFP_PCB, MC_OWNEDFP_OFFSET(%rdi)
+	je	3f
+	cmpq	$MC_OWNEDFP_FPU, MC_OWNEDFP_OFFSET(%rdi)
+	jne	4f
+3:	fxrstor	MC_FPREGS_OFFSET(%rdi)	/* restore XMM FP regs */
+	jmp	5f
+4:	fninit
+	fldcw	MC_FP_CW_OFFSET(%rdi)
+5:	movq	MC_RSP(%rdi), %rsp	/* switch to context stack */
+	subq	$REDZONE, %rsp
+	movq	MC_RIP(%rdi), %rax	/* return address on stack */
+	pushq	%rax
+	movq	MC_RDI(%rdi), %rax	/* rdi on stack */
+	pushq	%rax
+	movq	MC_RDX(%rdi), %rax	/* rdx on stack */
+	pushq	%rax
+	movq	MC_RSI(%rdi), %rax	/* rsi on stack */
+	pushq	%rax
+	movq	MC_RFLAGS(%rdi), %rax	/* flags on stack*/
+	pushq	%rax
+	movq	MC_RAX(%rdi), %rax	/* restore rax */
+	/* At this point we're done with the context. */
+	cmpq	$0, %rdx		/* set *loc to val */
+	je	6f
+	movq	%rsi, (%rdx)
+6:	popfq				/* restore flags */
+	popq	%rsi			/* restore rsi, rdx, and rdi */
+	popq	%rdx
+	popq	%rdi
+	ret	$REDZONE
+
--- /dev/null
+++ lib/libkse/arch/amd64/amd64/enter_uts.S
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2003 Daniel Eischen <deischen at 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 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.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD: src/lib/libkse/arch/amd64/amd64/enter_uts.S,v 1.6 2007/10/09 13:42:22 obrien Exp $");
+
+
+/*
+ * _amd64_enter_uts(struct kse_mailbox *km, kse_func_t uts, void *stack,
+ *     size_t stacksz);
+ */
+ENTRY(_amd64_enter_uts)
+	addq	%rcx, %rdx	/* get stack base */
+	andq	$~0xf, %rdx	/* align to 16 bytes */
+	movq	%rdx, %rsp	/* switch to UTS stack */
+	movq	%rdx, %rbp	/* set frame */
+	callq	*%rsi
+	ret
--- /dev/null
+++ lib/libkse/arch/amd64/amd64/pthread_md.c
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2003 Daniel Eischen <deischen at 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/libkse/arch/amd64/amd64/pthread_md.c,v 1.5 2007/10/09 13:42:22 obrien 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;
+		bzero(&tcb->tcb_tmbx, sizeof(tcb->tcb_tmbx));
+	}
+
+	return (tcb);
+}
+
+void
+_tcb_dtor(struct tcb *tcb)
+{
+	_rtld_free_tls(tcb, sizeof(struct tcb), 16);
+}
+
+struct kcb *
+_kcb_ctor(struct kse *kse)
+{
+	struct kcb *kcb;
+
+	kcb = malloc(sizeof(struct kcb));
+	if (kcb != NULL) {
+		bzero(kcb, sizeof(struct kcb));
+		kcb->kcb_self = kcb;
+		kcb->kcb_kse = kse;
+	}
+	return (kcb);
+}
+
+void
+_kcb_dtor(struct kcb *kcb)
+{
+	free(kcb);
+}
--- /dev/null
+++ lib/libkse/arch/amd64/include/pthread_md.h
@@ -0,0 +1,268 @@
+/*-
+ * Copyright (C) 2003 David Xu <davidxu at freebsd.org>
+ * Copyright (c) 2001 Daniel Eischen <deischen at 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/libkse/arch/amd64/include/pthread_md.h,v 1.11 2007/10/09 13:42:22 obrien 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	KSE_STACKSIZE		16384
+#define	DTV_OFFSET		offsetof(struct tcb, tcb_dtv)
+
+#define	THR_GETCONTEXT(ucp)	\
+	(void)_amd64_save_context(&(ucp)->uc_mcontext)
+#define	THR_SETCONTEXT(ucp)	\
+	(void)_amd64_restore_context(&(ucp)->uc_mcontext, 0, NULL)
+
+#define	PER_KSE
+#undef	PER_THREAD
+
+struct kse;
+struct pthread;
+struct tdv;
+
+/*
+ * %fs points to a struct kcb.
+ */
+struct kcb {
+	struct tcb		*kcb_curtcb;
+	struct kcb		*kcb_self;	/* self reference */
+	struct kse		*kcb_kse;
+	struct kse_mailbox	kcb_kmbx;
+};
+
+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 */
+	struct kse_thr_mailbox	tcb_tmbx;
+};
+
+/*
+ * Evaluates to the byte offset of the per-kse variable name.
+ */
+#define	__kcb_offset(name)	__offsetof(struct kcb, name)
+
+/*
+ * Evaluates to the type of the per-kse variable name.
+ */
+#define	__kcb_type(name)	__typeof(((struct kcb *)0)->name)
+
+/*
+ * Evaluates to the value of the per-kse variable name.
+ */
+#define	KCB_GET64(name) ({					\
+	__kcb_type(name) __result;				\
+								\
+	u_long __i;						\
+	__asm __volatile("movq %%fs:%1, %0"			\
+	    : "=r" (__i)					\
+	    : "m" (*(u_long *)(__kcb_offset(name))));		\
+	__result = (__kcb_type(name))__i;			\
+								\
+	__result;						\
+})
+
+/*
+ * Sets the value of the per-kse variable name to value val.
+ */
+#define	KCB_SET64(name, val) ({					\
+	__kcb_type(name) __val = (val);				\
+								\
+	u_long __i;						\
+	__i = (u_long)__val;					\
+	__asm __volatile("movq %1,%%fs:%0"			\
+	    : "=m" (*(u_long *)(__kcb_offset(name)))		\
+	    : "r" (__i));					\
+})
+
+static __inline u_long
+__kcb_readandclear64(volatile u_long *addr)
+{
+	u_long result;
+
+	__asm __volatile (
+	    "	xorq	%0, %0;"
+	    "	xchgq	%%fs:%1, %0;"
+	    "# __kcb_readandclear64"
+	    : "=&r" (result)
+	    : "m" (*addr));
+	return (result);
+}
+
+#define	KCB_READANDCLEAR64(name) ({				\
+	__kcb_type(name) __result;				\
+								\
+	__result = (__kcb_type(name))				\
+	    __kcb_readandclear64((u_long *)__kcb_offset(name)); \
+	__result;						\
+})
+
+
+#define	_kcb_curkcb()		KCB_GET64(kcb_self)
+#define	_kcb_curtcb()		KCB_GET64(kcb_curtcb)
+#define	_kcb_curkse()		((struct kse *)KCB_GET64(kcb_kmbx.km_udata))
+#define	_kcb_get_tmbx()		KCB_GET64(kcb_kmbx.km_curthread)
+#define	_kcb_set_tmbx(value)	KCB_SET64(kcb_kmbx.km_curthread, (void *)value)
+#define	_kcb_readandclear_tmbx() KCB_READANDCLEAR64(kcb_kmbx.km_curthread)
+
+/*
+ * The constructors.
+ */
+struct tcb	*_tcb_ctor(struct pthread *, int);
+void		_tcb_dtor(struct tcb *tcb);
+struct kcb	*_kcb_ctor(struct kse *);
+void		_kcb_dtor(struct kcb *);
+
+/* Called from the KSE to set its private data. */
+static __inline void
+_kcb_set(struct kcb *kcb)
+{
+	amd64_set_fsbase(kcb);
+}
+
+/* Get the current kcb. */
+static __inline struct kcb *
+_kcb_get(void)
+{
+	return (_kcb_curkcb());
+}
+
+static __inline struct kse_thr_mailbox *
+_kcb_critical_enter(void)
+{
+	struct kse_thr_mailbox *crit;
+
+	crit = _kcb_readandclear_tmbx();
+	return (crit);
+}
+
+static __inline void
+_kcb_critical_leave(struct kse_thr_mailbox *crit)
+{
+	_kcb_set_tmbx(crit);
+}
+
+static __inline int
+_kcb_in_critical(void)
+{
+	return (_kcb_get_tmbx() == NULL);
+}
+
+static __inline void
+_tcb_set(struct kcb *kcb, struct tcb *tcb)
+{
+	kcb->kcb_curtcb = tcb;
+}
+
+static __inline struct tcb *
+_tcb_get(void)
+{
+	return (_kcb_curtcb());
+}
+
+static __inline struct pthread *
+_get_curthread(void)
+{
+	struct tcb *tcb;
+
+	tcb = _kcb_curtcb();
+	if (tcb != NULL)
+		return (tcb->tcb_thread);
+	else
+		return (NULL);
+}
+
+static __inline struct kse *
+_get_curkse(void)
+{
+	return ((struct kse *)_kcb_curkse());
+}
+
+void _amd64_enter_uts(struct kse_mailbox *km, kse_func_t uts, void *stack,
+    size_t stacksz);
+int _amd64_restore_context(mcontext_t *mc, intptr_t val, intptr_t *loc);
+int _amd64_save_context(mcontext_t *mc);
+
+static __inline int
+_thread_enter_uts(struct tcb *tcb, struct kcb *kcb)
+{
+	int ret;
+
+	ret = _amd64_save_context(&tcb->tcb_tmbx.tm_context.uc_mcontext);
+	if (ret == 0) {
+		_amd64_enter_uts(&kcb->kcb_kmbx, kcb->kcb_kmbx.km_func,
+		    kcb->kcb_kmbx.km_stack.ss_sp,
+		    kcb->kcb_kmbx.km_stack.ss_size);
+		/* We should not reach here. */
+		return (-1);
+	}
+	else if (ret < 0)
+		return (-1);
+	return (0);
+}
+
+static __inline int
+_thread_switch(struct kcb *kcb, struct tcb *tcb, int setmbox)
+{
+	extern int _libkse_debug;
+
+	if ((kcb == NULL) || (tcb == NULL))
+		return (-1);
+	kcb->kcb_curtcb = tcb;
+
+	if (_libkse_debug == 0) {
+		tcb->tcb_tmbx.tm_lwp = kcb->kcb_kmbx.km_lwp;
+		if (setmbox != 0)
+			_amd64_restore_context(
+				&tcb->tcb_tmbx.tm_context.uc_mcontext,
+				(intptr_t)&tcb->tcb_tmbx,
+				(intptr_t *)&kcb->kcb_kmbx.km_curthread);
+		else
+			_amd64_restore_context(
+				&tcb->tcb_tmbx.tm_context.uc_mcontext,
+				0, NULL);
+		/* We should not reach here. */
+	} else {
+		if (setmbox)
+			kse_switchin(&tcb->tcb_tmbx, KSE_SWITCHIN_SETTMBX);
+		else
+			kse_switchin(&tcb->tcb_tmbx, 0);
+	}
+
+	return (-1);
+}
+#endif
--- /dev/null
+++ lib/libkse/arch/amd64/include/atomic_ops.h
@@ -0,0 +1,57 @@
+/*-
+ * Copyright (c) 2001 Daniel Eischen <deischen at 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/libkse/arch/amd64/include/atomic_ops.h,v 1.3 2007/10/09 13:42:22 obrien Exp $
+ */
+
+#ifndef	_ATOMIC_OPS_H_
+#define	_ATOMIC_OPS_H_
+
+/*
+ * Atomic swap:
+ *   Atomic (tmp = *dst, *dst = val), then *res = tmp
+ *
+ * void atomic_swap64(intptr_t *dst, intptr_t val, intptr_t *res);
+ */
+static inline void
+atomic_swap64(intptr_t *dst, intptr_t val, intptr_t *res)
+{
+	__asm __volatile(
+	"xchgq %2, %1; movq %2, %0"
+	 : "=m" (*res) : "m" (*dst), "r" (val) : "memory");
+}
+
+static inline void
+atomic_swap_int(int *dst, int val, int *res)
+{
+	__asm __volatile(
+	"xchgl %2, %1; movl %2, %0"
+	 : "=m" (*res) : "m" (*dst), "r" (val) : "memory");
+}
+
+#define	atomic_swap_ptr(d, v, r) \
+	atomic_swap64((intptr_t *)(d), (intptr_t)(v), (intptr_t *)(r))
+
+#endif
--- /dev/null
+++ lib/ncurses/config.mk
@@ -0,0 +1,54 @@
+# $FreeBSD: src/lib/ncurses/config.mk,v 1.4 2007/07/21 00:27:17 rafan Exp $
+
+# This Makefile is shared by libncurses, libform, libmenu, libpanel.
+
+NCURSES_DIR=	${.CURDIR}/../../../contrib/ncurses
+
+.if defined(ENABLE_WIDEC)
+LIB_SUFFIX=	w
+CFLAGS+=	-D_XOPEN_SOURCE_EXTENDED -DENABLE_WIDEC
+NCURSES_CFG_H=	${.CURDIR}/../ncurses/ncurses_cfg.h
+.else
+LIB_SUFFIX=
+NCURSES_CFG_H=	${.CURDIR}/ncurses_cfg.h
+.endif
+
+CFLAGS+=	-I.
+.if exists(${.OBJDIR}/../ncurses${LIB_SUFFIX})
+CFLAGS+=	-I${.OBJDIR}/../ncurses${LIB_SUFFIX}
+.endif
+CFLAGS+=	-I${.CURDIR}/../ncurses${LIB_SUFFIX}
+
+# for ${NCURSES_CFG_H}
+CFLAGS+=	-I${.CURDIR}/../ncurses
+
+CFLAGS+=	-I${NCURSES_DIR}/include
+CFLAGS+=	-I${NCURSES_DIR}/ncurses
+
+CFLAGS+=	-Wall
+
+CFLAGS+=	-DNDEBUG
+
+CFLAGS+=	-DHAVE_CONFIG_H
+
+# everyone needs this
+.PATH:		${NCURSES_DIR}/include
+
+# tools and directories
+AWK?=		awk
+TERMINFODIR?=	${SHAREDIR}/misc
+
+# Generate headers
+ncurses_def.h:	MKncurses_def.sh ncurses_defs
+	AWK=${AWK} sh ${NCURSES_DIR}/include/MKncurses_def.sh \
+	    ${NCURSES_DIR}/include/ncurses_defs > ncurses_def.h
+
+# Manual pages filter
+MANFILTER=	sed -e 's%@TERMINFO@%${TERMINFODIR}/terminfo%g' \
+		    -e 's%@DATADIR@%/usr/share%g' \
+		    -e 's%@NCURSES_OSPEED@%${NCURSES_OSPEED}%g' \
+		    -e 's%@NCURSES_MAJOR@%${NCURSES_MAJOR}%g' \
+		    -e 's%@NCURSES_MINOR@%${NCURSES_MINOR}%g' \
+		    -e 's%@NCURSES_PATCH@%${NCURSES_PATCH}%g' \
+		    -e 's%@TIC@%tic%g' \
+		    -e 's%@INFOCMP@%infocmp%g'
--- /dev/null
+++ lib/ncurses/Makefile.inc
@@ -0,0 +1,5 @@
+# $FreeBSD: src/lib/ncurses/Makefile.inc,v 1.2 2007/03/09 09:54:07 rafan Exp $
+
+# This is to include src/lib/Makefile.inc
+
+.include "../Makefile.inc"
--- /dev/null
+++ lib/ncurses/Makefile
@@ -0,0 +1,6 @@
+# $FreeBSD: src/lib/ncurses/Makefile,v 1.2 2007/03/09 12:11:56 rafan Exp $
+
+SUBDIR=	ncurses form menu panel \
+	ncursesw formw menuw panelw
+
+.include <bsd.subdir.mk>
--- /dev/null
+++ lib/libkse/arch/i386/i386/thr_getcontext.S
@@ -0,0 +1,156 @@
+/*-
+ * Copyright (c) 2001 Daniel Eischen <deischen at 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 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.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD: src/lib/libkse/arch/i386/i386/thr_getcontext.S,v 1.7 2007/10/09 13:42:23 obrien Exp $");
+
+/*
+ * Where do we define these?
+ */
+#define	MC_LEN_OFFSET		80	/* offset to mc_len from mcontext */
+#define	MC_LEN			640	/* mc_len <machine/ucontext.h> */
+#define	MC_FPFMT_OFFSET		84
+#define MC_FPFMT_NODEV		0x10000
+#define MC_FPFMT_387		0x10001
+#define	MC_FPFMT_XMM		0x10002
+#define	MC_OWNEDFP_OFFSET	88
+#define	MC_OWNEDFP_NONE		0x20000
+#define	MC_OWNEDFP_FPU		0x20001
+#define	MC_OWNEDFP_PCB		0x20002
+#define	MC_FPREGS_OFFSET	96	/* offset to FP regs from mcontext */
+#define	MC_FP_CW_OFFSET		96	/* offset to FP control word */
+
+/*
+ * int thr_setcontext(mcontext_t *mcp, intptr_t val, intptr_t *loc)
+ *
+ * Restores the context in mcp.
+ *
+ * Returns 0 if there are no errors; -1 otherwise
+ */
+	.weak CNAME(_thr_setcontext)
+	.set CNAME(_thr_setcontext),CNAME(__thr_setcontext)
+ENTRY(__thr_setcontext)
+	movl	4(%esp), %edx		/* get address of mcontext */
+	cmpl	$0, %edx		/* check for null pointer */
+	jne	1f
+	movl	$-1, %eax
+	jmp	8f
+1:	cmpl	$MC_LEN, MC_LEN_OFFSET(%edx)	/* is context valid? */
+	je	2f
+	movl	$-1, %eax		/* bzzzt, invalid context */
+	jmp	8f
+2:	/*movl	4(%edx), %gs*/		/* we don't touch %gs */
+	movw	8(%edx), %fs
+	movw	12(%edx), %es
+	movw	16(%edx), %ds
+	movw	76(%edx), %ss
+	movl	20(%edx), %edi
+	movl	24(%edx), %esi
+	movl	28(%edx), %ebp
+	movl	%esp, %ecx		/* save current stack in ecx */
+	movl	72(%edx), %esp		/* switch to context defined stack */
+	pushl	60(%edx)		/* push return address on stack */
+	pushl	44(%edx)		/* push ecx on stack */
+	pushl	48(%edx)		/* push eax on stack */
+	/*
+	 * if (mc_fpowned == MC_OWNEDFP_FPU || mc_fpowned == MC_OWNEDFP_PCB) {
+	 *    if (mc_fpformat == MC_FPFMT_387)
+	 *        restore 387 FP register format
+	 *    else if (mc_fpformat == MC_FPFMT_XMM)
+	 *        restore XMM/SSE FP register format
+	 * }
+	 */
+	cmpl	$MC_OWNEDFP_FPU, MC_OWNEDFP_OFFSET(%edx)
+	je	3f
+	cmpl	$MC_OWNEDFP_PCB, MC_OWNEDFP_OFFSET(%edx)
+	jne	5f
+3:	cmpl	$MC_FPFMT_387, MC_FPFMT_OFFSET(%edx)
+	jne	4f
+	frstor	MC_FPREGS_OFFSET(%edx)	/* restore 387 FP regs */
+	jmp	6f
+4:	cmpl	$MC_FPFMT_XMM, MC_FPFMT_OFFSET(%edx)
+	jne	5f
+	fxrstor	MC_FPREGS_OFFSET(%edx)	/* restore XMM FP regs */
+	jmp	6f
+5:	fninit
+	fldcw	MC_FP_CW_OFFSET(%edx)
+6:	pushl	68(%edx)		/* push flags register on stack*/
+	movl	36(%edx), %ebx		/* restore ebx and edx */
+	movl	40(%edx), %edx
+	movl	12(%ecx), %eax		/* get 3rd arg (loc) */
+	cmpl	$0, %eax		/* do nothing if loc == null */
+	je	7f
+	movl	8(%ecx), %ecx		/* get 2nd arg (val) */
+	movl	%ecx, (%eax)		/* set loc = val */
+7:	popfl				/* restore flags after test */
+	popl	%eax			/* restore eax and ecx last */
+	popl	%ecx
+8:	ret
+
+/*
+ * int thr_getcontext(mcontext_t *mcp);
+ *
+ * Returns -1 if there is an error, 0 no errors; 1 upon return
+ * from a setcontext().
+ */
+	.weak CNAME(_thr_getcontext)
+	.set CNAME(_thr_getcontext),CNAME(__thr_getcontext)
+ENTRY(__thr_getcontext)
+	pushl	%edx			/* save edx */
+	movl	8(%esp), %edx		/* get address of mcontext */
+	cmpl	$0, %edx		/* check for null pointer */
+	jne	1f
+	popl	%edx			/* restore edx and stack */
+	movl	$-1, %eax
+	jmp	2f
+1:	/*movw	%gs, 4(%edx)*/		/* we don't touch %gs */
+	movw	%fs, 8(%edx)
+	movw	%es, 12(%edx)
+	movw	%ds, 16(%edx)
+	movw	%ss, 76(%edx)
+	movl	%edi, 20(%edx)
+	movl	%esi, 24(%edx)
+	movl	%ebp, 28(%edx)
+	movl	%ebx, 36(%edx)
+	movl	$1, 48(%edx)		/* store successful return in eax */
+	popl	%eax			/* get saved value of edx */
+	movl	%eax, 40(%edx)		/* save edx */
+	movl	%ecx, 44(%edx)
+	movl	(%esp), %eax		/* get return address */
+	movl	%eax, 60(%edx)		/* save return address */
+	fnstcw	MC_FP_CW_OFFSET(%edx)
+	movl	$MC_LEN, MC_LEN_OFFSET(%edx)
+	movl	$MC_FPFMT_NODEV, MC_FPFMT_OFFSET(%edx)	/* no FP */
+	movl	$MC_OWNEDFP_NONE, MC_OWNEDFP_OFFSET(%edx) /* no FP */
+	pushfl
+	popl	%eax			/* get eflags */
+	movl	%eax, 68(%edx)		/* store eflags */
+	movl	%esp, %eax		/* setcontext pushes the return  */
+	addl	$4, %eax		/*   address onto the top of the */
+	movl	%eax, 72(%edx)		/*   stack; account for this     */
+	movl	40(%edx), %edx		/* restore edx -- is this needed? */
+	xorl	%eax, %eax		/* return 0 */
+2:	ret
--- /dev/null
+++ lib/libkse/arch/i386/i386/thr_enter_uts.S
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2002 Jonathan Mini <mini at freebsd.org>.
+ * Copyright (c) 2001 Daniel Eischen <deischen at 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 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.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD: src/lib/libkse/arch/i386/i386/thr_enter_uts.S,v 1.7 2007/10/09 13:42:23 obrien Exp $");
+
+
+/*
+ * _i386_enter_uts(struct kse_mailbox *km, kse_func_t uts, void *stack,
+ *     long stacksz);
+ * +4 = km, +8 = uts, +12 = stack, +16 = size
+ */
+ENTRY(_i386_enter_uts)
+	movl	%esp, %edx		/* save stack */
+	movl	12(%edx), %eax		/* get bottom of stack */
+	addl	16(%edx), %eax		/* add length */
+	movl	%eax, %esp		/* switch to uts stack */
+	pushl	4(%edx)			/* push the address of the mailbox */
+	call	*8(%edx)
+	ret
--- /dev/null
+++ lib/libkse/arch/i386/i386/pthread_md.c
@@ -0,0 +1,100 @@
+/*-
+ * Copyright (C) 2003 David Xu <davidxu at freebsd.org>
+ * Copyright (c) 2001,2003 Daniel Eischen <deischen at 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/lib/libkse/arch/i386/i386/pthread_md.c,v 1.9 2007/10/09 13:42:23 obrien Exp $");
+
+#include <sys/types.h>
+#include <machine/cpufunc.h>
+#include <machine/sysarch.h>
+
+#include <unistd.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ucontext.h>
+
+#include "rtld_tls.h"
+#include "pthread_md.h"
+
+struct tcb *
+_tcb_ctor(struct pthread *thread, int initial)
+{
+	struct tcb *tcb;
+	void *oldtls;
+
+	if (initial) {
+		__asm __volatile("movl %%gs:0, %0" : "=r" (oldtls));
+	} else {
+		oldtls = NULL;
+	}
+
+	tcb = _rtld_allocate_tls(oldtls, sizeof(struct tcb), 16);
+	if (tcb) {
+		tcb->tcb_thread = thread;
+		tcb->tcb_spare = 0;
+		bzero(&tcb->tcb_tmbx, sizeof(tcb->tcb_tmbx));
+	}
+
+	return (tcb);
+}
+
+void
+_tcb_dtor(struct tcb *tcb)
+{
+	_rtld_free_tls(tcb, sizeof(struct tcb), 16);
+}
+
+/*
+ * Initialize KSD.  This also includes setting up the LDT.
+ */
+struct kcb *
+_kcb_ctor(struct kse *kse)
+{
+	struct kcb *kcb;
+
+	kcb = malloc(sizeof(struct kcb));
+	if (kcb != NULL) {
+		bzero(kcb, sizeof(struct kcb));
+		kcb->kcb_self = kcb;
+		kcb->kcb_kse = kse;
+	}
+	return (kcb);
+}
+
+void
+_kcb_dtor(struct kcb *kcb)
+{
+	free(kcb);
+}
+
+int
+i386_set_gsbase(void *addr)
+{
+
+	return (sysarch(I386_SET_GSBASE, &addr));
+}
--- /dev/null
+++ lib/libkse/arch/i386/include/pthread_md.h
@@ -0,0 +1,264 @@
+/*-
+ * Copyright (c) 2002 Daniel Eischen <deischen at 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/libkse/arch/i386/include/pthread_md.h,v 1.17 2007/10/09 13:42:23 obrien 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>
+
+extern int _thr_setcontext(mcontext_t *, intptr_t, intptr_t *);
+extern int _thr_getcontext(mcontext_t *);
+
+#define	KSE_STACKSIZE		16384
+#define	DTV_OFFSET		offsetof(struct tcb, tcb_dtv)
+
+#define	THR_GETCONTEXT(ucp)	_thr_getcontext(&(ucp)->uc_mcontext)
+#define	THR_SETCONTEXT(ucp)	_thr_setcontext(&(ucp)->uc_mcontext, 0, NULL)
+
+#define	PER_KSE
+#undef	PER_THREAD
+
+struct kse;
+struct pthread;
+
+/*
+ * %gs points to a struct kcb.
+ */
+struct kcb {
+	struct tcb		*kcb_curtcb;
+	struct kcb		*kcb_self;	/* self reference */
+	struct kse		*kcb_kse;
+	struct kse_mailbox	kcb_kmbx;
+};
+
+struct tcb {
+	struct tcb		*tcb_self;	/* required by rtld */
+	void			*tcb_dtv;	/* required by rtld */
+	struct pthread		*tcb_thread;
+	void			*tcb_spare;	/* align tcb_tmbx to 16 bytes */
+	struct kse_thr_mailbox	tcb_tmbx;
+};
+
+/*
+ * Evaluates to the byte offset of the per-kse variable name.
+ */
+#define	__kcb_offset(name)	__offsetof(struct kcb, name)
+
+/*
+ * Evaluates to the type of the per-kse variable name.
+ */
+#define	__kcb_type(name)	__typeof(((struct kcb *)0)->name)
+
+/*
+ * Evaluates to the value of the per-kse variable name.
+ */
+#define	KCB_GET32(name) ({					\
+	__kcb_type(name) __result;				\
+								\
+	u_int __i;						\
+	__asm __volatile("movl %%gs:%1, %0"			\
+	    : "=r" (__i)					\
+	    : "m" (*(u_int *)(__kcb_offset(name))));		\
+	__result = (__kcb_type(name))__i;			\
+								\
+	__result;						\
+})
+
+/*
+ * Sets the value of the per-kse variable name to value val.
+ */
+#define	KCB_SET32(name, val) ({					\
+	__kcb_type(name) __val = (val);				\
+								\
+	u_int __i;						\
+	__i = (u_int)__val;					\
+	__asm __volatile("movl %1,%%gs:%0"			\
+	    : "=m" (*(u_int *)(__kcb_offset(name)))		\
+	    : "r" (__i));					\
+})
+
+static __inline u_long
+__kcb_readandclear32(volatile u_long *addr)
+{
+	u_long result;
+
+	__asm __volatile (
+	    "	xorl	%0, %0;"
+	    "	xchgl	%%gs:%1, %0;"
+	    "# __kcb_readandclear32"
+	    : "=&r" (result)
+	    : "m" (*addr));
+	return (result);
+}
+
+#define	KCB_READANDCLEAR32(name) ({				\
+	__kcb_type(name) __result;				\
+								\
+	__result = (__kcb_type(name))				\
+	    __kcb_readandclear32((u_long *)__kcb_offset(name)); \
+	__result;						\
+})
+
+
+#define	_kcb_curkcb()		KCB_GET32(kcb_self)
+#define	_kcb_curtcb()		KCB_GET32(kcb_curtcb)
+#define	_kcb_curkse()		((struct kse *)KCB_GET32(kcb_kmbx.km_udata))
+#define	_kcb_get_tmbx()		KCB_GET32(kcb_kmbx.km_curthread)
+#define	_kcb_set_tmbx(value)	KCB_SET32(kcb_kmbx.km_curthread, (void *)value)
+#define	_kcb_readandclear_tmbx() KCB_READANDCLEAR32(kcb_kmbx.km_curthread)
+
+
+/*
+ * The constructors.
+ */
+struct tcb	*_tcb_ctor(struct pthread *, int);
+void		_tcb_dtor(struct tcb *tcb);
+struct kcb	*_kcb_ctor(struct kse *);
+void		_kcb_dtor(struct kcb *);
+
+/* Called from the KSE to set its private data. */
+static __inline void
+_kcb_set(struct kcb *kcb)
+{
+	i386_set_gsbase(kcb);
+}
+
+/* Get the current kcb. */
+static __inline struct kcb *
+_kcb_get(void)
+{
+	return (_kcb_curkcb());
+}
+
+static __inline struct kse_thr_mailbox *
+_kcb_critical_enter(void)
+{
+	struct kse_thr_mailbox *crit;
+
+	crit = _kcb_readandclear_tmbx();
+	return (crit);
+}
+
+static __inline void
+_kcb_critical_leave(struct kse_thr_mailbox *crit)
+{
+	_kcb_set_tmbx(crit);
+}
+
+static __inline int
+_kcb_in_critical(void)
+{
+	return (_kcb_get_tmbx() == NULL);
+}
+
+static __inline void
+_tcb_set(struct kcb *kcb, struct tcb *tcb)
+{
+	kcb->kcb_curtcb = tcb;
+}
+
+static __inline struct tcb *
+_tcb_get(void)
+{
+	return (_kcb_curtcb());
+}
+
+static __inline struct pthread *
+_get_curthread(void)
+{
+	struct tcb *tcb;
+
+	tcb = _kcb_curtcb();
+	if (tcb != NULL)
+		return (tcb->tcb_thread);
+	else
+		return (NULL);
+}
+
+static __inline struct kse *
+_get_curkse(void)
+{
+	return ((struct kse *)_kcb_curkse());
+}
+
+void	_i386_enter_uts(struct kse_mailbox *km, kse_func_t uts, void *stack,
+    size_t stacksz);
+
+static __inline int
+_thread_enter_uts(struct tcb *tcb, struct kcb *kcb)
+{
+	int ret;
+
+	ret = _thr_getcontext(&tcb->tcb_tmbx.tm_context.uc_mcontext);
+	if (ret == 0) {
+		_i386_enter_uts(&kcb->kcb_kmbx, kcb->kcb_kmbx.km_func,
+		    kcb->kcb_kmbx.km_stack.ss_sp,
+		    kcb->kcb_kmbx.km_stack.ss_size);
+		/* We should not reach here. */
+		return (-1);
+	}
+	else if (ret < 0)
+		return (-1);
+	return (0);
+}
+
+static __inline int
+_thread_switch(struct kcb *kcb, struct tcb *tcb, int setmbox)
+{
+	extern int _libkse_debug;
+
+	if ((kcb == NULL) || (tcb == NULL))
+		return (-1);
+	kcb->kcb_curtcb = tcb;
+	if (_libkse_debug == 0) {
+		tcb->tcb_tmbx.tm_lwp = kcb->kcb_kmbx.km_lwp;
+		if (setmbox != 0)
+			_thr_setcontext(&tcb->tcb_tmbx.tm_context.uc_mcontext,
+			    (intptr_t)&tcb->tcb_tmbx,
+			    (intptr_t *)&kcb->kcb_kmbx.km_curthread);
+		else
+			_thr_setcontext(&tcb->tcb_tmbx.tm_context.uc_mcontext,
+				0, NULL);
+	} else {
+		if (setmbox)
+			kse_switchin(&tcb->tcb_tmbx, KSE_SWITCHIN_SETTMBX);
+		else
+			kse_switchin(&tcb->tcb_tmbx, 0);
+	}
+
+	/* We should not reach here. */
+	return (-1);
+}
+
+#endif
--- /dev/null
+++ lib/libkse/arch/i386/include/atomic_ops.h
@@ -0,0 +1,51 @@
+/*-
+ * Copyright (c) 2001 Daniel Eischen <deischen at 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/libkse/arch/i386/include/atomic_ops.h,v 1.4 2007/10/09 13:42:23 obrien Exp $
+ */
+
+#ifndef	_ATOMIC_OPS_H_
+#define	_ATOMIC_OPS_H_
+
+/*
+ * Atomic swap:
+ *   Atomic (tmp = *dst, *dst = val), then *res = tmp
+ *
+ * void atomic_swap32(intptr_t *dst, intptr_t val, intptr_t *res);
+ */
+static inline void
+atomic_swap32(intptr_t *dst, intptr_t val, intptr_t *res)
+{
+	__asm __volatile(
+	"xchgl %2, %1; movl %2, %0"
+	 : "=m" (*res) : "m" (*dst), "r" (val) : "memory");
+}
+
+#define	atomic_swap_ptr(d, v, r) \
+	atomic_swap32((intptr_t *)d, (intptr_t)v, (intptr_t *)r)
+
+#define	atomic_swap_int(d, v, r) \
+	atomic_swap32((intptr_t *)d, (intptr_t)v, (intptr_t *)r)
+#endif
--- /dev/null
+++ lib/libkse/arch/sparc64/Makefile.inc
@@ -0,0 +1,5 @@
+# $FreeBSD: src/lib/libkse/arch/sparc64/Makefile.inc,v 1.2 2007/10/09 13:42:25 obrien Exp $
+
+.PATH:	${.CURDIR}/arch/${MACHINE_ARCH}/${MACHINE_ARCH}
+
+SRCS+=	pthread_md.c thr_getcontext.S
--- /dev/null
+++ lib/libkse/arch/sparc64/include/pthread_md.h
@@ -0,0 +1,254 @@
+/*-
+ * Copyright (c) 2003 Jake Burkholder <jake at freebsd.org>.
+ * Copyright (c) 2003 Marcel Moolenaar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD: src/lib/libkse/arch/sparc64/include/pthread_md.h,v 1.6 2007/10/09 13:42:25 obrien Exp $
+ */
+
+/*
+ * Machine-dependent thread prototypes/definitions for the thread kernel.
+ */
+#ifndef _PTHREAD_MD_H_
+#define	_PTHREAD_MD_H_
+
+#include <sys/kse.h>
+#include <stddef.h>
+#include <ucontext.h>
+
+#define	KSE_STACKSIZE		16384
+#define	DTV_OFFSET		offsetof(struct tcb, tcb_tp.tp_tdv)
+
+int _thr_setcontext(mcontext_t *, intptr_t, intptr_t *);
+int _thr_getcontext(mcontext_t *);
+
+#define	THR_GETCONTEXT(ucp)	_thr_getcontext(&(ucp)->uc_mcontext)
+#define	THR_SETCONTEXT(ucp)	_thr_setcontext(&(ucp)->uc_mcontext, 0, NULL)
+
+#define	PER_THREAD
+
+struct kcb;
+struct kse;
+struct pthread;
+struct tcb;
+struct tdv;	/* We don't know what this is yet? */
+
+
+/*
+ * %g6 points to one of these. We define the static TLS as an array
+ * of long double to enforce 16-byte alignment of the TLS memory.
+ *
+ * XXX - Both static and dynamic allocation of any of these structures
+ *       will result in a valid, well-aligned thread pointer???
+ */
+struct sparc64_tp {
+	struct tdv		*tp_tdv;	/* dynamic TLS */
+	uint64_t		_reserved_;
+	long double		tp_tls[0];	/* static TLS */
+};
+
+struct tcb {
+	struct pthread		*tcb_thread;
+	void			*tcb_addr;	/* allocated tcb address */
+	struct kcb		*tcb_curkcb;
+	uint64_t		tcb_isfake;
+	uint64_t		tcb_spare[4];
+	struct kse_thr_mailbox	tcb_tmbx;	/* needs 64-byte alignment */
+	struct sparc64_tp	tcb_tp;
+} __aligned(64);
+
+struct kcb {
+	struct kse_mailbox	kcb_kmbx;
+	struct tcb		kcb_faketcb;
+	struct tcb		*kcb_curtcb;
+	struct kse		*kcb_kse;
+};
+
+register struct sparc64_tp *_tp __asm("%g6");
+
+#define	_tcb	((struct tcb*)((char*)(_tp) - offsetof(struct tcb, tcb_tp)))
+
+/*
+ * The kcb and tcb constructors.
+ */
+struct tcb	*_tcb_ctor(struct pthread *, int);
+void		_tcb_dtor(struct tcb *);
+struct kcb	*_kcb_ctor(struct kse *kse);
+void		_kcb_dtor(struct kcb *);
+
+/* Called from the KSE to set its private data. */
+static __inline void
+_kcb_set(struct kcb *kcb)
+{
+	/* There is no thread yet; use the fake tcb. */
+	_tp = &kcb->kcb_faketcb.tcb_tp;
+}
+
+/*
+ * Get the current kcb.
+ *
+ * This can only be called while in a critical region; don't
+ * worry about having the kcb changed out from under us.
+ */
+static __inline struct kcb *
+_kcb_get(void)
+{
+	return (_tcb->tcb_curkcb);
+}
+
+/*
+ * Enter a critical region.
+ *
+ * Read and clear km_curthread in the kse mailbox.
+ */
+static __inline struct kse_thr_mailbox *
+_kcb_critical_enter(void)
+{
+	struct kse_thr_mailbox *crit;
+	uint32_t flags;
+
+	if (_tcb->tcb_isfake != 0) {
+		/*
+		 * We already are in a critical region since
+		 * there is no current thread.
+		 */
+		crit = NULL;
+	} else {
+		flags = _tcb->tcb_tmbx.tm_flags;
+		_tcb->tcb_tmbx.tm_flags |= TMF_NOUPCALL;
+		crit = _tcb->tcb_curkcb->kcb_kmbx.km_curthread;
+		_tcb->tcb_curkcb->kcb_kmbx.km_curthread = NULL;
+		_tcb->tcb_tmbx.tm_flags = flags;
+	}
+	return (crit);
+}
+
+static __inline void
+_kcb_critical_leave(struct kse_thr_mailbox *crit)
+{
+	/* No need to do anything if this is a fake tcb. */
+	if (_tcb->tcb_isfake == 0)
+		_tcb->tcb_curkcb->kcb_kmbx.km_curthread = crit;
+}
+
+static __inline int
+_kcb_in_critical(void)
+{
+	uint32_t flags;
+	int ret;
+
+	if (_tcb->tcb_isfake != 0) {
+		/*
+		 * We are in a critical region since there is no
+		 * current thread.
+		 */
+		ret = 1;
+	} else {
+		flags = _tcb->tcb_tmbx.tm_flags;
+		_tcb->tcb_tmbx.tm_flags |= TMF_NOUPCALL;
+		ret = (_tcb->tcb_curkcb->kcb_kmbx.km_curthread == NULL);
+		_tcb->tcb_tmbx.tm_flags = flags;
+	}
+	return (ret);
+}
+
+static __inline void
+_tcb_set(struct kcb *kcb, struct tcb *tcb)
+{
+	if (tcb == NULL)
+		tcb = &kcb->kcb_faketcb;
+	kcb->kcb_curtcb = tcb;
+	tcb->tcb_curkcb = kcb;
+	_tp = &tcb->tcb_tp;
+}
+
+static __inline struct tcb *
+_tcb_get(void)
+{
+	return (_tcb);
+}
+
+static __inline struct pthread *
+_get_curthread(void)
+{
+	return (_tcb->tcb_thread);
+}
+
+/*
+ * Get the current kse.
+ *
+ * Like _kcb_get(), this can only be called while in a critical region.
+ */
+static __inline struct kse *
+_get_curkse(void)
+{
+	return (_tcb->tcb_curkcb->kcb_kse);
+}
+
+void _sparc64_enter_uts(kse_func_t uts, struct kse_mailbox *km, void *stack,
+    size_t stacksz);
+
+static __inline int
+_thread_enter_uts(struct tcb *tcb, struct kcb *kcb)
+{
+	if (_thr_getcontext(&tcb->tcb_tmbx.tm_context.uc_mcontext) == 0) {
+		/* Make the fake tcb the current thread. */
+		kcb->kcb_curtcb = &kcb->kcb_faketcb;
+		_tp = &kcb->kcb_faketcb.tcb_tp;
+		_sparc64_enter_uts(kcb->kcb_kmbx.km_func, &kcb->kcb_kmbx,
+		    kcb->kcb_kmbx.km_stack.ss_sp,
+		    kcb->kcb_kmbx.km_stack.ss_size);
+		/* We should not reach here. */
+		return (-1);
+	}
+	return (0);
+}
+
+static __inline int
+_thread_switch(struct kcb *kcb, struct tcb *tcb, int setmbox)
+{
+	extern int _libkse_debug;
+	mcontext_t *mc;
+
+	_tcb_set(kcb, tcb);
+	mc = &tcb->tcb_tmbx.tm_context.uc_mcontext;
+	if (_libkse_debug == 0) {
+		tcb->tcb_tmbx.tm_lwp = kcb->kcb_kmbx.km_lwp;
+		if (setmbox)
+			_thr_setcontext(mc, (intptr_t)&tcb->tcb_tmbx,
+			    (intptr_t *)&kcb->kcb_kmbx.km_curthread);
+		else
+			_thr_setcontext(mc, 0, NULL);
+	} else {
+		if (setmbox)
+			kse_switchin(&tcb->tcb_tmbx, KSE_SWITCHIN_SETTMBX);
+		else
+			kse_switchin(&tcb->tcb_tmbx, 0);
+	}
+
+	/* We should not reach here. */
+	return (-1);
+}
+
+#endif /* _PTHREAD_MD_H_ */
--- /dev/null
+++ lib/libkse/arch/sparc64/include/atomic_ops.h
@@ -0,0 +1,75 @@
+/*-
+ * Copyright (c) 2003 Jake Burkholder <jake at 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/libkse/arch/sparc64/include/atomic_ops.h,v 1.2 2007/10/09 13:42:25 obrien Exp $
+ */
+
+#ifndef	_ATOMIC_OPS_H_
+#define	_ATOMIC_OPS_H_
+
+#include <machine/atomic.h>
+
+/*
+ * Atomic swap:
+ *   Atomic (tmp = *dst, *dst = val), then *res = tmp
+ *
+ * void atomic_swap_long(long *dst, long val, long *res);
+ */
+static __inline void
+atomic_swap_long(long *dst, long val, long *res)
+{
+	long tmp;
+	long r;
+
+	tmp = *dst;
+	for (;;) {
+		r = atomic_cas_64(dst, tmp, val);
+		if (r == tmp)
+			break;
+		tmp = r;
+	}
+	*res = tmp;
+}
+
+static __inline void
+atomic_swap_int(int *dst, int val, int *res)
+{
+	int tmp;
+	int r;
+
+	tmp = *dst;
+	for (;;) {
+		r = atomic_cas_32(dst, tmp, val);
+		if (r == tmp)
+			break;
+		tmp = r;
+	}
+	*res = tmp;
+}
+
+#define	atomic_swap_ptr(dst, val, res) \
+	atomic_swap_long((long *)dst, (long)val, (long *)res)
+
+#endif
--- /dev/null
+++ lib/libkse/arch/sparc64/sparc64/thr_getcontext.S
@@ -0,0 +1,87 @@
+/*-
+ * Copyright (C) 2003 Jake Burkholder <jake at 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.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD: src/lib/libkse/arch/sparc64/sparc64/thr_getcontext.S,v 1.4 2007/10/09 13:42:25 obrien Exp $");
+
+#include "assym.s"
+
+	.weak	CNAME(_thr_getcontext)
+	.set	CNAME(_thr_getcontext),CNAME(__thr_getcontext)
+ENTRY(__thr_getcontext)
+	add	%o7, 8, %o1
+	add	%o1, 4, %o2
+	stx	%sp, [%o0 + MC_OUT + (6 * 8)]
+	stx	%o1, [%o0 + MC_TPC]
+	stx	%o2, [%o0 + MC_TNPC]
+	mov	MC_VALID_FLAGS, %l0		/* Validate the context. */
+	stx	%l0, [%o0 + MC_FLAGS]
+	mov	1, %l0
+	stx	%l0, [%o0 + MC_OUT + (0 * 8)]	/* return 1 when resumed */
+	retl
+	mov	0, %o0				/* return 0 */
+END(__thr_getcontext)
+
+	.weak	CNAME(_thr_setcontext)
+	.set	CNAME(_thr_setcontext),CNAME(__thr_setcontext)
+ENTRY(__thr_setcontext)
+	save	%sp, -CCFSZ, %sp
+	flushw
+	mov	%i0, %l0
+	mov	%i1, %l1
+	mov	%i2, %l2
+	ldx	[%l0 + MC_GLOBAL + (1 * 8)], %g1
+	ldx	[%l0 + MC_GLOBAL + (2 * 8)], %g2
+	ldx	[%l0 + MC_GLOBAL + (3 * 8)], %g3
+	ldx	[%l0 + MC_GLOBAL + (4 * 8)], %g4
+	ldx	[%l0 + MC_GLOBAL + (5 * 8)], %g5
+	ldx	[%l0 + MC_GLOBAL + (6 * 8)], %g6
+	ldx	[%l0 + MC_GLOBAL + (7 * 8)], %g7
+	ldx	[%l0 + MC_OUT + (0 * 8)], %i0
+	ldx	[%l0 + MC_OUT + (1 * 8)], %i1
+	ldx     [%l0 + MC_OUT + (2 * 8)], %i2
+	ldx	[%l0 + MC_OUT + (3 * 8)], %i3
+	ldx	[%l0 + MC_OUT + (4 * 8)], %i4
+	ldx	[%l0 + MC_OUT + (5 * 8)], %i5
+	ldx	[%l0 + MC_OUT + (6 * 8)], %i6
+	ldx	[%l0 + MC_OUT + (7 * 8)], %i7
+	ldx	[%l0 + MC_TPC], %l4
+	ldx	[%l0 + MC_TNPC], %l3
+	brz	%l2, 1f
+	nop
+	stx	%l1, [%l2]
+1:	jmpl	%l3, %g0
+	return	%l4
+END(__thr_setcontext)
+
+ENTRY(_sparc64_enter_uts)
+	save	%sp, -CCFSZ, %sp
+	flushw
+	add	%i2, %i3, %i2
+	sub	%i2, SPOFF + CCFSZ, %sp
+	jmpl	%i0, %g0
+	mov	%i1, %o0
+END(_sparc64_enter_uts)
--- /dev/null
+++ lib/libkse/arch/sparc64/sparc64/assym.s
@@ -0,0 +1,15 @@
+/*
+ * Offsets into structures used from asm.  Must be kept in sync with
+ * appropriate headers.
+ *
+ * $FreeBSD: src/lib/libkse/arch/sparc64/sparc64/assym.s,v 1.3 2007/10/09 13:42:25 obrien Exp $
+ */
+
+#define	UC_MCONTEXT	0x40
+
+#define	MC_FLAGS	0x0
+#define	MC_VALID_FLAGS	0x1
+#define	MC_GLOBAL	0x0
+#define	MC_OUT		0x40
+#define	MC_TPC		0xc8
+#define	MC_TNPC		0xc0
--- /dev/null
+++ lib/libkse/arch/sparc64/sparc64/pthread_md.c
@@ -0,0 +1,91 @@
+/*-
+ * Copyright (C) 2003 Jake Burkholder <jake at freebsd.org>
+ * Copyright (C) 2003 David Xu <davidxu at freebsd.org>
+ * Copyright (c) 2001,2003 Daniel Eischen <deischen at 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/lib/libkse/arch/sparc64/sparc64/pthread_md.c,v 1.4 2007/10/09 13:42:25 obrien Exp $");
+
+#include <sys/types.h>
+
+#include <unistd.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ucontext.h>
+
+#include "pthread_md.h"
+
+struct tcb *
+_tcb_ctor(struct pthread *thread, int initial)
+{
+	struct tcb *tcb;
+	void *addr;
+
+	addr = malloc(sizeof(struct tcb) + 63);
+	if (addr == NULL)
+		tcb = NULL;
+	else {
+		tcb = (struct tcb *)(((uintptr_t)(addr) + 63) & ~63);
+		bzero(tcb, sizeof(struct tcb));
+		tcb->tcb_addr = addr;
+		tcb->tcb_thread = thread;
+		/* XXX - Allocate tdv/tls */
+	}
+	return (tcb);
+}
+
+void
+_tcb_dtor(struct tcb *tcb)
+{
+	void *addr;
+
+	addr = tcb->tcb_addr;
+	tcb->tcb_addr = NULL;
+	free(addr);
+}
+
+struct kcb *
+_kcb_ctor(struct kse *kse)
+{
+	struct kcb *kcb;
+
+	kcb = malloc(sizeof(struct kcb));
+	if (kcb != NULL) {
+		bzero(kcb, sizeof(struct kcb));
+		kcb->kcb_faketcb.tcb_isfake = 1;
+		kcb->kcb_faketcb.tcb_tmbx.tm_flags = TMF_NOUPCALL;
+		kcb->kcb_curtcb = &kcb->kcb_faketcb;
+		kcb->kcb_kse = kse;
+	}
+	return (kcb);
+}
+
+void
+_kcb_dtor(struct kcb *kcb)
+{
+	free(kcb);
+}
--- /dev/null
+++ lib/libkse/support/Makefile.inc
@@ -0,0 +1,40 @@
+# $FreeBSD: src/lib/libkse/support/Makefile.inc,v 1.9 2007/10/09 13:42:25 obrien Exp $
+
+.PATH: ${.CURDIR}/support ${.CURDIR}/../libc/gen ${.CURDIR}/../libc/string
+.PATH: ${.CURDIR}/../libc/${MACHINE_ARCH}/sys
+
+CFLAGS+= -I${.CURDIR}/../libc/${MACHINE_ARCH}
+
+SYSCALLS= clock_gettime \
+	kse_create \
+	kse_exit \
+	kse_release \
+	kse_switchin \
+	kse_thr_interrupt \
+	kse_wakeup \
+	sigaction \
+	sigprocmask \
+	sigtimedwait \
+	write
+
+SYSCALL_SRC=   ${SYSCALLS:S/$/.S/}
+SYSCALL_OBJ=   ${SYSCALLS:S/$/.So/}
+
+${SYSCALL_SRC}:
+	printf '#include "SYS.h"\nRSYSCALL(${.PREFIX})\n' > ${.TARGET}
+
+LIBC_OBJS= sigsetops.So \
+	bcopy.So \
+	bzero.So \
+	cerror.So \
+	memcpy.So \
+	memset.So \
+	strcpy.So \
+	strlen.So
+
+SOBJS+=	thr_libc.So
+CLEANFILES+= ${SYSCALL_SRC} ${SYSCALL_OBJ} ${LIBC_OBJS}
+
+thr_libc.So: ${SYSCALL_OBJ} ${LIBC_OBJS}
+	${CC} -fPIC -nostdlib -o ${.TARGET} -r ${.ALLSRC}
+
--- /dev/null
+++ lib/libkse/support/thr_support.c
@@ -0,0 +1,62 @@
+/*-
+ * Copyright 2003 Alexander Kabaev.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must 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/libkse/support/thr_support.c,v 1.5 2007/10/09 13:42:25 obrien Exp $
+ */
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/kse.h>
+#include <signal.h>
+#include <string.h>
+
+#include "thr_private.h"
+
+__strong_reference(clock_gettime, _thr_clock_gettime);
+__strong_reference(kse_exit, _thr_kse_exit);
+__strong_reference(kse_wakeup, _thr_kse_wakeup);
+__strong_reference(kse_create, _thr_kse_create);
+__strong_reference(kse_thr_interrupt, _thr_kse_thr_interrupt);
+__strong_reference(kse_release, _thr_kse_release);
+__strong_reference(kse_switchin, _thr_kse_switchin);
+
+__strong_reference(sigaction, _thr_sigaction);
+__strong_reference(sigprocmask, _thr_sigprocmask);
+__strong_reference(sigemptyset, _thr_sigemptyset);
+__strong_reference(sigaddset, _thr_sigaddset);
+__strong_reference(sigfillset, _thr_sigfillset);
+__strong_reference(sigismember, _thr_sigismember);
+__strong_reference(sigdelset, _thr_sigdelset);
+
+__strong_reference(memset, _thr_memset);
+__strong_reference(memcpy, _thr_memcpy);
+__strong_reference(strcpy, _thr_strcpy);
+__strong_reference(strlen, _thr_strlen);
+__strong_reference(bzero, _thr_bzero);
+__strong_reference(bcopy, _thr_bcopy);
+
+__strong_reference(__sys_write, _thr__sys_write);
+__strong_reference(__sys_sigtimedwait, _thr__sys_sigtimedwait);
+
Index: Makefile
===================================================================
RCS file: /home/cvs/src/lib/Makefile,v
retrieving revision 1.5
retrieving revision 1.6
diff -L lib/Makefile -L lib/Makefile -u -r1.5 -r1.6
--- lib/Makefile
+++ lib/Makefile
@@ -2,6 +2,8 @@
 # $FreeBSD: src/lib/Makefile,v 1.205.2.1 2005/07/28 13:47:18 rwatson Exp $
 # $MidnightBSD$
 
+.include <bsd.own.mk>
+
 # To satisfy shared library or ELF linkage when only the libraries being
 # built are visible:
 #
@@ -21,21 +23,21 @@
 # libtacplus must be built before libpam.
 # libutil must be built before libpam.
 # libypclnt must be built before libpam.
-# libpthread must be built before libsqlite3
+# libkse must be built before libsqlite3
 # libbz2 must be built before libarchive
 # Otherwise, the SUBDIR list should be in alphabetical order.
 
-SUBDIR=	${_csu} libc ${_libc_r} libcom_err libcrypt libkvm msun libmd libncurses \
-	libnetgraph libradius librpcsvc libsbuf libtacplus libutil \
+SUBDIR=	${_csu} libc libbsm libcom_err libcrypt libkvm msun libmd \
+	ncurses libnetgraph libradius librpcsvc libsbuf libtacplus libutil \
 	${_libypclnt} libalias libbz2 libarchive ${_libatm} \
 	libbegemot ${_libbluetooth} libbsnmp \
-	libcalendar libcam libcompat libdevinfo libdevstat ${_libdisk} \
+	libcalendar libcam libcompat libdevinfo libdevstat libdisk \
 	libedit libexpat libfetch libform libftpio libgeom ${_libgpib} \
 	libipsec \
 	libipx libkiconv libmagic libmemstat libmenu ${_libmilter} ${_libmp} \
 	${_libncp} ${_libngatm} libopie libpam libpanel libpcap \
-	libpmc ${_libpthread} ${_libsdp} ${_libsm} ${_libsmb} ${_libsmdb} \
-	${_libsmutil} libstand libtelnet ${_libthr} ${_libthread_db} libufs \
+	libpmc ${_libkse} ${_libsdp} ${_libsm} ${_libsmb} ${_libsmdb} \
+	${_libsmutil} libstand libtelnet ${_libthr} libthread_db libufs \
 	libugidfw ${_libusbhid} ${_libvgl} libwrap liby libz ${_bind} \
 	libsqlite3
 
@@ -47,72 +49,72 @@
 _csu=csu
 .endif
 
-.if !defined(NO_ATM)
-_libatm=	libatm
+.if ${MK_ATM} != "no"
+# Not MPSAFE
+#_libatm=	libatm
 _libngatm=	libngatm
 .endif
 
-.if !defined(NO_BIND)
+.if ${MK_BIND} != "no"
 _bind=		bind
 .endif
 
-.if !defined(NO_BLUETOOTH)
+.if ${MK_BLUETOOTH} != "no"
 _libbluetooth=	libbluetooth
 _libsdp=	libsdp
 .endif
 
-.if ${MACHINE_ARCH} == "i386"
-_libncp=	libncp
-_libsmb=	libsmb
-_libvgl=	libvgl
+.if ${MK_GSSAPI} != "no"
+_libgssapi=	libgssapi
 .endif
 
-.if ${MACHINE_ARCH} != "arm" && ${MACHINE_ARCH} != "ia64" && \
-    ${MACHINE_ARCH} != "powerpc" && !defined(NO_LIBC_R)
-_libc_r=	libc_r
+.if ${MK_IPX} != "no"
+_libipx=	libipx
 .endif
 
-.if ${MACHINE_ARCH} != "arm"
-_libdisk=	libdisk
+.if ${MACHINE_ARCH} == "i386"
+.if ${MK_NCP} != "no"
+_libncp=	libncp
+.endif
+_libsmb=	libsmb
+_libvgl=	libvgl
 .endif
 
-.if !defined(NO_SENDMAIL)
+.if ${MK_SENDMAIL} != "no"
 _libmilter=	libmilter
 _libsm=		libsm
 _libsmdb=	libsmdb
 _libsmutil=	libsmutil
 .endif
 
-.if !defined(NO_CRYPT) && !defined(NO_OPENSSL)
+.if ${MK_OPENSSL} != "no"
 _libmp=		libmp
 .endif
 
 .if ${MACHINE_ARCH} == "amd64"
+.if ${MK_NCP} != "no"
 _libncp=	libncp
-_libsmb=	libsmb
 .endif
-
-.if !defined(NO_LIBPTHREAD)
-_libpthread=	libpthread
+_libsmb=	libsmb
 .endif
 
-.if !defined(NO_LIBTHR)
-_libthr= libthr
+.if ${MK_LIBKSE} != "no"
+_libkse=	libkse
 .endif
 
-.if ${MACHINE_ARCH} != "arm" && ${MACHINE_ARCH} != "powerpc"
-_libthread_db= libthread_db
+.if ${MK_LIBTHR} != "no"
+_libthr=	libthr
 .endif
 
-.if !defined(NO_USB)
+.if ${MK_USB} != "no"
 _libusbhid=	libusbhid
 .endif
 
-.if !defined(NO_NIS)
+.if ${MK_NIS} != "no"
 _libypclnt=	libypclnt
 .endif
 
-.if !defined(NO_GPIB)
+.if ${MK_GPIB} != "no"
 _libgpib=	libgpib
 .endif
 
--- /dev/null
+++ lib/libkse/Makefile
@@ -0,0 +1,63 @@
+# $FreeBSD: src/lib/libkse/Makefile,v 1.66.2.1 2007/12/06 16:22:18 brooks 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.
+
+.include <bsd.own.mk>
+
+.if ${DEFAULT_THREAD_LIB} == "libkse" || ${MK_LIBTHR} == "no"
+LIB=kse
+.if ${SHLIBDIR} == "/usr/lib"
+SHLIBDIR= /lib
+.endif
+.else
+SHLIB=kse
+.endif
+
+SHLIB_MAJOR= 3
+CFLAGS+=-DPTHREAD_KERNEL
+CFLAGS+=-I${.CURDIR}/../libc/include -I${.CURDIR}/thread \
+	-I${.CURDIR}/../../include
+CFLAGS+=-I${.CURDIR}/arch/${MACHINE_ARCH}/include
+CFLAGS+=-I${.CURDIR}/sys
+CFLAGS+=-I${.CURDIR}/../../libexec/rtld-elf
+CFLAGS+=-I${.CURDIR}/../../libexec/rtld-elf/${MACHINE_ARCH}
+CFLAGS+=-fno-builtin
+
+# Uncomment this if you want libkse to contain debug information for
+# thread locking.
+CFLAGS+=-D_LOCK_DEBUG
+WARNS?=2
+
+# Uncomment this if you want to build a 1:1 threading mode library
+# however it is no longer strictly conformed to POSIX
+# CFLAGS+=-DSYSTEM_SCOPE_ONLY
+
+# Enable extra internal consistancy checks.
+CFLAGS+=-D_PTHREADS_INVARIANTS -Wall
+
+VERSION_MAP=${.CURDIR}/kse.map
+
+PRECIOUSLIB=
+
+.include "${.CURDIR}/arch/${MACHINE_ARCH}/Makefile.inc"
+.include "${.CURDIR}/support/Makefile.inc"
+.include "${.CURDIR}/sys/Makefile.inc"
+.include "${.CURDIR}/thread/Makefile.inc"
+
+.if ${DEFAULT_THREAD_LIB} == "libkse" || ${MK_LIBTHR} == "no"
+SYMLINKS+=lib${LIB}.a ${LIBDIR}/libpthread.a
+.if !defined(NO_PIC)
+SYMLINKS+=lib${LIB}.so ${LIBDIR}/libpthread.so
+.endif
+.if ${MK_PROFILE} != "no"
+SYMLINKS+=lib${LIB}_p.a ${LIBDIR}/libpthread_p.a
+.endif
+.endif
+
+.include <bsd.lib.mk>
--- /dev/null
+++ lib/libkse/kse.map
@@ -0,0 +1,368 @@
+/* $FreeBSD: src/lib/libkse/kse.map,v 1.1 2007/10/09 13:42:21 obrien Exp $ */
+
+/*
+ * Use the same naming scheme as libc.
+ */
+FBSD_1.0 {
+global:
+	__error;
+	accept;
+	aio_suspend;
+	close;
+	connect;
+	creat;
+	execve;
+	fcntl;
+	fork;
+	fsync;
+	msync;
+	nanosleep;
+	open;
+	pause;
+	poll;
+	pselect;
+	pthread_atfork;
+	pthread_barrier_destroy;
+	pthread_barrier_init;
+	pthread_barrier_wait;
+	pthread_barrierattr_destroy;
+	pthread_barrierattr_getpshared;
+	pthread_barrierattr_init;
+	pthread_barrierattr_setpshared;
+	pthread_attr_destroy;
+	pthread_attr_get_np;
+	pthread_attr_getdetachstate;
+	pthread_attr_getguardsize;
+	pthread_attr_getinheritsched;
+	pthread_attr_getschedparam;
+	pthread_attr_getschedpolicy;
+	pthread_attr_getscope;
+	pthread_attr_getstack;
+	pthread_attr_getstackaddr;
+	pthread_attr_getstacksize;
+	pthread_attr_init;
+	pthread_attr_setcreatesuspend_np;
+	pthread_attr_setdetachstate;
+	pthread_attr_setguardsize;
+	pthread_attr_setinheritsched;
+	pthread_attr_setschedparam;
+	pthread_attr_setschedpolicy;
+	pthread_attr_setscope;
+	pthread_attr_setstack;
+	pthread_attr_setstackaddr;
+	pthread_attr_setstacksize;
+	pthread_cancel;
+	pthread_cleanup_pop;
+	pthread_cleanup_push;
+	pthread_cond_broadcast;
+	pthread_cond_destroy;
+	pthread_cond_init;
+	pthread_cond_signal;
+	pthread_cond_timedwait;
+	pthread_cond_wait;
+	pthread_condattr_destroy;
+	pthread_condattr_init;
+	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;
+	sched_yield;
+	select;
+	sem_init;
+	sem_post;
+	sem_timedwait;
+	sem_wait;
+	sigaction;
+	sigaltstack;
+	sigpending;
+	sigprocmask;
+	sigsuspend;
+	sigwait;
+	sigwaitinfo;
+	sigtimedwait;
+	sleep;
+	system;
+	tcdrain;
+	usleep;
+	vfork;
+	wait4;
+	wait;
+	waitpid;
+	write;
+	writev;
+local:
+	*;
+};
+
+/*
+ * List the private interfaces reserved for use in FreeBSD libraries.
+ * These are not part of our application ABI.
+ */
+FBSDprivate_1.0 {
+global:
+	___creat;
+	__accept;
+	__close;
+	__connect;
+	__fcntl;
+	__fsync;
+	__msync;
+	__nanosleep;
+	__open;
+	__poll;
+	__pthread_cond_timedwait;
+	__pthread_cond_wait;
+	__pthread_mutex_init;
+	__pthread_mutex_lock;
+	__pthread_mutex_trylock;
+	__pthread_mutex_timedlock;
+	__read;
+	__readv;
+	__select;
+	__sigsuspend;
+	__sigtimedwait;
+	__sigwait;
+	__sigwaitinfo;
+	__wait4;
+	__write;
+	__writev;
+	_aio_suspend;
+	_execve;
+	_fork;
+	_nanosleep;
+	_pause;
+	_pselect;
+	_pthread_atfork;
+	_pthread_barrier_destroy;
+	_pthread_barrier_init;
+	_pthread_barrier_wait;
+	_pthread_barrierattr_destroy;
+	_pthread_barrierattr_getpshared;
+	_pthread_barrierattr_init;
+	_pthread_barrierattr_setpshared;
+	_pthread_attr_destroy;
+	_pthread_attr_get_np;
+	_pthread_attr_getdetachstate;
+	_pthread_attr_getguardsize;
+	_pthread_attr_getinheritsched;
+	_pthread_attr_getschedparam;
+	_pthread_attr_getschedpolicy;
+	_pthread_attr_getscope;
+	_pthread_attr_getstack;
+	_pthread_attr_getstackaddr;
+	_pthread_attr_getstacksize;
+	_pthread_attr_init;
+	_pthread_attr_setcreatesuspend_np;
+	_pthread_attr_setdetachstate;
+	_pthread_attr_setguardsize;
+	_pthread_attr_setinheritsched;
+	_pthread_attr_setschedparam;
+	_pthread_attr_setschedpolicy;
+	_pthread_attr_setscope;
+	_pthread_attr_setstack;
+	_pthread_attr_setstackaddr;
+	_pthread_attr_setstacksize;
+	_pthread_cancel;
+	_pthread_cleanup_pop;
+	_pthread_cleanup_push;
+	_pthread_cond_broadcast;
+	_pthread_cond_destroy;
+	_pthread_cond_init;
+	_pthread_cond_signal;
+	_pthread_cond_timedwait;
+	_pthread_cond_wait;
+	_pthread_condattr_default;
+	_pthread_condattr_destroy;
+	_pthread_condattr_init;
+	_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;
+	_sched_yield;
+	_sem_init;
+	_sem_post;
+	_sem_timedwait;
+	_sem_wait;
+	_sigaction;
+	_sigaltstack;
+	_sigpending;
+	_sigprocmask;
+	_sigsuspend;
+	_sigtimedwait;
+	_sigwait;
+	_sigwaitinfo;
+	_sleep;
+	_spinlock;
+	_spinlock_debug;
+	_spinunlock;
+	_system;
+	_tcdrain;
+	_usleep;
+	_vfork;
+	_wait;
+	_waitpid;
+
+	/* Debugger needs these. */
+	_libkse_debug;
+	_thread_activated;
+	_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_tmbx;
+	_thread_off_key_allocated;
+	_thread_off_key_destructor;
+	_thread_off_kse;
+	_thread_off_kse_locklevel;
+	_thread_off_sigmask;
+	_thread_off_sigpend;
+	_thread_off_state;
+	_thread_off_thr_locklevel;
+	_thread_off_tlsindex;
+	_thread_size_key;
+	_thread_state_running;
+	_thread_state_zoombie;
+
+local:
+	*;
+};
--- /dev/null
+++ lib/libkse/arch/amd64/Makefile.inc
@@ -0,0 +1,5 @@
+# $FreeBSD: src/lib/libkse/arch/amd64/Makefile.inc,v 1.3 2007/10/09 13:42:22 obrien Exp $
+
+.PATH:	${.CURDIR}/arch/${MACHINE_ARCH}/${MACHINE_ARCH}
+
+SRCS+=	context.S enter_uts.S pthread_md.c
--- /dev/null
+++ lib/libkse/arch/i386/Makefile.inc
@@ -0,0 +1,5 @@
+# $FreeBSD: src/lib/libkse/arch/i386/Makefile.inc,v 1.4 2007/10/09 13:42:23 obrien Exp $
+
+.PATH:	${.CURDIR}/arch/${MACHINE_ARCH}/${MACHINE_ARCH}
+
+SRCS+=	thr_enter_uts.S thr_getcontext.S pthread_md.c
--- /dev/null
+++ lib/libkse/test/propagate_s.pl
@@ -0,0 +1,74 @@
+#!/usr/bin/perl -w
+#
+# Copyright (C) 2000 Jason Evans <jasone at freebsd.org>.
+# All rights reserved.
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice(s), this list of conditions and the following disclaimer as
+#    the first lines of this file unmodified other than the possible
+#    addition of one or more copyright notices.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice(s), this list of conditions and the following disclaimer in
+#    the documentation and/or other materials provided with the
+#    distribution.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+###########################################################################
+#
+# Verify that no cancellation points are propagated inside of libpthread.
+#
+# $FreeBSD: src/lib/libkse/test/propagate_s.pl,v 1.3 2007/10/09 13:42:26 obrien Exp $
+#
+
+ at CPOINTS = ("aio_suspend", "close", "creat", "fcntl", "fsync", "mq_receive",
+	    "mq_send", "msync", "nanosleep", "open", "pause",
+	    "pthread_cond_timedwait", "pthread_cond_wait", "pthread_join",
+	    "pthread_testcancel", "read", "sem_wait", "sigsuspend",
+	    "sigtimedwait", "sigwait", "sigwaitinfo", "sleep", "system",
+	    "tcdrain", "wait", "waitpid", "write");
+
+print "1..1\n";
+
+$cpoints = join '\|', @CPOINTS;
+$regexp = "\" U \\(" . $cpoints . "\\\)\$\"";
+
+`nm -a /usr/lib/libc.a |grep $regexp >propagate_s.out`;
+if (!open (NMOUT, "<./propagate_s.out"))
+{
+    print "not ok 1\n";
+}
+else
+{
+    $propagations = 0; 
+
+    while (<NMOUT>)
+    {
+	$propagations++;
+	print "$_\n";
+    }
+    if ($propagations != 0)
+    {
+	print "$propagations propagation(s)\n";
+	print "not ok 1\n";
+    }
+    else
+    {
+	print "ok 1\n";
+    }
+    close NMOUT;
+    unlink "propagate_s.out";
+}
--- /dev/null
+++ lib/libkse/test/sem_d.c
@@ -0,0 +1,133 @@
+/****************************************************************************
+ *
+ * Copyright (C) 2000 Jason Evans <jasone at freebsd.org>.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice(s), this list of conditions and the following disclaimer as
+ *    the first lines of this file unmodified other than the possible
+ *    addition of one or more copyright notices.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice(s), this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************
+ *
+ * sem test.
+ *
+ * $FreeBSD: src/lib/libkse/test/sem_d.c,v 1.3 2007/10/09 13:42:26 obrien Exp $
+ *
+ ****************************************************************************/
+
+#include <assert.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <semaphore.h>
+#include <pthread.h>
+
+#define NTHREADS 10
+
+void *
+entry(void * a_arg)
+{
+	sem_t * sem = (sem_t *) a_arg;
+
+	sem_wait(sem);
+	fprintf(stderr, "Got semaphore\n");
+  
+	return NULL;
+}
+
+int
+main()
+{
+	sem_t sem_a, sem_b;
+	pthread_t threads[NTHREADS];
+	unsigned i;
+	int val;
+  
+	fprintf(stderr, "Test begin\n");
+
+#ifdef _LIBC_R_
+	assert(-1 == sem_init(&sem_b, 1, 0));
+	assert(EPERM == errno);
+#endif
+
+	assert(0 == sem_init(&sem_b, 0, 0));
+	assert(0 == sem_getvalue(&sem_b, &val));
+	assert(0 == val);
+  
+	assert(0 == sem_post(&sem_b));
+	assert(0 == sem_getvalue(&sem_b, &val));
+	assert(1 == val);
+  
+	assert(0 == sem_wait(&sem_b));
+	assert(-1 == sem_trywait(&sem_b));
+	assert(EAGAIN == errno);
+	assert(0 == sem_post(&sem_b));
+	assert(0 == sem_trywait(&sem_b));
+	assert(0 == sem_post(&sem_b));
+	assert(0 == sem_wait(&sem_b));
+	assert(0 == sem_post(&sem_b));
+
+#ifdef _LIBC_R_
+	assert(SEM_FAILED == sem_open("/foo", O_CREAT | O_EXCL, 0644, 0));
+	assert(ENOSYS == errno);
+
+	assert(-1 == sem_close(&sem_b));
+	assert(ENOSYS == errno);
+  
+	assert(-1 == sem_unlink("/foo"));
+	assert(ENOSYS == errno);
+#endif
+
+	assert(0 == sem_destroy(&sem_b));
+  
+	assert(0 == sem_init(&sem_a, 0, 0));
+
+	for (i = 0; i < NTHREADS; i++) {
+		pthread_create(&threads[i], NULL, entry, (void *) &sem_a);
+	}
+
+	for (i = 0; i < NTHREADS; i++) {
+		assert(0 == sem_post(&sem_a));
+	}
+  
+	for (i = 0; i < NTHREADS; i++) {
+		pthread_join(threads[i], NULL);
+	}
+  
+	for (i = 0; i < NTHREADS; i++) {
+		pthread_create(&threads[i], NULL, entry, (void *) &sem_a);
+	}
+
+	for (i = 0; i < NTHREADS; i++) {
+		assert(0 == sem_post(&sem_a));
+	}
+  
+	for (i = 0; i < NTHREADS; i++) {
+		pthread_join(threads[i], NULL);
+	}
+  
+	assert(0 == sem_destroy(&sem_a));
+
+	fprintf(stderr, "Test end\n");
+	return 0;
+}
--- /dev/null
+++ lib/libkse/test/hello_d.exp
@@ -0,0 +1,2 @@
+# $FreeBSD: src/lib/libkse/test/hello_d.exp,v 1.2 2007/10/09 13:42:26 obrien Exp $
+Hello world
--- /dev/null
+++ lib/libkse/test/sigwait_d.c
@@ -0,0 +1,304 @@
+/*
+ * Copyright (c) 1998 Daniel M. Eischen <eischen at vigrid.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by Daniel M. Eischen.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY DANIEL M. EISCHEN AND CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/lib/libkse/test/sigwait_d.c,v 1.3 2007/10/09 13:42:26 obrien Exp $
+ */
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <errno.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+
+#if defined(_LIBC_R_)
+#include <pthread_np.h>
+#endif
+
+static int		sigcounts[NSIG + 1];
+static sigset_t		wait_mask;
+static pthread_mutex_t	waiter_mutex;
+
+
+static void *
+sigwaiter (void *arg)
+{
+	int signo;
+	sigset_t mask;
+
+	/* Block SIGHUP */
+	sigemptyset (&mask);
+	sigaddset (&mask, SIGHUP);
+	sigprocmask (SIG_BLOCK, &mask, NULL);
+
+	while (sigcounts[SIGINT] == 0) {
+		if (sigwait (&wait_mask, &signo) != 0) {
+			fprintf (stderr,
+			    "Unable to wait for signal, errno %d\n",
+			    errno);
+			exit (1);
+		}
+		sigcounts[signo]++;
+		fprintf (stderr, "Sigwait caught signal %d\n", signo);
+
+		/* Allow the main thread to prevent the sigwait. */
+		pthread_mutex_lock (&waiter_mutex);
+		pthread_mutex_unlock (&waiter_mutex);
+	}
+
+	pthread_exit (arg);
+	return (NULL);
+}
+
+
+static void
+sighandler (int signo)
+{
+	fprintf (stderr, "  -> Signal handler caught signal %d\n", signo);
+
+	if ((signo >= 0) && (signo <= NSIG))
+		sigcounts[signo]++;
+}
+
+static void
+send_thread_signal (pthread_t tid, int signo)
+{
+	if (pthread_kill (tid, signo) != 0) {
+		fprintf (stderr, "Unable to send thread signal, errno %d.\n",
+		    errno);
+		exit (1);
+	}
+}
+
+static void
+send_process_signal (int signo)
+{
+	if (kill (getpid (), signo) != 0) {
+		fprintf (stderr, "Unable to send process signal, errno %d.\n",
+		    errno);
+		exit (1);
+	}
+}
+
+
+int main (int argc, char *argv[])
+{
+	pthread_mutexattr_t mattr;
+	pthread_attr_t	pattr;
+	pthread_t	tid;
+	void *		exit_status;
+	struct sigaction act;
+
+	/* Initialize our signal counts. */
+	memset ((void *) sigcounts, 0, NSIG * sizeof (int));
+
+	/* Setup our wait mask. */
+	sigemptyset (&wait_mask);		/* Default action	*/
+	sigaddset (&wait_mask, SIGHUP);		/* terminate		*/
+	sigaddset (&wait_mask, SIGINT);		/* terminate		*/
+	sigaddset (&wait_mask, SIGQUIT);	/* create core image	*/
+	sigaddset (&wait_mask, SIGURG);		/* ignore		*/
+	sigaddset (&wait_mask, SIGIO);		/* ignore		*/
+	sigaddset (&wait_mask, SIGUSR1);	/* terminate		*/
+
+	/* Ignore signals SIGHUP and SIGIO. */
+	sigemptyset (&act.sa_mask);
+	sigaddset (&act.sa_mask, SIGHUP);
+	sigaddset (&act.sa_mask, SIGIO);
+	act.sa_handler = SIG_IGN;
+	act.sa_flags = 0;
+	sigaction (SIGHUP, &act, NULL);
+	sigaction (SIGIO, &act, NULL);
+
+	/* Install a signal handler for SIGURG */
+	sigemptyset (&act.sa_mask);
+	sigaddset (&act.sa_mask, SIGURG);
+	act.sa_handler = sighandler;
+	act.sa_flags = SA_RESTART;
+	sigaction (SIGURG, &act, NULL);
+
+	/* Install a signal handler for SIGXCPU */
+	sigemptyset (&act.sa_mask);
+	sigaddset (&act.sa_mask, SIGXCPU);
+	sigaction (SIGXCPU, &act, NULL);
+
+	/*
+	 * Initialize the thread attribute.
+	 */
+	if ((pthread_attr_init (&pattr) != 0) ||
+	    (pthread_attr_setdetachstate (&pattr,
+	    PTHREAD_CREATE_JOINABLE) != 0)) {
+		fprintf (stderr, "Unable to initialize thread attributes.\n");
+		exit (1);
+	}
+
+	/*
+	 * Initialize and create a mutex.
+	 */
+	if ((pthread_mutexattr_init (&mattr) != 0) ||
+	    (pthread_mutex_init (&waiter_mutex, &mattr) != 0)) {
+		fprintf (stderr, "Unable to create waiter mutex.\n");
+		exit (1);
+	}
+
+	/*
+	 * Create the sigwaiter thread.
+	 */
+	if (pthread_create (&tid, &pattr, sigwaiter, NULL) != 0) {
+		fprintf (stderr, "Unable to create thread.\n");
+		exit (1);
+	}
+#if defined(_LIBC_R_)
+	pthread_set_name_np (tid, "sigwaiter");
+#endif
+
+	/*
+	 * Verify that an ignored signal doesn't cause a wakeup.
+	 * We don't have a handler installed for SIGIO.
+	 */
+	send_thread_signal (tid, SIGIO);
+	sleep (1);
+	send_process_signal (SIGIO);
+	sleep (1);
+	if (sigcounts[SIGIO] != 0)
+		fprintf (stderr,
+		    "FAIL: sigwait wakes up for ignored signal SIGIO.\n");
+
+	/*
+	 * Verify that a signal with a default action of ignore, for
+	 * which we have a signal handler installed, will release a sigwait.
+	 */
+	send_thread_signal (tid, SIGURG);
+	sleep (1);
+	send_process_signal (SIGURG);
+	sleep (1);
+	if (sigcounts[SIGURG] != 2)
+		fprintf (stderr, "FAIL: sigwait doesn't wake up for SIGURG.\n");
+
+	/*
+	 * Verify that a signal with a default action that terminates
+	 * the process will release a sigwait.
+	 */
+	send_thread_signal (tid, SIGUSR1);
+	sleep (1);
+	send_process_signal (SIGUSR1);
+	sleep (1);
+	if (sigcounts[SIGUSR1] != 2)
+		fprintf (stderr,
+		    "FAIL: sigwait doesn't wake up for SIGUSR1.\n");
+
+	/*
+	 * Verify that if we install a signal handler for a previously
+	 * ignored signal, an occurrence of this signal will release
+	 * the (already waiting) sigwait.
+	 */
+
+	/* Install a signal handler for SIGHUP. */
+	sigemptyset (&act.sa_mask);
+	sigaddset (&act.sa_mask, SIGHUP);
+	act.sa_handler = sighandler;
+	act.sa_flags = SA_RESTART;
+	sigaction (SIGHUP, &act, NULL);
+
+	/* Sending SIGHUP should release the sigwait. */
+	send_process_signal (SIGHUP);
+	sleep (1);
+	send_thread_signal (tid, SIGHUP);
+	sleep (1);
+	if (sigcounts[SIGHUP] != 2)
+		fprintf (stderr, "FAIL: sigwait doesn't wake up for SIGHUP.\n");
+
+	/*
+	 * Verify that a pending signal in the waiters mask will
+	 * cause sigwait to return the pending signal.  We do this
+	 * by taking the waiters mutex and signaling the waiter to
+	 * release him from the sigwait.  The waiter will block
+	 * on taking the mutex, and we can then send the waiter a
+	 * signal which should be added to his pending signals.
+	 * The next time the waiter does a sigwait, he should
+	 * return with the pending signal.
+	 */
+	sigcounts[SIGHUP] = 0;
+ 	pthread_mutex_lock (&waiter_mutex);
+	/* Release the waiter from sigwait. */
+	send_process_signal (SIGHUP);
+	sleep (1);
+	if (sigcounts[SIGHUP] != 1)
+		fprintf (stderr, "FAIL: sigwait doesn't wake up for SIGHUP.\n");
+	/*
+	 * Add SIGHUP to the process pending signals.  Since there is
+	 * a signal handler installed for SIGHUP and this signal is
+	 * blocked from the waiter thread and unblocked in the main
+	 * thread, the signal handler should be called once for SIGHUP.
+	 */
+	send_process_signal (SIGHUP);
+	/* Release the waiter thread and allow him to run. */
+	pthread_mutex_unlock (&waiter_mutex);
+	sleep (1);
+	if (sigcounts[SIGHUP] != 2)
+		fprintf (stderr,
+		    "FAIL: sigwait doesn't return for pending SIGHUP.\n");
+
+	/*
+	 * Repeat the above test using pthread_kill and SIGUSR1.
+	 */
+	sigcounts[SIGUSR1] = 0;
+ 	pthread_mutex_lock (&waiter_mutex);
+	/* Release the waiter from sigwait. */
+	send_thread_signal (tid, SIGUSR1);
+	sleep (1);
+	if (sigcounts[SIGUSR1] != 1)
+		fprintf (stderr,
+		    "FAIL: sigwait doesn't wake up for SIGUSR1.\n");
+	/* Add SIGUSR1 to the waiters pending signals. */
+	send_thread_signal (tid, SIGUSR1);
+	/* Release the waiter thread and allow him to run. */
+	pthread_mutex_unlock (&waiter_mutex);
+	sleep (1);
+	if (sigcounts[SIGUSR1] != 2)
+		fprintf (stderr,
+		    "FAIL: sigwait doesn't return for pending SIGUSR1.\n");
+
+	/*
+	 * Verify that we can still kill the process for a signal
+	 * not being waited on by sigwait.
+	 */
+	send_process_signal (SIGPIPE);
+	fprintf (stderr, "FAIL: SIGPIPE did not terminate process.\n");
+
+	/*
+	 * Wait for the thread to finish.
+	 */
+	pthread_join (tid, &exit_status);
+
+	return (0);
+}
--- /dev/null
+++ lib/libkse/test/sigsuspend_d.c
@@ -0,0 +1,290 @@
+/*
+ * Copyright (c) 1998 Daniel M. Eischen <eischen at vigrid.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by Daniel M. Eischen.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY DANIEL M. EISCHEN AND CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/lib/libkse/test/sigsuspend_d.c,v 1.4 2007/10/09 13:42:26 obrien Exp $
+ */
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <errno.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+
+#if defined(_LIBC_R_)
+#include <pthread_np.h>
+#endif
+
+static int	sigcounts[NSIG + 1];
+static int	sigfifo[NSIG + 1];
+static int	fifo_depth = 0;
+static sigset_t suspender_mask;
+static pthread_t suspender_tid;
+
+
+static void *
+sigsuspender (void *arg)
+{
+	int save_count, status, i;
+	sigset_t run_mask;
+
+	/* Run with all signals blocked. */
+	sigfillset (&run_mask);
+	sigprocmask (SIG_SETMASK, &run_mask, NULL);
+
+	/* Allow these signals to wake us up during a sigsuspend. */
+	sigfillset (&suspender_mask);		/* Default action	*/
+	sigdelset (&suspender_mask, SIGKILL);	/* Cannot catch		*/
+	sigdelset (&suspender_mask, SIGSTOP);	/* Cannot catch		*/
+	sigdelset (&suspender_mask, SIGINT);	/* terminate		*/
+	sigdelset (&suspender_mask, SIGHUP);	/* terminate		*/
+	sigdelset (&suspender_mask, SIGQUIT);	/* create core image	*/
+	sigdelset (&suspender_mask, SIGURG);	/* ignore		*/
+	sigdelset (&suspender_mask, SIGIO);	/* ignore		*/
+	sigdelset (&suspender_mask, SIGUSR2);	/* terminate		*/
+
+	while (sigcounts[SIGINT] == 0) {
+		save_count = sigcounts[SIGUSR2];
+
+		status = sigsuspend (&suspender_mask);
+		if ((status == 0) || (errno != EINTR)) {
+			fprintf (stderr, "Unable to suspend for signals, "
+				"errno %d, return value %d\n",
+				errno, status);
+			exit (1);
+		}
+		for (i = 0; i < fifo_depth; i++)
+			fprintf (stderr, "Sigsuspend woke up by signal %d\n",
+				sigfifo[i]);
+		fifo_depth = 0;
+	}
+
+	pthread_exit (arg);
+	return (NULL);
+}
+
+
+static void
+sighandler (int signo)
+{
+	sigset_t set, suspend_set;
+	pthread_t self;
+
+	if ((signo >= 0) && (signo <= NSIG))
+		sigcounts[signo]++;
+
+	/*
+	 * If we are running on behalf of the suspender thread,
+	 * ensure that we have the correct mask set.
+	 */
+	self = pthread_self ();
+	if (self == suspender_tid) {
+		sigfifo[fifo_depth] = signo;
+		fifo_depth++;
+		fprintf (stderr,
+		    "  -> Suspender thread signal handler caught signal %d\n",
+		    signo);
+
+		/* Get the current signal mask. */
+		sigprocmask (SIG_SETMASK, NULL, &set);
+
+		/* The handler should run with the current signal masked. */
+		suspend_set = suspender_mask;
+		sigaddset(&suspend_set, signo);
+
+		if (memcmp(&set, &suspend_set, sizeof(set)))
+			fprintf (stderr,
+			    "  >>> FAIL: sigsuspender signal handler running "
+			    "with incorrect mask.\n");
+	}
+	else
+		fprintf (stderr,
+		    "  -> Main thread signal handler caught signal %d\n",
+		    signo);
+}
+
+
+static void
+send_thread_signal (pthread_t tid, int signo)
+{
+	if (pthread_kill (tid, signo) != 0) {
+		fprintf (stderr, "Unable to send thread signal, errno %d.\n",
+		    errno);
+		exit (1);
+	}
+}
+
+
+static void
+send_process_signal (int signo)
+{
+	if (kill (getpid (), signo) != 0) {
+		fprintf (stderr, "Unable to send process signal, errno %d.\n",
+		    errno);
+		exit (1);
+	}
+}
+
+
+int main (int argc, char *argv[])
+{
+	pthread_attr_t	pattr;
+	void *		exit_status;
+	struct sigaction act;
+	sigset_t	oldset;
+	sigset_t	newset;
+
+	/* Initialize our signal counts. */
+	memset ((void *) sigcounts, 0, NSIG * sizeof (int));
+
+	/* Ignore signal SIGIO. */
+	sigemptyset (&act.sa_mask);
+	sigaddset (&act.sa_mask, SIGIO);
+	act.sa_handler = SIG_IGN;
+	act.sa_flags = 0;
+	sigaction (SIGIO, &act, NULL);
+
+	/* Install a signal handler for SIGURG. */
+	sigemptyset (&act.sa_mask);
+	sigaddset (&act.sa_mask, SIGURG);
+	act.sa_handler = sighandler;
+	act.sa_flags = SA_RESTART;
+	sigaction (SIGURG, &act, NULL);
+
+	/* Install a signal handler for SIGXCPU */
+	sigemptyset (&act.sa_mask);
+	sigaddset (&act.sa_mask, SIGXCPU);
+	sigaction (SIGXCPU, &act, NULL);
+
+	/* Get our current signal mask. */
+	sigprocmask (SIG_SETMASK, NULL, &oldset);
+
+	/* Mask out SIGUSR1 and SIGUSR2. */
+	newset = oldset;
+	sigaddset (&newset, SIGUSR1);
+	sigaddset (&newset, SIGUSR2);
+	sigprocmask (SIG_SETMASK, &newset, NULL);
+
+	/* Install a signal handler for SIGUSR1 */
+	sigemptyset (&act.sa_mask);
+	sigaddset (&act.sa_mask, SIGUSR1);
+	sigaction (SIGUSR1, &act, NULL);
+
+	/* Install a signal handler for SIGUSR2 */
+	sigemptyset (&act.sa_mask);
+	sigaddset (&act.sa_mask, SIGUSR2);
+	sigaction (SIGUSR2, &act, NULL);
+
+	/*
+	 * Initialize the thread attribute.
+	 */
+	if ((pthread_attr_init (&pattr) != 0) ||
+	    (pthread_attr_setdetachstate (&pattr,
+	    PTHREAD_CREATE_JOINABLE) != 0)) {
+		fprintf (stderr, "Unable to initialize thread attributes.\n");
+		exit (1);
+	}
+
+	/*
+	 * Create the sigsuspender thread.
+	 */
+	if (pthread_create (&suspender_tid, &pattr, sigsuspender, NULL) != 0) {
+		fprintf (stderr, "Unable to create thread, errno %d.\n", errno);
+		exit (1);
+	}
+#if defined(_LIBC_R_)
+	pthread_set_name_np (suspender_tid, "sigsuspender");
+#endif
+
+	/*
+	 * Verify that an ignored signal doesn't cause a wakeup.
+	 * We don't have a handler installed for SIGIO.
+	 */
+	send_thread_signal (suspender_tid, SIGIO);
+	sleep (1);
+	send_process_signal (SIGIO);
+	sleep (1);
+	if (sigcounts[SIGIO] != 0)
+		fprintf (stderr, "FAIL: sigsuspend wakes up for ignored signal "
+			"SIGIO.\n");
+
+	/*
+	 * Verify that a signal with a default action of ignore, for
+	 * which we have a signal handler installed, will release a
+	 * sigsuspend.
+	 */
+	send_thread_signal (suspender_tid, SIGURG);
+	sleep (1);
+	send_process_signal (SIGURG);
+	sleep (1);
+	if (sigcounts[SIGURG] != 2)
+		fprintf (stderr,
+		    "FAIL: sigsuspend doesn't wake up for SIGURG.\n");
+
+	/*
+	 * Verify that a SIGUSR2 signal will release a sigsuspended
+	 * thread.
+	 */
+	send_thread_signal (suspender_tid, SIGUSR2);
+	sleep (1);
+	send_process_signal (SIGUSR2);
+	sleep (1);
+	if (sigcounts[SIGUSR2] != 2)
+		fprintf (stderr,
+		    "FAIL: sigsuspend doesn't wake up for SIGUSR2.\n");
+
+	/*
+	 * Verify that a signal, blocked in both the main and
+	 * sigsuspender threads, does not cause the signal handler
+	 * to be called.
+	 */
+	send_thread_signal (suspender_tid, SIGUSR1);
+	sleep (1);
+	send_process_signal (SIGUSR1);
+	sleep (1);
+	if (sigcounts[SIGUSR1] != 0)
+		fprintf (stderr, "FAIL: signal hander called for SIGUSR1.\n");
+
+	/*
+	 * Verify that we can still kill the process for a signal
+	 * not being waited on by sigwait.
+	 */
+	send_process_signal (SIGPIPE);
+	fprintf (stderr, "FAIL: SIGPIPE did not terminate process.\n");
+
+	/*
+	 * Wait for the thread to finish.
+	 */
+	pthread_join (suspender_tid, &exit_status);
+
+	return (0);
+}
--- /dev/null
+++ lib/libkse/test/verify
@@ -0,0 +1,474 @@
+#!/usr/bin/perl -w
+#-*-mode:perl-*-
+#############################################################################
+#
+# Copyright (C) 1999-2001 Jason Evans <jasone at freebsd.org>.
+# All rights reserved.
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice(s), this list of conditions and the following disclaimer as
+#    the first lines of this file unmodified other than the possible
+#    addition of one or more copyright notices.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice(s), this list of conditions and the following disclaimer in
+#    the documentation and/or other materials provided with the
+#    distribution.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+#############################################################################
+#
+# Test harness.
+#
+# $FreeBSD: src/lib/libkse/test/verify,v 1.3 2007/10/09 13:42:26 obrien Exp $
+#
+#############################################################################
+
+# Shut off buffering.
+select(STDOUT);
+$| = 1;
+
+#
+# Parse command-line arguments.
+#
+use Getopt::Long;
+Getopt::Long::config("bundling"); # Allow -hv rather than forcing -h -v.
+
+# Set option defaults for optional arguments.
+$opt_help = 0;
+$opt_verbose = 0;
+$opt_quiet = 0;
+$opt_srcdir = ".";
+$opt_objdir = ".";
+$opt_ustats = 0;
+$opt_zero = 0;
+
+$opt_retval =
+&GetOptions("h|help" => \$opt_help,
+	    "v|verbose" => \$opt_verbose,
+	    "q|quiet" => \$opt_quiet,
+	    "s|srcdir=s" => \$opt_srcdir,
+            "o|objdir=s" => \$opt_objdir,
+	    "u|ustats" => \$opt_ustats,
+	    "z|zero" => \$opt_zero
+	    );
+
+if ($opt_help)
+{
+    &usage();
+    exit(0);
+}
+
+if ($opt_retval == 0)
+{
+    &usage();
+    exit 1;
+}
+
+if ($opt_verbose && $opt_quiet)
+{
+    print STDERR "-v and -q are incompatible\n";
+    &usage();
+    exit 1;
+}
+
+if ($#ARGV + 1 == 0)
+{
+    print STDERR "No tests specified\n";
+    &usage();
+    exit 1;
+}
+
+if ($opt_verbose)
+{
+    print STDERR "Option values: h:$opt_help, v:$opt_verbose, "
+	. "s:\"$opt_srcdir\", o:\"$opt_objdir\" "
+	. "q:$opt_quiet, u:$opt_ustats, z:$opt_zero\n";
+    printf STDERR "Tests (%d total): @ARGV\n", $#ARGV + 1;
+}
+
+#
+# Create and print header.
+#
+ at TSTATS =
+(
+ "--------------------------------------------------------------------------\n",
+ "Test                                      c_user c_system c_total     chng\n",
+ " passed/FAILED                            h_user h_system h_total   %% chng\n"
+ );
+
+if (!$opt_quiet)
+{
+    foreach $line (@TSTATS)
+    {
+	printf STDOUT "$line";
+    }
+}
+
+#
+# Run sequence test(s).
+#
+$total_utime = 0.0; # Total user time.
+$total_stime = 0.0; # Total system time.
+$total_hutime = 0.0; # Total historical user time.
+$total_hstime = 0.0; # Total historical system time.
+$total_ntime = 0.0; # Total time for tests that have historical data.
+
+foreach $test (@ARGV)
+{
+    # Strip out any whitespace in $test.
+    $test =~ s/^\s*(.*)\s*$/$1/;
+
+    $okay = 1;
+
+    if (-e "$opt_srcdir/$test.exp")
+    {
+	# Diff mode.
+
+	($okay, $utime, $stime) = &run_test($test);
+
+	if (-e "$opt_objdir/$test.out")
+	{
+	    `diff $opt_srcdir/$test.exp $opt_objdir/$test.out > $opt_objdir/$test.diff 2>&1`;
+	    if ($?)
+	    {
+		# diff returns non-zero if there is a difference.
+		$okay = 0;
+	    }
+	}
+	else
+	{
+	    $okay = 0;
+	    if ($opt_verbose)
+	    {
+		print STDERR
+		    "Nonexistent output file \"$opt_objdir/$test.out\"\n";
+	    }
+	}
+
+	($hutime, $hstime) = &print_stats($test, $okay, 0, 0, $utime, $stime);
+    }
+    else
+    {
+	# Sequence mode.
+
+	($okay, $utime, $stime) = &run_test($test);
+
+	if (open (STEST_OUT, "<$opt_objdir/$test.out"))
+	{
+	    $num_subtests = 0;
+	    $num_failed_subtests = 0;
+
+	    while (defined($line = <STEST_OUT>))
+	    {
+		if ($line =~ /1\.\.(\d+)/)
+		{
+		    $num_subtests = $1;
+		    last;
+		}
+	    }
+	    if ($num_subtests == 0)
+	    {
+		$okay = 0;
+		if ($opt_verbose)
+		{
+		    print STDERR "Malformed or missing 1..n line\n";
+		}
+	    }
+	    else
+	    {
+		for ($subtest = 1; $subtest <= $num_subtests; $subtest++)
+		{
+		    while (defined($line = <STEST_OUT>))
+		    {
+			if ($line =~ /^not\s+ok\s+(\d+)?/)
+			{
+			    $not = 1;
+			    $test_num = $1;
+			    last;
+			}
+			elsif ($line =~ /^ok\s+(\d+)?/)
+			{
+			    $not = 0;
+			    $test_num = $1;
+			    last;
+			}
+		    }
+		    if (defined($line))
+		    {
+			if (defined($test_num) && ($test_num != $subtest))
+			{
+			    # There was no output printed for one or more tests.
+			    for (; $subtest < $test_num; $subtest++)
+			    {
+				$num_failed_subtests++;
+			    }
+			}
+			if ($not)
+			{
+			    $num_failed_subtests++;
+			}
+		    }
+		    else
+		    {
+			for (; $subtest <= $num_subtests; $subtest++)
+			{
+			    $num_failed_subtests++;
+			}
+		    }
+		}
+
+		if (0 < $num_failed_subtests)
+		{
+		    $okay = 0;
+		}
+	    }
+	}
+	else
+	{
+	    if (!$opt_quiet)
+	    {
+		print STDERR "Cannot open output file \"$opt_objdir/$test.out\"\n";
+	    }
+	    exit 1;
+	}
+
+	($hutime, $hstime) = &print_stats($test, $okay,
+					  $num_failed_subtests, $num_subtests,
+					  $utime, $stime);
+    }
+
+    $total_hutime += $hutime;
+    $total_hstime += $hstime;
+
+    if ($okay)
+    {
+	$total_utime += $utime;
+	$total_stime += $stime;
+    }
+    else
+    {
+	@FAILED_TESTS = (@FAILED_TESTS, $test);
+    }
+
+    # If there were historical data, add the run time to the total time to 
+    # compare against the historical run time.
+    if (0 < ($hutime + $hstime))
+    {
+	$total_ntime += $utime + $stime;
+    }
+}
+
+# Print summary stats.
+$tt_str = sprintf ("%d / %d passed (%5.2f%%%%)",
+		   ($#ARGV + 1) - ($#FAILED_TESTS + 1),
+		   $#ARGV + 1,
+		   (($#ARGV + 1) - ($#FAILED_TESTS + 1))
+		   / ($#ARGV + 1) * 100);
+
+$t_str = sprintf ("Totals                                   %7.2f  %7.2f %7.2f"
+                  . "  %7.2f\n"
+		  . " %s %7.2f  %7.2f %7.2f %7.2f%%%%\n",
+		  $total_utime, $total_stime, $total_utime + $total_stime,
+		  ($total_ntime - ($total_hutime + $total_hstime)),
+		  $tt_str . ' ' x (40 - length($tt_str)),
+		  $total_hutime, $total_hstime, $total_hutime + $total_hstime,
+		  ($total_hutime + $total_hstime == 0.0) ? 0.0 :
+		  (($total_ntime
+		    - ($total_hutime + $total_hstime))
+		   / ($total_hutime + $total_hstime) * 100));
+
+ at TSTATS = ("--------------------------------------------------------------------------\n",
+	   $t_str,
+	   "--------------------------------------------------------------------------\n"
+	   );
+if (!$opt_quiet)
+{
+    foreach $line (@TSTATS)
+    {
+	printf STDOUT "$line";
+    }
+}
+
+if ($#FAILED_TESTS >= 0)
+{
+    # One or more tests failed, so return an error.
+    exit 1;
+}
+# End of main execution.
+
+sub run_test
+{
+    my ($test) = @_;
+    my ($okay) = 1;
+    my ($tutime, $tstime);
+    my ($utime, $stime, $cutime, $cstime);
+    my (@TSTATS, @TPATH);
+    my ($t_str);
+    my ($srcdir, $objdir);
+
+    # Get the path component of $test, if any.
+    @TPATH = split(/\//, $test);
+    pop(@TPATH);
+    $srcdir = join('/', ($opt_srcdir, @TPATH));
+    $objdir = join('/', ($opt_objdir, @TPATH));
+
+    @TSTATS = ("--------------------------------------------------------------------------\n");
+
+    $t_str = sprintf ("%s%s", $test, ' ' x (40 - length($test)));
+    @TSTATS = (@TSTATS, $t_str);
+    @STATS = (@STATS, @TSTATS);
+    if (!$opt_quiet)
+    {
+	foreach $line (@TSTATS)
+	{
+	    printf STDOUT "$line";
+	}
+    }
+
+    ($utime, $stime, $cutime, $cstime) = times;
+    `$opt_objdir/$test $srcdir $objdir > $opt_objdir/$test.out 2>&1`;
+    ($utime, $stime, $tutime, $tstime) = times;
+
+    # Subtract the before time from the after time.
+    $tutime -= $cutime;
+    $tstime -= $cstime;
+
+    if ($opt_zero)
+    {
+	if ($?)
+	{
+	    $okay = 0;
+	    if ($opt_verbose)
+	    {
+		print STDERR
+		    "\"$opt_objdir/$test > $opt_objdir/$test.out 2>&1\" returned $?\n";
+	    }
+	}
+    }
+
+    return ($okay, $tutime, $tstime);
+}
+
+sub print_stats
+{
+    my ($test, $okay, $failed_subtests, $subtests, $utime, $stime) = @_;
+    my ($hutime, $hstime);
+#    my (TEST_PERF);
+    my (@TSTATS);
+    my ($t_str, $pass_str);
+
+    $pass_str = $okay ? "passed" : "*** FAILED ***";
+    if ((0 != $subtests) && (!$okay))
+    {
+	$pass_str = $pass_str . " ($failed_subtests/$subtests failed)";
+    }
+    $pass_str = $pass_str . ' ' x (39 - length($pass_str));
+    
+    if (-r "$test.perf")
+    {
+	if (!open (TEST_PERF, "<$opt_objdir/$test.perf"))
+	{
+	    print STDERR "Unable to open \"$opt_objdir/$test.perf\"\n";
+	    exit 1;
+	}
+	$_ = <TEST_PERF>;
+
+	($hutime, $hstime) = split;
+	close TEST_PERF;
+
+	$t_str = sprintf (" %7.2f  %7.2f %7.2f  %7.2f\n"
+			  . " %s %7.2f  %7.2f %7.2f %7.2f%%%%\n",
+			  $utime, $stime, $utime + $stime,
+			  ($utime + $stime) - ($hutime + $hstime),
+			  $pass_str,
+			  $hutime, $hstime, $hutime + $hstime,
+			  (($hutime + $hstime) == 0.0) ? 0.0 :
+			  ((($utime + $stime) - ($hutime + $hstime))
+			   / ($hutime + $hstime) * 100));
+    }
+    else
+    {
+	$hutime = 0.0;
+	$hstime = 0.0;
+
+	$t_str = sprintf (" %7.2f  %7.2f %7.2f        \n"
+			  . " %s\n",
+			  $utime, $stime, $utime + $stime,
+			  $pass_str);
+    }
+    @TSTATS = ($t_str);
+    if (!$opt_quiet)
+    {
+	foreach $line (@TSTATS)
+	{
+	    printf STDOUT "$line";
+	}
+    }
+
+    if ($okay && $opt_ustats)
+    {
+	if (!open (TEST_PERF, ">$opt_objdir/$test.perf"))
+	{
+	    if (!$opt_quiet)
+	    {
+		print STDERR "Unable to update \"$opt_objdir/$test.perf\"\n";
+	    }
+	}
+	else
+	{
+	    print TEST_PERF "$utime $stime\n";
+	    close TEST_PERF;
+	}
+    }
+
+    return ($hutime, $hstime);
+}
+
+sub usage
+{
+    print <<EOF;
+$0 usage:
+    $0 [<options>] <test>+
+
+    Option        | Description
+    --------------+-------------------------------------------------------------
+    -h --help     | Print usage and exit.
+    -v --verbose  | Verbose (incompatible with quiet).
+    -q --quiet    | Quiet (incompatible with verbose).
+    -s --srcdir   | Path to source tree (default is ".").
+    -o --objdir   | Path to object tree (default is ".").
+    -u --ustats   | Update historical statistics (stored in "<test>.perf".
+    -z --zero     | Consider non-zero exit code to be an error.
+    --------------+-------------------------------------------------------------
+
+    If <test>.exp exists, <test>'s output is diff'ed with <test>.exp.  Any
+    difference is considered failure.
+
+    If <test>.exp does not exist, output to stdout of the following form is
+    expected:
+
+        1..<n>
+        {not }ok[ 1]
+        {not }ok[ 2]
+        ...
+        {not }ok[ n]
+
+    1 <= <n> < 2^31
+
+    Lines which do not match the patterns shown above are ignored.
+EOF
+}
--- /dev/null
+++ lib/libkse/test/sigwait_d.exp
@@ -0,0 +1,11 @@
+# $FreeBSD: src/lib/libkse/test/sigwait_d.exp,v 1.2 2007/10/09 13:42:26 obrien Exp $
+Sigwait caught signal 16
+Sigwait caught signal 16
+Sigwait caught signal 30
+Sigwait caught signal 30
+Sigwait caught signal 1
+Sigwait caught signal 1
+Sigwait caught signal 1
+  -> Signal handler caught signal 1
+Sigwait caught signal 30
+Sigwait caught signal 30
--- /dev/null
+++ lib/libkse/test/sem_d.exp
@@ -0,0 +1,23 @@
+# $FreeBSD: src/lib/libkse/test/sem_d.exp,v 1.2 2007/10/09 13:42:26 obrien Exp $
+Test begin
+Got semaphore
+Got semaphore
+Got semaphore
+Got semaphore
+Got semaphore
+Got semaphore
+Got semaphore
+Got semaphore
+Got semaphore
+Got semaphore
+Got semaphore
+Got semaphore
+Got semaphore
+Got semaphore
+Got semaphore
+Got semaphore
+Got semaphore
+Got semaphore
+Got semaphore
+Got semaphore
+Test end
--- /dev/null
+++ lib/libkse/test/Makefile
@@ -0,0 +1,116 @@
+#
+# $FreeBSD: src/lib/libkse/test/Makefile,v 1.14 2007/10/09 13:42:26 obrien Exp $
+#
+# Automated test suite for libpthread (pthreads).
+#
+
+# File lists.
+
+# Tests written in C.
+CTESTS := hello_d.c hello_s.c join_leak_d.c mutex_d.c sem_d.c sigsuspend_d.c \
+	sigwait_d.c
+
+# C programs that are used internally by the tests.  The build system merely
+# compiles these.
+BTESTS := guard_b.c hello_b.c
+
+# Tests written in perl.
+PTESTS := guard_s.pl propagate_s.pl
+
+# Munge the file lists to their final executable names (strip the .c).
+CTESTS := $(CTESTS:R)
+BTESTS := $(BTESTS:R)
+
+CPPFLAGS := -D_LIBC_R_ -D_REENTRANT
+CFLAGS := -Wall -pipe -g3
+LDFLAGS_A := -static
+LDFLAGS_P := -pg
+LDFLAGS_S :=
+LIBS := -lpthread
+
+# Flags passed to verify.  "-v" or "-u" may be useful.
+VERIFY = perl verify
+VFLAGS :=
+
+all : default
+
+# Only use the following suffixes, in order to avoid any strange built-in rules.
+.SUFFIXES :
+.SUFFIXES : .c .o .d .pl
+
+# Clear out all paths, then set just one (default path) for the main build
+# directory.
+.PATH :
+.PATH : .
+
+# Build the C programs.
+.for bin in $(CTESTS) $(BTESTS)
+$(bin)_a : $(bin:S/$/&.c/)
+	$(CC) $(CFLAGS) $(CPPFLAGS) -c $(bin:S/$/&.c/) -o $(@:S/$/&.o/)
+	$(CC) -o $@ $(@:S/$/&.o/) $(LDFLAGS_A) $(LIBS)
+	@$(SHELL) -ec "$(CC) -M $(CPPFLAGS) $(bin:S/$/&.c/) | sed \"s/\($(bin:T)\)\.o\([ :]*\)/$(bin:H:S!/!\\/!g)\/\1_a.o \2/g\" > $(@:R:S/$/&.d/)"
+
+$(bin)_p : $(bin:S/$/&.c/)
+	$(CC) $(CFLAGS) $(CPPFLAGS) -c $(bin:S/$/&.c/) -o $(@:S/$/&.o/)
+	$(CC) -o $@ $(@:S/$/&.o/) $(LDFLAGS_P) $(LIBS)
+	@$(SHELL) -ec "$(CC) -M $(CPPFLAGS) $(bin:S/$/&.c/) | sed \"s/\($(bin:T)\)\.o\([ :]*\)/$(bin:H:S!/!\\/!g)\/\1_p.o \2/g\" > $(@:R:S/$/&.d/)"
+
+$(bin)_s : $(bin:S/$/&.c/)
+	$(CC) $(CFLAGS) $(CPPFLAGS) -c $(bin:S/$/&.c/) -o $(@:S/$/&.o/)
+	$(CC) -o $@ $(@:S/$/&.o/) $(LDFLAGS_S) $(LIBS)
+	@$(SHELL) -ec "$(CC) -M $(CPPFLAGS) $(bin:S/$/&.c/) | sed \"s/\($(bin:T)\)\.o\([ :]*\)/$(bin:H:S!/!\\/!g)\/\1_s.o \2/g\" > $(@:R:S/$/&.d/)"
+.endfor
+
+# Dependency file inclusion.
+.for depfile in $(CTESTS:R:S/$/&_a.d/) $(BTESTS:R:S/$/&_a.d/) \
+		$(CTESTS:R:S/$/&_p.d/) $(BTESTS:R:S/$/&_p.d/) \
+		$(CTESTS:R:S/$/&_s.d/) $(BTESTS:R:S/$/&_s.d/)
+.if exists($(depfile))
+.include "$(depfile)"
+.endif
+.endfor
+
+default : check
+
+tests_a : $(CTESTS:S/$/&_a/) $(BTESTS:S/$/&_a/)
+tests_p : $(CTESTS:S/$/&_p/) $(BTESTS:S/$/&_p/)
+tests_s : $(CTESTS:S/$/&_s/) $(BTESTS:S/$/&_s/)
+
+tests : tests_a tests_p tests_s
+
+check_a : tests_a
+.for bin in $(CTESTS) $(BTESTS)
+	@cp $(bin)_a $(bin)
+.endfor
+	@echo "Test static library:"
+	@$(VERIFY) $(VFLAGS) $(CTESTS) $(PTESTS)
+
+check_p : tests_p
+.for bin in $(CTESTS) $(BTESTS)
+	@cp $(bin)_p $(bin)
+.endfor
+	@echo "Test profile library:"
+	@$(VERIFY) $(VFLAGS) $(CTESTS) $(PTESTS)
+
+check_s : tests_s
+.for bin in $(CTESTS) $(BTESTS)
+	@cp $(bin)_s $(bin)
+.endfor
+	@echo "Test shared library:"
+	@$(VERIFY) $(VFLAGS) $(CTESTS) $(PTESTS)
+
+check : check_a check_p check_s
+
+clean :
+	rm -f *~
+	rm -f *.core
+	rm -f *.out
+	rm -f *.perf
+	rm -f *.diff
+	rm -f *.gmon
+	rm -f $(CTESTS) $(BTESTS)
+	rm -f $(CTESTS:S/$/&_a/) $(BTESTS:S/$/&_a/)
+	rm -f $(CTESTS:S/$/&_p/) $(BTESTS:S/$/&_p/)
+	rm -f $(CTESTS:S/$/&_s/) $(BTESTS:S/$/&_s/)
+	rm -f *.d
+	rm -f *.o
--- /dev/null
+++ lib/libkse/test/join_leak_d.exp
@@ -0,0 +1,3 @@
+# $FreeBSD: src/lib/libkse/test/join_leak_d.exp,v 1.2 2007/10/09 13:42:26 obrien Exp $
+Test begin
+Test end
--- /dev/null
+++ lib/libkse/test/mutex_d.exp
@@ -0,0 +1,291 @@
+# $FreeBSD: src/lib/libkse/test/mutex_d.exp,v 1.2 2007/10/09 13:42:26 obrien Exp $
+
+Testing pthread_mutex_init
+--------------------------
+  Protocol PTHREAD_PRIO_NONE, Type POSIX (type not specified) - PASS
+  Protocol PTHREAD_PRIO_NONE, Type SS2 PTHREAD_MUTEX_DEFAULT - PASS
+  Protocol PTHREAD_PRIO_NONE, Type SS2 PTHREAD_MUTEX_ERRORCHECK - PASS
+  Protocol PTHREAD_PRIO_NONE, Type SS2 PTHREAD_MUTEX_NORMAL - PASS
+  Protocol PTHREAD_PRIO_NONE, Type SS2 PTHREAD_MUTEX_RECURSIVE - PASS
+  Protocol PTHREAD_PRIO_INHERIT, Type POSIX (type not specified) - PASS
+  Protocol PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_DEFAULT - PASS
+  Protocol PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_ERRORCHECK - PASS
+  Protocol PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_NORMAL - PASS
+  Protocol PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_RECURSIVE - PASS
+  Protocol PTHREAD_PRIO_PROTECT, Type POSIX (type not specified) - PASS
+  Protocol PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_DEFAULT - PASS
+  Protocol PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_ERRORCHECK - PASS
+  Protocol PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_NORMAL - PASS
+  Protocol PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_RECURSIVE - PASS
+
+Testing pthread_mutex_destroy
+-----------------------------
+  Protocol PTHREAD_PRIO_NONE, Type POSIX (type not specified)
+    Destruction of unused mutex - PASS
+    Destruction of mutex locked by self - PASS
+    Destruction of mutex locked by another thread - PASS
+    Destruction of mutex while being used in cond_wait - PASS
+  Protocol PTHREAD_PRIO_NONE, Type SS2 PTHREAD_MUTEX_DEFAULT
+    Destruction of unused mutex - PASS
+    Destruction of mutex locked by self - PASS
+    Destruction of mutex locked by another thread - PASS
+    Destruction of mutex while being used in cond_wait - PASS
+  Protocol PTHREAD_PRIO_NONE, Type SS2 PTHREAD_MUTEX_ERRORCHECK
+    Destruction of unused mutex - PASS
+    Destruction of mutex locked by self - PASS
+    Destruction of mutex locked by another thread - PASS
+    Destruction of mutex while being used in cond_wait - PASS
+  Protocol PTHREAD_PRIO_NONE, Type SS2 PTHREAD_MUTEX_NORMAL
+    Destruction of unused mutex - PASS
+    Destruction of mutex locked by self - PASS
+    Destruction of mutex locked by another thread - PASS
+    Destruction of mutex while being used in cond_wait - PASS
+  Protocol PTHREAD_PRIO_NONE, Type SS2 PTHREAD_MUTEX_RECURSIVE
+    Destruction of unused mutex - PASS
+    Destruction of mutex locked by self - PASS
+    Destruction of mutex locked by another thread - PASS
+    Destruction of mutex while being used in cond_wait - PASS
+  Protocol PTHREAD_PRIO_INHERIT, Type POSIX (type not specified)
+    Destruction of unused mutex - PASS
+    Destruction of mutex locked by self - PASS
+    Destruction of mutex locked by another thread - PASS
+    Destruction of mutex while being used in cond_wait - PASS
+  Protocol PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_DEFAULT
+    Destruction of unused mutex - PASS
+    Destruction of mutex locked by self - PASS
+    Destruction of mutex locked by another thread - PASS
+    Destruction of mutex while being used in cond_wait - PASS
+  Protocol PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_ERRORCHECK
+    Destruction of unused mutex - PASS
+    Destruction of mutex locked by self - PASS
+    Destruction of mutex locked by another thread - PASS
+    Destruction of mutex while being used in cond_wait - PASS
+  Protocol PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_NORMAL
+    Destruction of unused mutex - PASS
+    Destruction of mutex locked by self - PASS
+    Destruction of mutex locked by another thread - PASS
+    Destruction of mutex while being used in cond_wait - PASS
+  Protocol PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_RECURSIVE
+    Destruction of unused mutex - PASS
+    Destruction of mutex locked by self - PASS
+    Destruction of mutex locked by another thread - PASS
+    Destruction of mutex while being used in cond_wait - PASS
+  Protocol PTHREAD_PRIO_PROTECT, Type POSIX (type not specified)
+    Destruction of unused mutex - PASS
+    Destruction of mutex locked by self - PASS
+    Destruction of mutex locked by another thread - PASS
+    Destruction of mutex while being used in cond_wait - PASS
+  Protocol PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_DEFAULT
+    Destruction of unused mutex - PASS
+    Destruction of mutex locked by self - PASS
+    Destruction of mutex locked by another thread - PASS
+    Destruction of mutex while being used in cond_wait - PASS
+  Protocol PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_ERRORCHECK
+    Destruction of unused mutex - PASS
+    Destruction of mutex locked by self - PASS
+    Destruction of mutex locked by another thread - PASS
+    Destruction of mutex while being used in cond_wait - PASS
+  Protocol PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_NORMAL
+    Destruction of unused mutex - PASS
+    Destruction of mutex locked by self - PASS
+    Destruction of mutex locked by another thread - PASS
+    Destruction of mutex while being used in cond_wait - PASS
+  Protocol PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_RECURSIVE
+    Destruction of unused mutex - PASS
+    Destruction of mutex locked by self - PASS
+    Destruction of mutex locked by another thread - PASS
+    Destruction of mutex while being used in cond_wait - PASS
+
+Testing pthread_mutex_lock
+--------------------------
+  Protocol PTHREAD_PRIO_NONE, Type POSIX (type not specified)
+    Lock on unlocked mutex - PASS
+    Lock on invalid mutex - PASS
+    Lock on mutex held by self - PASS
+  Protocol PTHREAD_PRIO_NONE, Type SS2 PTHREAD_MUTEX_DEFAULT
+    Lock on unlocked mutex - PASS
+    Lock on invalid mutex - PASS
+    Lock on mutex held by self - PASS
+  Protocol PTHREAD_PRIO_NONE, Type SS2 PTHREAD_MUTEX_ERRORCHECK
+    Lock on unlocked mutex - PASS
+    Lock on invalid mutex - PASS
+    Lock on mutex held by self - PASS
+  Protocol PTHREAD_PRIO_NONE, Type SS2 PTHREAD_MUTEX_NORMAL
+    Lock on unlocked mutex - PASS
+    Lock on invalid mutex - PASS
+    Lock on mutex held by self - PASS
+  Protocol PTHREAD_PRIO_NONE, Type SS2 PTHREAD_MUTEX_RECURSIVE
+    Lock on unlocked mutex - PASS
+    Lock on invalid mutex - PASS
+    Lock on mutex held by self - PASS
+  Protocol PTHREAD_PRIO_INHERIT, Type POSIX (type not specified)
+    Lock on unlocked mutex - PASS
+    Lock on invalid mutex - PASS
+    Lock on mutex held by self - PASS
+  Protocol PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_DEFAULT
+    Lock on unlocked mutex - PASS
+    Lock on invalid mutex - PASS
+    Lock on mutex held by self - PASS
+  Protocol PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_ERRORCHECK
+    Lock on unlocked mutex - PASS
+    Lock on invalid mutex - PASS
+    Lock on mutex held by self - PASS
+  Protocol PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_NORMAL
+    Lock on unlocked mutex - PASS
+    Lock on invalid mutex - PASS
+    Lock on mutex held by self - PASS
+  Protocol PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_RECURSIVE
+    Lock on unlocked mutex - PASS
+    Lock on invalid mutex - PASS
+    Lock on mutex held by self - PASS
+  Protocol PTHREAD_PRIO_PROTECT, Type POSIX (type not specified)
+    Lock on unlocked mutex - PASS
+    Lock on invalid mutex - PASS
+    Lock on mutex held by self - PASS
+  Protocol PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_DEFAULT
+    Lock on unlocked mutex - PASS
+    Lock on invalid mutex - PASS
+    Lock on mutex held by self - PASS
+  Protocol PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_ERRORCHECK
+    Lock on unlocked mutex - PASS
+    Lock on invalid mutex - PASS
+    Lock on mutex held by self - PASS
+  Protocol PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_NORMAL
+    Lock on unlocked mutex - PASS
+    Lock on invalid mutex - PASS
+    Lock on mutex held by self - PASS
+  Protocol PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_RECURSIVE
+    Lock on unlocked mutex - PASS
+    Lock on invalid mutex - PASS
+    Lock on mutex held by self - PASS
+
+Testing pthread_mutex_unlock
+----------------------------
+  Protocol PTHREAD_PRIO_NONE, Type POSIX (type not specified)
+    Unlock on mutex held by self - PASS
+    Unlock on invalid mutex - PASS
+    Unlock on mutex locked by another thread - PASS
+  Protocol PTHREAD_PRIO_NONE, Type SS2 PTHREAD_MUTEX_DEFAULT
+    Unlock on mutex held by self - PASS
+    Unlock on invalid mutex - PASS
+    Unlock on mutex locked by another thread - PASS
+  Protocol PTHREAD_PRIO_NONE, Type SS2 PTHREAD_MUTEX_ERRORCHECK
+    Unlock on mutex held by self - PASS
+    Unlock on invalid mutex - PASS
+    Unlock on mutex locked by another thread - PASS
+  Protocol PTHREAD_PRIO_NONE, Type SS2 PTHREAD_MUTEX_NORMAL
+    Unlock on mutex held by self - PASS
+    Unlock on invalid mutex - PASS
+    Unlock on mutex locked by another thread - PASS
+  Protocol PTHREAD_PRIO_NONE, Type SS2 PTHREAD_MUTEX_RECURSIVE
+    Unlock on mutex held by self - PASS
+    Unlock on invalid mutex - PASS
+    Unlock on mutex locked by another thread - PASS
+  Protocol PTHREAD_PRIO_INHERIT, Type POSIX (type not specified)
+    Unlock on mutex held by self - PASS
+    Unlock on invalid mutex - PASS
+    Unlock on mutex locked by another thread - PASS
+  Protocol PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_DEFAULT
+    Unlock on mutex held by self - PASS
+    Unlock on invalid mutex - PASS
+    Unlock on mutex locked by another thread - PASS
+  Protocol PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_ERRORCHECK
+    Unlock on mutex held by self - PASS
+    Unlock on invalid mutex - PASS
+    Unlock on mutex locked by another thread - PASS
+  Protocol PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_NORMAL
+    Unlock on mutex held by self - PASS
+    Unlock on invalid mutex - PASS
+    Unlock on mutex locked by another thread - PASS
+  Protocol PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_RECURSIVE
+    Unlock on mutex held by self - PASS
+    Unlock on invalid mutex - PASS
+    Unlock on mutex locked by another thread - PASS
+  Protocol PTHREAD_PRIO_PROTECT, Type POSIX (type not specified)
+    Unlock on mutex held by self - PASS
+    Unlock on invalid mutex - PASS
+    Unlock on mutex locked by another thread - PASS
+  Protocol PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_DEFAULT
+    Unlock on mutex held by self - PASS
+    Unlock on invalid mutex - PASS
+    Unlock on mutex locked by another thread - PASS
+  Protocol PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_ERRORCHECK
+    Unlock on mutex held by self - PASS
+    Unlock on invalid mutex - PASS
+    Unlock on mutex locked by another thread - PASS
+  Protocol PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_NORMAL
+    Unlock on mutex held by self - PASS
+    Unlock on invalid mutex - PASS
+    Unlock on mutex locked by another thread - PASS
+  Protocol PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_RECURSIVE
+    Unlock on mutex held by self - PASS
+    Unlock on invalid mutex - PASS
+    Unlock on mutex locked by another thread - PASS
+
+Testing queueing order
+----------------------
+  Queueing order on a mutex - PASS
+  Queueing order on a condition variable - PASS
+
+Testing priority inheritence
+----------------------------
+  Protype PTHREAD_PRIO_INHERIT, Type POSIX (type not specified)
+    Simple inheritence test - PASS
+    Inheritence test with change of priority - PASS
+  Protype PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_DEFAULT
+    Simple inheritence test - PASS
+    Inheritence test with change of priority - PASS
+  Protype PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_ERRORCHECK
+    Simple inheritence test - PASS
+    Inheritence test with change of priority - PASS
+  Protype PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_NORMAL
+    Simple inheritence test - PASS
+    Inheritence test with change of priority - PASS
+  Protype PTHREAD_PRIO_INHERIT, Type SS2 PTHREAD_MUTEX_RECURSIVE
+    Simple inheritence test - PASS
+    Inheritence test with change of priority - PASS
+
+Testing priority ceilings
+-------------------------
+  Protype PTHREAD_PRIO_PROTECT, Type POSIX (type not specified)
+    Lock with ceiling priority < thread priority - PASS
+    Lock with ceiling priority = thread priority - PASS
+    Lock with ceiling priority > thread priority - PASS
+    Preemption with ceiling priority < thread priority - PASS
+    Preemption with ceiling priority = thread priority - PASS
+    SCHED_FIFO scheduling and ceiling priority = thread priority - PASS
+    SCHED_FIFO scheduling and ceiling priority > thread priority - PASS
+  Protype PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_DEFAULT
+    Lock with ceiling priority < thread priority - PASS
+    Lock with ceiling priority = thread priority - PASS
+    Lock with ceiling priority > thread priority - PASS
+    Preemption with ceiling priority < thread priority - PASS
+    Preemption with ceiling priority = thread priority - PASS
+    SCHED_FIFO scheduling and ceiling priority = thread priority - PASS
+    SCHED_FIFO scheduling and ceiling priority > thread priority - PASS
+  Protype PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_ERRORCHECK
+    Lock with ceiling priority < thread priority - PASS
+    Lock with ceiling priority = thread priority - PASS
+    Lock with ceiling priority > thread priority - PASS
+    Preemption with ceiling priority < thread priority - PASS
+    Preemption with ceiling priority = thread priority - PASS
+    SCHED_FIFO scheduling and ceiling priority = thread priority - PASS
+    SCHED_FIFO scheduling and ceiling priority > thread priority - PASS
+  Protype PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_NORMAL
+    Lock with ceiling priority < thread priority - PASS
+    Lock with ceiling priority = thread priority - PASS
+    Lock with ceiling priority > thread priority - PASS
+    Preemption with ceiling priority < thread priority - PASS
+    Preemption with ceiling priority = thread priority - PASS
+    SCHED_FIFO scheduling and ceiling priority = thread priority - PASS
+    SCHED_FIFO scheduling and ceiling priority > thread priority - PASS
+  Protype PTHREAD_PRIO_PROTECT, Type SS2 PTHREAD_MUTEX_RECURSIVE
+    Lock with ceiling priority < thread priority - PASS
+    Lock with ceiling priority = thread priority - PASS
+    Lock with ceiling priority > thread priority - PASS
+    Preemption with ceiling priority < thread priority - PASS
+    Preemption with ceiling priority = thread priority - PASS
+    SCHED_FIFO scheduling and ceiling priority = thread priority - PASS
+    SCHED_FIFO scheduling and ceiling priority > thread priority - PASS
+
+Total tests 212, passed 212, failed 0
--- /dev/null
+++ lib/libkse/test/guard_b.c
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2001 Jason Evans <jasone at freebsd.org>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice(s), this list of conditions and the following disclaimer
+ *    unmodified other than the allowable addition of one or more
+ *    copyright notices.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice(s), this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD: src/lib/libkse/test/guard_b.c,v 1.4 2007/10/09 13:42:26 obrien Exp $
+ *
+ * Test thread stack guard functionality.
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include <pthread.h>
+
+#define FRAME_SIZE	1024
+#define FRAME_OVERHEAD	  40
+
+struct args
+{
+	void	*top;	/* Top of thread's initial stack frame. */
+	int	cur;	/* Recursion depth. */
+	int	max;	/* Maximum recursion depth. */
+};
+
+void *
+recurse(void *args)
+{
+	int		top;
+	struct args	*parms = (struct args *)args;
+	char		filler[FRAME_SIZE - FRAME_OVERHEAD];
+
+	/* Touch the memory in this stack frame. */
+	top = 0xa5;
+	memset(filler, 0xa5, sizeof(filler));
+
+	if (parms->top == NULL) {
+		/* Initial stack frame. */
+		parms->top = (void*)⊤
+	}
+
+	/*
+	 * Make sure frame size is what we expect.  Getting this right involves
+	 * hand tweaking, so just print a warning rather than aborting.
+	 */
+	if (parms->top - (void *)&top != FRAME_SIZE * parms->cur) {
+		fprintf(stderr,
+		    "Stack size (%ld) != expected (%ld), frame %ld\n",
+		    (long)parms->top - (long)&top,
+		    (long)(FRAME_SIZE * parms->cur), (long)parms->cur);
+	}
+
+	parms->cur++;
+	if (parms->cur < parms->max)
+		recurse(args);
+
+	return NULL;
+}
+
+
+int
+main(int argc, char **argv)
+{
+	size_t		def_stacksize, def_guardsize;
+	size_t		stacksize, guardsize;
+	pthread_t	thread;
+	pthread_attr_t	attr;
+	struct args	args;
+
+	if (argc != 3) {
+		fprintf(stderr, "usage: guard_b <stacksize> <guardsize>\n");
+		exit(1);
+	}
+	fprintf(stderr, "Test begin\n");
+
+	stacksize = strtoul(argv[1], NULL, 10);
+	guardsize = strtoul(argv[2], NULL, 10);
+
+	assert(pthread_attr_init(&attr) == 0);
+	/*
+	 * Exercise the attribute APIs more thoroughly than is strictly
+	 * necessary for the meat of this test program.
+	 */
+	assert(pthread_attr_getstacksize(&attr, &def_stacksize) == 0);
+	assert(pthread_attr_getguardsize(&attr, &def_guardsize) == 0);
+	if (def_stacksize != stacksize) {
+		assert(pthread_attr_setstacksize(&attr, stacksize) == 0);
+		assert(pthread_attr_getstacksize(&attr, &def_stacksize) == 0);
+		assert(def_stacksize == stacksize);
+	}
+	if (def_guardsize != guardsize) {
+		assert(pthread_attr_setguardsize(&attr, guardsize) == 0);
+		assert(pthread_attr_getguardsize(&attr, &def_guardsize) == 0);
+		assert(def_guardsize >= guardsize);
+	}
+
+	/*
+	 * Create a thread that will come just short of overflowing the thread
+	 * stack.  We need to leave a bit of breathing room in case the thread
+	 * is context switched, and we also have to take care not to call any
+	 * functions in the deepest stack frame.
+	 */
+	args.top = NULL;
+	args.cur = 0;
+	args.max = (stacksize / FRAME_SIZE) - 1;
+	fprintf(stderr, "No overflow:\n");
+	assert(pthread_create(&thread, &attr, recurse, &args) == 0);
+	assert(pthread_join(thread, NULL) == 0);
+	
+	/*
+	 * Create a thread that will barely of overflow the thread stack.  This
+	 * should cause a segfault.
+	 */
+	args.top = NULL;
+	args.cur = 0;
+	args.max = (stacksize / FRAME_SIZE) + 1;
+	fprintf(stderr, "Overflow:\n");
+	assert(pthread_create(&thread, &attr, recurse, &args) == 0);
+	assert(pthread_join(thread, NULL) == 0);
+
+	/* Not reached. */
+	fprintf(stderr, "Unexpected success\n");
+	abort();
+
+	return 0;
+}
--- /dev/null
+++ lib/libkse/test/sigsuspend_d.exp
@@ -0,0 +1,9 @@
+# $FreeBSD: src/lib/libkse/test/sigsuspend_d.exp,v 1.2 2007/10/09 13:42:26 obrien Exp $
+  -> Suspender thread signal handler caught signal 16
+Sigsuspend woke up by signal 16
+  -> Suspender thread signal handler caught signal 16
+Sigsuspend woke up by signal 16
+  -> Suspender thread signal handler caught signal 31
+Sigsuspend woke up by signal 31
+  -> Suspender thread signal handler caught signal 31
+Sigsuspend woke up by signal 31
--- /dev/null
+++ lib/libkse/test/guard_s.pl
@@ -0,0 +1,69 @@
+#!/usr/bin/perl -w
+#
+# Copyright (C) 2001 Jason Evans <jasone at freebsd.org>.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice(s), this list of conditions and the following disclaimer
+#    unmodified other than the allowable addition of one or more
+#    copyright notices.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice(s), this list of conditions and the following disclaimer in
+#    the documentation and/or other materials provided with the
+#    distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# $FreeBSD: src/lib/libkse/test/guard_s.pl,v 1.2 2007/10/09 13:42:26 obrien Exp $
+#
+# Test thread stack guard functionality.  The C test program needs to be driven
+# by this script because it segfaults when the stack guard is hit.
+#
+
+print "1..30\n";
+
+$i = 0;
+# Iterates 10 times.
+for ($stacksize = 65536; $stacksize < 131072; $stacksize += 7168)
+{
+    # Iterates 3 times (1024, 4096, 7168).
+    for ($guardsize = 1024; $guardsize < 8192; $guardsize += 3072)
+    {
+	$i++;
+
+	print "stacksize: $stacksize, guardsize: $guardsize\n";
+
+	`./guard_b $stacksize $guardsize >guard_b.out 2>&1`;
+
+	if (! -f "./guard_b.out")
+	{
+	    print "not ok $i\n";
+	}
+	else
+	{
+	    `diff guard_b.exp guard_b.out >guard_b.diff 2>&1`;
+	    if ($?)
+	    {
+		# diff returns non-zero if there is a difference.
+		print "not ok $i\n";
+	    }
+	    else
+	    {
+		print "ok $i\n";
+	    }
+	}
+    }
+}
--- /dev/null
+++ lib/libkse/test/join_leak_d.c
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2001 Jason Evans <jasone at 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/libkse/test/join_leak_d.c,v 1.2 2007/10/09 13:42:26 obrien Exp $
+ *
+ * Test for leaked joined threads.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <errno.h>
+#include <string.h>
+#include <pthread.h>
+
+#define	NITERATIONS	16384
+#define	MAXGROWTH	16384
+
+void *
+thread_entry(void *a_arg)
+{
+	return NULL;
+}
+
+int
+main(void)
+{
+	pthread_t	thread;
+	int		i, error;
+	char		*brk, *nbrk;
+	unsigned	growth;
+
+	fprintf(stderr, "Test begin\n");
+
+	/* Get an initial brk value. */
+	brk = sbrk(0);
+
+	/* Create threads and join them, one at a time. */
+	for (i = 0; i < NITERATIONS; i++) {
+		if ((error = pthread_create(&thread, NULL, thread_entry, NULL))
+		    != 0) {
+			fprintf(stderr, "Error in pthread_create(): %s\n",
+			    strerror(error));
+			exit(1);
+		}
+		if ((error = pthread_join(thread, NULL)) != 0) {
+			fprintf(stderr, "Error in pthread_join(): %s\n",
+			    strerror(error));
+			exit(1);
+		}
+	}
+
+	/* Get a final brk value. */
+	nbrk = sbrk(0);
+
+	/*
+	 * Check that the amount of heap space allocated is below an acceptable
+	 * threshold.  We could just compare brk and nbrk, but the test could
+	 * conceivably break if the internals of the threads library changes.
+	 */
+	if (nbrk > brk) {
+		/* Heap grows up. */
+		growth = nbrk - brk;
+	} else if (nbrk <= brk) {
+		/* Heap grows down, or no growth. */
+		growth = brk - nbrk;
+	}
+
+	if (growth > MAXGROWTH) {
+		fprintf(stderr, "Heap growth exceeded maximum (%u > %u)\n",
+		    growth, MAXGROWTH);
+	}
+#if (0)
+	else {
+		fprintf(stderr, "Heap growth acceptable (%u <= %u)\n",
+		    growth, MAXGROWTH);
+	}
+#endif
+
+	fprintf(stderr, "Test end\n");
+	return 0;
+}
--- /dev/null
+++ lib/libkse/test/hello_d.c
@@ -0,0 +1,38 @@
+/****************************************************************************
+ *
+ * Simple diff mode test.
+ *
+ * $FreeBSD: src/lib/libkse/test/hello_d.c,v 1.2 2007/10/09 13:42:26 obrien Exp $
+ *
+ ****************************************************************************/
+
+#include <stdio.h>
+#include <string.h>
+#include <pthread.h>
+
+void *
+entry(void * a_arg)
+{
+	fprintf(stderr, "Hello world\n");
+
+	return NULL;
+}
+
+int
+main()
+{
+	pthread_t thread;
+	int error;
+
+	error = pthread_create(&thread, NULL, entry, NULL);
+	if (error)
+		fprintf(stderr, "Error in pthread_create(): %s\n",
+			strerror(error));
+
+	error = pthread_join(thread, NULL);
+	if (error)
+		fprintf(stderr, "Error in pthread_join(): %s\n",
+			strerror(error));
+
+	return 0;
+}
--- /dev/null
+++ lib/libkse/test/hello_s.c
@@ -0,0 +1,47 @@
+/****************************************************************************
+ *
+ * Simple sequence mode test.
+ *
+ * $FreeBSD: src/lib/libkse/test/hello_s.c,v 1.2 2007/10/09 13:42:26 obrien Exp $
+ *
+ ****************************************************************************/
+
+#include <stdio.h>
+#include <string.h>
+#include <pthread.h>
+
+void *
+entry(void * a_arg)
+{
+	fprintf(stderr, "ok 1\n");
+	fprintf(stderr, "ok \n");
+	fprintf(stderr, "ok 3\n");
+
+	return NULL;
+}
+
+int
+main()
+{
+	pthread_t thread;
+	int error;
+
+	fprintf(stderr, "1..3\n");
+	
+	fprintf(stderr, "Some random text\n");
+	
+	error = pthread_create(&thread, NULL, entry, NULL);
+	fprintf(stderr, "More unimportant text\n");
+	if (error)
+		fprintf(stderr,"Error in pthread_create(): %s\n",
+			strerror(error));
+
+	error = pthread_join(thread, NULL);
+	if (error)
+		fprintf(stderr,	"Error in pthread_join(): %s\n",
+			strerror(error));
+
+	fprintf(stderr, "Hello world\n");
+
+	return 0;
+}
--- /dev/null
+++ lib/libkse/test/mutex_d.c
@@ -0,0 +1,1558 @@
+/*
+ * Copyright (c) 1998 Daniel M. Eischen <eischen at vigrid.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by Daniel M. Eischen.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY DANIEL M. EISCHEN AND CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/lib/libkse/test/mutex_d.c,v 1.6 2007/10/09 13:42:26 obrien Exp $
+ */
+
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <assert.h>
+#include <errno.h>
+#include <sched.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <sysexits.h>
+#include "pthread.h"
+
+#if defined(_LIBC_R_)
+#include <pthread_np.h>
+#endif
+
+#ifndef NELEMENTS
+#define NELEMENTS(arr)	(sizeof (arr) / sizeof (arr[0]))
+#endif
+
+#ifndef NUM_THREADS
+#define NUM_THREADS	10
+#endif
+
+#define MAX_THREAD_CMDS	10
+
+static void log_error(const char *, ...) __printflike(1, 2);
+static void log_trace (const char *, ...) __printflike(1, 2);
+static void log (const char *, ...) __printflike(1, 2);
+
+/*------------------------------------------------------------
+ * Types
+ *----------------------------------------------------------*/
+
+typedef enum {
+	STAT_INITIAL,		/* initial state */
+	STAT_WAITCONDVAR,	/* waiting for condition variable signal */
+	STAT_WAITMUTEX		/* waiting for mutex lock */
+} thread_status_t;
+
+typedef enum {
+	FLAGS_REPORT_WAITCONDMUTEX	= 0x01,
+	FLAGS_REPORT_WAITCONDVAR	= 0x02,
+	FLAGS_REPORT_WAITMUTEX		= 0x04,
+	FLAGS_REPORT_BUSY_LOOP		= 0x08,
+	FLAGS_IS_BUSY			= 0x10,
+	FLAGS_WAS_BUSY			= 0x20
+} thread_flags_t;
+
+typedef enum {
+	CMD_NONE,
+	CMD_TAKE_MUTEX,
+	CMD_RELEASE_MUTEX,
+	CMD_WAIT_FOR_SIGNAL,
+	CMD_BUSY_LOOP,
+	CMD_PROTECTED_OP,
+	CMD_RELEASE_ALL
+} thread_cmd_id_t;
+
+typedef struct {
+	thread_cmd_id_t	cmd_id;
+	pthread_mutex_t	*mutex;
+	pthread_cond_t	*cond;
+} thread_cmd_t;
+
+typedef struct {
+	pthread_cond_t	cond_var;
+	thread_status_t	status;
+	thread_cmd_t	cmd;
+	int		flags;
+	int		priority;
+	int		ret;
+	pthread_t	tid;
+	u_int8_t	id;
+} thread_state_t;
+
+typedef enum {
+	M_POSIX,
+	M_SS2_DEFAULT,
+	M_SS2_ERRORCHECK,
+	M_SS2_NORMAL,
+	M_SS2_RECURSIVE
+} mutex_kind_t;
+
+
+/*------------------------------------------------------------
+ * Constants
+ *----------------------------------------------------------*/
+
+const char *protocol_strs[] = {
+	"PTHREAD_PRIO_NONE",
+	"PTHREAD_PRIO_INHERIT",
+	"PTHREAD_PRIO_PROTECT"
+};
+
+const int protocols[] = {
+	PTHREAD_PRIO_NONE,
+	PTHREAD_PRIO_INHERIT,
+	PTHREAD_PRIO_PROTECT
+};
+
+const char *mutextype_strs[] = {
+	"POSIX (type not specified)",
+	"SS2 PTHREAD_MUTEX_DEFAULT",
+	"SS2 PTHREAD_MUTEX_ERRORCHECK",
+	"SS2 PTHREAD_MUTEX_NORMAL",
+	"SS2 PTHREAD_MUTEX_RECURSIVE"
+};
+
+const int mutex_types[] = {
+	0,				/* M_POSIX		*/
+	PTHREAD_MUTEX_DEFAULT,		/* M_SS2_DEFAULT	*/
+	PTHREAD_MUTEX_ERRORCHECK,	/* M_SS2_ERRORCHECK	*/
+	PTHREAD_MUTEX_NORMAL,		/* M_SS2_NORMAL		*/
+	PTHREAD_MUTEX_RECURSIVE		/* M_SS2_RECURSIVE	*/
+};
+
+
+/*------------------------------------------------------------
+ * Objects
+ *----------------------------------------------------------*/
+
+static int		done = 0;
+static int		trace_enabled = 0;
+static int		use_global_condvar = 0;
+static thread_state_t	states[NUM_THREADS];
+static int		pipefd[2];
+
+static pthread_mutex_t	waiter_mutex;
+static pthread_mutex_t	cond_mutex;
+static pthread_cond_t	cond_var;
+
+static FILE *logfile;
+static int error_count = 0, pass_count = 0, total = 0;
+
+
+/*------------------------------------------------------------
+ * Prototypes
+ *----------------------------------------------------------*/
+extern char *strtok_r(char *str, const char *sep, char **last);
+
+
+/*------------------------------------------------------------
+ * Functions
+ *----------------------------------------------------------*/
+
+#if defined(_LIBC_R_) && defined(DEBUG)
+static void
+kern_switch (pthread_t pthread_out, pthread_t pthread_in)
+{
+	if (pthread_out != NULL)
+		printf ("Swapping out thread 0x%lx, ", (long) pthread_out);
+	else
+		printf ("Swapping out kernel thread, ");
+
+	if (pthread_in != NULL)
+		printf ("swapping in thread 0x%lx\n", (long) pthread_in);
+	else
+		printf ("swapping in kernel thread.\n");
+}
+#endif
+
+
+static void
+log_error (const char *fmt, ...)
+{
+	va_list ap;
+
+	va_start (ap, fmt);
+	fprintf (logfile, "FAIL: ");
+	vfprintf (logfile, fmt, ap);
+	error_count = error_count + 1;
+	total = total + 1;
+}
+
+
+static void
+log_pass (void)
+{
+	fprintf (logfile, "PASS\n");
+	pass_count = pass_count + 1;
+	total = total + 1;
+}
+
+
+static void
+log_trace (const char *fmt, ...)
+{
+	va_list ap;
+
+	if (trace_enabled) {
+		va_start (ap, fmt);
+		vfprintf (logfile, fmt, ap);
+	}
+}
+
+
+static void
+log (const char *fmt, ...)
+{
+	va_list ap;
+
+	va_start (ap, fmt);
+	vfprintf (logfile, fmt, ap);
+}
+
+
+static void
+check_result (int expected, int actual)
+{
+	if (expected != actual)
+		log_error ("expected %d, returned %d\n", expected, actual);
+	else
+		log_pass ();
+}
+
+
+/*
+ * Check to see that the threads ran in the specified order.
+ */
+static void
+check_run_order (char *order)
+{
+	const char *sep = ":,";
+	char *tok, *last, *idstr, *endptr;
+	int expected_id, bytes, count = 0, errors = 0;
+	u_int8_t id;
+
+	assert ((tok = (char *) malloc (strlen(order) + 1)) != NULL);
+	strcpy (tok, order);	/* tok has to be larger than order */
+	assert (ioctl (pipefd[0], FIONREAD, &bytes) == 0);
+	log_trace ("%d bytes read from FIFO.\n", bytes);
+
+	for (idstr = strtok_r (tok, sep, &last);
+	     (idstr != NULL) && (count < bytes);
+	     idstr = strtok_r (NULL, sep, &last)) {
+
+		/* Get the expected id: */
+		expected_id = (int) strtol (idstr, &endptr, 10);
+		assert ((endptr != NULL) && (*endptr == '\0'));
+
+		/* Read the actual id from the pipe: */
+		assert (read (pipefd[0], &id, sizeof (id)) == sizeof (id));
+		count = count + sizeof (id);
+
+		if (id != expected_id) {
+			log_trace ("Thread %d ran out of order.\n", id);
+			errors = errors + 1;
+		}
+		else {
+			log_trace ("Thread %d at priority %d reporting.\n",
+			    (int) id, states[id].priority);
+		}
+	}
+
+	if (count < bytes) {
+		/* Clear the pipe: */
+		while (count < bytes) {
+			read (pipefd[0], &id, sizeof (id));
+			count = count + 1;
+			errors = errors + 1;
+		}
+	}
+	else if (bytes < count)
+		errors = errors + count - bytes;
+
+	if (errors == 0)
+		log_pass ();
+	else
+		log_error ("%d threads ran out of order", errors);
+}
+
+
+static void *
+waiter (void *arg)
+{
+	thread_state_t	*statep = (thread_state_t *) arg;
+	pthread_mutex_t	*held_mutex[MAX_THREAD_CMDS];
+	int 		held_mutex_owned[MAX_THREAD_CMDS];
+	sigset_t	mask;
+	struct timeval	tv1, tv2;
+	thread_cmd_t	cmd;
+	int 		i, mutex_count = 0;
+
+	statep->status = STAT_INITIAL;
+
+	/* Block all signals except for interrupt.*/
+	sigfillset (&mask);
+	sigdelset (&mask, SIGINT);
+	sigprocmask (SIG_BLOCK, &mask, NULL);
+
+	while (done == 0) {
+		/* Wait for signal from the main thread to continue. */
+		statep->status = STAT_WAITMUTEX;
+		log_trace ("Thread %d: locking cond_mutex.\n",
+		    (int) statep->id);
+		pthread_mutex_lock (&cond_mutex);
+
+		/* Do we report our status. */
+		if (statep->flags & FLAGS_REPORT_WAITCONDMUTEX)
+			write (pipefd[1], &statep->id, sizeof (statep->id));
+		log_trace ("Thread %d: waiting for cond_var.\n",
+		    (int) statep->id);
+
+		/* Wait for a command. */
+		statep->status = STAT_WAITCONDVAR;
+
+		/*
+		 * The threads are allowed commanded to wait either on
+		 * their own unique condition variable (so they may be
+		 * separately signaled) or on one global condition variable
+		 * (so they may be signaled together).
+		 */
+		if (use_global_condvar != 0)
+			pthread_cond_wait (&cond_var, &cond_mutex);
+		else
+			pthread_cond_wait (&statep->cond_var, &cond_mutex);
+
+		/* Do we report our status? */
+		if (statep->flags & FLAGS_REPORT_WAITCONDVAR) {
+			write (pipefd[1], &statep->id, sizeof (statep->id));
+			log_trace ("Thread %d: wrote to pipe.\n",
+			    (int) statep->id);
+		}
+		log_trace ("Thread %d: received cond_var signal.\n",
+		    (int) statep->id);
+
+		/* Get a copy of the command before releasing the mutex. */
+		cmd = statep->cmd;
+
+		/* Clear the command after copying it. */
+		statep->cmd.cmd_id = CMD_NONE;
+
+		/* Unlock the condition variable mutex. */
+		assert (pthread_mutex_unlock (&cond_mutex) == 0);
+
+		/* Peform the command.*/
+		switch (cmd.cmd_id) {
+		case CMD_TAKE_MUTEX:
+			statep->ret = pthread_mutex_lock (cmd.mutex);
+			if (statep->ret == 0) {
+				assert (mutex_count < sizeof (held_mutex));
+				held_mutex[mutex_count] = cmd.mutex;
+				held_mutex_owned[mutex_count] = 1;
+				mutex_count++;
+			}
+			else {
+				held_mutex_owned[mutex_count] = 0;
+				log_trace ("Thread id %d unable to lock mutex, "
+				    "error = %d\n", (int) statep->id,
+				    statep->ret);
+			}
+			break;
+
+		case CMD_RELEASE_MUTEX:
+			assert ((mutex_count <= sizeof (held_mutex)) &&
+			    (mutex_count > 0));
+			mutex_count--;
+			if (held_mutex_owned[mutex_count] != 0)
+				assert (pthread_mutex_unlock
+				    (held_mutex[mutex_count]) == 0);
+			break;
+
+		case CMD_WAIT_FOR_SIGNAL:
+			assert (pthread_mutex_lock (cmd.mutex) == 0);
+			assert (pthread_cond_wait (cmd.cond, cmd.mutex) == 0);
+			assert (pthread_mutex_unlock (cmd.mutex) == 0);
+			break;
+
+		case CMD_BUSY_LOOP:
+			log_trace ("Thread %d: Entering busy loop.\n",
+			    (int) statep->id);
+			/* Spin for 15 seconds. */
+			assert (gettimeofday (&tv2, NULL) == 0);
+			tv1.tv_sec = tv2.tv_sec + 5;
+			tv1.tv_usec = tv2.tv_usec;
+			statep->flags |= FLAGS_IS_BUSY;
+			while (timercmp (&tv2, &tv1,<)) {
+				assert (gettimeofday (&tv2, NULL) == 0);
+			}
+			statep->flags &= ~FLAGS_IS_BUSY;
+			statep->flags |= FLAGS_WAS_BUSY;
+
+			/* Do we report our status? */
+			if (statep->flags & FLAGS_REPORT_BUSY_LOOP)
+				write (pipefd[1], &statep->id,
+				    sizeof (statep->id));
+
+			log_trace ("Thread %d: Leaving busy loop.\n",
+			    (int) statep->id);
+			break;
+
+		case CMD_PROTECTED_OP:
+			assert (pthread_mutex_lock (cmd.mutex) == 0);
+			statep->flags |= FLAGS_WAS_BUSY;
+			/* Do we report our status? */
+			if (statep->flags & FLAGS_REPORT_BUSY_LOOP)
+				write (pipefd[1], &statep->id,
+				    sizeof (statep->id));
+
+			assert (pthread_mutex_unlock (cmd.mutex) == 0);
+			break;
+
+		case CMD_RELEASE_ALL:
+			assert ((mutex_count <= sizeof (held_mutex)) &&
+			    (mutex_count > 0));
+			for (i = mutex_count - 1; i >= 0; i--) {
+				if (held_mutex_owned[i] != 0)
+					assert (pthread_mutex_unlock
+					    (held_mutex[i]) == 0);
+			}
+			mutex_count = 0;
+			break;
+
+		case CMD_NONE:
+		default:
+			break;
+		}
+
+		/* Wait for the big giant waiter lock. */
+		statep->status = STAT_WAITMUTEX;
+		log_trace ("Thread %d: waiting for big giant lock.\n",
+		    (int) statep->id);
+		pthread_mutex_lock (&waiter_mutex);
+		if (statep->flags & FLAGS_REPORT_WAITMUTEX)
+			write (pipefd[1], &statep->id, sizeof (statep->id));
+		log_trace ("Thread %d: got big giant lock.\n",
+		    (int) statep->id);
+		statep->status = STAT_INITIAL;
+		pthread_mutex_unlock (&waiter_mutex);
+	}
+
+	log_trace ("Thread %ld: Exiting thread 0x%lx\n", (long) statep->id,
+	    (long) pthread_self());
+	pthread_exit (arg);
+	return (NULL);
+}
+
+
+static void *
+lock_twice (void *arg)
+{
+	thread_state_t	*statep = (thread_state_t *) arg;
+	sigset_t	mask;
+
+	statep->status = STAT_INITIAL;
+
+	/* Block all signals except for interrupt.*/
+	sigfillset (&mask);
+	sigdelset (&mask, SIGINT);
+	sigprocmask (SIG_BLOCK, &mask, NULL);
+
+	/* Wait for a signal to continue. */
+	log_trace ("Thread %d: locking cond_mutex.\n", (int) statep->id);
+	pthread_mutex_lock (&cond_mutex);
+
+	log_trace ("Thread %d: waiting for cond_var.\n", (int) statep->id);
+	statep->status = STAT_WAITCONDVAR;
+	pthread_cond_wait (&cond_var, &cond_mutex);
+
+	log_trace ("Thread %d: received cond_var signal.\n", (int) statep->id);
+
+	/* Unlock the condition variable mutex. */
+	assert (pthread_mutex_unlock (&cond_mutex) == 0);
+
+	statep->status = STAT_WAITMUTEX;
+	/* Lock the mutex once. */
+	assert (pthread_mutex_lock (statep->cmd.mutex) == 0);
+
+	/* Lock it again and capture the error. */
+	statep->ret = pthread_mutex_lock (statep->cmd.mutex);
+	statep->status = 0;
+
+	assert (pthread_mutex_unlock (statep->cmd.mutex) == 0);
+
+	/* Unlock it again if it is locked recursively. */
+	if (statep->ret == 0)
+		pthread_mutex_unlock (statep->cmd.mutex);
+
+	log_trace ("Thread %ld: Exiting thread 0x%lx\n", (long) statep->id,
+	    (long) pthread_self());
+	pthread_exit (arg);
+	return (NULL);
+}
+
+
+static void
+sighandler (int signo)
+{
+	log ("Signal handler caught signal %d, thread id 0x%lx\n",
+	    signo, (long) pthread_self());
+
+	if (signo == SIGINT)
+		done = 1;
+}
+
+
+static void
+send_cmd (int id, thread_cmd_id_t cmd)
+{
+	assert (pthread_mutex_lock (&cond_mutex) == 0);
+	assert (states[id].status == STAT_WAITCONDVAR);
+	states[id].cmd.cmd_id = cmd;
+	states[id].cmd.mutex = NULL;
+	states[id].cmd.cond = NULL;
+	/* Clear the busy flags. */
+	states[id].flags &= ~(FLAGS_WAS_BUSY | FLAGS_IS_BUSY);
+	assert (pthread_cond_signal (&states[id].cond_var) == 0);
+	assert (pthread_mutex_unlock (&cond_mutex) == 0);
+}
+
+
+static void
+send_mutex_cmd (int id, thread_cmd_id_t cmd, pthread_mutex_t *m)
+{
+	assert (pthread_mutex_lock (&cond_mutex) == 0);
+	assert (states[id].status == STAT_WAITCONDVAR);
+	states[id].cmd.cmd_id = cmd;
+	states[id].cmd.mutex = m;
+	states[id].cmd.cond = NULL;
+	/* Clear the busy flags. */
+	states[id].flags &= ~(FLAGS_WAS_BUSY | FLAGS_IS_BUSY);
+	assert (pthread_cond_signal (&states[id].cond_var) == 0);
+	assert (pthread_mutex_unlock (&cond_mutex) == 0);
+}
+
+
+static void
+send_mutex_cv_cmd (int id, thread_cmd_id_t cmd, pthread_mutex_t *m,
+    pthread_cond_t *cv)
+{
+	assert (pthread_mutex_lock (&cond_mutex) == 0);
+	assert (states[id].status == STAT_WAITCONDVAR);
+	states[id].cmd.cmd_id = cmd;
+	states[id].cmd.mutex = m;
+	states[id].cmd.cond = cv;
+	/* Clear the busy flags. */
+	states[id].flags &= ~(FLAGS_WAS_BUSY | FLAGS_IS_BUSY);
+	assert (pthread_cond_signal (&states[id].cond_var) == 0);
+	assert (pthread_mutex_unlock (&cond_mutex) == 0);
+}
+
+
+static void
+mutex_init_test (void)
+{
+	pthread_mutexattr_t mattr;
+	pthread_mutex_t	mutex;
+	mutex_kind_t mkind;
+	int mproto, ret;
+
+	/*
+	 * Initialize a mutex attribute.
+	 *
+	 * pthread_mutexattr_init not tested for: ENOMEM
+	 */
+	assert (pthread_mutexattr_init (&mattr) == 0);
+
+	/*
+	 * Initialize a mutex.
+	 *
+	 * pthread_mutex_init not tested for: EAGAIN ENOMEM EPERM EBUSY
+	 */
+	log ("Testing pthread_mutex_init\n");
+	log ("--------------------------\n");
+
+	for (mproto = 0; mproto < NELEMENTS(protocols); mproto++) {
+		for (mkind = M_POSIX; mkind <= M_SS2_RECURSIVE; mkind++) {
+			/* Initialize the mutex attribute. */
+			assert (pthread_mutexattr_init (&mattr) == 0);
+			assert (pthread_mutexattr_setprotocol (&mattr,
+			    protocols[mproto]) == 0);
+
+			/*
+			 * Ensure that the first mutex type is a POSIX
+			 * compliant mutex.
+			 */
+			if (mkind != M_POSIX) {
+				assert (pthread_mutexattr_settype (&mattr,
+				    mutex_types[mkind]) == 0);
+			}
+
+			log ("  Protocol %s, Type %s - ",
+			    protocol_strs[mproto], mutextype_strs[mkind]);
+			ret = pthread_mutex_init (&mutex, &mattr);
+			check_result (/* expected */ 0, ret);
+			assert (pthread_mutex_destroy (&mutex) == 0);
+
+			/*
+			 * Destroy a mutex attribute.
+			 *
+			 * XXX - There should probably be a magic number
+			 *       associated with a mutex attribute so that
+			 *       destroy can be reasonably sure the attribute
+			 *       is valid.
+			 *
+			 * pthread_mutexattr_destroy not tested for: EINVAL
+			 */
+			assert (pthread_mutexattr_destroy (&mattr) == 0);
+		}
+	}
+}
+
+
+static void
+mutex_destroy_test (void)
+{
+	pthread_mutexattr_t mattr;
+	pthread_mutex_t	mutex;
+	pthread_condattr_t cattr;
+	pthread_cond_t	cv;
+	pthread_attr_t pattr;
+	int mproto, ret;
+	mutex_kind_t mkind;
+	thread_state_t state;
+
+	/*
+	 * Destroy a mutex.
+	 *
+	 * XXX - There should probably be a magic number associated
+	 *       with a mutex so that destroy can be reasonably sure
+	 *       the mutex is valid.
+	 *
+	 * pthread_mutex_destroy not tested for: 
+	 */
+	log ("Testing pthread_mutex_destroy\n");
+	log ("-----------------------------\n");
+
+	assert (pthread_attr_init (&pattr) == 0);
+	assert (pthread_attr_setdetachstate (&pattr,
+	    PTHREAD_CREATE_DETACHED) == 0);
+	state.flags = 0;	/* No flags yet. */
+
+	for (mproto = 0; mproto < NELEMENTS(protocols); mproto++) {
+		for (mkind = M_POSIX; mkind <= M_SS2_RECURSIVE; mkind++) {
+			/* Initialize the mutex attribute. */
+			assert (pthread_mutexattr_init (&mattr) == 0);
+			assert (pthread_mutexattr_setprotocol (&mattr,
+			    protocols[mproto]) == 0);
+
+			/*
+			 * Ensure that the first mutex type is a POSIX
+			 * compliant mutex.
+			 */
+			if (mkind != M_POSIX) {
+				assert (pthread_mutexattr_settype (&mattr,
+				    mutex_types[mkind]) == 0);
+			}
+
+			/* Create the mutex. */
+			assert (pthread_mutex_init (&mutex, &mattr) == 0);
+
+			log ("  Protocol %s, Type %s\n",
+			    protocol_strs[mproto], mutextype_strs[mkind]);
+
+			log ("    Destruction of unused mutex - ");
+			assert (pthread_mutex_init (&mutex, &mattr) == 0);
+			ret = pthread_mutex_destroy (&mutex);
+			check_result (/* expected */ 0, ret);
+
+			log ("    Destruction of mutex locked by self - ");
+			assert (pthread_mutex_init (&mutex, &mattr) == 0);
+			assert (pthread_mutex_lock (&mutex) == 0);
+			ret = pthread_mutex_destroy (&mutex);
+			check_result (/* expected */ EBUSY, ret);
+			assert (pthread_mutex_unlock (&mutex) == 0);
+			assert (pthread_mutex_destroy (&mutex) == 0);
+
+			log ("    Destruction of mutex locked by another "
+			    "thread - ");
+			assert (pthread_mutex_init (&mutex, &mattr) == 0);
+			send_mutex_cmd (0, CMD_TAKE_MUTEX, &mutex);
+			sleep (1);
+			ret = pthread_mutex_destroy (&mutex);
+			check_result (/* expected */ EBUSY, ret);
+			send_cmd (0, CMD_RELEASE_ALL);
+			sleep (1);
+			assert (pthread_mutex_destroy (&mutex) == 0);
+
+			log ("    Destruction of mutex while being used in "
+			    "cond_wait - ");
+			assert (pthread_mutex_init (&mutex, &mattr) == 0);
+			assert (pthread_condattr_init (&cattr) == 0);
+			assert (pthread_cond_init (&cv, &cattr) == 0);
+			send_mutex_cv_cmd (0, CMD_WAIT_FOR_SIGNAL, &mutex, &cv);
+			sleep (1);
+			ret = pthread_mutex_destroy (&mutex);
+			check_result (/* expected */ EBUSY, ret);
+			pthread_cond_signal (&cv);
+			sleep (1);
+			assert (pthread_mutex_destroy (&mutex) == 0);
+		}
+	}
+}
+
+
+static void
+mutex_lock_test (void)
+{
+	pthread_mutexattr_t mattr;
+	pthread_mutex_t	mutex;
+	pthread_attr_t pattr;
+	int mproto, ret;
+	mutex_kind_t mkind;
+	thread_state_t state;
+
+	/*
+	 * Lock a mutex.
+	 *
+	 * pthread_lock not tested for: 
+	 */
+	log ("Testing pthread_mutex_lock\n");
+	log ("--------------------------\n");
+
+	assert (pthread_attr_init (&pattr) == 0);
+	assert (pthread_attr_setdetachstate (&pattr,
+	    PTHREAD_CREATE_DETACHED) == 0);
+	state.flags = 0;	/* No flags yet. */
+
+	for (mproto = 0; mproto < NELEMENTS(protocols); mproto++) {
+		for (mkind = M_POSIX; mkind <= M_SS2_RECURSIVE; mkind++) {
+			/* Initialize the mutex attribute. */
+			assert (pthread_mutexattr_init (&mattr) == 0);
+			assert (pthread_mutexattr_setprotocol (&mattr,
+			    protocols[mproto]) == 0);
+
+			/*
+			 * Ensure that the first mutex type is a POSIX
+			 * compliant mutex.
+			 */
+			if (mkind != M_POSIX) {
+				assert (pthread_mutexattr_settype (&mattr,
+				    mutex_types[mkind]) == 0);
+			}
+
+			/* Create the mutex. */
+			assert (pthread_mutex_init (&mutex, &mattr) == 0);
+
+			log ("  Protocol %s, Type %s\n",
+			    protocol_strs[mproto], mutextype_strs[mkind]);
+
+			log ("    Lock on unlocked mutex - ");
+			ret = pthread_mutex_lock (&mutex);
+			check_result (/* expected */ 0, ret);
+			pthread_mutex_unlock (&mutex);
+
+			log ("    Lock on invalid mutex - ");
+			ret = pthread_mutex_lock (NULL);
+			check_result (/* expected */ EINVAL, ret);
+
+			log ("    Lock on mutex held by self - ");
+			assert (pthread_create (&state.tid, &pattr, lock_twice,
+			    (void *) &state) == 0);
+			/* Let the thread start. */
+			sleep (1);
+			state.cmd.mutex = &mutex;
+			state.ret = 0xdeadbeef;
+			assert (pthread_mutex_lock (&cond_mutex) == 0);
+			assert (pthread_cond_signal (&cond_var) == 0);
+			assert (pthread_mutex_unlock (&cond_mutex) == 0);
+			/* Let the thread receive and process the command. */
+			sleep (1);
+
+			switch (mkind) {
+			case M_POSIX:
+				check_result (/* expected */ EDEADLK,
+				    state.ret);
+				break;
+			case M_SS2_DEFAULT:
+				check_result (/* expected */ EDEADLK,
+				    state.ret);
+				break;
+			case M_SS2_ERRORCHECK:
+				check_result (/* expected */ EDEADLK,
+				    state.ret);
+				break;
+			case M_SS2_NORMAL:
+				check_result (/* expected */ 0xdeadbeef,
+				    state.ret);
+				break;
+			case M_SS2_RECURSIVE:
+				check_result (/* expected */ 0, state.ret);
+				break;
+			}
+			pthread_mutex_destroy (&mutex);
+			pthread_mutexattr_destroy (&mattr);
+		}
+	}
+}
+
+
+static void
+mutex_unlock_test (void)
+{
+	const int test_thread_id = 0;	/* ID of test thread */
+	pthread_mutexattr_t mattr;
+	pthread_mutex_t	mutex;
+	int mproto, ret;
+	mutex_kind_t mkind;
+
+	/*
+	 * Unlock a mutex.
+	 *
+	 * pthread_unlock not tested for: 
+	 */
+	log ("Testing pthread_mutex_unlock\n");
+	log ("----------------------------\n");
+
+	for (mproto = 0; mproto < NELEMENTS(protocols); mproto++) {
+		for (mkind = M_POSIX; mkind <= M_SS2_RECURSIVE; mkind++) {
+			/* Initialize the mutex attribute. */
+			assert (pthread_mutexattr_init (&mattr) == 0);
+			assert (pthread_mutexattr_setprotocol (&mattr,
+			    protocols[mproto]) == 0);
+
+			/*
+			 * Ensure that the first mutex type is a POSIX
+			 * compliant mutex.
+			 */
+			if (mkind != M_POSIX) {
+				assert (pthread_mutexattr_settype (&mattr,
+				    mutex_types[mkind]) == 0);
+			}
+
+			/* Create the mutex. */
+			assert (pthread_mutex_init (&mutex, &mattr) == 0);
+
+			log ("  Protocol %s, Type %s\n",
+			    protocol_strs[mproto], mutextype_strs[mkind]);
+
+			log ("    Unlock on mutex held by self - ");
+			assert (pthread_mutex_lock (&mutex) == 0);
+			ret = pthread_mutex_unlock (&mutex);
+			check_result (/* expected */ 0, ret);
+
+			log ("    Unlock on invalid mutex - ");
+			ret = pthread_mutex_unlock (NULL);
+			check_result (/* expected */ EINVAL, ret);
+
+			log ("    Unlock on mutex locked by another thread - ");
+			send_mutex_cmd (test_thread_id, CMD_TAKE_MUTEX, &mutex);
+			sleep (1);
+			ret = pthread_mutex_unlock (&mutex);
+			switch (mkind) {
+			case M_POSIX:
+				check_result (/* expected */ EPERM, ret);
+				break;
+			case M_SS2_DEFAULT:
+				check_result (/* expected */ EPERM, ret);
+				break;
+			case M_SS2_ERRORCHECK:
+				check_result (/* expected */ EPERM, ret);
+				break;
+			case M_SS2_NORMAL:
+				check_result (/* expected */ EPERM, ret);
+				break;
+			case M_SS2_RECURSIVE:
+				check_result (/* expected */ EPERM, ret);
+				break;
+			}
+			if (ret == 0) {
+				/*
+				 * If for some reason we were able to unlock
+				 * the mutex, relock it so that the test
+				 * thread has no problems releasing the mutex.
+				 */
+				pthread_mutex_lock (&mutex);
+			}
+			send_cmd (test_thread_id, CMD_RELEASE_ALL);
+			sleep (1);
+
+			pthread_mutex_destroy (&mutex);
+			pthread_mutexattr_destroy (&mattr);
+		}
+	}
+}
+
+
+static void
+queueing_order_test (void)
+{
+	int i;
+
+	log ("Testing queueing order\n");
+	log ("----------------------\n");
+	assert (pthread_mutex_lock (&waiter_mutex) == 0);
+	/*
+	 * Tell the threads to report when they take the waiters mutex.
+	 */
+	assert (pthread_mutex_lock (&cond_mutex) == 0);
+	for (i = 0; i < NUM_THREADS; i++) {
+		states[i].flags = FLAGS_REPORT_WAITMUTEX;
+		assert (pthread_cond_signal (&states[i].cond_var) == 0);
+	}
+	assert (pthread_mutex_unlock (&cond_mutex) == 0);
+
+	/* Signal the threads to continue. */
+	sleep (1);
+
+	/* Use the global condition variable next time. */
+	use_global_condvar = 1;
+
+	/* Release the waiting threads and allow them to run again. */
+	assert (pthread_mutex_unlock (&waiter_mutex) == 0);
+	sleep (1);
+
+	log ("  Queueing order on a mutex - ");
+	check_run_order ("9,8,7,6,5,4,3,2,1,0");
+	for (i = 0; i < NUM_THREADS; i = i + 1) {
+		/* Tell the threads to report when they've been signaled. */
+		states[i].flags = FLAGS_REPORT_WAITCONDVAR;
+	}
+
+	/*
+	 * Prevent the threads from continuing their loop after we
+	 * signal them.
+	 */
+	assert (pthread_mutex_lock (&waiter_mutex) == 0);
+
+
+	log ("  Queueing order on a condition variable - ");
+	/*
+	 * Signal one thread to run and see that the highest priority
+	 * thread executes.
+	 */
+	assert (pthread_mutex_lock (&cond_mutex) == 0);
+	assert (pthread_cond_signal (&cond_var) == 0);
+	assert (pthread_mutex_unlock (&cond_mutex) == 0);
+	sleep (1);
+	if (states[NUM_THREADS - 1].status != STAT_WAITMUTEX)
+		log_error ("highest priority thread does not run.\n");
+
+	/* Signal the remaining threads. */
+	assert (pthread_mutex_lock (&cond_mutex) == 0);
+	assert (pthread_cond_broadcast (&cond_var) == 0);
+	assert (pthread_mutex_unlock (&cond_mutex) == 0);
+	sleep (1);
+
+	check_run_order ("9,8,7,6,5,4,3,2,1,0");
+	for (i = 0; i < NUM_THREADS; i = i + 1) {
+		/* Tell the threads not to report anything. */
+		states[i].flags = 0;
+	}
+
+	/* Use the thread unique condition variable next time. */
+	use_global_condvar = 0;
+
+	/* Allow the threads to continue their loop. */
+	assert (pthread_mutex_unlock (&waiter_mutex) == 0);
+	sleep (1);
+}
+
+
+static void
+mutex_prioceiling_test (void)
+{
+	const int test_thread_id = 0;	/* ID of test thread */
+	pthread_mutexattr_t mattr;
+	struct sched_param param;
+	pthread_mutex_t	m[3];
+	mutex_kind_t	mkind;
+	int		i, ret, policy, my_prio, old_ceiling;
+
+	log ("Testing priority ceilings\n");
+	log ("-------------------------\n");
+	for (mkind = M_POSIX; mkind <= M_SS2_RECURSIVE; mkind++) {
+
+		log ("  Protype PTHREAD_PRIO_PROTECT, Type %s\n",
+		    mutextype_strs[mkind]);
+
+		/*
+		 * Initialize and create a mutex.
+		 */
+		assert (pthread_mutexattr_init (&mattr) == 0);
+
+		/* Get this threads current priority. */
+		assert (pthread_getschedparam (pthread_self(), &policy,
+		    &param) == 0);
+		my_prio = param.sched_priority;	/* save for later use */
+		log_trace ("Current scheduling policy %d, priority %d\n",
+		    policy, my_prio);
+
+		/*
+		 * Initialize and create 3 priority protection mutexes with
+		 * default (max priority) ceilings.
+		 */
+		assert (pthread_mutexattr_setprotocol(&mattr,
+		    PTHREAD_PRIO_PROTECT) == 0);
+
+		/*
+		 * Ensure that the first mutex type is a POSIX
+		 * compliant mutex.
+		 */
+		if (mkind != M_POSIX) {
+			assert (pthread_mutexattr_settype (&mattr,
+			    mutex_types[mkind]) == 0);
+		}
+
+		for (i = 0; i < 3; i++)
+			assert (pthread_mutex_init (&m[i], &mattr) == 0);
+
+		/*
+		 * Set the ceiling priorities for the 3 priority protection
+		 * mutexes to, 5 less than, equal to, and 5 greater than,
+		 * this threads current priority.
+		 */
+		for (i = 0; i < 3; i++)
+			assert (pthread_mutex_setprioceiling (&m[i],
+			    my_prio - 5 + 5*i, &old_ceiling) == 0);
+
+		/*
+		 * Check that if we attempt to take a mutex whose priority
+		 * ceiling is lower than our priority, we get an error.
+		 */
+		log ("    Lock with ceiling priority < thread priority - ");
+		ret = pthread_mutex_lock (&m[0]);
+		check_result (/* expected */ EINVAL, ret);
+		if (ret == 0)
+			pthread_mutex_unlock (&m[0]);
+
+		/*
+		 * Check that we can take a mutex whose priority ceiling
+		 * is equal to our priority.
+		 */
+		log ("    Lock with ceiling priority = thread priority - ");
+		ret = pthread_mutex_lock (&m[1]);
+		check_result (/* expected */ 0, ret);
+		if (ret == 0)
+			pthread_mutex_unlock (&m[1]);
+
+		/*
+		 * Check that we can take a mutex whose priority ceiling
+		 * is higher than our priority.
+		 */
+		log ("    Lock with ceiling priority > thread priority - ");
+		ret = pthread_mutex_lock (&m[2]);
+		check_result (/* expected */ 0, ret);
+		if (ret == 0)
+			pthread_mutex_unlock (&m[2]);
+
+		/*
+		 * Have the test thread go into a busy loop for 5 seconds
+		 * and see that it doesn't block this thread (since the
+		 * priority ceiling of mutex 0 and the priority of the test
+		 * thread are both less than the priority of this thread).
+		 */
+		log ("    Preemption with ceiling priority < thread "
+		    "priority - ");
+		/* Have the test thread take mutex 0. */
+		send_mutex_cmd (test_thread_id, CMD_TAKE_MUTEX, &m[0]);
+		sleep (1);
+
+		log_trace ("Sending busy command.\n");
+		send_cmd (test_thread_id, CMD_BUSY_LOOP);
+		log_trace ("Busy sent, yielding\n");
+		pthread_yield ();
+		log_trace ("Returned from yield.\n");
+		if (states[test_thread_id].flags &
+		    (FLAGS_IS_BUSY | FLAGS_WAS_BUSY))
+			log_error ("test thread inproperly preempted us.\n");
+		else {
+			/* Let the thread finish its busy loop. */
+			sleep (6);
+			if ((states[test_thread_id].flags & FLAGS_WAS_BUSY) == 0)
+				log_error ("test thread never finished.\n");
+			else
+				log_pass ();
+		}
+		states[test_thread_id].flags &= ~FLAGS_WAS_BUSY;
+
+		/* Have the test thread release mutex 0. */
+		send_cmd (test_thread_id, CMD_RELEASE_ALL);
+		sleep (1);
+
+		/*
+		 * Have the test thread go into a busy loop for 5 seconds
+		 * and see that it preempts this thread (since the priority
+		 * ceiling of mutex 1 is the same as the priority of this
+		 * thread).  The test thread should not run to completion
+		 * as its time quantum should expire before the 5 seconds
+		 * are up.
+		 */
+		log ("    Preemption with ceiling priority = thread "
+		    "priority - ");
+
+		/* Have the test thread take mutex 1. */
+		send_mutex_cmd (test_thread_id, CMD_TAKE_MUTEX, &m[1]);
+		sleep (1);
+
+		log_trace ("Sending busy\n");
+		send_cmd (test_thread_id, CMD_BUSY_LOOP);
+		log_trace ("Busy sent, yielding\n");
+		pthread_yield ();
+		log_trace ("Returned from yield.\n");
+		if ((states[test_thread_id].flags & FLAGS_IS_BUSY) == 0)
+			log_error ("test thread did not switch in on yield.\n");
+		else if (states[test_thread_id].flags & FLAGS_WAS_BUSY)
+			log_error ("test thread ran to completion.\n");
+		else {
+			/* Let the thread finish its busy loop. */
+			sleep (6);
+			if ((states[test_thread_id].flags & FLAGS_WAS_BUSY) == 0)
+				log_error ("test thread never finished.\n");
+			else
+				log_pass ();
+		}
+		states[test_thread_id].flags &= ~FLAGS_WAS_BUSY;
+
+		/* Have the test thread release mutex 1. */
+		send_cmd (test_thread_id, CMD_RELEASE_ALL);
+		sleep (1);
+
+		/*
+		 * Set the scheduling policy of the test thread to SCHED_FIFO
+		 * and have it go into a busy loop for 5 seconds.  This
+		 * thread is SCHED_RR, and since the priority ceiling of
+		 * mutex 1 is the same as the priority of this thread, the
+		 * test thread should run to completion once it is switched
+		 * in.
+		 */
+		log ("    SCHED_FIFO scheduling and ceiling priority = "
+		    "thread priority - ");
+		param.sched_priority = states[test_thread_id].priority;
+		assert (pthread_setschedparam (states[test_thread_id].tid,
+		    SCHED_FIFO, &param) == 0);
+
+		/* Have the test thread take mutex 1. */
+		send_mutex_cmd (test_thread_id, CMD_TAKE_MUTEX, &m[1]);
+		sleep (1);
+
+		log_trace ("Sending busy\n");
+		send_cmd (test_thread_id, CMD_BUSY_LOOP);
+		log_trace ("Busy sent, yielding\n");
+		pthread_yield ();
+		log_trace ("Returned from yield.\n");
+		if ((states[test_thread_id].flags & FLAGS_WAS_BUSY) == 0) {
+			log_error ("test thread did not run to completion.\n");
+			/* Let the thread finish it's busy loop. */
+			sleep (6);
+		}
+		else
+			log_pass ();
+		states[test_thread_id].flags &= ~FLAGS_WAS_BUSY;
+
+		/* Restore the test thread scheduling parameters. */
+		param.sched_priority = states[test_thread_id].priority;
+		assert (pthread_setschedparam (states[test_thread_id].tid,
+		    SCHED_RR, &param) == 0);
+
+		/* Have the test thread release mutex 1. */
+		send_cmd (test_thread_id, CMD_RELEASE_ALL);
+		sleep (1);
+
+		/*
+		 * Have the test thread go into a busy loop for 5 seconds
+		 * and see that it preempts this thread (since the priority
+		 * ceiling of mutex 2 is the greater than the priority of
+		 * this thread).  The test thread should run to completion
+		 * and block this thread because its active priority is
+		 * higher.
+		 */
+		log ("    SCHED_FIFO scheduling and ceiling priority > "
+		    "thread priority - ");
+		/* Have the test thread take mutex 2. */
+		send_mutex_cmd (test_thread_id, CMD_TAKE_MUTEX, &m[2]);
+		sleep (1);
+
+		log_trace ("Sending busy\n");
+		send_cmd (test_thread_id, CMD_BUSY_LOOP);
+		log_trace ("Busy sent, yielding\n");
+		pthread_yield ();
+		log_trace ("Returned from yield.\n");
+		if ((states[test_thread_id].flags & FLAGS_IS_BUSY) != 0) {
+			log_error ("test thread did not run to completion.\n");
+			/* Let the thread finish it's busy loop. */
+			sleep (6);
+		}
+		else if ((states[test_thread_id].flags & FLAGS_WAS_BUSY) == 0)
+			log_error ("test thread never finished.\n");
+		else
+			log_pass ();
+		states[test_thread_id].flags &= ~FLAGS_WAS_BUSY;
+
+		/* Have the test thread release mutex 2. */
+		send_cmd (test_thread_id, CMD_RELEASE_ALL);
+		sleep (1);
+
+		/* Destroy the mutexes. */
+		for (i = 0; i < 3; i++)
+			assert (pthread_mutex_destroy (&m[i]) == 0);
+	}
+}
+
+
+static void
+mutex_prioinherit_test (void)
+{
+	pthread_mutexattr_t mattr;
+	struct sched_param param;
+	pthread_mutex_t	m[3];
+	mutex_kind_t	mkind;
+	int		i, policy, my_prio;
+
+	/* Get this threads current priority. */
+	assert (pthread_getschedparam (pthread_self(), &policy,
+	    &param) == 0);
+	my_prio = param.sched_priority;	/* save for later use */
+	log_trace ("Current scheduling policy %d, priority %d\n",
+	    policy, my_prio);
+
+	log ("Testing priority inheritence\n");
+	log ("----------------------------\n");
+	for (mkind = M_POSIX; mkind <= M_SS2_RECURSIVE; mkind++) {
+
+		log ("  Protype PTHREAD_PRIO_INHERIT, Type %s\n",
+		    mutextype_strs[mkind]);
+
+		/*
+		 * Initialize and create a mutex.
+		 */
+		assert (pthread_mutexattr_init (&mattr) == 0);
+
+		/*
+		 * Initialize and create 3 priority inheritence mutexes with
+		 * default (max priority) ceilings.
+		 */
+		assert (pthread_mutexattr_setprotocol(&mattr,
+		    PTHREAD_PRIO_INHERIT) == 0);
+
+		/*
+		 * Ensure that the first mutex type is a POSIX
+		 * compliant mutex.
+		 */
+		if (mkind != M_POSIX) {
+			assert (pthread_mutexattr_settype (&mattr,
+			    mutex_types[mkind]) == 0);
+		}
+
+		for (i = 0; i < 3; i++)
+			assert (pthread_mutex_init (&m[i], &mattr) == 0);
+
+		/*
+		 * Test setup:
+		 *   Thread 4 - take mutex 0, 1
+		 *   Thread 2 - enter protected busy loop with mutex 0
+		 *   Thread 3 - enter protected busy loop with mutex 1
+		 *   Thread 4 - enter protected busy loop with mutex 2
+		 *   Thread 5 - enter busy loop
+		 *   Thread 6 - enter protected busy loop with mutex 0
+		 *   Thread 4 - releases mutexes 1 and 0.
+		 *
+		 * Expected results:
+		 *   Threads complete in order 4, 6, 5, 3, 2
+		 */
+		log ("    Simple inheritence test - ");
+
+		/*
+		 * Command thread 4 to take mutexes 0 and 1.
+		 */
+		send_mutex_cmd (4, CMD_TAKE_MUTEX, &m[0]);
+		sleep (1);	/* Allow command to be received. */
+		send_mutex_cmd (4, CMD_TAKE_MUTEX, &m[1]);
+		sleep (1);
+
+		/*
+		 * Tell the threads to report themselves when they are
+		 * at the bottom of their loop (waiting on wait_mutex).
+		 */
+		for (i = 0; i < NUM_THREADS; i++)
+			states[i].flags |= FLAGS_REPORT_WAITMUTEX;
+
+		/*
+		 * Command thread 2 to take mutex 0 and thread 3 to take
+		 * mutex 1, both via a protected operation command.  Since
+		 * thread 4 owns mutexes 0 and 1, both threads 2 and 3
+		 * will block until the mutexes are released by thread 4.
+		 */
+		log_trace ("Commanding protected operation to thread 2.\n");
+		send_mutex_cmd (2, CMD_PROTECTED_OP, &m[0]);
+		log_trace ("Commanding protected operation to thread 3.\n");
+		send_mutex_cmd (3, CMD_PROTECTED_OP, &m[1]);
+		sleep (1);
+
+		/*
+		 * Command thread 4 to take mutex 2 via a protected operation
+		 * and thread 5 to enter a busy loop for 5 seconds.  Since
+		 * thread 5 has higher priority than thread 4, thread 5 will
+		 * enter the busy loop before thread 4 is activated.
+		 */
+		log_trace ("Commanding protected operation to thread 4.\n");
+		send_mutex_cmd (4, CMD_PROTECTED_OP, &m[2]);
+		log_trace ("Commanding busy loop to thread 5.\n");
+		send_cmd (5, CMD_BUSY_LOOP);
+		sleep (1);
+		if ((states[5].flags & FLAGS_IS_BUSY) == 0)
+			log_error ("thread 5 is not running.\n");
+		log_trace ("Commanding protected operation thread 6.\n");
+		send_mutex_cmd (6, CMD_PROTECTED_OP, &m[0]);
+		sleep (1);
+		if ((states[4].flags & FLAGS_WAS_BUSY) == 0)
+			log_error ("thread 4 failed to inherit priority.\n");
+		states[4].flags = 0;
+		send_cmd (4, CMD_RELEASE_ALL);
+		sleep (5);
+		check_run_order ("4,6,5,3,2");
+
+		/*
+		 * Clear the flags.
+		 */
+		for (i = 0; i < NUM_THREADS; i++)
+			states[i].flags = 0;
+
+		/*
+		 * Test setup:
+		 *   Thread 2 - enter busy loop (SCHED_FIFO)
+		 *   Thread 4 - take mutex 0
+		 *   Thread 4 - priority change to same priority as thread 2
+		 *   Thread 4 - release mutex 0
+		 *
+		 * Expected results:
+		 *   Since thread 4 owns a priority mutex, it should be
+		 *   placed at the front of the run queue (for its new
+		 *   priority slot) when its priority is lowered to the
+		 *   same priority as thread 2.  If thread 4 did not own
+		 *   a priority mutex, then it would have been added to
+		 *   the end of the run queue and thread 2 would have
+		 *   executed until it blocked (because it's scheduling
+		 *   policy is SCHED_FIFO).
+		 *   
+		 */
+		log ("    Inheritence test with change of priority - ");
+
+		/*
+		 * Change threads 2 and 4 scheduling policies to be
+		 * SCHED_FIFO.
+		 */
+		param.sched_priority = states[2].priority;
+		assert (pthread_setschedparam (states[2].tid, SCHED_FIFO,
+		    &param) == 0);
+		param.sched_priority = states[4].priority;
+		assert (pthread_setschedparam (states[4].tid, SCHED_FIFO,
+		    &param) == 0);
+
+		/*
+		 * Command thread 4 to take mutex 0.
+		 */
+		send_mutex_cmd (4, CMD_TAKE_MUTEX, &m[0]);
+		sleep (1);
+
+		/*
+		 * Command thread 2 to enter busy loop.
+		 */
+		send_cmd (2, CMD_BUSY_LOOP);
+		sleep (1);	/* Allow command to be received. */
+
+		/*
+		 * Command thread 4 to enter busy loop.
+		 */
+		send_cmd (4, CMD_BUSY_LOOP);
+		sleep (1);	/* Allow command to be received. */
+
+		/* Have threads 2 and 4 report themselves. */
+		states[2].flags = FLAGS_REPORT_WAITMUTEX;
+		states[4].flags = FLAGS_REPORT_WAITMUTEX;
+
+		/* Change the priority of thread 4. */
+		param.sched_priority = states[2].priority;
+		assert (pthread_setschedparam (states[4].tid, SCHED_FIFO,
+		    &param) == 0);
+		sleep (5);
+		check_run_order ("4,2");
+
+		/* Clear the flags */
+		states[2].flags = 0;
+		states[4].flags = 0;
+
+		/* Reset the policies. */
+		param.sched_priority = states[2].priority;
+		assert (pthread_setschedparam (states[2].tid, SCHED_RR,
+		    &param) == 0);
+		param.sched_priority = states[4].priority;
+		assert (pthread_setschedparam (states[4].tid, SCHED_RR,
+		    &param) == 0);
+
+		send_cmd (4, CMD_RELEASE_MUTEX);
+		sleep (1);
+
+		/* Destroy the mutexes. */
+		for (i = 0; i < 3; i++)
+			assert (pthread_mutex_destroy (&m[i]) == 0);
+	}
+}
+
+
+int main (int argc, char *argv[])
+{
+	pthread_mutexattr_t mattr;
+	pthread_condattr_t cattr;
+	pthread_attr_t	pattr;
+	int		i, policy, main_prio;
+	void *		exit_status;
+	sigset_t	mask;
+	struct sigaction act;
+	struct sched_param param;
+
+	logfile = stdout;
+ 
+	assert (pthread_getschedparam (pthread_self (), &policy, &param) == 0);
+	main_prio = param.sched_priority;
+
+	/* Setupt our signal mask. */
+	sigfillset (&mask);
+	sigdelset (&mask, SIGINT);
+	sigprocmask (SIG_SETMASK, &mask, NULL);
+
+	/* Install a signal handler for SIGINT */
+	sigemptyset (&act.sa_mask);
+	sigaddset (&act.sa_mask, SIGINT);
+	act.sa_handler = sighandler;
+	act.sa_flags = SA_RESTART;
+	sigaction (SIGINT, &act, NULL);
+
+	/* This test relies on the concurrency level being 1. */
+	pthread_setconcurrency(1);
+
+	/*
+	 * Initialize the thread attribute.
+	 */
+	assert (pthread_attr_init (&pattr) == 0);
+	assert (pthread_attr_setdetachstate (&pattr,
+	    PTHREAD_CREATE_JOINABLE) == 0);
+
+	/*
+	 * Initialize and create the waiter and condvar mutexes.
+	 */
+	assert (pthread_mutexattr_init (&mattr) == 0);
+	assert (pthread_mutex_init (&waiter_mutex, &mattr) == 0);
+	assert (pthread_mutex_init (&cond_mutex, &mattr) == 0);
+
+	/*
+	 * Initialize and create a condition variable.
+	 */
+	assert (pthread_condattr_init (&cattr) == 0);
+	assert (pthread_cond_init (&cond_var, &cattr) == 0);
+
+	/* Create a pipe to catch the results of thread wakeups. */
+	assert (pipe (pipefd) == 0);
+
+#if defined(_LIBC_R_) && defined(DEBUG)
+	assert (pthread_switch_add_np (kern_switch) == 0);
+#endif
+
+	/*
+	 * Create the waiting threads.
+	 */
+	for (i = 0; i < NUM_THREADS; i++) {
+		assert (pthread_cond_init (&states[i].cond_var, &cattr) == 0);
+		states[i].id = (u_int8_t) i;  /* NUM_THREADS must be <= 256 */
+		states[i].status = 0;
+		states[i].cmd.cmd_id = CMD_NONE;
+		states[i].flags = 0;	/* No flags yet. */
+		assert (pthread_create (&states[i].tid, &pattr, waiter,
+		    (void *) &states[i]) == 0);
+		param.sched_priority = main_prio - 10 + i;
+		states[i].priority = param.sched_priority;
+		assert (pthread_setschedparam (states[i].tid, SCHED_OTHER,
+		    &param) == 0);
+#if defined(_LIBC_R_)
+		{
+			char buf[30];
+
+			snprintf (buf, sizeof(buf), "waiter_%d", i);
+			pthread_set_name_np (states[i].tid, buf);
+		}
+#endif
+	}
+
+	/* Allow the threads to start. */
+	sleep (1);
+	log_trace ("Done creating threads.\n");
+
+	log ("\n");
+	mutex_init_test ();
+	log ("\n");
+	mutex_destroy_test ();
+	log ("\n");
+	mutex_lock_test ();
+	log ("\n");
+	mutex_unlock_test ();
+	log ("\n");
+	queueing_order_test ();
+	log ("\n");
+	mutex_prioinherit_test ();
+	log ("\n");
+	mutex_prioceiling_test ();
+	log ("\n");
+
+	log ("Total tests %d, passed %d, failed %d\n",
+	    total, pass_count, error_count);
+
+	/* Set the done flag and signal the threads to exit. */
+	log_trace ("Setting done flag.\n");
+	done = 1;
+
+	/*
+	 * Wait for the threads to finish.
+	 */
+	log_trace ("Trying to join threads.\n");
+	for (i = 0; i < NUM_THREADS; i++) {
+		send_cmd (i, CMD_NONE);
+		assert (pthread_join (states[i].tid, &exit_status) == 0);
+	}
+
+	/* Clean up after ourselves. */
+	close (pipefd[0]);
+	close (pipefd[1]);
+
+	if (error_count != 0)
+		exit (EX_OSERR);	/* any better ideas??? */
+	else
+		exit (EX_OK);
+}
--- /dev/null
+++ lib/libkse/test/hello_b.c
@@ -0,0 +1,13 @@
+/****************************************************************************
+ *
+ * Back end C programs can be anything compilable.
+ *
+ * $FreeBSD: src/lib/libkse/test/hello_b.c,v 1.2 2007/10/09 13:42:26 obrien Exp $
+ *
+ ****************************************************************************/
+
+int
+main()
+{
+	return 0;
+}
--- /dev/null
+++ lib/libkse/test/guard_b.exp
@@ -0,0 +1,4 @@
+# $FreeBSD: src/lib/libkse/test/guard_b.exp,v 1.2 2007/10/09 13:42:26 obrien Exp $
+Test begin
+No overflow:
+Overflow:
--- /dev/null
+++ lib/libkse/test/README
@@ -0,0 +1,28 @@
+$FreeBSD: src/lib/libkse/test/README,v 1.3 2007/10/09 13:42:26 obrien Exp $
+
+This test suite is meant to test general functionality of pthreads, as well as
+provide a simple framework for regression tests.  In general, this test suite
+can be used with any pthreads library, but in reality there are a number of
+libpthread-specific aspects to this test suite which would require some
+effort to get around if testing another pthreads library.
+
+This test suite assumes that libpthread is installed.
+
+There are two forms of test that the 'verify' script understands.  The simpler
+form is the diff format, where the output of the test program is diff'ed with
+the correspondingly named .exp file.  If there is diff output, the test fails.
+The sequence test format is somewhat more complex, and is documented in the
+command line usage output for verify.  The advantage of this format is that it
+allows multiple tests to pass/fail within one program.
+
+There is no driving need for test naming consistency, but the existing tests
+generally follow these conventions:
+
+<name>_d.c <name>_d.exp     : Diff mode C test and expected output file.
+<name>_s.c                  : Sequence mode C test.
+<name>_b*.c                 : Back end C program used by perl tests.
+<name>_d.pl <name>_d.pl.exp : Diff mode perl test and expected output file.
+<name>_s.pl                 : Sequence mode perl test.
+
+<name> is something descriptive, such as "pr14685" in the case of a PR-related
+regression test, or "mutex" in the case of a test of mutexes.
Index: libthr.3
===================================================================
RCS file: /home/cvs/src/lib/libthr/libthr.3,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L lib/libthr/libthr.3 -L lib/libthr/libthr.3 -u -r1.1.1.1 -r1.2
--- lib/libthr/libthr.3
+++ lib/libthr/libthr.3
@@ -22,14 +22,14 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.\" $FreeBSD: src/lib/libthr/libthr.3,v 1.3 2005/06/16 19:01:07 ru Exp $
+.\" $FreeBSD: src/lib/libthr/libthr.3,v 1.3.10.1 2007/10/23 12:53:02 ru Exp $
 .\"
-.Dd June 11, 2005
+.Dd October 19, 2007
 .Os
 .Dt LIBTHR 3
 .Sh NAME
 .Nm libthr
-.Nd "alternative POSIX threads library"
+.Nd "1:1 POSIX threads library"
 .Sh LIBRARY
 .Lb libthr
 .Sh SYNOPSIS
@@ -37,22 +37,14 @@
 .Sh DESCRIPTION
 The
 .Nm
-library provides an alternative 1:1 implementation of the
+library provides a 1:1 implementation of the
 .Xr pthread 3
 library interfaces for application threading.
-While applications may be linked directly against
-.Nm ,
-system administrators are offered maximum flexibility by linking against
-.Xr pthread 3 ,
-as they can then use
-.Xr libmap.conf 5
-to select the threading implementation on a per-application basis.
-.Pp
-The
-.Nm
-library
+It
 has been optimized for use by applications expecting system scope thread
-semantics, and can provide significant performance improvements.
+semantics, and can provide significant performance improvements
+compared to
+.Lb libkse .
 .Sh SEE ALSO
 .Xr pthread 3
 .Sh AUTHORS
Index: pthread.map
===================================================================
RCS file: /home/cvs/src/lib/libthr/pthread.map,v
retrieving revision 1.1.1.2
retrieving revision 1.2
diff -L lib/libthr/pthread.map -L lib/libthr/pthread.map -u -r1.1.1.2 -r1.2
--- lib/libthr/pthread.map
+++ lib/libthr/pthread.map
@@ -1,187 +1,13 @@
-# $FreeBSD: src/lib/libthr/pthread.map,v 1.3.2.3 2005/12/26 12:30:53 davidxu Exp $
-LIBTHREAD_1_0 {
+/*
+ * $FreeBSD: src/lib/libthr/pthread.map,v 1.18 2007/05/13 14:12:39 deischen Exp $
+ */
+
+/*
+ * Use the same naming scheme as libc.
+ */
+FBSD_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_getpshared;
-	_pthread_mutexattr_gettype;
-	_pthread_mutexattr_init;
-	_pthread_mutexattr_setkind_np;
-	_pthread_mutexattr_setprioceiling;
-	_pthread_mutexattr_setprotocol;
-	_pthread_mutexattr_setpshared;
-	_pthread_mutexattr_settype;
-	_pthread_once;
-	_pthread_resume_all_np;
-	_pthread_resume_np;
-	_pthread_rwlock_destroy;
-	_pthread_rwlock_init;
-	_pthread_rwlock_rdlock;
-	_pthread_rwlock_timedrdlock;
-	_pthread_rwlock_timedwrlock;
-	_pthread_rwlock_tryrdlock;
-	_pthread_rwlock_trywrlock;
-	_pthread_rwlock_unlock;
-	_pthread_rwlock_wrlock;
-	_pthread_rwlockattr_destroy;
-	_pthread_rwlockattr_getpshared;
-	_pthread_rwlockattr_init;
-	_pthread_rwlockattr_setpshared;
-	_pthread_self;
-	_pthread_set_name_np;
-	_pthread_setcancelstate;
-	_pthread_setcanceltype;
-	_pthread_setconcurrency;
-	_pthread_setprio;
-	_pthread_setschedparam;
-	_pthread_setspecific;
-	_pthread_sigmask;
-	_pthread_single_np;
-	_pthread_spin_destroy;
-	_pthread_spin_init;
-	_pthread_spin_lock;
-	_pthread_spin_trylock;
-	_pthread_spin_unlock;
-	_pthread_suspend_all_np;
-	_pthread_suspend_np;
-	_pthread_switch_add_np;
-	_pthread_switch_delete_np;
-	_pthread_testcancel;
-	_pthread_timedjoin_np;
-	_pthread_yield;
-	_raise;
-	_sem_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;
-	_usleep;
-	_vfork;
-	_wait;
-	_waitpid;
 	accept;
 	aio_suspend;
 	close;
@@ -320,21 +146,16 @@
 	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;
@@ -343,17 +164,202 @@
 	sleep;
 	system;
 	tcdrain;
-	timer_create;
-	timer_delete;
 	usleep;
 	vfork;
 	wait;
+	wait3;
 	wait4;
 	waitpid;
 	write;
 	writev;
+local:
+	*;
+};
+
+/*
+ * List the private interfaces reserved for use in FreeBSD libraries.
+ * These are not part of our application ABI.
+ */
+FBSDprivate_1.0 {
+global:
+	___creat;
+	___pause;
+	___pselect;
+	___sleep;
+	___system;
+	___tcdrain;
+	___usleep;
+	___wait;
+	___waitpid;
+	__accept;
+	__aio_suspend;
+	__close;
+	__connect;
+	__fcntl;
+	__fsync;
+	__msync;
+	__nanosleep;
+	__open;
+	__poll;
+	__pthread_cond_timedwait;
+	__pthread_cond_wait;
+	__pthread_mutex_init;
+	__pthread_mutex_lock;
+	__pthread_mutex_timedlock;
+	__pthread_mutex_trylock;
+	__read;
+	__readv;
+	__recvfrom;
+	__recvmsg;
+	__select;
+	__sendmsg;
+	__sendto;
+	__sigsuspend;
+	__sigtimedwait;
+	__sigwait;
+	__sigwaitinfo;
+	__wait3;
+	__wait4;
+	__write;
+	__writev;
+	_fork;
+	_pthread_atfork;
+	_pthread_barrier_destroy;
+	_pthread_barrier_init;
+	_pthread_barrier_wait;
+	_pthread_barrierattr_destroy;
+	_pthread_barrierattr_getpshared;
+	_pthread_barrierattr_init;
+	_pthread_barrierattr_setpshared;
+	_pthread_attr_destroy;
+	_pthread_attr_get_np;
+	_pthread_attr_getdetachstate;
+	_pthread_attr_getguardsize;
+	_pthread_attr_getinheritsched;
+	_pthread_attr_getschedparam;
+	_pthread_attr_getschedpolicy;
+	_pthread_attr_getscope;
+	_pthread_attr_getstack;
+	_pthread_attr_getstackaddr;
+	_pthread_attr_getstacksize;
+	_pthread_attr_init;
+	_pthread_attr_setcreatesuspend_np;
+	_pthread_attr_setdetachstate;
+	_pthread_attr_setguardsize;
+	_pthread_attr_setinheritsched;
+	_pthread_attr_setschedparam;
+	_pthread_attr_setschedpolicy;
+	_pthread_attr_setscope;
+	_pthread_attr_setstack;
+	_pthread_attr_setstackaddr;
+	_pthread_attr_setstacksize;
+	_pthread_cancel;
+	_pthread_cleanup_pop;
+	_pthread_cleanup_push;
+	_pthread_cond_broadcast;
+	_pthread_cond_destroy;
+	_pthread_cond_init;
+	_pthread_cond_signal;
+	_pthread_cond_timedwait;
+	_pthread_cond_wait;
+	_pthread_condattr_destroy;
+	_pthread_condattr_getclock;
+	_pthread_condattr_getpshared;
+	_pthread_condattr_init;
+	_pthread_condattr_setclock;
+	_pthread_condattr_setpshared;
+	_pthread_create;
+	_pthread_detach;
+	_pthread_equal;
+	_pthread_exit;
+	_pthread_getconcurrency;
+	_pthread_getprio;
+	_pthread_getschedparam;
+	_pthread_getspecific;
+	_pthread_join;
+	_pthread_key_create;
+	_pthread_key_delete;
+	_pthread_kill;
+	_pthread_main_np;
+	_pthread_multi_np;
+	_pthread_mutex_destroy;
+	_pthread_mutex_getprioceiling;
+	_pthread_mutex_init;
+	_pthread_mutex_lock;
+	_pthread_mutex_setprioceiling;
+	_pthread_mutex_timedlock;
+	_pthread_mutex_trylock;
+	_pthread_mutex_unlock;
+	_pthread_mutexattr_destroy;
+	_pthread_mutexattr_getkind_np;
+	_pthread_mutexattr_getprioceiling;
+	_pthread_mutexattr_getprotocol;
+	_pthread_mutexattr_getpshared;
+	_pthread_mutexattr_gettype;
+	_pthread_mutexattr_init;
+	_pthread_mutexattr_setkind_np;
+	_pthread_mutexattr_setprioceiling;
+	_pthread_mutexattr_setprotocol;
+	_pthread_mutexattr_setpshared;
+	_pthread_mutexattr_settype;
+	_pthread_once;
+	_pthread_resume_all_np;
+	_pthread_resume_np;
+	_pthread_rwlock_destroy;
+	_pthread_rwlock_init;
+	_pthread_rwlock_rdlock;
+	_pthread_rwlock_timedrdlock;
+	_pthread_rwlock_timedwrlock;
+	_pthread_rwlock_tryrdlock;
+	_pthread_rwlock_trywrlock;
+	_pthread_rwlock_unlock;
+	_pthread_rwlock_wrlock;
+	_pthread_rwlockattr_destroy;
+	_pthread_rwlockattr_getpshared;
+	_pthread_rwlockattr_init;
+	_pthread_rwlockattr_setpshared;
+	_pthread_self;
+	_pthread_set_name_np;
+	_pthread_setcancelstate;
+	_pthread_setcanceltype;
+	_pthread_setconcurrency;
+	_pthread_setprio;
+	_pthread_setschedparam;
+	_pthread_setspecific;
+	_pthread_sigmask;
+	_pthread_single_np;
+	_pthread_spin_destroy;
+	_pthread_spin_init;
+	_pthread_spin_lock;
+	_pthread_spin_trylock;
+	_pthread_spin_unlock;
+	_pthread_suspend_all_np;
+	_pthread_suspend_np;
+	_pthread_switch_add_np;
+	_pthread_switch_delete_np;
+	_pthread_testcancel;
+	_pthread_timedjoin_np;
+	_pthread_yield;
+	_raise;
+	_sem_destroy;
+	_sem_getvalue;
+	_sem_init;
+	_sem_post;
+	_sem_timedwait;
+	_sem_trywait;
+	_sem_wait;
+	_sigaction;
+	_sigprocmask;
+	_sigsuspend;
+	_sigtimedwait;
+	_sigwait;
+	_sigwaitinfo;
+	_spinlock;
+	_spinlock_debug;
+	_spinunlock;
+	_vfork;
 
-	# Debugger needs these.
+	/* Debugger needs these. */
 	_libthr_debug;
 	_thread_active_threads;
 	_thread_bp_create;
Index: Makefile
===================================================================
RCS file: /home/cvs/src/lib/libthr/Makefile,v
retrieving revision 1.3
retrieving revision 1.4
diff -L lib/libthr/Makefile -L lib/libthr/Makefile -u -r1.3 -r1.4
--- lib/libthr/Makefile
+++ lib/libthr/Makefile
@@ -1,5 +1,4 @@
-# $FreeBSD: src/lib/libthr/Makefile,v 1.13.2.2 2006/01/16 05:36:29 davidxu Exp $
-# $MidnightBSD$
+# $FreeBSD: src/lib/libthr/Makefile,v 1.28 2007/10/09 23:31:10 obrien 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
@@ -9,12 +8,16 @@
 # (for system call stubs) to CFLAGS below.  -DSYSLIBC_SCCS affects just the
 # system call stubs.
 
-.if ${MACHINE_ARCH} == "sparc64"
-SHLIBDIR?=/lib
+.include <bsd.own.mk>
+
+.if (${DEFAULT_THREAD_LIB} == "libthr" || ${MK_LIBKSE} == "no") && \
+    ${SHLIBDIR} == "/usr/lib"
+SHLIBDIR= /lib
 .endif
 
 LIB=thr
-SHLIB_MAJOR= 2
+SHLIB_MAJOR= 3
+WARNS?= 2
 CFLAGS+=-DPTHREAD_KERNEL
 CFLAGS+=-I${.CURDIR}/../libc/include -I${.CURDIR}/thread \
 	-I${.CURDIR}/../../include
@@ -27,12 +30,12 @@
 
 # CFLAGS+=-DSYSTEM_SCOPE_ONLY
 
-LDFLAGS= -Wl,--version-script=${.CURDIR}/pthread.map
+VERSION_MAP=${.CURDIR}/pthread.map
 
 MAN=	libthr.3
 
 # enable extra internal consistancy checks
-CFLAGS+=-D_PTHREADS_INVARIANTS -Wall
+CFLAGS+=-D_PTHREADS_INVARIANTS
 #CFLAGS+=-g
 
 PRECIOUSLIB=
@@ -41,12 +44,12 @@
 .include "${.CURDIR}/sys/Makefile.inc"
 .include "${.CURDIR}/thread/Makefile.inc"
 
-.if ${MACHINE_ARCH} == "sparc64"
+.if ${DEFAULT_THREAD_LIB} == "libthr" || ${MK_LIBKSE} == "no"
 SYMLINKS+=lib${LIB}.a ${LIBDIR}/libpthread.a
 .if !defined(NO_PIC)
 SYMLINKS+=lib${LIB}.so ${LIBDIR}/libpthread.so
 .endif
-.if NO_PROFILE
+.if ${MK_PROFILE} != "no"
 SYMLINKS+=lib${LIB}_p.a ${LIBDIR}/libpthread_p.a
 .endif
 .endif
--- /dev/null
+++ lib/ncurses/form/Makefile
@@ -0,0 +1,166 @@
+# $FreeBSD: src/lib/ncurses/form/Makefile,v 1.14 2007/05/25 02:27:46 rafan Exp $
+
+.include "${.CURDIR}/../config.mk"
+
+SRCDIR=	${NCURSES_DIR}/form
+
+LIB=	form${LIB_SUFFIX}
+
+.PATH: ${SRCDIR}
+SRCS=	\
+	ncurses_def.h \
+	fld_arg.c \
+	fld_attr.c \
+	fld_current.c \
+	fld_def.c \
+	fld_dup.c \
+	fld_ftchoice.c \
+	fld_ftlink.c \
+	fld_info.c \
+	fld_just.c \
+	fld_link.c \
+	fld_max.c \
+	fld_move.c \
+	fld_newftyp.c \
+	fld_opts.c \
+	fld_pad.c \
+	fld_page.c \
+	fld_stat.c \
+	fld_type.c \
+	fld_user.c \
+	frm_cursor.c \
+	frm_data.c \
+	frm_def.c \
+	frm_driver.c \
+	frm_hook.c \
+	frm_opts.c \
+	frm_page.c \
+	frm_post.c \
+	frm_req_name.c \
+	frm_scale.c \
+	frm_sub.c \
+	frm_user.c \
+	frm_win.c \
+	fty_alnum.c \
+	fty_alpha.c \
+	fty_enum.c \
+	fty_int.c \
+	fty_ipv4.c \
+	fty_num.c \
+	fty_regex.c
+
+CLEANFILES=	ncurses_def.h
+
+CFLAGS+=	-I${SRCDIR}
+CFLAGS+=	-I${NCURSES_DIR}/menu
+
+DPADD=	${LIBNCURSES${LIB_SUFFIX:U}}
+LDADD=	-lncurses${LIB_SUFFIX}
+
+.if defined(ENABLE_WIDEC)
+INCS=	form.h
+.endif
+
+.PATH: ${NCURSES_DIR}/man
+MAN=	\
+	form.3 \
+	form_cursor.3 \
+	form_data.3 \
+	form_driver.3 \
+	form_field.3 \
+	form_field_attributes.3 \
+	form_field_buffer.3 \
+	form_field_info.3 \
+	form_field_just.3 \
+	form_field_new.3 \
+	form_field_opts.3 \
+	form_field_userptr.3 \
+	form_field_validation.3 \
+	form_fieldtype.3 \
+	form_hook.3 \
+	form_new.3 \
+	form_new_page.3 \
+	form_opts.3 \
+	form_page.3 \
+	form_post.3 \
+	form_requestname.3 \
+	form_userptr.3 \
+	form_win.3
+
+CLEANFILES+=	${MAN:M*.3}
+
+MLINKS=	form_cursor.3 pos_form_cursor.3 \
+	form_data.3 data_ahead.3 \
+	form_data.3 data_behind.3 \
+	form_field.3 field_count.3 \
+	form_field.3 form_fields.3 \
+	form_field.3 move_field.3 \
+	form_field.3 set_form_fields.3 \
+	form_field_attributes.3 field_back.3 \
+	form_field_attributes.3 field_fore.3 \
+	form_field_attributes.3 field_pad.3 \
+	form_field_attributes.3 set_field_back.3 \
+	form_field_attributes.3 set_field_fore.3 \
+	form_field_attributes.3 set_field_pad.3 \
+	form_field_buffer.3 field_buffer.3 \
+	form_field_buffer.3 field_status.3 \
+	form_field_buffer.3 set_field_buffer.3 \
+	form_field_buffer.3 set_field_status.3 \
+	form_field_buffer.3 set_max_field.3 \
+	form_field_info.3 dynamic_fieldinfo.3 \
+	form_field_info.3 field_info.3 \
+	form_field_just.3 field_just.3 \
+	form_field_just.3 set_field_just.3 \
+	form_field_new.3 dup_field.3 \
+	form_field_new.3 free_field.3 \
+	form_field_new.3 link_field.3 \
+	form_field_new.3 new_field.3 \
+	form_field_opts.3 field_opts.3 \
+	form_field_opts.3 field_opts_off.3 \
+	form_field_opts.3 field_opts_on.3 \
+	form_field_opts.3 set_field_opts.3 \
+	form_field_userptr.3 field_userptr.3 \
+	form_field_userptr.3 set_field_userptr.3 \
+	form_field_validation.3 field_arg.3 \
+	form_field_validation.3 field_type.3 \
+	form_field_validation.3 set_field_type.3 \
+	form_fieldtype.3 free_fieldtype.3 \
+	form_fieldtype.3 link_fieldtype.3 \
+	form_fieldtype.3 new_fieldtype.3 \
+	form_fieldtype.3 set_fieldtype_arg.3 \
+	form_fieldtype.3 set_fieldtype_choice.3 \
+	form_hook.3 field_init.3 \
+	form_hook.3 field_term.3 \
+	form_hook.3 form_init.3 \
+	form_hook.3 form_term.3 \
+	form_hook.3 set_field_init.3 \
+	form_hook.3 set_field_term.3 \
+	form_hook.3 set_form_init.3 \
+	form_hook.3 set_form_term.3 \
+	form_new.3 free_form.3 \
+	form_new.3 new_form.3 \
+	form_new_page.3 new_page.3 \
+	form_new_page.3 set_new_page.3 \
+	form_opts.3 form_opts_off.3 \
+	form_opts.3 form_opts_on.3 \
+	form_opts.3 set_form_opts.3 \
+	form_page.3 current_field.3 \
+	form_page.3 field_index.3 \
+	form_page.3 set_current_field.3 \
+	form_page.3 set_form_page.3 \
+	form_post.3 post_form.3 \
+	form_post.3 unpost_form.3 \
+	form_requestname.3 form_request_by_name.3 \
+	form_requestname.3 form_request_name.3 \
+	form_userptr.3 set_form_userptr.3 \
+	form_win.3 form_sub.3 \
+	form_win.3 scale_form.3 \
+	form_win.3 set_form_sub.3 \
+	form_win.3 set_form_win.3
+
+.include <bsd.lib.mk>
+
+# Keep the .SUFFIXES line after the include of bsd.lib.mk
+.SUFFIXES: .3 .3x
+.3x.3:
+	cat ${.IMPSRC} > ${.TARGET}
--- /dev/null
+++ lib/ncurses/formw/Makefile
@@ -0,0 +1,5 @@
+# $FreeBSD: src/lib/ncurses/formw/Makefile,v 1.1 2007/03/09 12:11:57 rafan Exp $
+
+ENABLE_WIDEC=
+
+.include "${.CURDIR}/../form/Makefile"
--- /dev/null
+++ lib/ncurses/menu/Makefile
@@ -0,0 +1,139 @@
+# $FreeBSD: src/lib/ncurses/menu/Makefile,v 1.16 2007/05/25 02:27:46 rafan Exp $
+
+.include "${.CURDIR}/../config.mk"
+
+SRCDIR=	${NCURSES_DIR}/menu
+
+LIB=	menu${LIB_SUFFIX}
+
+.PATH: ${SRCDIR}
+SRCS=	\
+	ncurses_def.h \
+	m_attribs.c \
+	m_cursor.c \
+	m_driver.c \
+	m_format.c \
+	m_global.c \
+	m_hook.c \
+	m_item_cur.c \
+	m_item_nam.c \
+	m_item_new.c \
+	m_item_opt.c \
+	m_item_top.c \
+	m_item_use.c \
+	m_item_val.c \
+	m_item_vis.c \
+	m_items.c \
+	m_new.c \
+	m_opts.c \
+	m_pad.c \
+	m_pattern.c \
+	m_post.c \
+	m_req_name.c \
+	m_scale.c \
+	m_spacing.c \
+	m_sub.c \
+	m_userptr.c \
+	m_win.c
+
+CLEANFILES=	ncurses_def.h
+
+CFLAGS+=	-I${SRCDIR}
+
+DPADD=	${LIBNCURSES${LIB_SUFFIX:U}}
+LDADD=	-lncurses${LIB_SUFFIX}
+
+.if defined(ENABLE_WIDEC)
+INCS=	menu.h eti.h
+.endif
+
+.PATH: ${NCURSES_DIR}/man
+MAN=	\
+	menu.3 \
+	menu_attributes.3 \
+	menu_cursor.3 \
+	menu_driver.3 \
+	menu_format.3 \
+	menu_hook.3 \
+	menu_items.3 \
+	menu_mark.3 \
+	menu_new.3 \
+	menu_opts.3 \
+	menu_pattern.3 \
+	menu_post.3 \
+	menu_requestname.3 \
+	menu_spacing.3 \
+	menu_userptr.3 \
+	menu_win.3 \
+	mitem_current.3 \
+	mitem_name.3 \
+	mitem_new.3 \
+	mitem_opts.3 \
+	mitem_userptr.3 \
+	mitem_value.3 \
+	mitem_visible.3
+
+CLEANFILES+=	${MAN:M*.3}
+
+MLINKS=	menu_attributes.3 menu_back.3 \
+	menu_attributes.3 menu_fore.3 \
+	menu_attributes.3 menu_grey.3 \
+	menu_attributes.3 menu_pad.3 \
+	menu_attributes.3 set_menu_back.3 \
+	menu_attributes.3 set_menu_fore.3 \
+	menu_attributes.3 set_menu_grey.3 \
+	menu_attributes.3 set_menu_pad.3 \
+	menu_cursor.3 pos_menu_cursor.3 \
+	menu_format.3 set_menu_format.3 \
+	menu_hook.3 item_init.3 \
+	menu_hook.3 item_term.3 \
+	menu_hook.3 menu_init.3 \
+	menu_hook.3 menu_term.3 \
+	menu_hook.3 set_item_init.3 \
+	menu_hook.3 set_item_term.3 \
+	menu_hook.3 set_menu_init.3 \
+	menu_hook.3 set_menu_term.3 \
+	menu_items.3 item_count.3 \
+	menu_items.3 set_menu_items.3 \
+	menu_mark.3 set_menu_mark.3 \
+	menu_new.3 free_menu.3 \
+	menu_new.3 new_menu.3 \
+	menu_opts.3 menu_opts_off.3 \
+	menu_opts.3 menu_opts_on.3 \
+	menu_opts.3 set_menu_opts.3 \
+	menu_pattern.3 set_menu_pattern.3 \
+	menu_post.3 post_menu.3 \
+	menu_post.3 unpost_menu.3 \
+	menu_requestname.3 menu_request_by_name.3 \
+	menu_requestname.3 menu_request_name.3 \
+	menu_spacing.3 set_menu_spacing.3 \
+	menu_userptr.3 set_menu_userptr.3 \
+	menu_win.3 menu_sub.3 \
+	menu_win.3 scale_menu.3 \
+	menu_win.3 set_menu_sub.3 \
+	menu_win.3 set_menu_win.3 \
+	mitem_current.3 current_item.3 \
+	mitem_current.3 item_index.3 \
+	mitem_current.3 set_current_item.3 \
+	mitem_current.3 set_top_row.3 \
+	mitem_current.3 top_row.3 \
+	mitem_name.3 item_description.3 \
+	mitem_name.3 item_name.3 \
+	mitem_new.3 free_item.3 \
+	mitem_new.3 new_item.3 \
+	mitem_opts.3 item_opts.3 \
+	mitem_opts.3 item_opts_off.3 \
+	mitem_opts.3 item_opts_on.3 \
+	mitem_opts.3 set_item_opts.3 \
+	mitem_userptr.3 item_userptr.3 \
+	mitem_userptr.3 set_item_userptr.3 \
+	mitem_value.3 item_value.3 \
+	mitem_value.3 set_item_value.3 \
+	mitem_visible.3 item_visible.3
+
+.include <bsd.lib.mk>
+
+# Keep the .SUFFIXES line after the include of bsd.lib.mk
+.SUFFIXES: .3 .3x
+.3x.3:
+	cat ${.IMPSRC} > ${.TARGET}
--- /dev/null
+++ lib/ncurses/menuw/Makefile
@@ -0,0 +1,5 @@
+# $FreeBSD: src/lib/ncurses/menuw/Makefile,v 1.1 2007/03/09 12:11:57 rafan Exp $
+
+ENABLE_WIDEC=
+
+.include "${.CURDIR}/../menu/Makefile"
--- /dev/null
+++ lib/ncurses/ncurses/termcap.c
@@ -0,0 +1,262 @@
+/* A portion of this file is from ncurses: */
+/***************************************************************************
+*                            COPYRIGHT NOTICE                              *
+****************************************************************************
+*                ncurses is copyright (C) 1992-1995                        *
+*                          Zeyd M. Ben-Halim                               *
+*                          zmbenhal at netcom.com                             *
+*                          Eric S. Raymond                                 *
+*                          esr at snark.thyrsus.com                           *
+*                                                                          *
+*        Permission is hereby granted to reproduce and distribute ncurses  *
+*        by any means and for any fee, whether alone or as part of a       *
+*        larger distribution, in source or in binary form, PROVIDED        *
+*        this notice is included with any such distribution, and is not    *
+*        removed from any of its header files. Mention of ncurses in any   *
+*        applications linked with it is highly appreciated.                *
+*                                                                          *
+*        ncurses comes AS IS with no warranty, implied or expressed.       *
+*                                                                          *
+***************************************************************************/
+
+#include <curses.priv.h>
+
+#include <string.h>
+#include <term.h>
+#include <tic.h>
+#include <term_entry.h>
+
+/* The rest is from BSD */
+/*
+ * Copyright (c) 1980, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University 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 REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/lib/ncurses/ncurses/termcap.c,v 1.9 2007/01/20 07:46:44 rafan Exp $");
+
+#ifndef lint
+static const char sccsid[] = "@(#)termcap.c	8.1 (Berkeley) 6/4/93";
+#endif /* not lint */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/param.h>
+#include "pathnames.h"
+
+#define	PBUFSIZ	MAXPATHLEN	/* max length of filename path */
+#define	PVECSIZ	32		/* max number of names in path */
+#define	TBUFSIZ 1024		/* max length of _nc_tgetent buffer */
+
+char _nc_termcap[TBUFSIZ + 1]; /* Last getcap, provided to tgetent() emul */
+
+/*
+ * termcap - routines for dealing with the terminal capability data base
+ *
+ * BUG:		Should use a "last" pointer in tbuf, so that searching
+ *		for capabilities alphabetically would not be a n**2/2
+ *		process when large numbers of capabilities are given.
+ * Note:	If we add a last pointer now we will screw up the
+ *		tc capability. We really should compile termcap.
+ *
+ * Essentially all the work here is scanning and decoding escapes
+ * in string capabilities.  We don't use stdio because the editor
+ * doesn't, and because living w/o it is not hard.
+ */
+
+/*
+ * Get an entry for terminal name in buffer _nc_termcap from the termcap
+ * file.
+ */
+int
+_nc_read_termcap_entry(const char *const name, TERMTYPE *const tp)
+{
+	ENTRY	*ep;
+	char *p;
+	char *cp;
+	char  *dummy;
+	char **fname;
+	char  *home;
+	int    i;
+	char   pathbuf[PBUFSIZ];	/* holds raw path of filenames */
+	char  *pathvec[PVECSIZ];	/* to point to names in pathbuf */
+	char **pvec;			/* holds usable tail of path vector */
+	char  *termpath;
+
+	_nc_termcap[0] = '\0';		/* in case */
+	dummy = NULL;
+	fname = pathvec;
+	pvec = pathvec;
+	p = pathbuf;
+	cp = getenv("TERMCAP");
+	/*
+	 * TERMCAP can have one of two things in it. It can be the
+	 * name of a file to use instead of /etc/termcap. In this
+	 * case it better start with a "/". Or it can be an entry to
+	 * use so we don't have to read the file. In this case it
+	 * has to already have the newlines crunched out.  If TERMCAP
+	 * does not hold a file name then a path of names is searched
+	 * instead.  The path is found in the TERMPATH variable, or
+	 * becomes "$HOME/.termcap /etc/termcap" if no TERMPATH exists.
+	 */
+	if (!cp || *cp != '/') {	/* no TERMCAP or it holds an entry */
+		if ( (termpath = getenv("TERMPATH")) )
+			strncpy(pathbuf, termpath, PBUFSIZ);
+		else {
+			if ( (home = getenv("HOME")) ) {/* set up default */
+				strncpy(pathbuf, home, PBUFSIZ - 1); /* $HOME first */
+				pathbuf[PBUFSIZ - 2] = '\0'; /* -2 because we add a slash */
+				p += strlen(pathbuf);	/* path, looking in */
+				*p++ = '/';
+			}	/* if no $HOME look in current directory */
+			strncpy(p, _PATH_DEF, PBUFSIZ - (p - pathbuf));
+		}
+	}
+	else				/* user-defined name in TERMCAP */
+		strncpy(pathbuf, cp, PBUFSIZ);	/* still can be tokenized */
+
+	/* For safety */
+	if (issetugid())
+		strcpy(pathbuf, _PATH_DEF_SEC);
+
+	pathbuf[PBUFSIZ - 1] = '\0';
+
+	*fname++ = pathbuf;	/* tokenize path into vector of names */
+	while (*++p)
+		if (*p == ' ' || *p == ':') {
+			*p = '\0';
+			while (*++p)
+				if (*p != ' ' && *p != ':')
+					break;
+			if (*p == '\0')
+				break;
+			*fname++ = p;
+			if (fname >= pathvec + PVECSIZ) {
+				fname--;
+				break;
+			}
+		}
+	*fname = (char *) 0;			/* mark end of vector */
+	if (cp && *cp && *cp != '/')
+		if (cgetset(cp) < 0)
+			return(-2);
+
+	i = cgetent(&dummy, pathvec, (char *)name);
+
+	if (i == 0) {
+		char *pd, *ps, *tok, *s, *tcs;
+		size_t len;
+
+		pd = _nc_termcap;
+		ps = dummy;
+		if ((tok = strchr(ps, ':')) == NULL) {
+			len = strlen(ps);
+			if (len >= TBUFSIZ)
+				i = -1;
+			else
+				strcpy(pd, ps);
+			goto done;
+		}
+		len = tok - ps + 1;
+		if (pd + len + 1 - _nc_termcap >= TBUFSIZ) {
+			i = -1;
+			goto done;
+		}
+		memcpy(pd, ps, len);
+		ps += len;
+		pd += len;
+		*pd = '\0';
+		tcs = pd - 1;
+		for (;;) {
+			while ((tok = strsep(&ps, ":")) != NULL &&
+			       *(tok - 2) != '\\' &&
+			       (*tok == '\0' || *tok == '\\' || !isgraph(UChar(*tok))))
+				;
+			if (tok == NULL)
+				break;
+			for (s = tcs; s != NULL && s[1] != '\0';
+			     s = strchr(s, ':')) {
+				s++;
+				if (s[0] == tok[0] && s[1] == tok[1])
+					goto skip_it;
+			}
+			len = strlen(tok);
+			if (pd + len + 1 - _nc_termcap >= TBUFSIZ) {
+				i = -1;
+				break;
+			}
+			memcpy(pd, tok, len);
+			pd += len;
+			*pd++ = ':';
+			*pd = '\0';
+		skip_it: ;
+		}
+	}
+done:
+	if (dummy)
+		free(dummy);
+
+
+/*
+ * From here on is ncurses-specific glue code
+ */
+
+	if (i < 0)
+		return(TGETENT_ERR);
+
+	_nc_set_source("TERMCAP");
+	_nc_read_entry_source((FILE *)NULL, _nc_termcap, FALSE, TRUE, NULLHOOK);
+
+	if (_nc_head == (ENTRY *)NULL)
+		return(TGETENT_ERR);
+
+	/* resolve all use references */
+	_nc_resolve_uses2(TRUE, FALSE);
+
+	for_entry_list(ep)
+		if (_nc_name_match(ep->tterm.term_names, name, "|:"))
+		{
+			/*
+			 * Make a local copy of the terminal capabilities, delinked
+			 * from the list.
+			 */
+			memcpy(tp, &ep->tterm, sizeof(TERMTYPE));
+			_nc_delink_entry(_nc_head, &(ep->tterm));
+			free(ep);
+			_nc_free_entries(_nc_head);
+			_nc_head = _nc_tail = NULL;	/* do not reuse! */
+
+			return TGETENT_YES;	/* OK */
+		}
+
+	_nc_free_entries(_nc_head);
+	_nc_head = _nc_tail = NULL;	/* do not reuse! */
+	return(TGETENT_NO);	/* not found */
+}
--- /dev/null
+++ lib/ncurses/ncurses/ncurses_cfg.h
@@ -0,0 +1,202 @@
+/* include/ncurses_cfg.h.  Generated automatically by configure.  */
+/****************************************************************************
+ * Copyright (c) 1998-2004,2005 Free Software Foundation, Inc.              *
+ *                                                                          *
+ * Permission is hereby granted, free of charge, to any person obtaining a  *
+ * copy of this software and associated documentation files (the            *
+ * "Software"), to deal in the Software without restriction, including      *
+ * without limitation the rights to use, copy, modify, merge, publish,      *
+ * distribute, distribute with modifications, sublicense, and/or sell       *
+ * copies of the Software, and to permit persons to whom the Software is    *
+ * furnished to do so, subject to the following conditions:                 *
+ *                                                                          *
+ * The above copyright notice and this permission notice shall be included  *
+ * in all copies or substantial portions of the Software.                   *
+ *                                                                          *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
+ *                                                                          *
+ * Except as contained in this notice, the name(s) of the above copyright   *
+ * holders shall not be used in advertising or otherwise to promote the     *
+ * sale, use or other dealings in this Software without prior written       *
+ * authorization.                                                           *
+ ****************************************************************************/
+
+/****************************************************************************
+ *  Author: Thomas E. Dickey <dickey at clark.net> 1997                        *
+ ****************************************************************************/
+/*
+ * $Id: ncurses_cfg.hin,v 1.7 2005/01/02 01:26:58 tom Exp $
+ *
+ * This is a template-file used to generate the "ncurses_cfg.h" file.
+ *
+ * Rather than list every definition, the configuration script substitutes the
+ * definitions that it finds using 'sed'.  You need a patch (original date
+ * 971222) to autoconf 2.12 or 2.13 to do this.
+ *
+ * See:
+ *	http://invisible-island.net/autoconf/
+ *	ftp://invisible-island.net/autoconf/
+ */
+
+/* $FreeBSD: src/lib/ncurses/ncurses/ncurses_cfg.h,v 1.8 2007/03/09 12:11:57 rafan Exp $ */
+
+#ifndef NC_CONFIG_H
+#define NC_CONFIG_H
+
+#ifdef __cplusplus
+#include <stdlib.h>
+#endif
+#define BSD_TPUTS 1
+#define CC_HAS_INLINE_FUNCS 1
+#define CC_HAS_PROTOS 1
+#define CPP_HAS_STATIC_CAST 1
+#define CPP_HAS_VSCAN_FUNC 1
+#define ETIP_NEEDS_MATH_H 1
+#define GCC_NORETURN __attribute__((noreturn))
+#define GCC_PRINTF 1
+#define GCC_SCANF 1
+#define GCC_UNUSED __attribute__((unused))
+#define HAVE_BIG_CORE 1
+#define HAVE_BSD_CGETENT 1
+#define HAVE_CURSES_VERSION 1
+#define HAVE_DIRENT_H 1
+#define HAVE_ERRNO 1
+#define HAVE_FCNTL_H 1
+#define HAVE_FORM_H 1
+#define HAVE_FSEEKO 1
+#define HAVE_GETCWD 1
+#define HAVE_GETEGID 1
+#define HAVE_GETEUID 1
+#define HAVE_GETOPT_H 1
+#define HAVE_GETTIMEOFDAY 1
+#define HAVE_GETTTYNAM 1
+#define HAVE_HAS_KEY 1
+#define HAVE_INTTYPES_H 1
+#define HAVE_ISASCII 1
+#define HAVE_ISSETUGID 1
+#define HAVE_LANGINFO_CODESET 1
+#define HAVE_LIBFORM 1
+#define HAVE_LIBMENU 1
+#define HAVE_LIBPANEL 1
+#define HAVE_LIMITS_H 1
+#define HAVE_LINK 1
+#define HAVE_LOCALE_H 1
+#define HAVE_LONG_FILE_NAMES 1
+#define HAVE_MEMORY_H 1
+#define HAVE_MENU_H 1
+#define HAVE_MKSTEMP 1
+#define HAVE_NANOSLEEP 1
+#define HAVE_NC_ALLOC_H 1
+#define HAVE_PANEL_H 1
+#define HAVE_POLL 1
+#define HAVE_POLL_H 1
+#define HAVE_REGEX_H_FUNCS 1
+#define HAVE_REMOVE 1
+#define HAVE_REMOVE 1
+#define HAVE_RESIZETERM 1
+#define HAVE_RESIZE_TERM 1
+#define HAVE_SELECT 1
+#define HAVE_SETBUF 1
+#define HAVE_SETBUFFER 1
+#define HAVE_SETVBUF 1
+#define HAVE_SIGACTION 1
+#define HAVE_SIGVEC 1
+#define HAVE_SIZECHANGE 1
+#define HAVE_SLK_COLOR 1
+#define HAVE_STDINT_H 1
+#define HAVE_STDLIB_H 1
+#define HAVE_STRDUP 1
+#define HAVE_STRINGS_H 1
+#define HAVE_STRING_H 1
+#define HAVE_STRSTR 1
+#define HAVE_SYMLINK 1
+#define HAVE_SYS_IOCTL_H 1
+#define HAVE_SYS_PARAM_H 1
+#define HAVE_SYS_POLL_H 1
+#define HAVE_SYS_SELECT_H 1
+#define HAVE_SYS_STAT_H 1
+#define HAVE_SYS_TIMES_H 1
+#define HAVE_SYS_TIME_H 1
+#define HAVE_SYS_TIME_SELECT 1
+#define HAVE_SYS_TYPES_H 1
+#define HAVE_TCGETATTR 1
+#define HAVE_TCGETPGRP 1
+#define HAVE_TERMIOS_H 1
+#define HAVE_TIMES 1
+#define HAVE_TTYENT_H 1
+#define HAVE_TYPEINFO 1
+#define HAVE_UNISTD_H 1
+#define HAVE_UNISTD_H 1
+#define HAVE_UNISTD_H 1
+#define HAVE_UNLINK 1
+#define HAVE_USE_DEFAULT_COLORS 1
+#define HAVE_VSNPRINTF 1
+#define HAVE_VSSCANF 1
+#define HAVE_WCTYPE_H 1
+#define HAVE_WORKING_POLL 1
+#define HAVE_WRESIZE 1
+#define MIXEDCASE_FILENAMES 1
+#define NCURSES_EXT_FUNCS 1
+#define NCURSES_NO_PADDING 1
+#define NCURSES_PATHSEP ':'
+#define NCURSES_VERSION_STRING "5.6.20061217"
+#define NDEBUG 1
+#define RETSIGTYPE void
+#define SIZEOF_SIGNED_CHAR 1
+#define STDC_HEADERS 1
+#define SYSTEM_NAME "FreeBSD"
+#define TERMPATH "/etc/termcap:/usr/share/misc/termcap"
+#define TIME_WITH_SYS_TIME 1
+#define TYPEOF_CHTYPE int
+#define USE_ASSUMED_COLOR 1
+#define USE_COLORFGBG 1
+#define USE_GETCAP 1
+#define USE_HASHMAP 1
+#define USE_LINKS 1
+#define USE_SIGWINCH 1
+#define USE_STDIO_VSCAN 1
+#define USE_SYSMOUSE 1
+#define USE_TERMCAP 1
+#ifdef ENABLE_WIDEC
+#define USE_WIDEC_SUPPORT 1
+#define HAVE_PUTWC 1
+#define HAVE_BTOWC 1
+#define HAVE_WCTOB 1
+#define HAVE_MBTOWC 1
+#define HAVE_WCTOMB 1
+#define HAVE_MBLEN 1
+#define HAVE_MBRLEN 1
+#define HAVE_MBRTOWC 1
+#define NEED_WCHAR_H 1 
+#endif
+
+#include <ncurses_def.h>
+
+	/* The C compiler may not treat these properly but C++ has to */
+#ifdef __cplusplus
+#undef const
+#undef inline
+#else
+#if defined(lint) || defined(TRACE)
+#undef inline
+#define inline /* nothing */
+#endif
+#endif
+
+	/* On HP-UX, the C compiler doesn't grok mbstate_t without
+	   -D_XOPEN_SOURCE=500. However, this causes problems on
+	   IRIX. So, we #define mbstate_t to int in configure.in
+	   only for the C compiler if needed. */
+#ifndef __cplusplus
+#ifdef NEED_MBSTATE_T_DEF
+#define mbstate_t int
+#endif
+#endif
+
+#endif /* NC_CONFIG_H */
--- /dev/null
+++ lib/ncurses/ncurses/Makefile
@@ -0,0 +1,948 @@
+# $FreeBSD: src/lib/ncurses/ncurses/Makefile,v 1.92.2.1 2007/10/23 15:41:34 ru Exp $
+
+SHLIBDIR?=	/lib
+
+.include <bsd.own.mk>
+
+.include "${.CURDIR}/../config.mk"
+
+LIB=		ncurses${LIB_SUFFIX}
+SHLIB_MAJOR=	7
+
+NO_LINT=
+
+NCURSES_MAJOR!=	egrep 'NCURSES_MAJOR[ 	]*=' ${NCURSES_DIR}/dist.mk | sed -e 's%^[^0-9]*%%'
+NCURSES_MINOR!=	egrep 'NCURSES_MINOR[ 	]*=' ${NCURSES_DIR}/dist.mk | sed -e 's%^[^0-9]*%%'
+NCURSES_PATCH!=	egrep 'NCURSES_PATCH[ 	]*=' ${NCURSES_DIR}/dist.mk | sed -e 's%^[^0-9]*%%'
+
+# From autoconf (!)
+.if defined(ENABLE_WIDEC)
+NCURSES_CH_T=		cchar_t
+NEED_WCHAR_H=		1
+.else
+NCURSES_CH_T=		chtype
+NEED_WCHAR_H=		0
+.endif
+NCURSES_CONST=		const
+NCURSES_EXT_COLORS=	0
+NCURSES_EXT_FUNCS=	1
+NCURSES_INLINE=		inline
+NCURSES_LIBUTF8=	0
+NCURSES_MBSTATE_T=	0
+NCURSES_MOUSE_VERSION=	1
+NCURSES_OSPEED=		short
+NCURSES_SBOOL=		char
+NCURSES_TPARM_VARARGS=	1
+NCURSES_WCHAR_T=	0
+NCURSES_WINT_T=		0
+NCURSES_XNAMES=		1
+BROKEN_LINKER=		0
+BUILTIN_BOOL=		1
+ENABLE_LP64=		0
+HAVE_TCGETATTR=		1
+HAVE_TERMIOS_H=		1
+HAVE_TERMIO_H=		0
+HAVE_VSSCANF=		1
+HEADER_STDBOOL=		1
+# XXX amd64, ia64 1L and int
+ONEUL=			1UL
+TYPEOF_CHTYPE=		long
+TYPEOF_MMASK_T=		long
+TYPE_OF_BOOL=		unsigned char
+USE_CXX_BOOL=		defined(__cplusplus)
+
+GENSRCS=	\
+	codes.c \
+	expanded.c \
+	fallback.c \
+	lib_gen.c \
+	lib_keyname.c \
+	names.c \
+	unctrl.c
+
+GENHDRS=	\
+	curses.h \
+	hashsize.h \
+	init_keytry.h \
+	ncurses_def.h \
+	nomacros.h \
+	parametrized.h \
+	term.h \
+	termcap.h \
+	unctrl.h
+
+SRCS=	${GENHDRS} ${GENSRCS}
+
+.PATH: ${NCURSES_DIR}/ncurses/base
+SRCS+=	\
+	define_key.c \
+	key_defined.c \
+	keybound.c \
+	keyok.c \
+	legacy_coding.c \
+	lib_addch.c \
+	lib_addstr.c \
+	lib_beep.c \
+	lib_bkgd.c \
+	lib_box.c \
+	lib_chgat.c \
+	lib_clear.c \
+	lib_clearok.c \
+	lib_clrbot.c \
+	lib_clreol.c \
+	lib_color.c \
+	lib_colorset.c \
+	lib_delch.c \
+	lib_delwin.c \
+	lib_dft_fgbg.c \
+	lib_echo.c \
+	lib_endwin.c \
+	lib_erase.c \
+	lib_flash.c \
+	lib_freeall.c \
+	lib_getch.c \
+	lib_getstr.c \
+	lib_hline.c \
+	lib_immedok.c \
+	lib_inchstr.c \
+	lib_initscr.c \
+	lib_insch.c \
+	lib_insdel.c \
+	lib_insnstr.c \
+	lib_instr.c \
+	lib_isendwin.c \
+	lib_leaveok.c \
+	lib_mouse.c \
+	lib_move.c \
+	lib_mvwin.c \
+	lib_newterm.c \
+	lib_newwin.c \
+	lib_nl.c \
+	lib_overlay.c \
+	lib_pad.c \
+	lib_printw.c \
+	lib_redrawln.c \
+	lib_refresh.c \
+	lib_restart.c \
+	lib_scanw.c \
+	lib_screen.c \
+	lib_scroll.c \
+	lib_scrollok.c \
+	lib_scrreg.c \
+	lib_set_term.c \
+	lib_slk.c \
+	lib_slkatr_set.c \
+	lib_slkatrof.c \
+	lib_slkatron.c \
+	lib_slkatrset.c \
+	lib_slkattr.c \
+	lib_slkclear.c \
+	lib_slkcolor.c \
+	lib_slkinit.c \
+	lib_slklab.c \
+	lib_slkrefr.c \
+	lib_slkset.c \
+	lib_slktouch.c \
+	lib_touch.c \
+	lib_ungetch.c \
+	lib_vline.c \
+	lib_wattroff.c \
+	lib_wattron.c \
+	lib_winch.c \
+	lib_window.c \
+	memmove.c \
+	nc_panel.c \
+	resizeterm.c \
+	safe_sprintf.c \
+	tries.c \
+	version.c \
+	vsscanf.c \
+	wresize.c
+
+.PATH: ${NCURSES_DIR}/ncurses/tinfo
+SRCS+=	\
+	access.c \
+	add_tries.c \
+	alloc_entry.c \
+	alloc_ttype.c \
+	captoinfo.c \
+	comp_captab.c \
+	comp_error.c \
+	comp_expand.c \
+	comp_hash.c \
+	comp_parse.c \
+	comp_scan.c \
+	db_iterator.c \
+	doalloc.c \
+	free_ttype.c \
+	getenv_num.c \
+	hashed_db.c \
+	home_terminfo.c \
+	init_keytry.c \
+	lib_acs.c \
+	lib_baudrate.c \
+	lib_cur_term.c \
+	lib_data.c \
+	lib_has_cap.c \
+	lib_kernel.c \
+	lib_longname.c \
+	lib_napms.c \
+	lib_options.c \
+	lib_print.c \
+	lib_raw.c \
+	lib_setup.c \
+	lib_termcap.c \
+	lib_termname.c \
+	lib_tgoto.c \
+	lib_ti.c \
+	lib_tparm.c \
+	lib_tputs.c \
+	lib_ttyflags.c \
+	name_match.c \
+	parse_entry.c \
+	read_entry.c \
+	setbuf.c \
+	strings.c \
+	trim_sgr0.c \
+	write_entry.c
+
+.PATH: ${NCURSES_DIR}/ncurses/tty
+SRCS+=	\
+	hardscroll.c \
+	hashmap.c \
+	lib_mvcur.c \
+	lib_tstp.c \
+	lib_twait.c \
+	lib_vidattr.c \
+	tty_update.c
+
+.if defined(ENABLE_WIDEC)
+.PATH: ${NCURSES_DIR}/ncurses/widechar
+SRCS+=	\
+	charable.c \
+	lib_add_wch.c \
+	lib_box_set.c \
+	lib_cchar.c \
+	lib_erasewchar.c \
+	lib_get_wch.c \
+	lib_get_wstr.c \
+	lib_hline_set.c \
+	lib_in_wch.c \
+	lib_in_wchnstr.c \
+	lib_ins_wch.c \
+	lib_inwstr.c \
+	lib_pecho_wchar.c \
+	lib_slk_wset.c \
+	lib_unget_wch.c \
+	lib_vid_attr.c \
+	lib_vline_set.c \
+	lib_wacs.c \
+	lib_wunctrl.c
+.endif
+
+.PATH: ${NCURSES_DIR}/ncurses/trace
+SRCS+=	\
+	lib_trace.c \
+	visbuf.c
+
+# Currently unused, for debugging libncurses itself.
+DBGSRCS= \
+	lib_traceatr.c \
+	lib_tracebits.c \
+	lib_tracechr.c \
+	lib_tracedmp.c \
+	lib_tracemse.c \
+	trace_buf.c \
+	trace_tries.c \
+	trace_xnames.c \
+	varargs.c
+
+# From our old libtermcap.
+# Used instead of the hideous read_termcap.c abomination.
+SRCS+=	termcap.c
+
+# Components of names.c and codes.c
+NAMESRCS=	boolnames boolfnames numnames numfnames strnames strfnames
+CODESRCS=	boolcodes numcodes strcodes
+
+CLEANFILES=	${GENSRCS} ${GENHDRS} keys.list make_hash term.h.new \
+		make_keys MKterm.h.awk comp_captab.c curses.head \
+		namehdr nameftr codeftr ${NAMESRCS} ${CODESRCS}
+
+CFLAGS+=	-DFREEBSD_NATIVE -DTERMIOS
+
+# Installed
+HEADERS=	curses.h term.h termcap.h unctrl.h
+SRCHDRS=	ncurses_dll.h
+
+.if defined(ENABLE_WIDEC)
+INCS=		${HEADERS} ${SRCHDRS}
+INCSLINKS=	curses.h ${INCLUDEDIR}/ncurses.h
+.endif
+
+.if ${MK_INSTALLLIB} != "no"
+SYMLINKS+=	libncurses${LIB_SUFFIX}.a ${LIBDIR}/libcurses${LIB_SUFFIX}.a
+SYMLINKS+=	libncurses${LIB_SUFFIX}.a ${LIBDIR}/libtermcap${LIB_SUFFIX}.a
+SYMLINKS+=	libncurses${LIB_SUFFIX}.a ${LIBDIR}/libtermlib${LIB_SUFFIX}.a
+SYMLINKS+=	libncurses${LIB_SUFFIX}.a ${LIBDIR}/libtinfo${LIB_SUFFIX}.a
+.endif
+.if !defined(NO_PIC)
+# no need for major at all, it's an ld-time redirection only
+SYMLINKS+=	libncurses${LIB_SUFFIX}.so ${LIBDIR}/libcurses${LIB_SUFFIX}.so
+SYMLINKS+=	libncurses${LIB_SUFFIX}.so ${LIBDIR}/libtermcap${LIB_SUFFIX}.so
+SYMLINKS+=	libncurses${LIB_SUFFIX}.so ${LIBDIR}/libtermlib${LIB_SUFFIX}.so
+SYMLINKS+=	libncurses${LIB_SUFFIX}.so ${LIBDIR}/libtinfo${LIB_SUFFIX}.so
+.endif
+.if ${MK_PROFILE} != "no"
+SYMLINKS+=	libncurses${LIB_SUFFIX}_p.a ${LIBDIR}/libcurses${LIB_SUFFIX}_p.a
+SYMLINKS+=	libncurses${LIB_SUFFIX}_p.a ${LIBDIR}/libtermcap${LIB_SUFFIX}_p.a
+SYMLINKS+=	libncurses${LIB_SUFFIX}_p.a ${LIBDIR}/libtermlib${LIB_SUFFIX}_p.a
+SYMLINKS+=	libncurses${LIB_SUFFIX}_p.a ${LIBDIR}/libtinfo${LIB_SUFFIX}_p.a
+.endif
+
+DOCSDIR=	${SHAREDIR}/doc/ncurses
+DOCS=		ncurses-intro.html hackguide.html
+
+.if ${MK_HTML} != "no"
+.PATH: ${NCURSES_DIR}/doc/html
+FILESGROUPS=	DOCS
+.endif
+
+# Generated source
+namehdr nameftr codeftr ${NAMESRCS} ${CODESRCS}: MKnames.awk Caps
+	${AWK} -f ${NCURSES_DIR}/ncurses/tinfo/MKnames.awk ${NCURSES_DIR}/include/Caps
+
+.ORDER: namehdr ${NAMESRCS} ${CODESRCS} nameftr codeftr names.c codes.c
+
+names.c: namehdr ${NAMESRCS} nameftr
+	cat namehdr ${NAMESRCS} nameftr > $@
+
+codes.c: namehdr ${CODESRCS} codeftr
+	cat namehdr ${CODESRCS} codeftr > $@
+
+lib_gen.c: MKlib_gen.sh curses.h
+	LC_ALL=C sh ${NCURSES_DIR}/ncurses/base/MKlib_gen.sh "${CC} -E ${CFLAGS}" \
+	    "${AWK}" generated < curses.h >$@
+
+lib_keyname.c: keys.list MKkeyname.awk
+	${AWK} -f ${NCURSES_DIR}/ncurses/base/MKkeyname.awk keys.list > lib_keyname.c
+
+unctrl.c: MKunctrl.awk
+	echo | ${AWK} -f ${NCURSES_DIR}/ncurses/base/MKunctrl.awk > unctrl.c
+
+comp_captab.c: MKcaptab.awk Caps make_hash
+	sh ${NCURSES_DIR}/ncurses/tinfo/MKcaptab.awk "${AWK}" \
+	    ${NCURSES_DIR}/include/Caps > comp_captab.c
+
+expanded.c: MKexpanded.sh
+	sh ${NCURSES_DIR}/ncurses/tty/MKexpanded.sh "${CC} -E" ${CFLAGS} >expanded.c
+
+fallback.c: MKfallback.sh
+	sh ${NCURSES_DIR}/ncurses/tinfo/MKfallback.sh > fallback.c
+
+# Generated headers
+nomacros.h: MKlib_gen.sh curses.h
+	LC_ALL=C sh ${NCURSES_DIR}/ncurses/base/MKlib_gen.sh "${CC} -E ${CFLAGS}" \
+	    "${AWK}" generated < curses.h | fgrep undef > $@
+
+init_keytry.h: keys.list make_keys
+	./make_keys keys.list > init_keytry.h
+
+hashsize.h: MKhashsize.sh Caps
+	sh ${NCURSES_DIR}/include/MKhashsize.sh ${NCURSES_DIR}/include/Caps > $@
+
+parametrized.h: MKparametrized.sh Caps
+	AWK=${AWK} sh ${NCURSES_DIR}/include/MKparametrized.sh \
+	    ${NCURSES_DIR}/include/Caps > $@
+
+term.h: MKterm.h.awk edit_cfg.sh Caps
+	${AWK} -f MKterm.h.awk ${NCURSES_DIR}/include/Caps > $@.new
+	sh ${NCURSES_DIR}/include/edit_cfg.sh ${NCURSES_CFG_H} $@.new
+	mv -f $@.new $@
+
+curses.h: curses.head MKkey_defs.sh Caps
+	cat curses.head > $@.new
+	AWK=${AWK} _POSIX2_VERSION=199209 sh ${NCURSES_DIR}/include/MKkey_defs.sh \
+	    ${NCURSES_DIR}/include/Caps >> $@.new
+.if defined(ENABLE_WIDEC)
+	cat ${NCURSES_DIR}/include/curses.wide >> $@.new
+.endif
+	cat ${NCURSES_DIR}/include/curses.tail >> $@.new
+	mv -f $@.new $@
+
+# Generated intermediate files
+keys.list: MKkeys_list.sh Caps
+	AWK=${AWK} sh ${NCURSES_DIR}/ncurses/tinfo/MKkeys_list.sh \
+	    ${NCURSES_DIR}/include/Caps | LC_ALL=C sort > keys.list
+
+# Build tools
+build-tools: make_hash make_keys
+
+make_keys: make_keys.c names.c ncurses_def.h ${HEADERS}
+	${CC} -o $@ ${CFLAGS} ${NCURSES_DIR}/ncurses/tinfo/make_keys.c
+
+make_hash: comp_hash.c hashsize.h ncurses_def.h ${HEADERS}
+	${CC} -o $@ ${CFLAGS} -DMAIN_PROGRAM \
+		${NCURSES_DIR}/ncurses/tinfo/comp_hash.c
+
+# ./configure generated
+MKterm.h.awk: MKterm.h.awk.in
+	sed <${NCURSES_DIR}/include/MKterm.h.awk.in >$@ \
+	    -e "/@NCURSES_MAJOR@/s%%${NCURSES_MAJOR}%" \
+	    -e "/@NCURSES_MINOR@/s%%${NCURSES_MINOR}%" \
+	    -e "/@NCURSES_CONST@/s%%${NCURSES_CONST}%" \
+	    -e "/@NCURSES_TPARM_VARARGS@/s%%${NCURSES_TPARM_VARARGS}%" \
+	    -e "/@NCURSES_SBOOL@/s%%${NCURSES_SBOOL}%" \
+	    -e "/@NCURSES_XNAMES@/s%%${NCURSES_XNAMES}%" \
+	    -e "/@HAVE_TERMIOS_H@/s%%${HAVE_TERMIOS_H}%" \
+	    -e "/@HAVE_TERMIO_H@/s%%${HAVE_TERMIO_H}%" \
+	    -e "/@HAVE_TCGETATTR@/s%%${HAVE_TCGETATTR}%"
+
+termcap.h: termcap.h.in
+	sed <${NCURSES_DIR}/include/termcap.h.in >$@ \
+	    -e "/@NCURSES_MAJOR@/s%%${NCURSES_MAJOR}%" \
+	    -e "/@NCURSES_MINOR@/s%%${NCURSES_MINOR}%" \
+	    -e "/@NCURSES_CONST@/s%%${NCURSES_CONST}%" \
+	    -e "/@NCURSES_OSPEED@/s%%${NCURSES_OSPEED}%"
+
+curses.head: curses.h.in
+	sed <${NCURSES_DIR}/include/curses.h.in >$@ \
+	    -e "/@BROKEN_LINKER@/s%%${BROKEN_LINKER}%" \
+	    -e "/@HAVE_VSSCANF@/s%%${HAVE_VSSCANF}%" \
+	    -e "/@NCURSES_CH_T@/s%%${NCURSES_CH_T}%" \
+	    -e "/@NCURSES_CONST@/s%%${NCURSES_CONST}%" \
+	    -e "/@NCURSES_EXT_COLORS@/s%%${NCURSES_EXT_COLORS}%" \
+	    -e "/@NCURSES_EXT_FUNCS@/s%%${NCURSES_EXT_FUNCS}%" \
+	    -e "/@NCURSES_INLINE@/s%%${NCURSES_INLINE}%" \
+	    -e "/@NCURSES_LIBUTF8@/s%%${NCURSES_LIBUTF8}%" \
+	    -e "/@NCURSES_MAJOR@/s%%${NCURSES_MAJOR}%" \
+	    -e "/@NCURSES_MBSTATE_T@/s%%${NCURSES_MBSTATE_T}%" \
+	    -e "/@NCURSES_MINOR@/s%%${NCURSES_MINOR}%" \
+	    -e "/@NCURSES_MOUSE_VERSION@/s%%${NCURSES_MOUSE_VERSION}%" \
+	    -e "/@NCURSES_PATCH@/s%%${NCURSES_PATCH}%" \
+	    -e "/@NCURSES_TPARM_VARARGS@/s%%${NCURSES_TPARM_VARARGS}%" \
+	    -e "/@NCURSES_WCHAR_T@/s%%${NCURSES_WCHAR_T}%" \
+	    -e "/@NCURSES_WCHAR_T@/s%%${NCURSES_WCHAR_T}%" \
+	    -e "/@NCURSES_WINT_T@/s%%${NCURSES_WINT_T}%" \
+	    -e "/@NEED_WCHAR_H@/s%%${NEED_WCHAR_H}%" \
+	    -e "/@USE_CXX_BOOL@/s%%${USE_CXX_BOOL}%" \
+	    -e "s%@cf_cv_1UL@%${ONEUL}%g" \
+	    -e "s%@cf_cv_builtin_bool@%${BUILTIN_BOOL}%g" \
+	    -e "s%@cf_cv_enable_lp64@%${ENABLE_LP64}%g" \
+	    -e "s%@cf_cv_header_stdbool_h@%${HEADER_STDBOOL}%g" \
+	    -e "s%@cf_cv_type_of_bool@%${TYPE_OF_BOOL}%g" \
+	    -e "s%@cf_cv_typeof_chtype@%${TYPEOF_CHTYPE}%g" \
+	    -e "s%@cf_cv_typeof_mmask_t@%${TYPEOF_MMASK_T}%g" \
+	    -e "s/ _WCHAR_T/ __wchar_t/g" \
+	    -e "s/ _WINT_T/ __wint_t/g"
+
+unctrl.h: unctrl.h.in
+	sed <${NCURSES_DIR}/include/$@.in >$@ \
+	    -e "/@NCURSES_MAJOR@/s%%${NCURSES_MAJOR}%" \
+	    -e "/@NCURSES_MINOR@/s%%${NCURSES_MINOR}%"
+
+# MAN page gunk
+terminfo.5: MKterminfo.sh terminfo.head Caps
+	sh ${NCURSES_DIR}/man/MKterminfo.sh ${NCURSES_DIR}/man/terminfo.head \
+	    ${NCURSES_DIR}/include/Caps ${NCURSES_DIR}/man/terminfo.tail >$@
+
+CLEANFILES+=	terminfo.5
+
+.PATH: ${NCURSES_DIR}/man
+MAN=	\
+	curs_addch.3 \
+	curs_addchstr.3 \
+	curs_addstr.3 \
+	curs_attr.3 \
+	curs_beep.3 \
+	curs_bkgd.3 \
+	curs_bkgrnd.3 \
+	curs_border.3 \
+	curs_border_set.3 \
+	curs_clear.3 \
+	curs_color.3 \
+	curs_delch.3 \
+	curs_deleteln.3 \
+	curs_extend.3 \
+	curs_getcchar.3 \
+	curs_getch.3 \
+	curs_getstr.3 \
+	curs_getyx.3 \
+	curs_inch.3 \
+	curs_inchstr.3 \
+	curs_initscr.3 \
+	curs_inopts.3 \
+	curs_insch.3 \
+	curs_insstr.3 \
+	curs_instr.3 \
+	curs_inwstr.3 \
+	curs_kernel.3 \
+	curs_mouse.3 \
+	curs_move.3 \
+	curs_outopts.3 \
+	curs_overlay.3 \
+	curs_pad.3 \
+	curs_print.3 \
+	curs_refresh.3 \
+	curs_scr_dump.3 \
+	curs_scroll.3 \
+	curs_slk.3 \
+	curs_termattrs.3 \
+	curs_termcap.3 \
+	curs_terminfo.3 \
+	curs_touch.3 \
+	curs_trace.3 \
+	curs_util.3 \
+	curs_window.3 \
+	default_colors.3 \
+	define_key.3 \
+	key_defined.3 \
+	keybound.3 \
+	keyok.3 \
+	legacy_coding.3 \
+	ncurses.3 \
+	resizeterm.3 \
+	wresize.3
+
+.if defined(ENABLE_WIDEC)
+MAN+=	\
+	curs_add_wch.3 \
+	curs_add_wchstr.3 \
+	curs_addwstr.3 \
+	curs_get_wch.3 \
+	curs_get_wstr.3 \
+	curs_in_wch.3 \
+	curs_in_wchstr.3 \
+	curs_ins_wch.3 \
+	curs_ins_wstr.3 \
+	curs_printw.3 \
+	curs_scanw.3
+.endif
+
+CLEANFILES+=	${MAN:M*.3}
+
+MAN+=	term.5 terminfo.5
+MAN+=	term.7
+
+MLINKS=	ncurses.3 curses.3 \
+	curs_addch.3 addch.3 \
+	curs_addch.3 echochar.3 \
+	curs_addch.3 mvaddch.3 \
+	curs_addch.3 mvwaddch.3 \
+	curs_addch.3 waddch.3 \
+	curs_addch.3 wechochar.3 \
+	curs_addchstr.3 addchnstr.3 \
+	curs_addchstr.3 addchstr.3 \
+	curs_addchstr.3 mvaddchnstr.3 \
+	curs_addchstr.3 mvaddchstr.3 \
+	curs_addchstr.3 mvwaddchnstr.3 \
+	curs_addchstr.3 mvwaddchstr.3 \
+	curs_addchstr.3 waddchnstr.3 \
+	curs_addchstr.3 waddchstr.3 \
+	curs_addstr.3 addnstr.3 \
+	curs_addstr.3 addstr.3 \
+	curs_addstr.3 mvaddnstr.3 \
+	curs_addstr.3 mvaddstr.3 \
+	curs_addstr.3 mvwaddnstr.3 \
+	curs_addstr.3 mvwaddstr.3 \
+	curs_addstr.3 waddnstr.3 \
+	curs_addstr.3 waddstr.3 \
+	curs_attr.3 PAIR_NUMBER.3 \
+	curs_attr.3 attr_get.3 \
+	curs_attr.3 attr_off.3 \
+	curs_attr.3 attr_on.3 \
+	curs_attr.3 attr_set.3 \
+	curs_attr.3 attroff.3 \
+	curs_attr.3 attron.3 \
+	curs_attr.3 attrset.3 \
+	curs_attr.3 chgat.3 \
+	curs_attr.3 color_set.3 \
+	curs_attr.3 mvchgat.3 \
+	curs_attr.3 mvwchgat.3 \
+	curs_attr.3 standend.3 \
+	curs_attr.3 standout.3 \
+	curs_attr.3 wattr_get.3 \
+	curs_attr.3 wattr_off.3 \
+	curs_attr.3 wattr_on.3 \
+	curs_attr.3 wattr_set.3 \
+	curs_attr.3 wattroff.3 \
+	curs_attr.3 wattron.3 \
+	curs_attr.3 wattrset.3 \
+	curs_attr.3 wchgat.3 \
+	curs_attr.3 wcolor_set.3 \
+	curs_attr.3 wstandend.3 \
+	curs_attr.3 wstandout.3 \
+	curs_beep.3 beep.3 \
+	curs_beep.3 flash.3 \
+	curs_bkgd.3 bkgd.3 \
+	curs_bkgd.3 bkgdset.3 \
+	curs_bkgd.3 getbkgd.3 \
+	curs_bkgd.3 wbkgd.3 \
+	curs_bkgd.3 wbkgdset.3 \
+	curs_bkgrnd.3 bkgrnd.3 \
+	curs_bkgrnd.3 bkgrndset.3 \
+	curs_bkgrnd.3 getbkgrnd.3 \
+	curs_bkgrnd.3 wbkgrnd.3 \
+	curs_bkgrnd.3 wbkgrndset.3 \
+	curs_bkgrnd.3 wgetbkgrnd.3 \
+	curs_border.3 border.3 \
+	curs_border.3 box.3 \
+	curs_border.3 hline.3 \
+	curs_border.3 mvhline.3 \
+	curs_border.3 mvvline.3 \
+	curs_border.3 mvwhline.3 \
+	curs_border.3 mvwvline.3 \
+	curs_border.3 vline.3 \
+	curs_border.3 wborder.3 \
+	curs_border.3 whline.3 \
+	curs_border.3 wvline.3 \
+	curs_border_set.3 border_set.3 \
+	curs_border_set.3 box_set.3 \
+	curs_border_set.3 hline_set.3 \
+	curs_border_set.3 mvhline_set.3 \
+	curs_border_set.3 mvvline_set.3 \
+	curs_border_set.3 mvwhline_set.3 \
+	curs_border_set.3 mvwvline_set.3 \
+	curs_border_set.3 vline_set.3 \
+	curs_border_set.3 wborder_set.3 \
+	curs_border_set.3 whline_set.3 \
+	curs_border_set.3 wvline_set.3 \
+	curs_clear.3 clear.3 \
+	curs_clear.3 clrtobot.3 \
+	curs_clear.3 clrtoeol.3 \
+	curs_clear.3 erase.3 \
+	curs_clear.3 wclear.3 \
+	curs_clear.3 wclrtobot.3 \
+	curs_clear.3 wclrtoeol.3 \
+	curs_clear.3 werase.3 \
+	curs_color.3 COLOR_PAIR.3 \
+	curs_color.3 can_change_color.3 \
+	curs_color.3 color_content.3 \
+	curs_color.3 has_colors.3 \
+	curs_color.3 init_color.3 \
+	curs_color.3 init_pair.3 \
+	curs_color.3 pair_content.3 \
+	curs_color.3 start_color.3 \
+	curs_delch.3 delch.3 \
+	curs_delch.3 mvdelch.3 \
+	curs_delch.3 mvwdelch.3 \
+	curs_delch.3 wdelch.3 \
+	curs_deleteln.3 deleteln.3 \
+	curs_deleteln.3 insdelln.3 \
+	curs_deleteln.3 insertln.3 \
+	curs_deleteln.3 wdeleteln.3 \
+	curs_deleteln.3 winsdelln.3 \
+	curs_deleteln.3 winsertln.3 \
+	curs_extend.3 curses_version.3 \
+	curs_extend.3 use_extended_names.3 \
+	curs_getcchar.3 getcchar.3 \
+	curs_getcchar.3 setcchar.3 \
+	curs_getch.3 getch.3 \
+	curs_getch.3 has_key.3 \
+	curs_getch.3 mvgetch.3 \
+	curs_getch.3 mvwgetch.3 \
+	curs_getch.3 ungetch.3 \
+	curs_getch.3 wgetch.3 \
+	curs_getstr.3 getnstr.3 \
+	curs_getstr.3 getstr.3 \
+	curs_getstr.3 mvgetnstr.3 \
+	curs_getstr.3 mvgetstr.3 \
+	curs_getstr.3 mvwgetnstr.3 \
+	curs_getstr.3 mvwgetstr.3 \
+	curs_getstr.3 wgetnstr.3 \
+	curs_getstr.3 wgetstr.3 \
+	curs_getyx.3 getbegyx.3 \
+	curs_getyx.3 getmaxyx.3 \
+	curs_getyx.3 getparyx.3 \
+	curs_getyx.3 getyx.3 \
+	curs_inch.3 inch.3 \
+	curs_inch.3 mvinch.3 \
+	curs_inch.3 mvwinch.3 \
+	curs_inch.3 winch.3 \
+	curs_inchstr.3 inchnstr.3 \
+	curs_inchstr.3 inchstr.3 \
+	curs_inchstr.3 mvinchnstr.3 \
+	curs_inchstr.3 mvinchstr.3 \
+	curs_inchstr.3 mvwinchnstr.3 \
+	curs_inchstr.3 mvwinchstr.3 \
+	curs_inchstr.3 winchnstr.3 \
+	curs_inchstr.3 winchstr.3 \
+	curs_initscr.3 delscreen.3 \
+	curs_initscr.3 endwin.3 \
+	curs_initscr.3 initscr.3 \
+	curs_initscr.3 isendwin.3 \
+	curs_initscr.3 newterm.3 \
+	curs_initscr.3 set_term.3 \
+	curs_inopts.3 cbreak.3 \
+	curs_inopts.3 echo.3 \
+	curs_inopts.3 halfdelay.3 \
+	curs_inopts.3 intrflush.3 \
+	curs_inopts.3 keypad.3 \
+	curs_inopts.3 meta.3 \
+	curs_inopts.3 nocbreak.3 \
+	curs_inopts.3 nodelay.3 \
+	curs_inopts.3 noecho.3 \
+	curs_inopts.3 noqiflush.3 \
+	curs_inopts.3 noraw.3 \
+	curs_inopts.3 notimeout.3 \
+	curs_inopts.3 qiflush.3 \
+	curs_inopts.3 raw.3 \
+	curs_inopts.3 timeout.3 \
+	curs_inopts.3 typeahead.3 \
+	curs_inopts.3 wtimeout.3 \
+	curs_insch.3 insch.3 \
+	curs_insch.3 mvinsch.3 \
+	curs_insch.3 mvwinsch.3 \
+	curs_insch.3 winsch.3 \
+	curs_insstr.3 insnstr.3 \
+	curs_insstr.3 insstr.3 \
+	curs_insstr.3 mvinsnstr.3 \
+	curs_insstr.3 mvinsstr.3 \
+	curs_insstr.3 mvwinsnstr.3 \
+	curs_insstr.3 mvwinsstr.3 \
+	curs_insstr.3 winsnstr.3 \
+	curs_insstr.3 winsstr.3 \
+	curs_instr.3 innstr.3 \
+	curs_instr.3 instr.3 \
+	curs_instr.3 mvinnstr.3 \
+	curs_instr.3 mvinstr.3 \
+	curs_instr.3 mvwinnstr.3 \
+	curs_instr.3 mvwinstr.3 \
+	curs_instr.3 winnstr.3 \
+	curs_instr.3 winstr.3 \
+	curs_kernel.3 curs_set.3 \
+	curs_kernel.3 def_prog_mode.3 \
+	curs_kernel.3 def_shell_mode.3 \
+	curs_kernel.3 getsyx.3 \
+	curs_kernel.3 napms.3 \
+	curs_kernel.3 reset_prog_mode.3 \
+	curs_kernel.3 reset_shell_mode.3 \
+	curs_kernel.3 resetty.3 \
+	curs_kernel.3 ripoffline.3 \
+	curs_kernel.3 savetty.3 \
+	curs_kernel.3 setsyx.3 \
+	curs_mouse.3 getmouse.3 \
+	curs_mouse.3 mouse_trafo.3 \
+	curs_mouse.3 mouseinterval.3 \
+	curs_mouse.3 mousemask.3 \
+	curs_mouse.3 ungetmouse.3 \
+	curs_mouse.3 wenclose.3 \
+	curs_mouse.3 wmouse_trafo.3 \
+	curs_move.3 move.3 \
+	curs_move.3 wmove.3 \
+	curs_outopts.3 clearok.3 \
+	curs_outopts.3 idcok.3 \
+	curs_outopts.3 idlok.3 \
+	curs_outopts.3 immedok.3 \
+	curs_outopts.3 leaveok.3 \
+	curs_outopts.3 nl.3 \
+	curs_outopts.3 nonl.3 \
+	curs_outopts.3 scrollok.3 \
+	curs_outopts.3 setscrreg.3 \
+	curs_outopts.3 wsetscrreg.3 \
+	curs_overlay.3 copywin.3 \
+	curs_overlay.3 overlay.3 \
+	curs_overlay.3 overwrite.3 \
+	curs_pad.3 newpad.3 \
+	curs_pad.3 pecho_wchar.3 \
+	curs_pad.3 pechochar.3 \
+	curs_pad.3 pnoutrefresh.3 \
+	curs_pad.3 prefresh.3 \
+	curs_pad.3 subpad.3 \
+	curs_print.3 mcprint.3 \
+	curs_refresh.3 doupdate.3 \
+	curs_refresh.3 redrawwin.3 \
+	curs_refresh.3 refresh.3 \
+	curs_refresh.3 wnoutrefresh.3 \
+	curs_refresh.3 wredrawln.3 \
+	curs_refresh.3 wrefresh.3 \
+	curs_scr_dump.3 scr_dump.3 \
+	curs_scr_dump.3 scr_init.3 \
+	curs_scr_dump.3 scr_restore.3 \
+	curs_scr_dump.3 scr_set.3 \
+	curs_scroll.3 scrl.3 \
+	curs_scroll.3 scroll.3 \
+	curs_scroll.3 wscrl.3 \
+	curs_slk.3 slk_attr.3 \
+	curs_slk.3 slk_attr_off.3 \
+	curs_slk.3 slk_attr_on.3 \
+	curs_slk.3 slk_attr_set.3 \
+	curs_slk.3 slk_attroff.3 \
+	curs_slk.3 slk_attron.3 \
+	curs_slk.3 slk_attrset.3 \
+	curs_slk.3 slk_clear.3 \
+	curs_slk.3 slk_color.3 \
+	curs_slk.3 slk_init.3 \
+	curs_slk.3 slk_label.3 \
+	curs_slk.3 slk_noutrefresh.3 \
+	curs_slk.3 slk_refresh.3 \
+	curs_slk.3 slk_restore.3 \
+	curs_slk.3 slk_set.3 \
+	curs_slk.3 slk_touch.3 \
+	curs_termattrs.3 baudrate.3 \
+	curs_termattrs.3 erasechar.3 \
+	curs_termattrs.3 erasewchar.3 \
+	curs_termattrs.3 has_ic.3 \
+	curs_termattrs.3 has_il.3 \
+	curs_termattrs.3 killchar.3 \
+	curs_termattrs.3 killwchar.3 \
+	curs_termattrs.3 longname.3 \
+	curs_termattrs.3 term_attrs.3 \
+	curs_termattrs.3 termattrs.3 \
+	curs_termattrs.3 termname.3 \
+	curs_termcap.3 termcap.3 \
+	curs_termcap.3 tgetent.3 \
+	curs_termcap.3 tgetflag.3 \
+	curs_termcap.3 tgetnum.3 \
+	curs_termcap.3 tgetstr.3 \
+	curs_termcap.3 tgoto.3 \
+	curs_termcap.3 tputs.3 \
+	curs_terminfo.3 del_curterm.3 \
+	curs_terminfo.3 mvcur.3 \
+	curs_terminfo.3 putp.3 \
+	curs_terminfo.3 restartterm.3 \
+	curs_terminfo.3 set_curterm.3 \
+	curs_terminfo.3 setterm.3 \
+	curs_terminfo.3 setupterm.3 \
+	curs_terminfo.3 tigetflag.3 \
+	curs_terminfo.3 tigetnum.3 \
+	curs_terminfo.3 tigetstr.3 \
+	curs_terminfo.3 tparm.3 \
+	curs_terminfo.3 tputs.3 \
+	curs_terminfo.3 vid_attr.3 \
+	curs_terminfo.3 vid_puts.3 \
+	curs_terminfo.3 vidattr.3 \
+	curs_terminfo.3 vidputs.3 \
+	curs_touch.3 is_linetouched.3 \
+	curs_touch.3 is_wintouched.3 \
+	curs_touch.3 touchline.3 \
+	curs_touch.3 touchwin.3 \
+	curs_touch.3 untouchwin.3 \
+	curs_touch.3 wtouchln.3 \
+	curs_trace.3 _nc_tracebits.3 \
+	curs_trace.3 _traceattr.3 \
+	curs_trace.3 _traceattr2.3 \
+	curs_trace.3 _tracechar.3 \
+	curs_trace.3 _tracechtype.3 \
+	curs_trace.3 _tracechtype2.3 \
+	curs_trace.3 _tracedump.3 \
+	curs_trace.3 _tracef.3 \
+	curs_trace.3 _tracemouse.3 \
+	curs_trace.3 trace.3 \
+	curs_util.3 delay_output.3 \
+	curs_util.3 filter.3 \
+	curs_util.3 flushinp.3 \
+	curs_util.3 getwin.3 \
+	curs_util.3 key_name.3 \
+	curs_util.3 keyname.3 \
+	curs_util.3 nofilter.3 \
+	curs_util.3 putwin.3 \
+	curs_util.3 unctrl.3 \
+	curs_util.3 use_env.3 \
+	curs_util.3 wunctrl.3 \
+	curs_window.3 delwin.3 \
+	curs_window.3 derwin.3 \
+	curs_window.3 dupwin.3 \
+	curs_window.3 mvderwin.3 \
+	curs_window.3 mvwin.3 \
+	curs_window.3 newwin.3 \
+	curs_window.3 subwin.3 \
+	curs_window.3 syncok.3 \
+	curs_window.3 wcursyncup.3 \
+	curs_window.3 wsyncdown.3 \
+	curs_window.3 wsyncup.3 \
+	default_colors.3 assume_default_colors.3 \
+	default_colors.3 use_default_colors.3 \
+	legacy_coding.3 use_legacy_coding.3 \
+	resizeterm.3 is_term_resized.3 \
+	resizeterm.3 resize_term.3
+
+.if defined(ENABLE_WIDEC)
+MLINKS+=curs_add_wch.3 add_wch.3 \
+	curs_add_wch.3 echo_wchar.3 \
+	curs_add_wch.3 mvadd_wch.3 \
+	curs_add_wch.3 mvwadd_wch.3 \
+	curs_add_wch.3 wadd_wch.3 \
+	curs_add_wch.3 wecho_wchar.3 \
+	curs_add_wchstr.3 add_wchnstr.3 \
+	curs_add_wchstr.3 add_wchstr.3 \
+	curs_add_wchstr.3 mvadd_wchnstr.3 \
+	curs_add_wchstr.3 mvadd_wchstr.3 \
+	curs_add_wchstr.3 mvwadd_wchnstr.3 \
+	curs_add_wchstr.3 mvwadd_wchstr.3 \
+	curs_add_wchstr.3 wadd_wchnstr.3 \
+	curs_add_wchstr.3 wadd_wchstr.3 \
+	curs_addwstr.3 addnwstr.3 \
+	curs_addwstr.3 addwstr.3 \
+	curs_addwstr.3 mvaddnwstr.3 \
+	curs_addwstr.3 mvaddwstr.3 \
+	curs_addwstr.3 mvwaddnwstr.3 \
+	curs_addwstr.3 mvwaddwstr.3 \
+	curs_addwstr.3 waddnwstr.3 \
+	curs_addwstr.3 waddwstr.3 \
+	curs_get_wch.3 get_wch.3 \
+	curs_get_wch.3 mvget_wch.3 \
+	curs_get_wch.3 mvwget_wch.3 \
+	curs_get_wch.3 unget_wch.3 \
+	curs_get_wch.3 wget_wch.3 \
+	curs_get_wstr.3 get_wstr.3 \
+	curs_get_wstr.3 getn_wstr.3 \
+	curs_get_wstr.3 mvget_wstr.3 \
+	curs_get_wstr.3 mvgetn_wstr.3 \
+	curs_get_wstr.3 mvwget_wstr.3 \
+	curs_get_wstr.3 mvwgetn_wstr.3 \
+	curs_get_wstr.3 wget_wstr.3 \
+	curs_get_wstr.3 wgetn_wstr.3 \
+	curs_in_wch.3 in_wch.3 \
+	curs_in_wch.3 mvin_wch.3 \
+	curs_in_wch.3 mvwin_wch.3 \
+	curs_in_wch.3 win_wch.3 \
+	curs_in_wchstr.3 in_wchnstr.3 \
+	curs_in_wchstr.3 in_wchstr.3 \
+	curs_in_wchstr.3 mvin_wchnstr.3 \
+	curs_in_wchstr.3 mvin_wchstr.3 \
+	curs_in_wchstr.3 mvwin_wchnstr.3 \
+	curs_in_wchstr.3 mvwin_wchstr.3 \
+	curs_in_wchstr.3 win_wchnstr.3 \
+	curs_in_wchstr.3 win_wchstr.3 \
+	curs_ins_wch.3 ins_wch.3 \
+	curs_ins_wch.3 mvins_wch.3 \
+	curs_ins_wch.3 mvwins_wch.3 \
+	curs_ins_wch.3 wins_wch.3 \
+	curs_ins_wstr.3 ins_nwstr.3 \
+	curs_ins_wstr.3 ins_wstr.3 \
+	curs_ins_wstr.3 mvins_nwstr.3 \
+	curs_ins_wstr.3 mvins_wstr.3 \
+	curs_ins_wstr.3 mvwins_nwstr.3 \
+	curs_ins_wstr.3 mvwins_wstr.3 \
+	curs_ins_wstr.3 wins_nwstr.3 \
+	curs_ins_wstr.3 wins_wstr.3 \
+	curs_inwstr.3 innwstr.3 \
+	curs_inwstr.3 inwstr.3 \
+	curs_inwstr.3 mvinnwstr.3 \
+	curs_inwstr.3 mvinwstr.3 \
+	curs_inwstr.3 mvwinnwstr.3 \
+	curs_inwstr.3 mvwinwstr.3 \
+	curs_inwstr.3 winnwstr.3 \
+	curs_inwstr.3 winwstr.3 \
+	curs_printw.3 mvprintw.3 \
+	curs_printw.3 mvwprintw.3 \
+	curs_printw.3 printw.3 \
+	curs_printw.3 vw_printw.3 \
+	curs_printw.3 vwprintw.3 \
+	curs_printw.3 wprintw.3 \
+	curs_scanw.3 mvscanw.3 \
+	curs_scanw.3 mvwscanw.3 \
+	curs_scanw.3 scanw.3 \
+	curs_scanw.3 vw_scanw.3 \
+	curs_scanw.3 vwscanw.3 \
+	curs_scanw.3 wscanw.3
+.endif
+
+
+.include <bsd.lib.mk>
+
+# Keep the .SUFFIXES line after the include of bsd.lib.mk
+.SUFFIXES: .3 .3x
+.3x.3:
+	cat ${.IMPSRC} > ${.TARGET}
--- /dev/null
+++ lib/ncurses/ncurses/pathnames.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 1989, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University 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 REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED 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.
+ *
+ *	@(#)pathnames.h	8.1 (Berkeley) 6/4/93
+ * $FreeBSD: src/lib/ncurses/ncurses/pathnames.h,v 1.3 2007/01/20 07:43:46 rafan Exp $
+ */
+
+#define	_PATH_DEF	".termcap /usr/share/misc/termcap"
+#define	_PATH_DEF_SEC	"/usr/share/misc/termcap"
--- /dev/null
+++ lib/ncurses/ncursesw/Makefile
@@ -0,0 +1,7 @@
+# $FreeBSD: src/lib/ncurses/ncursesw/Makefile,v 1.1 2007/03/09 12:11:57 rafan Exp $
+
+ENABLE_WIDEC=
+
+.PATH: ${.CURDIR}/../ncurses
+
+.include "${.CURDIR}/../ncurses/Makefile"
--- /dev/null
+++ lib/libkse/thread/thr_seterrno.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 1995 John Birrell <jb at 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. Neither the name of the author nor the names of any 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/libkse/thread/thr_seterrno.c,v 1.9 2007/10/09 13:42:29 obrien Exp $
+ */
+#include <pthread.h>
+#include "thr_private.h"
+
+/*
+ * This function needs to reference the global error variable which is
+ * normally hidden from the user. 
+ */
+#ifdef errno
+#undef errno;
+#endif
+extern int      errno;
+
+void
+_thread_seterrno(pthread_t thread, int error)
+{
+	/* Check for the initial thread: */
+	if (thread == _thr_initial)
+		/* The initial thread always uses the global error variable: */
+		errno = error;
+	else
+		/*
+		 * Threads other than the initial thread always use the error
+		 * field in the thread structureL 
+		 */
+		thread->error = error;
+}
--- /dev/null
+++ lib/libkse/thread/thr_barrier.c
@@ -0,0 +1,129 @@
+/*-
+ * Copyright (c) 2003 David Xu <davidxu at 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/libkse/thread/thr_barrier.c,v 1.4 2007/10/09 13:42:27 obrien Exp $
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+#include "namespace.h"
+#include <pthread.h>
+#include "un-namespace.h"
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_barrier_init);
+LT10_COMPAT_DEFAULT(pthread_barrier_init);
+LT10_COMPAT_PRIVATE(_pthread_barrier_wait);
+LT10_COMPAT_DEFAULT(pthread_barrier_wait);
+LT10_COMPAT_PRIVATE(_pthread_barrier_destroy);
+LT10_COMPAT_DEFAULT(pthread_barrier_destroy);
+
+__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;
+	int			ret, ret2;
+
+	if (barrier == NULL || *barrier == NULL)
+		return (EINVAL);
+
+	bar = *barrier;
+	if (bar->b_waiters > 0)
+		return (EBUSY);
+	*barrier = NULL;
+	ret  = _pthread_mutex_destroy(&bar->b_lock);
+	ret2 = _pthread_cond_destroy(&bar->b_cond);
+	free(bar);
+	return (ret ? ret : ret2);
+}
+
+int
+_pthread_barrier_init(pthread_barrier_t *barrier,
+		      const pthread_barrierattr_t *attr, unsigned count)
+{
+	pthread_barrier_t	bar;
+	int			ret;
+
+	if (barrier == NULL || count <= 0)
+		return (EINVAL);
+
+	bar = malloc(sizeof(struct pthread_barrier));
+	if (bar == NULL)
+		return (ENOMEM);
+
+	if ((ret = _pthread_mutex_init(&bar->b_lock, NULL)) != 0) {
+		free(bar);
+		return (ret);
+	}
+
+	if ((ret = _pthread_cond_init(&bar->b_cond, NULL)) != 0) {
+		_pthread_mutex_destroy(&bar->b_lock);
+		free(bar);
+		return (ret);
+	}
+
+	bar->b_waiters		= 0;
+	bar->b_count		= count;
+	bar->b_generation	= 0;
+	*barrier		= bar;
+
+	return (0);
+}
+
+int
+_pthread_barrier_wait(pthread_barrier_t *barrier)
+{
+	int ret, gen;
+	pthread_barrier_t bar;
+
+	if (barrier == NULL || *barrier == NULL)
+		return (EINVAL);
+
+	bar = *barrier;
+	if ((ret = _pthread_mutex_lock(&bar->b_lock)) != 0)
+		return (ret);
+
+	if (++bar->b_waiters == bar->b_count) {
+		/* Current thread is lastest thread */
+		bar->b_generation++;
+		bar->b_waiters = 0;
+		ret = _pthread_cond_broadcast(&bar->b_cond);
+		if (ret == 0)
+			ret = PTHREAD_BARRIER_SERIAL_THREAD;
+	} else {
+		gen = bar->b_generation;
+		do {
+			ret = _pthread_cond_wait(
+				&bar->b_cond, &bar->b_lock);
+		/* test generation to avoid bogus wakeup */
+		} while (ret == 0 && gen == bar->b_generation);
+	}
+	_pthread_mutex_unlock(&bar->b_lock);
+	return (ret);
+}
--- /dev/null
+++ lib/libkse/thread/thr_setprio.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 1995 John Birrell <jb at 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. Neither the name of the author nor the names of any 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/libkse/thread/thr_setprio.c,v 1.13 2007/10/09 13:42:29 obrien Exp $
+ */
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_setprio);
+LT10_COMPAT_DEFAULT(pthread_setprio);
+
+__weak_reference(_pthread_setprio, pthread_setprio);
+
+int
+_pthread_setprio(pthread_t pthread, int prio)
+{
+	int ret, policy;
+	struct sched_param param;
+
+	if ((ret = pthread_getschedparam(pthread, &policy, &param)) == 0) {
+		param.sched_priority = prio;
+		ret = pthread_setschedparam(pthread, policy, &param);
+	}
+
+	/* Return the error status: */
+	return (ret);
+}
--- /dev/null
+++ lib/libkse/thread/thr_select.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 1995-1998 John Birrell <jb at 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. Neither the name of the author nor the names of any 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/libkse/thread/thr_select.c,v 1.29 2007/10/09 13:42:29 obrien Exp $
+ */
+#include <unistd.h>
+#include <errno.h>
+#include <poll.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/fcntl.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(__select);
+LT10_COMPAT_DEFAULT(select);
+
+__weak_reference(__select, select);
+
+int 
+__select(int numfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
+	struct timeval *timeout)
+{
+	struct pthread *curthread = _get_curthread();
+	struct timespec ts;
+	int ret;
+
+	if (numfds == 0 && timeout != NULL) {
+		TIMEVAL_TO_TIMESPEC(timeout, &ts);
+		return nanosleep(&ts, NULL);
+	} else {
+		_thr_cancel_enter(curthread);
+		ret = __sys_select(numfds, readfds, writefds, exceptfds, timeout);
+		_thr_cancel_leave(curthread, 1);
+	}
+	return ret;
+}
--- /dev/null
+++ lib/libkse/thread/thr_fsync.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 1995-1998 John Birrell <jb at 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. Neither the name of the author nor the names of any 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/libkse/thread/thr_fsync.c,v 1.17 2007/10/09 13:42:28 obrien Exp $
+ */
+#include <unistd.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(__fsync);
+LT10_COMPAT_DEFAULT(fsync);
+
+__weak_reference(__fsync, fsync);
+
+int
+__fsync(int fd)
+{
+	struct pthread *curthread = _get_curthread();
+	int	ret;
+
+	_thr_cancel_enter(curthread);
+	ret = __sys_fsync(fd);
+	_thr_cancel_leave(curthread, 1);
+
+	return (ret);
+}
--- /dev/null
+++ lib/libkse/thread/thr_attr_setinheritsched.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 1998 Daniel Eischen <eischen at 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/libkse/thread/thr_attr_setinheritsched.c,v 1.9 2007/10/09 13:42:27 obrien Exp $
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_attr_setinheritsched);
+LT10_COMPAT_DEFAULT(pthread_attr_setinheritsched);
+
+__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);
+}
--- /dev/null
+++ lib/libkse/thread/thr_attr_getschedparam.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 1998 Daniel Eischen <eischen at 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/libkse/thread/thr_attr_getschedparam.c,v 1.9 2007/10/09 13:42:27 obrien Exp $
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_attr_getschedparam);
+LT10_COMPAT_DEFAULT(pthread_attr_getschedparam);
+
+__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);
+}
--- /dev/null
+++ lib/libkse/thread/thr_getprio.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 1995 John Birrell <jb at 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. Neither the name of the author nor the names of any 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/libkse/thread/thr_getprio.c,v 1.13 2007/10/09 13:42:28 obrien Exp $
+ */
+
+#include "namespace.h"
+#include <errno.h>
+#include <pthread.h>
+#include "un-namespace.h"
+
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_getprio);
+LT10_COMPAT_DEFAULT(pthread_getprio);
+
+__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);
+}
--- /dev/null
+++ lib/libkse/thread/thr_attr_getdetachstate.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 1997 John Birrell <jb at 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. Neither the name of the author nor the names of any 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/libkse/thread/thr_attr_getdetachstate.c,v 1.10 2007/10/09 13:42:27 obrien Exp $
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_attr_getdetachstate);
+LT10_COMPAT_DEFAULT(pthread_attr_getdetachstate);
+
+__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);
+}
--- /dev/null
+++ lib/libkse/thread/thr_system.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2000 Jason Evans <jasone at 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/libkse/thread/thr_system.c,v 1.10 2007/10/09 13:42:29 obrien Exp $
+ */
+
+#include <stdlib.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+extern int __system(const char *);
+
+LT10_COMPAT_PRIVATE(_system);
+LT10_COMPAT_DEFAULT(system);
+
+__weak_reference(_system, system);
+
+int
+_system(const char *string)
+{
+	struct pthread *curthread = _get_curthread();
+	int	ret;
+
+	_thr_cancel_enter(curthread);
+	ret = __system(string);
+	_thr_cancel_leave(curthread, 1);
+	
+	return ret;
+}
--- /dev/null
+++ lib/libkse/thread/thr_creat.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2000 Jason Evans <jasone at 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/libkse/thread/thr_creat.c,v 1.10 2007/10/09 13:42:27 obrien Exp $
+ */
+
+#include <fcntl.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(___creat);
+LT10_COMPAT_DEFAULT(creat);
+
+extern int __creat(const char *, mode_t);
+
+__weak_reference(___creat, creat);
+
+int
+___creat(const char *path, mode_t mode)
+{
+	struct pthread *curthread = _get_curthread();
+	int ret;
+
+	_thr_cancel_enter(curthread);
+	ret = __creat(path, mode);
+	/*
+	 * To avoid possible file handle leak, 
+	 * only check cancellation point if it is failure
+	 */
+	_thr_cancel_leave(curthread, (ret == -1));
+	
+	return ret;
+}
--- /dev/null
+++ lib/libkse/thread/thr_vfork.c
@@ -0,0 +1,17 @@
+/*
+ * $FreeBSD: src/lib/libkse/thread/thr_vfork.c,v 1.5 2007/10/09 13:42:29 obrien Exp $
+ */
+#include <unistd.h>
+
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_vfork);
+LT10_COMPAT_DEFAULT(vfork);
+
+__weak_reference(_vfork, vfork);
+
+int
+_vfork(void)
+{
+	return (fork());
+}
--- /dev/null
+++ lib/libkse/thread/thr_detach.c
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 1995 John Birrell <jb at 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. Neither the name of the author nor the names of any 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/libkse/thread/thr_detach.c,v 1.26 2007/10/09 13:42:27 obrien Exp $
+ */
+#include <sys/types.h>
+#include <machine/atomic.h>
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_detach);
+LT10_COMPAT_DEFAULT(pthread_detach);
+
+__weak_reference(_pthread_detach, pthread_detach);
+
+int
+_pthread_detach(pthread_t pthread)
+{
+	struct pthread *curthread = _get_curthread();
+	struct kse_mailbox *kmbx = NULL;
+	struct pthread *joiner;
+	int rval = 0;
+
+	/* Check for invalid calling parameters: */
+	if (pthread == NULL || pthread->magic != THR_MAGIC)
+		/* Return an invalid argument error: */
+		rval = EINVAL;
+
+	else if ((rval = _thr_ref_add(curthread, pthread,
+	    /*include dead*/1)) != 0) {
+		/* Return an error: */
+	}
+
+	/* Check if the thread is already detached: */
+	else if ((pthread->attr.flags & PTHREAD_DETACHED) != 0) {
+		/* Return an error: */
+		_thr_ref_delete(curthread, pthread);
+		rval = EINVAL;
+	} else {
+		/* Lock the detached thread: */
+		THR_SCHED_LOCK(curthread, pthread);
+
+		/* Flag the thread as detached: */
+		pthread->attr.flags |= PTHREAD_DETACHED;
+
+		/* Retrieve any joining thread and remove it: */
+		joiner = pthread->joiner;
+		if ((joiner != NULL) && (joiner->kseg == pthread->kseg)) {
+			/*
+			 * We already own the scheduler lock for the joiner.
+			 * Take advantage of that and make the joiner runnable.
+			 */
+			if (joiner->join_status.thread == pthread) {
+				/*
+				 * Set the return value for the woken thread:
+				 */
+				joiner->join_status.error = ESRCH;
+				joiner->join_status.ret = NULL;
+				joiner->join_status.thread = NULL;
+
+				kmbx = _thr_setrunnable_unlocked(joiner);
+			}
+			joiner = NULL;
+		}
+		THR_SCHED_UNLOCK(curthread, pthread);
+		/* See if there is a thread waiting in pthread_join(): */
+		if ((joiner != NULL) &&
+		    (_thr_ref_add(curthread, joiner, 0) == 0)) {
+			/* Lock the joiner before fiddling with it. */
+			THR_SCHED_LOCK(curthread, joiner);
+			if (joiner->join_status.thread == pthread) {
+				/*
+				 * Set the return value for the woken thread:
+				 */
+				joiner->join_status.error = ESRCH;
+				joiner->join_status.ret = NULL;
+				joiner->join_status.thread = NULL;
+
+				kmbx = _thr_setrunnable_unlocked(joiner);
+			}
+			THR_SCHED_UNLOCK(curthread, joiner);
+			_thr_ref_delete(curthread, joiner);
+		}
+		_thr_ref_delete(curthread, pthread);
+		if (kmbx != NULL)
+			kse_wakeup(kmbx);
+	}
+
+	/* Return the completion status: */
+	return (rval);
+}
--- /dev/null
+++ lib/libkse/thread/thr_msync.c
@@ -0,0 +1,36 @@
+/*
+ * David Leonard <d at openbsd.org>, 1999. Public Domain.
+ *
+ * $OpenBSD: uthread_msync.c,v 1.2 1999/06/09 07:16:17 d Exp $
+ *
+ * $FreeBSD: src/lib/libkse/thread/thr_msync.c,v 1.11 2007/10/09 13:42:28 obrien Exp $
+ */
+
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(__msync);
+LT10_COMPAT_DEFAULT(msync);
+
+__weak_reference(__msync, msync);
+
+int
+__msync(void *addr, size_t len, int flags)
+{
+	struct pthread *curthread = _get_curthread();
+	int	ret;
+
+	/*
+	 * XXX This is quite pointless unless we know how to get the
+	 * file descriptor associated with the memory, and lock it for
+	 * write. The only real use of this wrapper is to guarantee
+	 * a cancellation point, as per the standard. sigh.
+	 */
+	_thr_cancel_enter(curthread);
+	ret = __sys_msync(addr, len, flags);
+	_thr_cancel_leave(curthread, 1);
+
+	return ret;
+}
--- /dev/null
+++ lib/libkse/thread/thr_writev.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 1995-1998 John Birrell <jb at 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. Neither the name of the author nor the names of any 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/libkse/thread/thr_writev.c,v 1.27 2007/10/09 13:42:30 obrien Exp $
+ *
+ */
+#include <sys/types.h>
+#include <sys/fcntl.h>
+#include <sys/uio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(__writev);
+LT10_COMPAT_DEFAULT(writev);
+
+__weak_reference(__writev, writev);
+
+ssize_t
+__writev(int fd, const struct iovec *iov, int iovcnt)
+{
+	struct pthread *curthread = _get_curthread();
+	ssize_t ret;
+
+	_thr_cancel_enter(curthread);
+	ret = __sys_writev(fd, iov, iovcnt);
+	_thr_cancel_leave(curthread, 1);
+
+	return ret;
+}
--- /dev/null
+++ lib/libkse/thread/thr_mutex.c
@@ -0,0 +1,1832 @@
+/*
+ * Copyright (c) 1995 John Birrell <jb at 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. Neither the name of the author nor the names of any 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/libkse/thread/thr_mutex.c,v 1.53.2.1 2007/11/14 09:54:48 kris 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 {		\
+	_lock_destroy(&(m)->m_lock);	\
+	free(m);			\
+} while (0)
+
+
+/*
+ * Prototypes
+ */
+static struct kse_mailbox *mutex_handoff(struct pthread *,
+			    struct pthread_mutex *);
+static inline int	mutex_self_trylock(struct pthread *, pthread_mutex_t);
+static inline int	mutex_self_lock(struct pthread *, pthread_mutex_t);
+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 *);
+static inline pthread_t	mutex_queue_deq(pthread_mutex_t);
+static inline void	mutex_queue_remove(pthread_mutex_t, pthread_t);
+static inline void	mutex_queue_enq(pthread_mutex_t, pthread_t);
+static void		mutex_lock_backout(void *arg);
+
+static struct pthread_mutex_attr	static_mutex_attr =
+    PTHREAD_MUTEXATTR_STATIC_INITIALIZER;
+static pthread_mutexattr_t		static_mattr = &static_mutex_attr;
+
+LT10_COMPAT_PRIVATE(__pthread_mutex_init);
+LT10_COMPAT_PRIVATE(_pthread_mutex_init);
+LT10_COMPAT_DEFAULT(pthread_mutex_init);
+LT10_COMPAT_PRIVATE(__pthread_mutex_lock);
+LT10_COMPAT_PRIVATE(_pthread_mutex_lock);
+LT10_COMPAT_DEFAULT(pthread_mutex_lock);
+LT10_COMPAT_PRIVATE(__pthread_mutex_timedlock);
+LT10_COMPAT_PRIVATE(_pthread_mutex_timedlock);
+LT10_COMPAT_DEFAULT(pthread_mutex_timedlock);
+LT10_COMPAT_PRIVATE(__pthread_mutex_trylock);
+LT10_COMPAT_PRIVATE(_pthread_mutex_trylock);
+LT10_COMPAT_DEFAULT(pthread_mutex_trylock);
+LT10_COMPAT_PRIVATE(_pthread_mutex_destroy);
+LT10_COMPAT_DEFAULT(pthread_mutex_destroy);
+LT10_COMPAT_PRIVATE(_pthread_mutex_unlock);
+LT10_COMPAT_DEFAULT(pthread_mutex_unlock);
+
+/* Single underscore versions provided for libc internal usage: */
+__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);
+
+/* 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);
+
+
+
+int
+__pthread_mutex_init(pthread_mutex_t *mutex,
+    const pthread_mutexattr_t *mutex_attr)
+{
+	struct pthread_mutex *pmutex;
+	enum pthread_mutextype type;
+	int		protocol;
+	int		ceiling;
+	int		flags;
+	int		ret = 0;
+
+	if (mutex == NULL)
+		ret = EINVAL;
+
+	/* Check if default mutex attributes: */
+	else if (mutex_attr == NULL || *mutex_attr == NULL) {
+		/* Default to a (error checking) POSIX mutex: */
+		type = PTHREAD_MUTEX_ERRORCHECK;
+		protocol = PTHREAD_PRIO_NONE;
+		ceiling = THR_MAX_PRIORITY;
+		flags = 0;
+	}
+
+	/* Check mutex type: */
+	else if (((*mutex_attr)->m_type < PTHREAD_MUTEX_ERRORCHECK) ||
+	    ((*mutex_attr)->m_type >= PTHREAD_MUTEX_TYPE_MAX))
+		/* Return an invalid argument error: */
+		ret = EINVAL;
+
+	/* Check mutex protocol: */
+	else if (((*mutex_attr)->m_protocol < PTHREAD_PRIO_NONE) ||
+	    ((*mutex_attr)->m_protocol > PTHREAD_MUTEX_RECURSIVE))
+		/* Return an invalid argument error: */
+		ret = EINVAL;
+
+	else {
+		/* Use the requested mutex type and protocol: */
+		type = (*mutex_attr)->m_type;
+		protocol = (*mutex_attr)->m_protocol;
+		ceiling = (*mutex_attr)->m_ceiling;
+		flags = (*mutex_attr)->m_flags;
+	}
+
+	/* Check no errors so far: */
+	if (ret == 0) {
+		if ((pmutex = (pthread_mutex_t)
+		    malloc(sizeof(struct pthread_mutex))) == NULL)
+			ret = ENOMEM;
+		else if (_lock_init(&pmutex->m_lock, LCK_ADAPTIVE,
+		    _thr_lock_wait, _thr_lock_wakeup) != 0) {
+			free(pmutex);
+			*mutex = NULL;
+			ret = ENOMEM;
+		} else {
+			/* Set the mutex flags: */
+			pmutex->m_flags = flags;
+
+			/* Process according to mutex type: */
+			switch (type) {
+			/* case PTHREAD_MUTEX_DEFAULT: */
+			case PTHREAD_MUTEX_ERRORCHECK:
+			case PTHREAD_MUTEX_NORMAL:
+			case PTHREAD_MUTEX_ADAPTIVE_NP:
+				/* 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;
+				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);
+}
+
+int
+_pthread_mutex_init(pthread_mutex_t *mutex,
+    const pthread_mutexattr_t *mutex_attr)
+{
+	struct pthread_mutex_attr mattr, *mattrp;
+
+	if ((mutex_attr == NULL) || (*mutex_attr == NULL))
+		return (__pthread_mutex_init(mutex, &static_mattr));
+	else {
+		mattr = **mutex_attr;
+		mattr.m_flags |= MUTEX_FLAGS_PRIVATE;
+		mattrp = &mattr;
+		return (__pthread_mutex_init(mutex, &mattrp));
+	}
+}
+
+void
+_thr_mutex_reinit(pthread_mutex_t *mutex)
+{
+	_lock_reinit(&(*mutex)->m_lock, LCK_ADAPTIVE,
+	    _thr_lock_wait, _thr_lock_wakeup);
+	TAILQ_INIT(&(*mutex)->m_queue);
+	(*mutex)->m_owner = NULL;
+	(*mutex)->m_count = 0;
+	(*mutex)->m_refcount = 0;
+	(*mutex)->m_prio = 0;
+	(*mutex)->m_saved_prio = 0;
+}
+
+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 {
+		/* Lock the mutex structure: */
+		THR_LOCK_ACQUIRE(curthread, &(*mutex)->m_lock);
+
+		/*
+		 * Check to see if this mutex is in use:
+		 */
+		if (((*mutex)->m_owner != NULL) ||
+		    (!TAILQ_EMPTY(&(*mutex)->m_queue)) ||
+		    ((*mutex)->m_refcount != 0)) {
+			ret = EBUSY;
+
+			/* Unlock the mutex structure: */
+			THR_LOCK_RELEASE(curthread, &(*mutex)->m_lock);
+		} 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_LOCK_RELEASE(curthread, &m->m_lock);
+
+			/*
+			 * Free the memory allocated for the mutex
+			 * structure:
+			 */
+			MUTEX_ASSERT_NOT_OWNED(m);
+			MUTEX_DESTROY(m);
+		}
+	}
+
+	/* 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 = pthread_mutex_init(mutex, NULL);
+	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 = pthread_mutex_init(mutex, &static_mattr);
+	else
+		ret = 0;
+
+	THR_LOCK_RELEASE(thread, &_mutex_static_lock);
+
+	return (ret);
+}
+
+static int
+mutex_trylock_common(struct pthread *curthread, pthread_mutex_t *mutex)
+{
+	int private;
+	int ret = 0;
+
+	THR_ASSERT((mutex != NULL) && (*mutex != NULL),
+	    "Uninitialized mutex in pthread_mutex_trylock_basic");
+
+	/* Lock the mutex structure: */
+	THR_LOCK_ACQUIRE(curthread, &(*mutex)->m_lock);
+	private = (*mutex)->m_flags & MUTEX_FLAGS_PRIVATE;
+
+	/*
+	 * If the mutex was statically allocated, properly
+	 * initialize the tail queue.
+	 */
+	if (((*mutex)->m_flags & MUTEX_FLAGS_INITED) == 0) {
+		TAILQ_INIT(&(*mutex)->m_queue);
+		MUTEX_INIT_LINK(*mutex);
+		(*mutex)->m_flags |= MUTEX_FLAGS_INITED;
+	}
+
+	/* Process according to mutex type: */
+	switch ((*mutex)->m_protocol) {
+	/* Default POSIX mutex: */
+	case PTHREAD_PRIO_NONE:	
+		/* Check if this mutex is not locked: */
+		if ((*mutex)->m_owner == NULL) {
+			/* Lock the mutex for the running thread: */
+			(*mutex)->m_owner = curthread;
+
+			/* Add to the list of owned mutexes: */
+			MUTEX_ASSERT_NOT_OWNED(*mutex);
+			TAILQ_INSERT_TAIL(&curthread->mutexq,
+			    (*mutex), m_qe);
+		} else if ((*mutex)->m_owner == curthread)
+			ret = mutex_self_trylock(curthread, *mutex);
+		else
+			/* Return a busy error: */
+			ret = EBUSY;
+		break;
+
+	/* POSIX priority inheritence mutex: */
+	case PTHREAD_PRIO_INHERIT:
+		/* Check if this mutex is not locked: */
+		if ((*mutex)->m_owner == NULL) {
+			/* Lock the mutex for the running thread: */
+			(*mutex)->m_owner = curthread;
+
+			THR_SCHED_LOCK(curthread, 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_SCHED_UNLOCK(curthread, 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 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_SCHED_LOCK(curthread, 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_SCHED_UNLOCK(curthread, 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 a busy error: */
+			ret = EBUSY;
+		break;
+
+	/* Trap invalid mutex types: */
+	default:
+		/* Return an invalid argument error: */
+		ret = EINVAL;
+		break;
+	}
+
+	if (ret == 0 && private)
+		THR_CRITICAL_ENTER(curthread);
+
+	/* 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 (mutex == NULL)
+		ret = EINVAL;
+
+	/*
+	 * If the mutex is statically initialized, perform the dynamic
+	 * initialization:
+	 */
+	else 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 (mutex == NULL)
+		ret = EINVAL;
+
+	/*
+	 * If the mutex is statically initialized, perform the dynamic
+	 * initialization marking the mutex private (delete safe):
+	 */
+	else if ((*mutex != NULL) ||
+	    ((ret = init_static_private(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)
+{
+	int	private;
+	int	ret = 0;
+
+	THR_ASSERT((m != NULL) && (*m != NULL),
+	    "Uninitialized mutex in pthread_mutex_trylock_basic");
+
+	if (abstime != NULL && (abstime->tv_sec < 0 || abstime->tv_nsec < 0 ||
+	    abstime->tv_nsec >= 1000000000))
+		return (EINVAL);
+
+	/* Reset the interrupted flag: */
+	curthread->interrupted = 0;
+	curthread->timeout = 0;
+	curthread->wakeup_time.tv_sec = -1;
+
+	private = (*m)->m_flags & MUTEX_FLAGS_PRIVATE;
+
+	/*
+	 * 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) {
+		/* Default POSIX mutex: */
+		case PTHREAD_PRIO_NONE:
+			if ((*m)->m_owner == NULL) {
+				/* Lock the mutex for this thread: */
+				(*m)->m_owner = curthread;
+
+				/* Add to the list of owned mutexes: */
+				MUTEX_ASSERT_NOT_OWNED(*m);
+				TAILQ_INSERT_TAIL(&curthread->mutexq,
+				    (*m), m_qe);
+				if (private)
+					THR_CRITICAL_ENTER(curthread);
+
+				/* Unlock the mutex structure: */
+				THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
+			} else if ((*m)->m_owner == curthread) {
+				ret = mutex_self_lock(curthread, *m);
+
+				/* 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;
+				curthread->sigbackout = mutex_lock_backout;
+				/*
+				 * This thread is active and is in a critical
+				 * region (holding the mutex lock); we should
+				 * be able to safely set the state.
+				 */
+				THR_SCHED_LOCK(curthread, curthread);
+				/* Set the wakeup time: */
+				if (abstime) {
+					curthread->wakeup_time.tv_sec =
+						abstime->tv_sec;
+					curthread->wakeup_time.tv_nsec =
+						abstime->tv_nsec;
+				}
+
+				THR_SET_STATE(curthread, PS_MUTEX_WAIT);
+				THR_SCHED_UNLOCK(curthread, curthread);
+
+				/* Unlock the mutex structure: */
+				THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
+
+				/* Schedule the next thread: */
+				_thr_sched_switch(curthread);
+
+				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;
+				curthread->sigbackout = NULL;
+			}
+			break;
+
+		/* 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_SCHED_LOCK(curthread, 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_SCHED_UNLOCK(curthread, curthread);
+
+				/* Add to the list of owned mutexes: */
+				MUTEX_ASSERT_NOT_OWNED(*m);
+				TAILQ_INSERT_TAIL(&curthread->mutexq,
+				    (*m), m_qe);
+				if (private)
+					THR_CRITICAL_ENTER(curthread);
+
+				/* Unlock the mutex structure: */
+				THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
+			} else if ((*m)->m_owner == curthread) {
+				ret = mutex_self_lock(curthread, *m);
+
+				/* 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;
+				curthread->sigbackout = mutex_lock_backout;
+
+				/*
+				 * This thread is active and is in a critical
+				 * region (holding the mutex lock); we should
+				 * be able to safely set the state.
+				 */
+				if (curthread->active_priority > (*m)->m_prio)
+					/* Adjust priorities: */
+					mutex_priority_adjust(curthread, *m);
+
+				THR_SCHED_LOCK(curthread, curthread);
+				/* Set the wakeup time: */
+				if (abstime) {
+					curthread->wakeup_time.tv_sec =
+						abstime->tv_sec;
+					curthread->wakeup_time.tv_nsec =
+						abstime->tv_nsec;
+				}
+				THR_SET_STATE(curthread, PS_MUTEX_WAIT);
+				THR_SCHED_UNLOCK(curthread, curthread);
+
+				/* Unlock the mutex structure: */
+				THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
+
+				/* Schedule the next thread: */
+				_thr_sched_switch(curthread);
+
+				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;
+				curthread->sigbackout = 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_SCHED_LOCK(curthread, 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_SCHED_UNLOCK(curthread, curthread);
+
+				/* Add to the list of owned mutexes: */
+				MUTEX_ASSERT_NOT_OWNED(*m);
+				TAILQ_INSERT_TAIL(&curthread->mutexq,
+				    (*m), m_qe);
+				if (private)
+					THR_CRITICAL_ENTER(curthread);
+
+				/* Unlock the mutex structure: */
+				THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
+			} else if ((*m)->m_owner == curthread) {
+				ret = mutex_self_lock(curthread, *m);
+
+				/* 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;
+				curthread->sigbackout = mutex_lock_backout;
+
+				/* Clear any previous error: */
+				curthread->error = 0;
+
+				/*
+				 * This thread is active and is in a critical
+				 * region (holding the mutex lock); we should
+				 * be able to safely set the state.
+				 */
+
+				THR_SCHED_LOCK(curthread, curthread);
+				/* Set the wakeup time: */
+				if (abstime) {
+					curthread->wakeup_time.tv_sec =
+						abstime->tv_sec;
+					curthread->wakeup_time.tv_nsec =
+						abstime->tv_nsec;
+				}
+				THR_SET_STATE(curthread, PS_MUTEX_WAIT);
+				THR_SCHED_UNLOCK(curthread, curthread);
+
+				/* Unlock the mutex structure: */
+				THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
+
+				/* Schedule the next thread: */
+				_thr_sched_switch(curthread);
+
+				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;
+				curthread->sigbackout = 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) &&
+	    (curthread->interrupted == 0) && (curthread->timeout == 0));
+
+	if (ret == 0 && (*m)->m_owner != curthread && curthread->timeout)
+		ret = ETIMEDOUT;
+
+	/*
+	 * Check to see if this thread was interrupted and
+	 * is still in the mutex queue of waiting threads:
+	 */
+	if (curthread->interrupted != 0) {
+		/* Remove this thread from the mutex queue. */
+		THR_LOCK_ACQUIRE(curthread, &(*m)->m_lock);
+		if (THR_IN_SYNCQ(curthread))
+			mutex_queue_remove(*m, curthread);
+		THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
+
+		/* Check for asynchronous cancellation. */
+		if (curthread->continuation != NULL)
+			curthread->continuation((void *) curthread);
+	}
+
+	/* Return the completion status: */
+	return (ret);
+}
+
+int
+__pthread_mutex_lock(pthread_mutex_t *m)
+{
+	struct pthread *curthread;
+	int	ret = 0;
+
+	if (_thr_initial == NULL)
+		_libpthread_init(NULL);
+
+	curthread = _get_curthread();
+	if (m == NULL)
+		ret = EINVAL;
+
+	/*
+	 * If the mutex is statically initialized, perform the dynamic
+	 * initialization:
+	 */
+	else 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;
+
+	if (_thr_initial == NULL)
+		_libpthread_init(NULL);
+	curthread = _get_curthread();
+
+	if (m == NULL)
+		ret = EINVAL;
+
+	/*
+	 * If the mutex is statically initialized, perform the dynamic
+	 * initialization marking it private (delete safe):
+	 */
+	else 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;
+
+	if (_thr_initial == NULL)
+		_libpthread_init(NULL);
+
+	curthread = _get_curthread();
+	if (m == NULL)
+		ret = EINVAL;
+
+	/*
+	 * If the mutex is statically initialized, perform the dynamic
+	 * initialization:
+	 */
+	else 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;
+
+	if (_thr_initial == NULL)
+		_libpthread_init(NULL);
+	curthread = _get_curthread();
+
+	if (m == NULL)
+		ret = EINVAL;
+
+	/*
+	 * If the mutex is statically initialized, perform the dynamic
+	 * initialization marking it private (delete safe):
+	 */
+	else 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) {
+		THR_LOCK_ACQUIRE(curthread, &(*m)->m_lock);
+		(*m)->m_refcount--;
+		THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
+	}
+	return (ret);
+}
+
+static inline int
+mutex_self_trylock(struct pthread *curthread, pthread_mutex_t m)
+{
+	int	ret = 0;
+
+	switch (m->m_type) {
+	/* case PTHREAD_MUTEX_DEFAULT: */
+	case PTHREAD_MUTEX_ERRORCHECK:
+	case PTHREAD_MUTEX_NORMAL:
+	case PTHREAD_MUTEX_ADAPTIVE_NP:
+		ret = EBUSY; 
+		break;
+
+	case PTHREAD_MUTEX_RECURSIVE:
+		/* Increment the lock count: */
+		m->m_count++;
+		break;
+
+	default:
+		/* Trap invalid mutex types; */
+		ret = EINVAL;
+	}
+
+	return (ret);
+}
+
+static inline int
+mutex_self_lock(struct pthread *curthread, pthread_mutex_t m)
+{
+	int ret = 0;
+
+	/*
+	 * Don't allow evil recursive mutexes for private use
+	 * in libc and libpthread.
+	 */
+	if (m->m_flags & MUTEX_FLAGS_PRIVATE)
+		PANIC("Recurse on a private mutex.");
+
+	switch (m->m_type) {
+	/* case PTHREAD_MUTEX_DEFAULT: */
+	case PTHREAD_MUTEX_ERRORCHECK:
+	case PTHREAD_MUTEX_ADAPTIVE_NP:
+		/*
+		 * 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.
+		 */
+
+		THR_SCHED_LOCK(curthread, curthread);
+		THR_SET_STATE(curthread, PS_DEADLOCK);
+		THR_SCHED_UNLOCK(curthread, curthread);
+
+		/* Unlock the mutex structure: */
+		THR_LOCK_RELEASE(curthread, &m->m_lock);
+
+		/* Schedule the next thread: */
+		_thr_sched_switch(curthread);
+		break;
+
+	case PTHREAD_MUTEX_RECURSIVE:
+		/* Increment the lock count: */
+		m->m_count++;
+		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();
+	struct kse_mailbox *kmbx = NULL;
+	int ret = 0;
+
+	if (m == NULL || *m == NULL)
+		ret = EINVAL;
+	else {
+		/* Lock the mutex structure: */
+		THR_LOCK_ACQUIRE(curthread, &(*m)->m_lock);
+
+		/* Process according to mutex type: */
+		switch ((*m)->m_protocol) {
+		/* Default POSIX mutex: */
+		case PTHREAD_PRIO_NONE:
+			/*
+			 * 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;
+
+				/* Remove the mutex from the threads queue. */
+				MUTEX_ASSERT_IS_OWNED(*m);
+				TAILQ_REMOVE(&(*m)->m_owner->mutexq,
+				    (*m), m_qe);
+				MUTEX_INIT_LINK(*m);
+
+				/*
+				 * Hand off the mutex to the next waiting
+				 * thread:
+				 */
+				kmbx = mutex_handoff(curthread, *m);
+			}
+			break;
+
+		/* 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_SCHED_LOCK(curthread, 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_SCHED_UNLOCK(curthread, curthread);
+
+				/* Remove the mutex from the threads queue. */
+				MUTEX_ASSERT_IS_OWNED(*m);
+				TAILQ_REMOVE(&(*m)->m_owner->mutexq,
+				    (*m), m_qe);
+				MUTEX_INIT_LINK(*m);
+
+				/*
+				 * Hand off the mutex to the next waiting
+				 * thread:
+				 */
+				kmbx = 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_SCHED_LOCK(curthread, 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_SCHED_UNLOCK(curthread, curthread);
+
+				/* Remove the mutex from the threads queue. */
+				MUTEX_ASSERT_IS_OWNED(*m);
+				TAILQ_REMOVE(&(*m)->m_owner->mutexq,
+				    (*m), m_qe);
+				MUTEX_INIT_LINK(*m);
+
+				/*
+				 * Hand off the mutex to the next waiting
+				 * thread:
+				 */
+				kmbx = 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++;
+
+		/* Leave the critical region if this is a private mutex. */
+		if ((ret == 0) && ((*m)->m_flags & MUTEX_FLAGS_PRIVATE))
+			THR_CRITICAL_LEAVE(curthread);
+
+		/* Unlock the mutex structure: */
+		THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
+
+		if (kmbx != NULL)
+			kse_wakeup(kmbx);
+	}
+
+	/* 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->mutexq);
+		if (m != NULL) {
+			THR_LOCK_ACQUIRE(curthread, &m->m_lock);
+			/*
+			 * Make sure the thread still owns the lock.
+			 */
+			if (m == TAILQ_FIRST(&pthread->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_SCHED_LOCK(curthread, pthread);
+
+		if (((pthread->sflags & THR_FLAGS_IN_SYNCQ) == 0) ||
+		    ((m = pthread->data.mutex) == NULL))
+			THR_SCHED_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_SCHED_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->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_SCHED_LOCK(curthread, pthread);
+
+		if ((pthread->flags & THR_FLAGS_IN_RUNQ) == 0) {
+			/*
+			 * 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_SCHED_UNLOCK(curthread, pthread);
+	}
+}
+
+void
+_mutex_unlock_private(pthread_t pthread)
+{
+	struct pthread_mutex	*m, *m_next;
+
+	for (m = TAILQ_FIRST(&pthread->mutexq); m != NULL; m = m_next) {
+		m_next = TAILQ_NEXT(m, m_qe);
+		if ((m->m_flags & MUTEX_FLAGS_PRIVATE) != 0)
+			pthread_mutex_unlock(&m);
+	}
+}
+
+/*
+ * This is called by the current thread when it wants to back out of a
+ * mutex_lock in order to run a signal handler.
+ */
+static void
+mutex_lock_backout(void *arg)
+{
+	struct pthread *curthread = (struct pthread *)arg;
+	struct pthread_mutex *m;
+
+	if ((curthread->sflags & THR_FLAGS_IN_SYNCQ) != 0) {
+		/*
+		 * Any other thread may clear the "in sync queue flag",
+		 * but only the current thread can clear the pointer
+		 * to the mutex.  So if the flag is set, we can
+		 * guarantee that the pointer to the mutex is valid.
+		 * The only problem may be if the mutex is destroyed
+		 * out from under us, but that should be considered
+		 * an application bug.
+		 */
+		m = curthread->data.mutex;
+
+		/* Lock the mutex structure: */
+		THR_LOCK_ACQUIRE(curthread, &m->m_lock);
+
+
+		/*
+		 * Check to make sure this thread doesn't already own
+		 * the mutex.  Since mutexes are unlocked with direct
+		 * handoffs, it is possible the previous owner gave it
+		 * to us after we checked the sync queue flag and before
+		 * we locked the mutex structure.
+		 */
+		if (m->m_owner == curthread) {
+			THR_LOCK_RELEASE(curthread, &m->m_lock);
+			mutex_unlock_common(&m, /* add_reference */ 0);
+		} else {
+			/*
+			 * Remove ourselves from the mutex queue and
+			 * clear the pointer to the mutex.  We may no
+			 * longer be in the mutex queue, but the removal
+			 * function will DTRT.
+			 */
+			mutex_queue_remove(m, curthread);
+			curthread->data.mutex = NULL;
+			THR_LOCK_RELEASE(curthread, &m->m_lock);
+		}
+	}
+	/* No need to call this again. */
+	curthread->sigbackout = NULL;
+}
+
+/*
+ * 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 struct kse_mailbox *
+mutex_handoff(struct pthread *curthread, struct pthread_mutex *mutex)
+{
+	struct kse_mailbox *kmbx = NULL;
+	struct pthread *pthread;
+
+	/* 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_SCHED_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->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->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->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: */
+		kmbx = _thr_setrunnable_unlocked(pthread);
+
+		/* Add a preemption point. */
+		if ((curthread->kseg == pthread->kseg) &&
+		    (pthread->active_priority > curthread->active_priority))
+			curthread->critical_yield = 1;
+
+		if (mutex->m_owner == pthread) {
+			/* We're done; a valid owner was found. */
+			if (mutex->m_flags & MUTEX_FLAGS_PRIVATE)
+				THR_CRITICAL_ENTER(pthread);
+			THR_SCHED_UNLOCK(curthread, pthread);
+			break;
+		}
+		THR_SCHED_UNLOCK(curthread, pthread);
+		/* 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 (kmbx);
+}
+
+/*
+ * Dequeue a waiting thread from the head of a mutex queue in descending
+ * priority order.
+ */
+static inline 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;
+
+		/*
+		 * Only exit the loop if the thread hasn't been
+		 * cancelled.
+		 */
+		if (pthread->interrupted == 0)
+			break;
+	}
+
+	return (pthread);
+}
+
+/*
+ * Remove a waiting thread from a mutex queue in descending priority order.
+ */
+static inline void
+mutex_queue_remove(pthread_mutex_t mutex, pthread_t pthread)
+{
+	if ((pthread->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 inline 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;
+}
--- /dev/null
+++ lib/libkse/thread/thr_rtld.c
@@ -0,0 +1,302 @@
+/*
+ * Copyright (c) 2001 Alexander Kabaev
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer
+ *    in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD: src/lib/libkse/thread/thr_rtld.c,v 1.7 2007/10/09 13:42:29 obrien Exp $
+ */
+#include <sys/cdefs.h>
+#include <stdlib.h>
+
+#include "rtld_lock.h"
+#include "thr_private.h"
+
+static int	_thr_rtld_clr_flag(int);
+static void	*_thr_rtld_lock_create(void);
+static void	_thr_rtld_lock_destroy(void *);
+static void	_thr_rtld_lock_release(void *);
+static void	_thr_rtld_rlock_acquire(void *);
+static int	_thr_rtld_set_flag(int);
+static void	_thr_rtld_wlock_acquire(void *);
+
+#ifdef NOTYET
+static void *
+_thr_rtld_lock_create(void)
+{
+	pthread_rwlock_t prwlock;
+	if (_pthread_rwlock_init(&prwlock, NULL))
+		return (NULL);
+	return (prwlock);
+}
+
+static void
+_thr_rtld_lock_destroy(void *lock)
+{
+	pthread_rwlock_t prwlock;
+
+	prwlock = (pthread_rwlock_t)lock;
+	if (prwlock != NULL)
+		_pthread_rwlock_destroy(&prwlock);
+}
+
+static void
+_thr_rtld_rlock_acquire(void *lock)
+{
+	pthread_rwlock_t prwlock;
+
+	prwlock = (pthread_rwlock_t)lock;
+	_thr_rwlock_rdlock(&prwlock);
+}
+
+static void
+_thr_rtld_wlock_acquire(void *lock)
+{
+	pthread_rwlock_t prwlock;
+
+	prwlock = (pthread_rwlock_t)lock;
+	_thr_rwlock_wrlock(&prwlock);
+}
+
+static void
+_thr_rtld_lock_release(void *lock)
+{
+	pthread_rwlock_t prwlock;
+
+	prwlock = (pthread_rwlock_t)lock;
+	_thr_rwlock_unlock(&prwlock);
+}
+
+
+static int
+_thr_rtld_set_flag(int mask)
+{
+	struct pthread *curthread;
+	int bits;
+
+	curthread = _get_curthread();
+	if (curthread != NULL) {
+		bits = curthread->rtld_bits;
+		curthread->rtld_bits |= mask;
+	} else {
+		bits = 0;
+		PANIC("No current thread in rtld call");
+	}
+
+	return (bits);
+}
+
+static int
+_thr_rtld_clr_flag(int mask)
+{
+	struct pthread *curthread;
+	int bits;
+
+	curthread = _get_curthread();
+	if (curthread != NULL) {
+		bits = curthread->rtld_bits;
+		curthread->rtld_bits &= ~mask;
+	} else {
+		bits = 0;
+		PANIC("No current thread in rtld call");
+	}
+	return (bits);
+}
+
+void
+_thr_rtld_init(void)
+{
+	struct RtldLockInfo li;
+
+	li.lock_create  = _thr_rtld_lock_create;
+	li.lock_destroy = _thr_rtld_lock_destroy;
+	li.rlock_acquire = _thr_rtld_rlock_acquire;
+	li.wlock_acquire = _thr_rtld_wlock_acquire;
+	li.lock_release  = _thr_rtld_lock_release;
+	li.thread_set_flag = _thr_rtld_set_flag;
+	li.thread_clr_flag = _thr_rtld_clr_flag;
+	li.at_fork = NULL;
+	_rtld_thread_init(&li);
+}
+
+void
+_thr_rtld_fini(void)
+{
+	_rtld_thread_init(NULL);
+}
+#endif
+
+struct rtld_kse_lock {
+	struct lock	lck;
+	struct kse	*owner;
+	kse_critical_t	crit;
+	int		count;
+	int		write;
+};
+
+static void *
+_thr_rtld_lock_create(void)
+{
+	struct rtld_kse_lock *l;
+
+	if ((l = malloc(sizeof(struct rtld_kse_lock))) != NULL) {
+		_lock_init(&l->lck, LCK_ADAPTIVE, _kse_lock_wait,
+		    _kse_lock_wakeup);
+		l->owner = NULL;
+		l->count = 0;
+		l->write = 0;
+	}
+	return (l);
+}
+
+static void
+_thr_rtld_lock_destroy(void *lock)
+{
+	/* XXX We really can not free memory after a fork() */
+#if 0
+	struct rtld_kse_lock *l;
+
+	l = (struct rtld_kse_lock *)lock;
+	_lock_destroy(&l->lck);
+	free(l);
+#endif
+	return;
+}
+
+static void
+_thr_rtld_rlock_acquire(void *lock)
+{
+	struct rtld_kse_lock *l;
+	kse_critical_t crit;
+	struct kse *curkse;
+
+	l  = (struct rtld_kse_lock *)lock;
+	crit = _kse_critical_enter();
+	curkse = _get_curkse();
+	if (l->owner == curkse) {
+		l->count++;
+		_kse_critical_leave(crit);	/* probably not necessary */
+	} else {
+		KSE_LOCK_ACQUIRE(curkse, &l->lck);
+		l->crit = crit;
+		l->owner = curkse;
+		l->count = 1;
+		l->write = 0;
+	}
+}
+
+static void
+_thr_rtld_wlock_acquire(void *lock)
+{
+	struct rtld_kse_lock *l;
+	kse_critical_t crit;
+	struct kse *curkse;
+
+	l = (struct rtld_kse_lock *)lock;
+	crit = _kse_critical_enter();
+	curkse = _get_curkse();
+	if (l->owner == curkse) {
+		_kse_critical_leave(crit);
+		PANIC("Recursive write lock attempt on rtld lock");
+	} else {
+		KSE_LOCK_ACQUIRE(curkse, &l->lck);
+		l->crit = crit;
+		l->owner = curkse;
+		l->count = 1;
+		l->write = 1;
+	}
+}
+
+static void
+_thr_rtld_lock_release(void *lock)
+{
+	struct rtld_kse_lock *l;
+	kse_critical_t crit;
+	struct kse *curkse;
+
+	l = (struct rtld_kse_lock *)lock;
+	crit = _kse_critical_enter();
+	curkse = _get_curkse();
+	if (l->owner != curkse) {
+		/*
+		 * We might want to forcibly unlock the rtld lock
+		 * and/or disable threaded mode so there is better
+		 * chance that the panic will work.  Otherwise,
+		 * we could end up trying to take the rtld lock
+		 * again.
+		 */
+		_kse_critical_leave(crit);
+		PANIC("Attempt to unlock rtld lock when not owner.");
+	} else {
+		l->count--;
+		if (l->count == 0) {
+			/*
+			 * If there ever is a count associated with
+			 * _kse_critical_leave(), we'll need to add
+			 * another call to it here with the crit
+			 * value from above.
+			 */
+			crit  = l->crit;
+			l->owner = NULL;
+			l->write = 0;
+			KSE_LOCK_RELEASE(curkse, &l->lck);
+		}
+		_kse_critical_leave(crit);
+	}
+}
+
+
+static int
+_thr_rtld_set_flag(int mask)
+{
+	return (0);
+}
+
+static int
+_thr_rtld_clr_flag(int mask)
+{
+	return (0);
+}
+
+void
+_thr_rtld_init(void)
+{
+	struct RtldLockInfo li;
+
+	li.lock_create  = _thr_rtld_lock_create;
+	li.lock_destroy = _thr_rtld_lock_destroy;
+	li.rlock_acquire = _thr_rtld_rlock_acquire;
+	li.wlock_acquire = _thr_rtld_wlock_acquire;
+	li.lock_release  = _thr_rtld_lock_release;
+	li.thread_set_flag = _thr_rtld_set_flag;
+	li.thread_clr_flag = _thr_rtld_clr_flag;
+	li.at_fork = NULL;
+	_rtld_thread_init(&li);
+}
+
+void
+_thr_rtld_fini(void)
+{
+	_rtld_thread_init(NULL);
+}
--- /dev/null
+++ lib/libkse/thread/thr_attr_init.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 1996 John Birrell <jb at 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. Neither the name of the author nor the names of any 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/libkse/thread/thr_attr_init.c,v 1.13 2007/10/09 13:42:27 obrien Exp $
+ */
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_attr_init);
+LT10_COMPAT_DEFAULT(pthread_attr_init);
+
+__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;
+		pattr->stacksize_attr = _thr_stack_default;
+
+		/* Return a pointer to the attribute object: */
+		*attr = pattr;
+		ret = 0;
+	}
+	return(ret);
+}
--- /dev/null
+++ lib/libkse/thread/thr_attr_getscope.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 1998 Daniel Eischen <eischen at 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/libkse/thread/thr_attr_getscope.c,v 1.9 2007/10/09 13:42:27 obrien Exp $
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_attr_getscope);
+LT10_COMPAT_DEFAULT(pthread_attr_getscope);
+
+__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);
+}
--- /dev/null
+++ lib/libkse/thread/thr_nanosleep.c
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 1995 John Birrell <jb at 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. Neither the name of the author nor the names of any 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/libkse/thread/thr_nanosleep.c,v 1.28 2007/10/09 13:42:28 obrien Exp $
+ */
+#include <stdio.h>
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(__nanosleep);
+LT10_COMPAT_PRIVATE(_nanosleep);
+LT10_COMPAT_DEFAULT(nanosleep);
+
+__weak_reference(__nanosleep, nanosleep);
+
+int
+_nanosleep(const struct timespec *time_to_sleep,
+    struct timespec *time_remaining)
+{
+	struct pthread	*curthread = _get_curthread();
+	int             ret = 0;
+	struct timespec ts, ts1;
+	struct timespec remaining_time;
+	struct timespec wakeup_time;
+
+	/* Check if the time to sleep is legal: */
+	if ((time_to_sleep == NULL) || (time_to_sleep->tv_sec < 0) ||
+	    (time_to_sleep->tv_nsec < 0) ||
+	    (time_to_sleep->tv_nsec >= 1000000000)) {
+		/* Return an EINVAL error : */
+		errno = EINVAL;
+		ret = -1;
+	} else {
+		if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM)
+			return (__sys_nanosleep(time_to_sleep, time_remaining));
+			
+		KSE_GET_TOD(curthread->kse, &ts);
+
+		/* Calculate the time for the current thread to wake up: */
+		TIMESPEC_ADD(&wakeup_time, &ts, time_to_sleep);
+
+		THR_LOCK_SWITCH(curthread);
+		curthread->interrupted = 0;
+		curthread->wakeup_time = wakeup_time;
+		THR_SET_STATE(curthread, PS_SLEEP_WAIT);
+
+		/* Reschedule the current thread to sleep: */
+		_thr_sched_switch_unlocked(curthread);
+
+		/* Calculate the remaining time to sleep: */
+		KSE_GET_TOD(curthread->kse, &ts1);
+		remaining_time.tv_sec = time_to_sleep->tv_sec
+		    + ts.tv_sec - ts1.tv_sec;
+		remaining_time.tv_nsec = time_to_sleep->tv_nsec
+		    + ts.tv_nsec - ts1.tv_nsec;
+
+		/* Check if the nanosecond field has underflowed: */
+		if (remaining_time.tv_nsec < 0) {
+			/* Handle the underflow: */
+			remaining_time.tv_sec -= 1;
+			remaining_time.tv_nsec += 1000000000;
+		}
+		/* Check if the nanosecond field has overflowed: */
+		else if (remaining_time.tv_nsec >= 1000000000) {
+			/* Handle the overflow: */
+			remaining_time.tv_sec += 1;
+			remaining_time.tv_nsec -= 1000000000;
+		}
+
+		/* Check if the sleep was longer than the required time: */
+		if (remaining_time.tv_sec < 0) {
+			/* Reset the time left: */
+			remaining_time.tv_sec = 0;
+			remaining_time.tv_nsec = 0;
+		}
+
+		/* Check if the time remaining is to be returned: */
+		if (time_remaining != NULL) {
+			/* Return the actual time slept: */
+			time_remaining->tv_sec = remaining_time.tv_sec;
+			time_remaining->tv_nsec = remaining_time.tv_nsec;
+		}
+
+		/* Check if the sleep was interrupted: */
+		if (curthread->interrupted) {
+			/* Return an EINTR error : */
+			errno = EINTR;
+			ret = -1;
+		}
+	}
+	return (ret);
+}
+
+int
+__nanosleep(const struct timespec *time_to_sleep,
+    struct timespec *time_remaining)
+{
+	struct pthread *curthread = _get_curthread();
+	int		ret;
+
+	_thr_cancel_enter(curthread);
+	ret = _nanosleep(time_to_sleep, time_remaining);
+	_thr_cancel_leave(curthread, 1);
+
+	return (ret);
+}
--- /dev/null
+++ lib/libkse/thread/thr_mattr_kind_np.c
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 1996 Jeffrey Hsu <hsu at 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. Neither the name of the author nor the names of any 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/libkse/thread/thr_mattr_kind_np.c,v 1.12 2007/10/09 13:42:28 obrien Exp $
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_mutexattr_setkind_np);
+LT10_COMPAT_DEFAULT(pthread_mutexattr_setkind_np);
+LT10_COMPAT_PRIVATE(_pthread_mutexattr_getkind_np);
+LT10_COMPAT_DEFAULT(pthread_mutexattr_getkind_np);
+LT10_COMPAT_PRIVATE(_pthread_mutexattr_gettype);
+LT10_COMPAT_DEFAULT(pthread_mutexattr_gettype);
+LT10_COMPAT_PRIVATE(_pthread_mutexattr_settype);
+LT10_COMPAT_DEFAULT(pthread_mutexattr_settype);
+
+__weak_reference(_pthread_mutexattr_setkind_np, pthread_mutexattr_setkind_np);
+__weak_reference(_pthread_mutexattr_getkind_np, pthread_mutexattr_getkind_np);
+__weak_reference(_pthread_mutexattr_gettype, pthread_mutexattr_gettype);
+__weak_reference(_pthread_mutexattr_settype, pthread_mutexattr_settype);
+
+int
+_pthread_mutexattr_setkind_np(pthread_mutexattr_t *attr, int kind)
+{
+	int	ret;
+	if (attr == NULL || *attr == NULL) {
+		errno = EINVAL;
+		ret = -1;
+	} else {
+		(*attr)->m_type = kind;
+		ret = 0;
+	}
+	return(ret);
+}
+
+int
+_pthread_mutexattr_getkind_np(pthread_mutexattr_t attr)
+{
+	int	ret;
+	if (attr == NULL) {
+		errno = EINVAL;
+		ret = -1;
+	} else {
+		ret = attr->m_type;
+	}
+	return(ret);
+}
+
+int
+_pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type)
+{
+	int	ret;
+	if (attr == NULL || *attr == NULL || type >= PTHREAD_MUTEX_TYPE_MAX) {
+		errno = EINVAL;
+		ret = -1;
+	} else {
+		(*attr)->m_type = type;
+		ret = 0;
+	}
+	return(ret);
+}
+
+int
+_pthread_mutexattr_gettype(pthread_mutexattr_t *attr, int *type)
+{
+	int	ret;
+
+	if (attr == NULL || *attr == NULL || (*attr)->m_type >=
+	    PTHREAD_MUTEX_TYPE_MAX) {
+		ret = EINVAL;
+	} else {
+		*type = (*attr)->m_type;
+		ret = 0;
+	}
+	return ret;
+}
--- /dev/null
+++ lib/libkse/thread/thr_mutex_protocol.c
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 1998 Daniel Eischen <eischen at 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/libkse/thread/thr_mutex_protocol.c,v 1.9 2007/10/09 13:42:28 obrien Exp $
+ */
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_mutexattr_getprotocol);
+LT10_COMPAT_DEFAULT(pthread_mutexattr_getprotocol);
+LT10_COMPAT_PRIVATE(_pthread_mutexattr_setprotocol);
+LT10_COMPAT_DEFAULT(pthread_mutexattr_setprotocol);
+
+__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);
+}
+
--- /dev/null
+++ lib/libkse/thread/thr_printf.c
@@ -0,0 +1,135 @@
+/*-
+ * Copyright (c) 2002 Jonathan Mini <mini at 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/lib/libkse/thread/thr_printf.c,v 1.5 2007/10/09 13:42:28 obrien Exp $");
+
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.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));
+}
+
--- /dev/null
+++ lib/libkse/thread/thr_concurrency.c
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2003 Daniel M. Eischen <deischen at freebsd.org>
+ * Copyright (c) 2003 Sergey Osokin <osa at 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/libkse/thread/thr_concurrency.c,v 1.11 2007/10/09 13:42:27 obrien Exp $
+ */
+#include <errno.h>
+#include <pthread.h>
+#include <sys/types.h>
+#include <sys/sysctl.h>
+
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_getconcurrency);
+LT10_COMPAT_DEFAULT(pthread_getconcurrency);
+LT10_COMPAT_PRIVATE(_pthread_setconcurrency);
+LT10_COMPAT_DEFAULT(pthread_setconcurrency);
+
+/*#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)
+{
+	int ret;
+
+	if (new_level < 0)
+		ret = EINVAL;
+	else if (new_level == level)
+		ret = 0;
+	else if (new_level == 0) {
+		level = 0;
+		ret = 0;
+	} else if ((_kse_isthreaded() == 0) && (_kse_setthreaded(1) != 0)) {
+		DBG_MSG("Can't enable threading.\n");
+		ret = EAGAIN;
+	} else {
+		ret = _thr_setconcurrency(new_level);
+		if (ret == 0)
+			level = new_level;
+	}
+	return (ret);
+}
+
+int
+_thr_setconcurrency(int new_level)
+{
+	struct pthread *curthread;
+	struct kse *newkse, *kse;
+	kse_critical_t crit;
+	int kse_count;
+	int i;
+	int ret;
+
+	/*
+	 * Turn on threaded mode, if failed, it is unnecessary to
+	 * do further work.
+	 */
+	if (_kse_isthreaded() == 0 && _kse_setthreaded(1))
+		return (EAGAIN);
+
+	ret = 0;
+	curthread = _get_curthread();
+	/* Race condition, but so what. */
+	kse_count = _kse_initial->k_kseg->kg_ksecount;
+	if (new_level > kse_count) {
+		for (i = kse_count; i < new_level; i++) {
+			newkse = _kse_alloc(curthread, 0);
+			if (newkse == NULL) {
+				DBG_MSG("Can't alloc new KSE.\n");
+				ret = EAGAIN;
+				break;
+			}
+			newkse->k_kseg = _kse_initial->k_kseg;
+			newkse->k_schedq = _kse_initial->k_schedq;
+			newkse->k_curthread = NULL;
+			crit = _kse_critical_enter();
+			KSE_SCHED_LOCK(curthread->kse, newkse->k_kseg);
+			TAILQ_INSERT_TAIL(&newkse->k_kseg->kg_kseq,
+			    newkse, k_kgqe);
+			newkse->k_kseg->kg_ksecount++;
+			newkse->k_flags |= KF_STARTED;
+			KSE_SCHED_UNLOCK(curthread->kse, newkse->k_kseg);
+			if (kse_create(&newkse->k_kcb->kcb_kmbx, 0) != 0) {
+				KSE_SCHED_LOCK(curthread->kse, newkse->k_kseg);
+				TAILQ_REMOVE(&newkse->k_kseg->kg_kseq,
+				    newkse, k_kgqe);
+				newkse->k_kseg->kg_ksecount--;
+				KSE_SCHED_UNLOCK(curthread->kse,
+				    newkse->k_kseg);
+				_kse_critical_leave(crit);
+				_kse_free(curthread, newkse);
+				DBG_MSG("kse_create syscall failed.\n");
+				ret = EAGAIN;
+				break;
+			} else {
+				_kse_critical_leave(crit);
+			}
+		}
+	} else if (new_level < kse_count) {
+		kse_count = 0;
+		crit = _kse_critical_enter();
+		KSE_SCHED_LOCK(curthread->kse, _kse_initial->k_kseg);
+		/* Count the number of active KSEs */
+		TAILQ_FOREACH(kse, &_kse_initial->k_kseg->kg_kseq, k_kgqe) {
+			if ((kse->k_flags & KF_TERMINATED) == 0)
+				kse_count++;
+		}
+		/* Reduce the number of active KSEs appropriately. */
+		kse = TAILQ_FIRST(&_kse_initial->k_kseg->kg_kseq);
+		while ((kse != NULL) && (kse_count > new_level)) {
+			if ((kse != _kse_initial) &&
+			    ((kse->k_flags & KF_TERMINATED) == 0)) {
+				kse->k_flags |= KF_TERMINATED;
+				kse_count--;
+				/* Wakup the KSE in case it is idle. */
+				kse_wakeup(&kse->k_kcb->kcb_kmbx);
+			}
+			kse = TAILQ_NEXT(kse, k_kgqe);
+		}
+		KSE_SCHED_UNLOCK(curthread->kse, _kse_initial->k_kseg);
+		_kse_critical_leave(crit);
+	}
+	return (ret);
+}
+
+int
+_thr_setmaxconcurrency(void)
+{
+	int vcpu;
+	size_t len;
+	int ret;
+
+	len = sizeof(vcpu);
+	ret = sysctlbyname("kern.threads.virtual_cpu", &vcpu, &len, NULL, 0);
+	if (ret == 0 && vcpu > 0)
+		ret = _thr_setconcurrency(vcpu);
+	return (ret);
+}
+
--- /dev/null
+++ lib/libkse/thread/thr_sigpending.c
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 1999 Daniel Eischen <eischen at vigrid.com>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by John Birrell.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY DANIEL EISCHEN AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/lib/libkse/thread/thr_sigpending.c,v 1.18 2007/10/09 13:42:29 obrien Exp $
+ */
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/signalvar.h>
+#include <signal.h>
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_sigpending);
+LT10_COMPAT_DEFAULT(sigpending);
+
+__weak_reference(_sigpending, sigpending);
+
+int
+_sigpending(sigset_t *set)
+{
+	struct pthread *curthread = _get_curthread();
+	kse_critical_t crit;
+	sigset_t sigset;
+	int ret = 0;
+
+	/* Check for a null signal set pointer: */
+	if (set == NULL) {
+		/* Return an invalid argument: */
+		ret = EINVAL;
+	}
+	else {
+		if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM)
+			return (__sys_sigpending(set));
+
+		crit = _kse_critical_enter();
+		KSE_SCHED_LOCK(curthread->kse, curthread->kseg);
+		sigset = curthread->sigpend;
+		KSE_SCHED_UNLOCK(curthread->kse, curthread->kseg);
+		KSE_LOCK_ACQUIRE(curthread->kse, &_thread_signal_lock);
+		SIGSETOR(sigset, _thr_proc_sigpending);
+		KSE_LOCK_RELEASE(curthread->kse, &_thread_signal_lock);
+		_kse_critical_leave(crit);
+		*set = sigset;
+	}
+	/* Return the completion status: */
+	return (ret);
+}
--- /dev/null
+++ lib/libkse/thread/thr_cond.c
@@ -0,0 +1,844 @@
+/*
+ * Copyright (c) 1995 John Birrell <jb at 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. Neither the name of the author nor the names of any 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/libkse/thread/thr_cond.c,v 1.57 2007/10/09 13:42:27 obrien Exp $
+ */
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(__pthread_cond_wait);
+LT10_COMPAT_PRIVATE(_pthread_cond_wait);
+LT10_COMPAT_DEFAULT(pthread_cond_wait);
+LT10_COMPAT_PRIVATE(__pthread_cond_timedwait);
+LT10_COMPAT_PRIVATE(_pthread_cond_timedwait);
+LT10_COMPAT_DEFAULT(pthread_cond_timedwait);
+LT10_COMPAT_PRIVATE(_pthread_cond_init);
+LT10_COMPAT_DEFAULT(pthread_cond_init);
+LT10_COMPAT_PRIVATE(_pthread_cond_destroy);
+LT10_COMPAT_DEFAULT(pthread_cond_destroy);
+LT10_COMPAT_PRIVATE(_pthread_cond_signal);
+LT10_COMPAT_DEFAULT(pthread_cond_signal);
+LT10_COMPAT_PRIVATE(_pthread_cond_broadcast);
+LT10_COMPAT_DEFAULT(pthread_cond_broadcast);
+
+#define	THR_IN_CONDQ(thr)	(((thr)->sflags & THR_FLAGS_IN_SYNCQ) != 0)
+#define	THR_CONDQ_SET(thr)	(thr)->sflags |= THR_FLAGS_IN_SYNCQ
+#define	THR_CONDQ_CLEAR(thr)	(thr)->sflags &= ~THR_FLAGS_IN_SYNCQ
+
+/*
+ * Prototypes
+ */
+static inline struct pthread	*cond_queue_deq(pthread_cond_t);
+static inline void		cond_queue_remove(pthread_cond_t, pthread_t);
+static inline void		cond_queue_enq(pthread_cond_t, pthread_t);
+static void			cond_wait_backout(void *);
+static inline void		check_continuation(struct pthread *,
+				    struct pthread_cond *, pthread_mutex_t *);
+
+/*
+ * 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);
+
+
+int
+_pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *cond_attr)
+{
+	enum pthread_cond_type type;
+	pthread_cond_t	pcond;
+	int		flags;
+	int             rval = 0;
+
+	if (cond == NULL)
+		rval = EINVAL;
+	else {
+		/*
+		 * Check if a pointer to a condition variable attribute
+		 * structure was passed by the caller: 
+		 */
+		if (cond_attr != NULL && *cond_attr != NULL) {
+			/* Default to a fast condition variable: */
+			type = (*cond_attr)->c_type;
+			flags = (*cond_attr)->c_flags;
+		} else {
+			/* Default to a fast condition variable: */
+			type = COND_TYPE_FAST;
+			flags = 0;
+		}
+
+		/* Process according to condition variable type: */
+		switch (type) {
+		/* Fast condition variable: */
+		case COND_TYPE_FAST:
+			/* Nothing to do here. */
+			break;
+
+		/* Trap invalid condition variable types: */
+		default:
+			/* Return an invalid argument error: */
+			rval = EINVAL;
+			break;
+		}
+
+		/* Check for no errors: */
+		if (rval == 0) {
+			if ((pcond = (pthread_cond_t)
+			    malloc(sizeof(struct pthread_cond))) == NULL) {
+				rval = ENOMEM;
+			} else if (_lock_init(&pcond->c_lock, LCK_ADAPTIVE,
+			    _thr_lock_wait, _thr_lock_wakeup) != 0) {
+				free(pcond);
+				rval = ENOMEM;
+			} else {
+				/*
+				 * Initialise the condition variable
+				 * structure:
+				 */
+				TAILQ_INIT(&pcond->c_queue);
+				pcond->c_flags = COND_FLAGS_INITED;
+				pcond->c_type = type;
+				pcond->c_mutex = NULL;
+				pcond->c_seqno = 0;
+				*cond = pcond;
+			}
+		}
+	}
+	/* Return the completion status: */
+	return (rval);
+}
+
+int
+_pthread_cond_destroy(pthread_cond_t *cond)
+{
+	struct pthread_cond	*cv;
+	struct pthread		*curthread = _get_curthread();
+	int			rval = 0;
+
+	if (cond == NULL || *cond == NULL)
+		rval = EINVAL;
+	else {
+		/* Lock the condition variable structure: */
+		THR_LOCK_ACQUIRE(curthread, &(*cond)->c_lock);
+
+		/*
+		 * 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: */
+		_lock_destroy(&cv->c_lock);
+
+		/*
+		 * Free the memory allocated for the condition
+		 * variable structure:
+		 */
+		free(cv);
+
+	}
+	/* Return the completion status: */
+	return (rval);
+}
+
+int
+_pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
+{
+	struct pthread	*curthread = _get_curthread();
+	int	rval = 0;
+	int	done = 0;
+	int	mutex_locked = 1;
+	int	seqno;
+
+	if (cond == NULL)
+		return (EINVAL);
+
+	/*
+	 * If the condition variable is statically initialized,
+	 * perform the dynamic initialization:
+	 */
+	if (*cond == NULL &&
+	    (rval = pthread_cond_init(cond, NULL)) != 0)
+		return (rval);
+
+	if (!_kse_isthreaded())
+		_kse_setthreaded(1);
+
+	/*
+	 * Enter a loop waiting for a condition signal or broadcast
+	 * to wake up this thread.  A loop is needed in case the waiting
+	 * thread is interrupted by a signal to execute a signal handler.
+	 * It is not (currently) possible to remain in the waiting queue
+	 * while running a handler.  Instead, the thread is interrupted
+	 * and backed out of the waiting queue prior to executing the
+	 * signal handler.
+	 */
+
+	/* Lock the condition variable structure: */
+	THR_LOCK_ACQUIRE(curthread, &(*cond)->c_lock);
+	seqno = (*cond)->c_seqno;
+	do {
+		/*
+		 * If the condvar was statically allocated, properly
+		 * initialize the tail queue.
+		 */
+		if (((*cond)->c_flags & COND_FLAGS_INITED) == 0) {
+			TAILQ_INIT(&(*cond)->c_queue);
+			(*cond)->c_flags |= COND_FLAGS_INITED;
+		}
+
+		/* Process according to condition variable type: */
+		switch ((*cond)->c_type) {
+		/* Fast condition variable: */
+		case COND_TYPE_FAST:
+			if ((mutex == NULL) || (((*cond)->c_mutex != NULL) &&
+			    ((*cond)->c_mutex != *mutex))) {
+				/* Return invalid argument error: */
+				rval = EINVAL;
+			} else {
+				/* Reset the timeout and interrupted flags: */
+				curthread->timeout = 0;
+				curthread->interrupted = 0;
+
+				/*
+				 * Queue the running thread for the condition
+				 * variable:
+				 */
+				cond_queue_enq(*cond, curthread);
+
+				/* Wait forever: */
+				curthread->wakeup_time.tv_sec = -1;
+
+				/* Unlock the mutex: */
+				if (mutex_locked &&
+				    ((rval = _mutex_cv_unlock(mutex)) != 0)) {
+					/*
+					 * Cannot unlock the mutex, so remove
+					 * the running thread from the condition
+					 * variable queue:
+					 */
+					cond_queue_remove(*cond, curthread);
+				}
+				else {
+					/* Remember the mutex: */
+					(*cond)->c_mutex = *mutex;
+
+					/*
+					 * Don't unlock the mutex the next
+					 * time through the loop (if the
+					 * thread has to be requeued after
+					 * handling a signal).
+					 */
+					mutex_locked = 0;
+
+					/*
+					 * This thread is active and is in a
+					 * critical region (holding the cv
+					 * lock); we should be able to safely
+					 * set the state.
+					 */
+					THR_SCHED_LOCK(curthread, curthread);
+					THR_SET_STATE(curthread, PS_COND_WAIT);
+
+					/* Remember the CV: */
+					curthread->data.cond = *cond;
+					curthread->sigbackout = cond_wait_backout;
+					THR_SCHED_UNLOCK(curthread, curthread);
+
+					/* Unlock the CV structure: */
+					THR_LOCK_RELEASE(curthread,
+					    &(*cond)->c_lock);
+
+					/* Schedule the next thread: */
+					_thr_sched_switch(curthread);
+
+					/*
+					 * XXX - This really isn't a good check
+					 * since there can be more than one
+					 * thread waiting on the CV.  Signals
+					 * sent to threads waiting on mutexes
+					 * or CVs should really be deferred
+					 * until the threads are no longer
+					 * waiting, but POSIX says that signals
+					 * should be sent "as soon as possible".
+					 */
+					done = (seqno != (*cond)->c_seqno);
+					if (done && !THR_IN_CONDQ(curthread)) {
+						/*
+						 * The thread is dequeued, so
+						 * it is safe to clear these.
+						 */
+						curthread->data.cond = NULL;
+						curthread->sigbackout = NULL;
+						check_continuation(curthread,
+						    NULL, mutex);
+						return (_mutex_cv_lock(mutex));
+					}
+
+					/* Relock the CV structure: */
+					THR_LOCK_ACQUIRE(curthread,
+					    &(*cond)->c_lock);
+
+					/*
+					 * Clear these after taking the lock to
+					 * prevent a race condition where a
+					 * signal can arrive before dequeueing
+					 * the thread.
+					 */
+					curthread->data.cond = NULL;
+					curthread->sigbackout = NULL;
+					done = (seqno != (*cond)->c_seqno);
+
+					if (THR_IN_CONDQ(curthread)) {
+						cond_queue_remove(*cond,
+						    curthread);
+
+						/* Check for no more waiters: */
+						if (TAILQ_EMPTY(&(*cond)->c_queue))
+							(*cond)->c_mutex = NULL;
+					}
+				}
+			}
+			break;
+
+		/* Trap invalid condition variable types: */
+		default:
+			/* Return an invalid argument error: */
+			rval = EINVAL;
+			break;
+		}
+
+		check_continuation(curthread, *cond,
+		    mutex_locked ? NULL : mutex);
+	} while ((done == 0) && (rval == 0));
+
+	/* Unlock the condition variable structure: */
+	THR_LOCK_RELEASE(curthread, &(*cond)->c_lock);
+
+	if (mutex_locked == 0)
+		_mutex_cv_lock(mutex);
+
+	/* Return the completion status: */
+	return (rval);
+}
+
+__strong_reference(_pthread_cond_wait, _thr_cond_wait);
+
+int
+__pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
+{
+	struct pthread *curthread = _get_curthread();
+	int ret;
+
+	_thr_cancel_enter(curthread);
+	ret = _pthread_cond_wait(cond, mutex);
+	_thr_cancel_leave(curthread, 1);
+	return (ret);
+}
+
+int
+_pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex,
+		       const struct timespec * abstime)
+{
+	struct pthread	*curthread = _get_curthread();
+	int	rval = 0;
+	int	done = 0;
+	int	mutex_locked = 1;
+	int	seqno;
+
+	THR_ASSERT(curthread->locklevel == 0,
+	    "cv_timedwait: locklevel is not zero!");
+
+	if (abstime == NULL || abstime->tv_sec < 0 || abstime->tv_nsec < 0 ||
+	    abstime->tv_nsec >= 1000000000)
+		return (EINVAL);
+	/*
+	 * If the condition variable is statically initialized, perform dynamic
+	 * initialization.
+	 */
+	if (*cond == NULL && (rval = pthread_cond_init(cond, NULL)) != 0)
+		return (rval);
+
+	if (!_kse_isthreaded())
+		_kse_setthreaded(1);
+
+	/*
+	 * Enter a loop waiting for a condition signal or broadcast
+	 * to wake up this thread.  A loop is needed in case the waiting
+	 * thread is interrupted by a signal to execute a signal handler.
+	 * It is not (currently) possible to remain in the waiting queue
+	 * while running a handler.  Instead, the thread is interrupted
+	 * and backed out of the waiting queue prior to executing the
+	 * signal handler.
+	 */
+
+	/* Lock the condition variable structure: */
+	THR_LOCK_ACQUIRE(curthread, &(*cond)->c_lock);
+	seqno = (*cond)->c_seqno;
+	do {
+		/*
+		 * If the condvar was statically allocated, properly
+		 * initialize the tail queue.
+		 */
+		if (((*cond)->c_flags & COND_FLAGS_INITED) == 0) {
+			TAILQ_INIT(&(*cond)->c_queue);
+			(*cond)->c_flags |= COND_FLAGS_INITED;
+		}
+
+		/* Process according to condition variable type: */
+		switch ((*cond)->c_type) {
+		/* Fast condition variable: */
+		case COND_TYPE_FAST:
+			if ((mutex == NULL) || (((*cond)->c_mutex != NULL) &&
+			    ((*cond)->c_mutex != *mutex))) {
+				/* Return invalid argument error: */
+				rval = EINVAL;
+			} else {
+				/* Reset the timeout and interrupted flags: */
+				curthread->timeout = 0;
+				curthread->interrupted = 0;
+
+				/*
+				 * Queue the running thread for the condition
+				 * variable:
+				 */
+				cond_queue_enq(*cond, curthread);
+
+				/* Unlock the mutex: */
+				if (mutex_locked &&
+				   ((rval = _mutex_cv_unlock(mutex)) != 0)) {
+					/*
+					 * Cannot unlock the mutex; remove the
+					 * running thread from the condition
+					 * variable queue: 
+					 */
+					cond_queue_remove(*cond, curthread);
+				} else {
+					/* Remember the mutex: */
+					(*cond)->c_mutex = *mutex;
+
+					/*
+					 * Don't unlock the mutex the next
+					 * time through the loop (if the
+					 * thread has to be requeued after
+					 * handling a signal).
+					 */
+					mutex_locked = 0;
+
+					/*
+					 * This thread is active and is in a
+					 * critical region (holding the cv
+					 * lock); we should be able to safely
+					 * set the state.
+					 */
+					THR_SCHED_LOCK(curthread, curthread);
+					/* Set the wakeup time: */
+					curthread->wakeup_time.tv_sec =
+					    abstime->tv_sec;
+					curthread->wakeup_time.tv_nsec =
+					    abstime->tv_nsec;
+					THR_SET_STATE(curthread, PS_COND_WAIT);
+
+					/* Remember the CV: */
+					curthread->data.cond = *cond;
+					curthread->sigbackout = cond_wait_backout;
+					THR_SCHED_UNLOCK(curthread, curthread);
+
+					/* Unlock the CV structure: */
+					THR_LOCK_RELEASE(curthread,
+					    &(*cond)->c_lock);
+
+					/* Schedule the next thread: */
+					_thr_sched_switch(curthread);
+
+					/*
+					 * XXX - This really isn't a good check
+					 * since there can be more than one
+					 * thread waiting on the CV.  Signals
+					 * sent to threads waiting on mutexes
+					 * or CVs should really be deferred
+					 * until the threads are no longer
+					 * waiting, but POSIX says that signals
+					 * should be sent "as soon as possible".
+					 */
+					done = (seqno != (*cond)->c_seqno);
+					if (done && !THR_IN_CONDQ(curthread)) {
+						/*
+						 * The thread is dequeued, so
+						 * it is safe to clear these.
+						 */
+						curthread->data.cond = NULL;
+						curthread->sigbackout = NULL;
+						check_continuation(curthread,
+						    NULL, mutex);
+						return (_mutex_cv_lock(mutex));
+					}
+
+					/* Relock the CV structure: */
+					THR_LOCK_ACQUIRE(curthread,
+					    &(*cond)->c_lock);
+
+					/*
+					 * Clear these after taking the lock to
+					 * prevent a race condition where a
+					 * signal can arrive before dequeueing
+					 * the thread.
+					 */
+					curthread->data.cond = NULL;
+					curthread->sigbackout = NULL;
+
+					done = (seqno != (*cond)->c_seqno);
+
+					if (THR_IN_CONDQ(curthread)) {
+						cond_queue_remove(*cond,
+						    curthread);
+
+						/* Check for no more waiters: */
+						if (TAILQ_EMPTY(&(*cond)->c_queue))
+							(*cond)->c_mutex = NULL;
+					}
+
+					if (curthread->timeout != 0) {
+						/* The wait timedout. */
+						rval = ETIMEDOUT;
+					}
+				}
+			}
+			break;
+
+		/* Trap invalid condition variable types: */
+		default:
+			/* Return an invalid argument error: */
+			rval = EINVAL;
+			break;
+		}
+
+		check_continuation(curthread, *cond,
+		    mutex_locked ? NULL : mutex);
+	} while ((done == 0) && (rval == 0));
+
+	/* Unlock the condition variable structure: */
+	THR_LOCK_RELEASE(curthread, &(*cond)->c_lock);
+
+	if (mutex_locked == 0)
+		_mutex_cv_lock(mutex);
+
+	/* Return the completion status: */
+	return (rval);
+}
+
+int
+__pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
+		       const struct timespec *abstime)
+{
+	struct pthread *curthread = _get_curthread();
+	int ret;
+
+	_thr_cancel_enter(curthread);
+	ret = _pthread_cond_timedwait(cond, mutex, abstime);
+	_thr_cancel_leave(curthread, 1);
+	return (ret);
+}
+
+
+int
+_pthread_cond_signal(pthread_cond_t * cond)
+{
+	struct pthread	*curthread = _get_curthread();
+	struct pthread	*pthread;
+	struct kse_mailbox *kmbx;
+	int		rval = 0;
+
+	THR_ASSERT(curthread->locklevel == 0,
+	    "cv_timedwait: locklevel is not zero!");
+	if (cond == NULL)
+		rval = EINVAL;
+       /*
+        * If the condition variable is statically initialized, perform dynamic
+        * initialization.
+        */
+	else if (*cond != NULL || (rval = pthread_cond_init(cond, NULL)) == 0) {
+		/* Lock the condition variable structure: */
+		THR_LOCK_ACQUIRE(curthread, &(*cond)->c_lock);
+
+		/* Process according to condition variable type: */
+		switch ((*cond)->c_type) {
+		/* Fast condition variable: */
+		case COND_TYPE_FAST:
+			/* Increment the sequence number: */
+			(*cond)->c_seqno++;
+
+			/*
+			 * Wakeups have to be done with the CV lock held;
+			 * otherwise there is a race condition where the
+			 * thread can timeout, run on another KSE, and enter
+			 * another blocking state (including blocking on a CV).
+			 */
+			if ((pthread = TAILQ_FIRST(&(*cond)->c_queue))
+			    != NULL) {
+				THR_SCHED_LOCK(curthread, pthread);
+				cond_queue_remove(*cond, pthread);
+				pthread->sigbackout = NULL;
+				if ((pthread->kseg == curthread->kseg) &&
+				    (pthread->active_priority >
+				    curthread->active_priority))
+					curthread->critical_yield = 1;
+				kmbx = _thr_setrunnable_unlocked(pthread);
+				THR_SCHED_UNLOCK(curthread, pthread);
+				if (kmbx != NULL)
+					kse_wakeup(kmbx);
+			}
+			/* Check for no more waiters: */
+			if (TAILQ_EMPTY(&(*cond)->c_queue))
+				(*cond)->c_mutex = NULL;
+			break;
+
+		/* Trap invalid condition variable types: */
+		default:
+			/* Return an invalid argument error: */
+			rval = EINVAL;
+			break;
+		}
+
+		/* Unlock the condition variable structure: */
+		THR_LOCK_RELEASE(curthread, &(*cond)->c_lock);
+	}
+
+	/* Return the completion status: */
+	return (rval);
+}
+
+__strong_reference(_pthread_cond_signal, _thr_cond_signal);
+
+int
+_pthread_cond_broadcast(pthread_cond_t * cond)
+{
+	struct pthread	*curthread = _get_curthread();
+	struct pthread	*pthread;
+	struct kse_mailbox *kmbx;
+	int		rval = 0;
+
+	THR_ASSERT(curthread->locklevel == 0,
+	    "cv_timedwait: locklevel is not zero!");
+	if (cond == NULL)
+		rval = EINVAL;
+       /*
+        * If the condition variable is statically initialized, perform dynamic
+        * initialization.
+        */
+	else if (*cond != NULL || (rval = pthread_cond_init(cond, NULL)) == 0) {
+		/* Lock the condition variable structure: */
+		THR_LOCK_ACQUIRE(curthread, &(*cond)->c_lock);
+
+		/* Process according to condition variable type: */
+		switch ((*cond)->c_type) {
+		/* Fast condition variable: */
+		case COND_TYPE_FAST:
+			/* Increment the sequence number: */
+			(*cond)->c_seqno++;
+
+			/*
+			 * Enter a loop to bring all threads off the
+			 * condition queue:
+			 */
+			while ((pthread = TAILQ_FIRST(&(*cond)->c_queue))
+			    != NULL) {
+				THR_SCHED_LOCK(curthread, pthread);
+				cond_queue_remove(*cond, pthread);
+				pthread->sigbackout = NULL;
+				if ((pthread->kseg == curthread->kseg) &&
+				    (pthread->active_priority >
+				    curthread->active_priority))
+					curthread->critical_yield = 1;
+				kmbx = _thr_setrunnable_unlocked(pthread);
+				THR_SCHED_UNLOCK(curthread, pthread);
+				if (kmbx != NULL)
+					kse_wakeup(kmbx);
+			}
+
+			/* There are no more waiting threads: */
+			(*cond)->c_mutex = NULL;
+			break;
+
+		/* Trap invalid condition variable types: */
+		default:
+			/* Return an invalid argument error: */
+			rval = EINVAL;
+			break;
+		}
+
+		/* Unlock the condition variable structure: */
+		THR_LOCK_RELEASE(curthread, &(*cond)->c_lock);
+	}
+
+	/* Return the completion status: */
+	return (rval);
+}
+
+__strong_reference(_pthread_cond_broadcast, _thr_cond_broadcast);
+
+static inline void
+check_continuation(struct pthread *curthread, struct pthread_cond *cond,
+    pthread_mutex_t *mutex)
+{
+	if ((curthread->interrupted != 0) &&
+	    (curthread->continuation != NULL)) {
+		if (cond != NULL)
+			/* Unlock the condition variable structure: */
+			THR_LOCK_RELEASE(curthread, &cond->c_lock);
+		/*
+		 * Note that even though this thread may have been
+		 * canceled, POSIX requires that the mutex be
+		 * reaquired prior to cancellation.
+		 */
+		if (mutex != NULL)
+			_mutex_cv_lock(mutex);
+		curthread->continuation((void *) curthread);
+		PANIC("continuation returned in pthread_cond_wait.\n");
+	}
+}
+
+static void
+cond_wait_backout(void *arg)
+{
+	struct pthread *curthread = (struct pthread *)arg;
+	pthread_cond_t	cond;
+
+	cond = curthread->data.cond;
+	if (cond != NULL) {
+		/* Lock the condition variable structure: */
+		THR_LOCK_ACQUIRE(curthread, &cond->c_lock);
+
+		/* Process according to condition variable type: */
+		switch (cond->c_type) {
+		/* Fast condition variable: */
+		case COND_TYPE_FAST:
+			cond_queue_remove(cond, curthread);
+
+			/* Check for no more waiters: */
+			if (TAILQ_EMPTY(&cond->c_queue))
+				cond->c_mutex = NULL;
+			break;
+
+		default:
+			break;
+		}
+
+		/* Unlock the condition variable structure: */
+		THR_LOCK_RELEASE(curthread, &cond->c_lock);
+	}
+	/* No need to call this again. */
+	curthread->sigbackout = NULL;
+}
+
+/*
+ * Dequeue a waiting thread from the head of a condition queue in
+ * descending priority order.
+ */
+static inline struct pthread *
+cond_queue_deq(pthread_cond_t cond)
+{
+	struct pthread	*pthread;
+
+	while ((pthread = TAILQ_FIRST(&cond->c_queue)) != NULL) {
+		TAILQ_REMOVE(&cond->c_queue, pthread, sqe);
+		THR_CONDQ_CLEAR(pthread);
+		if ((pthread->timeout == 0) && (pthread->interrupted == 0))
+			/*
+			 * Only exit the loop when we find a thread
+			 * that hasn't timed out or been canceled;
+			 * those threads are already running and don't
+			 * need their run state changed.
+			 */
+			break;
+	}
+
+	return (pthread);
+}
+
+/*
+ * Remove a waiting thread from a condition queue in descending priority
+ * order.
+ */
+static inline void
+cond_queue_remove(pthread_cond_t cond, struct pthread *pthread)
+{
+	/*
+	 * Because pthread_cond_timedwait() can timeout as well
+	 * as be signaled by another thread, it is necessary to
+	 * guard against removing the thread from the queue if
+	 * it isn't in the queue.
+	 */
+	if (THR_IN_CONDQ(pthread)) {
+		TAILQ_REMOVE(&cond->c_queue, pthread, sqe);
+		THR_CONDQ_CLEAR(pthread);
+	}
+}
+
+/*
+ * Enqueue a waiting thread to a condition queue in descending priority
+ * order.
+ */
+static inline void
+cond_queue_enq(pthread_cond_t cond, struct pthread *pthread)
+{
+	struct pthread *tid = TAILQ_LAST(&cond->c_queue, cond_head);
+
+	THR_ASSERT(!THR_IN_SYNCQ(pthread),
+	    "cond_queue_enq: thread already queued!");
+
+	/*
+	 * For the common case of all threads having equal priority,
+	 * we perform a quick check against the priority of the thread
+	 * at the tail of the queue.
+	 */
+	if ((tid == NULL) || (pthread->active_priority <= tid->active_priority))
+		TAILQ_INSERT_TAIL(&cond->c_queue, pthread, sqe);
+	else {
+		tid = TAILQ_FIRST(&cond->c_queue);
+		while (pthread->active_priority <= tid->active_priority)
+			tid = TAILQ_NEXT(tid, sqe);
+		TAILQ_INSERT_BEFORE(tid, pthread, sqe);
+	}
+	THR_CONDQ_SET(pthread);
+	pthread->data.cond = cond;
+}
--- /dev/null
+++ lib/libkse/thread/thr_sigwait.c
@@ -0,0 +1,209 @@
+//depot/projects/kse/lib/libpthread/thread/thr_sigwait.c#1 - branch change 15154 (text+ko)
+/*
+ * Copyright (c) 1997 John Birrell <jb at 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. Neither the name of the author nor the names of any 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/libkse/thread/thr_sigwait.c,v 1.38 2007/10/09 13:42:29 obrien Exp $
+ */
+#include <signal.h>
+#include <sys/param.h>
+#include <sys/signalvar.h>
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(__sigwait);
+LT10_COMPAT_PRIVATE(_sigwait);
+LT10_COMPAT_DEFAULT(sigwait);
+LT10_COMPAT_PRIVATE(__sigtimedwait);
+LT10_COMPAT_PRIVATE(_sigtimedwait);
+LT10_COMPAT_DEFAULT(sigtimedwait);
+LT10_COMPAT_PRIVATE(__sigwaitinfo);
+LT10_COMPAT_PRIVATE(_sigwaitinfo);
+LT10_COMPAT_DEFAULT(sigwaitinfo);
+
+__weak_reference(__sigwait, sigwait);
+__weak_reference(__sigtimedwait, sigtimedwait);
+__weak_reference(__sigwaitinfo, sigwaitinfo);
+
+static int
+lib_sigtimedwait(const sigset_t *set, siginfo_t *info,
+	const struct timespec * timeout)
+{
+	struct pthread	*curthread = _get_curthread();
+	int		ret = 0;
+	int		i;
+	struct sigwait_data waitdata;
+	sigset_t	waitset;
+	kse_critical_t  crit;
+	siginfo_t	siginfo;
+
+	if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM) {
+		if (info == NULL)
+			info = &siginfo;
+		return (__sys_sigtimedwait((sigset_t *)set, info,
+			(struct timespec *)timeout));
+	}
+
+	/*
+	 * Initialize the set of signals that will be waited on:
+	 */
+	waitset = *set;
+
+	/* These signals can't be waited on. */
+	SIGDELSET(waitset, SIGKILL);
+	SIGDELSET(waitset, SIGSTOP);
+
+	/*
+	 * POSIX says that the _application_ must explicitly install
+	 * a dummy handler for signals that are SIG_IGN in order
+	 * to sigwait on them. Note that SIG_IGN signals are left in
+	 * the mask because a subsequent sigaction could enable an
+	 * ignored signal.
+	 */
+
+	crit = _kse_critical_enter();
+	KSE_SCHED_LOCK(curthread->kse, curthread->kseg);
+	for (i = 1; i <= _SIG_MAXSIG; ++i) {
+		if (SIGISMEMBER(waitset, i) &&
+		    SIGISMEMBER(curthread->sigpend, i)) {
+			SIGDELSET(curthread->sigpend, i);
+			siginfo = curthread->siginfo[i - 1];
+			KSE_SCHED_UNLOCK(curthread->kse,
+				curthread->kseg);
+			_kse_critical_leave(crit);
+			ret = i;
+			goto OUT;
+		}
+	}
+	curthread->timeout = 0;
+	curthread->interrupted = 0;
+	_thr_set_timeout(timeout);
+	/* Wait for a signal: */
+	siginfo.si_signo = 0;
+	waitdata.waitset = &waitset;
+	waitdata.siginfo = &siginfo;
+	curthread->data.sigwait = &waitdata;
+	THR_SET_STATE(curthread, PS_SIGWAIT);
+	_thr_sched_switch_unlocked(curthread);
+	/*
+	 * Return the signal number to the caller:
+	 */
+	if (siginfo.si_signo > 0) {
+		ret = siginfo.si_signo;
+	} else {
+		if (curthread->interrupted)
+			errno = EINTR;
+		else if (curthread->timeout)
+			errno = EAGAIN;
+		ret = -1;
+	}
+	curthread->timeout = 0;
+	curthread->interrupted = 0;
+	/*
+	 * Probably unnecessary, but since it's in a union struct
+	 * we don't know how it could be used in the future.
+	 */
+	curthread->data.sigwait = NULL;
+
+OUT:
+	if (ret > 0 && info != NULL)
+		*info = siginfo;
+
+	return (ret);
+}
+
+int
+__sigtimedwait(const sigset_t *set, siginfo_t *info,
+	const struct timespec * timeout)
+{
+	struct pthread	*curthread = _get_curthread();
+	int ret;
+
+	_thr_cancel_enter(curthread);
+	ret = lib_sigtimedwait(set, info, timeout);
+	_thr_cancel_leave(curthread, 1);
+	return (ret);
+}
+
+int _sigtimedwait(const sigset_t *set, siginfo_t *info,
+	const struct timespec * timeout)
+{
+	return lib_sigtimedwait(set, info, timeout);
+}
+
+int
+__sigwaitinfo(const sigset_t *set, siginfo_t *info)
+{
+	struct pthread	*curthread = _get_curthread();
+	int ret;
+
+	_thr_cancel_enter(curthread);
+	ret = lib_sigtimedwait(set, info, NULL);
+	_thr_cancel_leave(curthread, 1);
+	return (ret);
+}
+
+int
+_sigwaitinfo(const sigset_t *set, siginfo_t *info)
+{
+	return lib_sigtimedwait(set, info, NULL);
+}
+
+int
+__sigwait(const sigset_t *set, int *sig)
+{
+	struct pthread	*curthread = _get_curthread();
+	int ret;
+
+	_thr_cancel_enter(curthread);
+	ret = lib_sigtimedwait(set, NULL, NULL);
+	if (ret > 0) {
+		*sig = ret;
+		ret = 0;
+	} else {
+		ret = errno;
+	}
+	_thr_cancel_leave(curthread, 1);
+	return (ret);
+}
+
+int
+_sigwait(const sigset_t *set, int *sig)
+{
+	int ret;
+
+	ret = lib_sigtimedwait(set, NULL, NULL);
+	if (ret > 0) {
+		*sig = ret;
+		ret = 0;
+	} else {
+		ret = errno;
+	}
+	return (ret);
+}
+
--- /dev/null
+++ lib/libkse/thread/thr_init.c
@@ -0,0 +1,530 @@
+/*
+ * Copyright (c) 2003 Daniel M. Eischen <deischen at freebsd.org>
+ * Copyright (c) 1995-1998 John Birrell <jb at 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. Neither the name of the author nor the names of any 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/libkse/thread/thr_init.c,v 1.76 2007/10/09 13:42:28 obrien 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"
+
+LT10_COMPAT_PRIVATE(_libkse_debug);
+LT10_COMPAT_PRIVATE(_thread_activated);
+LT10_COMPAT_PRIVATE(_thread_active_threads);
+LT10_COMPAT_PRIVATE(_thread_list);
+
+int	__pthread_cond_wait(pthread_cond_t *, pthread_mutex_t *);
+int	__pthread_mutex_lock(pthread_mutex_t *);
+int	__pthread_mutex_trylock(pthread_mutex_t *);
+void	_thread_init_hack(void);
+extern int _thread_state_running;
+
+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_hack,
+	&_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
+};
+
+#define	DUAL_ENTRY(entry)	\
+	(pthread_func_t)entry, (pthread_func_t)entry
+
+static pthread_func_t jmp_table[][2] = {
+	{DUAL_ENTRY(_pthread_atfork)},	/* PJT_ATFORK */
+	{DUAL_ENTRY(_pthread_attr_destroy)},	/* PJT_ATTR_DESTROY */
+	{DUAL_ENTRY(_pthread_attr_getdetachstate)},	/* PJT_ATTR_GETDETACHSTATE */
+	{DUAL_ENTRY(_pthread_attr_getguardsize)},	/* PJT_ATTR_GETGUARDSIZE */
+	{DUAL_ENTRY(_pthread_attr_getinheritsched)},	/* PJT_ATTR_GETINHERITSCHED */
+	{DUAL_ENTRY(_pthread_attr_getschedparam)},	/* PJT_ATTR_GETSCHEDPARAM */
+	{DUAL_ENTRY(_pthread_attr_getschedpolicy)},	/* PJT_ATTR_GETSCHEDPOLICY */
+	{DUAL_ENTRY(_pthread_attr_getscope)},	/* PJT_ATTR_GETSCOPE */
+	{DUAL_ENTRY(_pthread_attr_getstackaddr)},	/* PJT_ATTR_GETSTACKADDR */
+	{DUAL_ENTRY(_pthread_attr_getstacksize)},	/* PJT_ATTR_GETSTACKSIZE */
+	{DUAL_ENTRY(_pthread_attr_init)},	/* PJT_ATTR_INIT */
+	{DUAL_ENTRY(_pthread_attr_setdetachstate)},	/* PJT_ATTR_SETDETACHSTATE */
+	{DUAL_ENTRY(_pthread_attr_setguardsize)},	/* PJT_ATTR_SETGUARDSIZE */
+	{DUAL_ENTRY(_pthread_attr_setinheritsched)},	/* PJT_ATTR_SETINHERITSCHED */
+	{DUAL_ENTRY(_pthread_attr_setschedparam)},	/* PJT_ATTR_SETSCHEDPARAM */
+	{DUAL_ENTRY(_pthread_attr_setschedpolicy)},	/* PJT_ATTR_SETSCHEDPOLICY */
+	{DUAL_ENTRY(_pthread_attr_setscope)},	/* PJT_ATTR_SETSCOPE */
+	{DUAL_ENTRY(_pthread_attr_setstackaddr)},	/* PJT_ATTR_SETSTACKADDR */
+	{DUAL_ENTRY(_pthread_attr_setstacksize)},	/* PJT_ATTR_SETSTACKSIZE */
+	{DUAL_ENTRY(_pthread_cancel)},	/* PJT_CANCEL */
+	{DUAL_ENTRY(_pthread_cleanup_pop)},	/* PJT_CLEANUP_POP */
+	{DUAL_ENTRY(_pthread_cleanup_push)},	/* PJT_CLEANUP_PUSH */
+	{DUAL_ENTRY(_pthread_cond_broadcast)},	/* PJT_COND_BROADCAST */
+	{DUAL_ENTRY(_pthread_cond_destroy)},	/* PJT_COND_DESTROY */
+	{DUAL_ENTRY(_pthread_cond_init)},	/* PJT_COND_INIT */
+	{DUAL_ENTRY(_pthread_cond_signal)},	/* PJT_COND_SIGNAL */
+	{DUAL_ENTRY(_pthread_cond_timedwait)},	/* PJT_COND_TIMEDWAIT */
+	{(pthread_func_t)__pthread_cond_wait,
+	 (pthread_func_t)_pthread_cond_wait},	/* PJT_COND_WAIT */
+	{DUAL_ENTRY(_pthread_detach)},	/* PJT_DETACH */
+	{DUAL_ENTRY(_pthread_equal)},	/* PJT_EQUAL */
+	{DUAL_ENTRY(_pthread_exit)},	/* PJT_EXIT */
+	{DUAL_ENTRY(_pthread_getspecific)},	/* PJT_GETSPECIFIC */
+	{DUAL_ENTRY(_pthread_join)},	/* PJT_JOIN */
+	{DUAL_ENTRY(_pthread_key_create)},	/* PJT_KEY_CREATE */
+	{DUAL_ENTRY(_pthread_key_delete)},	/* PJT_KEY_DELETE*/
+	{DUAL_ENTRY(_pthread_kill)},	/* PJT_KILL */
+	{DUAL_ENTRY(_pthread_main_np)},		/* PJT_MAIN_NP */
+	{DUAL_ENTRY(_pthread_mutexattr_destroy)}, /* PJT_MUTEXATTR_DESTROY */
+	{DUAL_ENTRY(_pthread_mutexattr_init)},	/* PJT_MUTEXATTR_INIT */
+	{DUAL_ENTRY(_pthread_mutexattr_settype)}, /* PJT_MUTEXATTR_SETTYPE */
+	{DUAL_ENTRY(_pthread_mutex_destroy)},	/* PJT_MUTEX_DESTROY */
+	{DUAL_ENTRY(_pthread_mutex_init)},	/* PJT_MUTEX_INIT */
+	{(pthread_func_t)__pthread_mutex_lock,
+	 (pthread_func_t)_pthread_mutex_lock},	/* PJT_MUTEX_LOCK */
+	{(pthread_func_t)__pthread_mutex_trylock,
+	 (pthread_func_t)_pthread_mutex_trylock},/* PJT_MUTEX_TRYLOCK */
+	{DUAL_ENTRY(_pthread_mutex_unlock)},	/* PJT_MUTEX_UNLOCK */
+	{DUAL_ENTRY(_pthread_once)},		/* PJT_ONCE */
+	{DUAL_ENTRY(_pthread_rwlock_destroy)},	/* PJT_RWLOCK_DESTROY */
+	{DUAL_ENTRY(_pthread_rwlock_init)},	/* PJT_RWLOCK_INIT */
+	{DUAL_ENTRY(_pthread_rwlock_rdlock)},	/* PJT_RWLOCK_RDLOCK */
+	{DUAL_ENTRY(_pthread_rwlock_tryrdlock)},/* PJT_RWLOCK_TRYRDLOCK */
+	{DUAL_ENTRY(_pthread_rwlock_trywrlock)},/* PJT_RWLOCK_TRYWRLOCK */
+	{DUAL_ENTRY(_pthread_rwlock_unlock)},	/* PJT_RWLOCK_UNLOCK */
+	{DUAL_ENTRY(_pthread_rwlock_wrlock)},	/* PJT_RWLOCK_WRLOCK */
+	{DUAL_ENTRY(_pthread_self)},		/* PJT_SELF */
+	{DUAL_ENTRY(_pthread_setcancelstate)},	/* PJT_SETCANCELSTATE */
+	{DUAL_ENTRY(_pthread_setcanceltype)},	/* PJT_SETCANCELTYPE */
+	{DUAL_ENTRY(_pthread_setspecific)},	/* PJT_SETSPECIFIC */
+	{DUAL_ENTRY(_pthread_sigmask)},		/* PJT_SIGMASK */
+	{DUAL_ENTRY(_pthread_testcancel)}	/* PJT_TESTCANCEL */
+};
+
+static int	init_once = 0;
+
+/*
+ * 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;
+
+	/* 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;
+
+	/*
+	 * Check the size of the jump table to make sure it is preset
+	 * with the correct number of entries.
+	 */
+	if (sizeof(jmp_table) != (sizeof(pthread_func_t) * PJT_MAX * 2))
+		PANIC("Thread jump table not properly initialized");
+	memcpy(__thr_jtable, jmp_table, sizeof(jmp_table));
+
+	/*
+	 * Check for the special case of this process running as
+	 * or in place of init as pid = 1:
+	 */
+	if ((_thr_pid = getpid()) == 1) {
+		/*
+		 * Setup a new session for this process which is
+		 * assumed to be running as root.
+		 */
+		if (setsid() == -1)
+			PANIC("Can't set session ID");
+		if (revoke(_PATH_CONSOLE) != 0)
+			PANIC("Can't revoke console");
+		if ((fd = __sys_open(_PATH_CONSOLE, O_RDWR)) < 0)
+			PANIC("Can't open console");
+		if (setlogin("root") == -1)
+			PANIC("Can't set login to root");
+		if (__sys_ioctl(fd, TIOCSCTTY, (char *) NULL) == -1)
+			PANIC("Can't set controlling terminal");
+	}
+
+	/* Initialize pthread private data. */
+	init_private();
+	_kse_init();
+
+	/* Initialize the initial kse and kseg. */
+	_kse_initial = _kse_alloc(NULL, _thread_scope_system > 0);
+	if (_kse_initial == NULL)
+		PANIC("Can't allocate initial kse.");
+	_kse_initial->k_kseg = _kseg_alloc(NULL);
+	if (_kse_initial->k_kseg == NULL)
+		PANIC("Can't allocate initial kseg.");
+	_kse_initial->k_kseg->kg_flags |= KGF_SINGLE_THREAD;
+	_kse_initial->k_schedq = &_kse_initial->k_kseg->kg_schedq;
+
+	TAILQ_INSERT_TAIL(&_kse_initial->k_kseg->kg_kseq, _kse_initial, k_kgqe);
+	_kse_initial->k_kseg->kg_ksecount = 1;
+
+	/* Set the initial thread. */
+	if (curthread == NULL) {
+		/* Create and initialize the initial thread. */
+		curthread = _thr_alloc(NULL);
+		if (curthread == NULL)
+			PANIC("Can't allocate initial thread");
+		_thr_initial = curthread;
+		init_main_thread(curthread);
+	} else {
+		/*
+		 * The initial thread is the current thread.  It is
+		 * assumed that the current thread is already initialized
+		 * because it is left over from a fork().
+		 */
+		_thr_initial = curthread;
+	}
+	_kse_initial->k_kseg->kg_threadcount = 0;
+	_thr_initial->kse = _kse_initial;
+	_thr_initial->kseg = _kse_initial->k_kseg;
+	_thr_initial->active = 1;
+
+	/*
+	 * Add the thread to the thread list and to the KSEG's thread
+         * queue.
+	 */
+	THR_LIST_ADD(_thr_initial);
+	KSEG_THRQ_ADD(_kse_initial->k_kseg, _thr_initial);
+
+	/* Setup the KSE/thread specific data for the current KSE/thread. */
+	_thr_initial->kse->k_curthread = _thr_initial;
+	_kcb_set(_thr_initial->kse->k_kcb);
+	_tcb_set(_thr_initial->kse->k_kcb, _thr_initial->tcb);
+	_thr_initial->kse->k_flags |= KF_INITIALIZED;
+
+	_thr_signal_init();
+	_kse_critical_leave(&_thr_initial->tcb->tcb_tmbx);
+	/*
+	 * activate threaded mode as soon as possible if we are
+	 * being debugged
+	 */
+	if (_libkse_debug)
+		_kse_setthreaded(1);
+}
+
+/*
+ * 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->attr = _pthread_attr_default;
+	thread->attr.flags |= PTHREAD_SCOPE_SYSTEM;
+	/*
+	 * 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->slice_usec = -1;
+	thread->cancelflags = PTHREAD_CANCEL_ENABLE | PTHREAD_CANCEL_DEFERRED;
+	thread->name = strdup("initial thread");
+
+	/* Initialize the thread for signals: */
+	SIGEMPTYSET(thread->sigmask);
+
+	/*
+	 * Set up the thread mailbox.  The threads saved context
+	 * is also in the mailbox.
+	 */
+	thread->tcb->tcb_tmbx.tm_udata = thread;
+	thread->tcb->tcb_tmbx.tm_context.uc_stack.ss_size =
+	    thread->attr.stacksize_attr;
+	thread->tcb->tcb_tmbx.tm_context.uc_stack.ss_sp =
+	    thread->attr.stackaddr_attr;
+
+	/* 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);
+
+	/* Initialize hooks in the thread structure: */
+	thread->specific = NULL;
+	thread->cleanup = NULL;
+	thread->flags = 0;
+	thread->sigbackout = NULL;
+	thread->continuation = NULL;
+
+	thread->state = PS_RUNNING;
+	thread->uniqueid = 0;
+}
+
+static void
+init_private(void)
+{
+	struct clockinfo clockinfo;
+	size_t len;
+	int mib[2];
+
+	/*
+	 * 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");
+		/* Get the kernel clockrate: */
+		mib[0] = CTL_KERN;
+		mib[1] = KERN_CLOCKRATE;
+		len = sizeof (struct clockinfo);
+		if (sysctl(mib, 2, &clockinfo, &len, NULL, 0) == 0)
+			_clock_res_usec = 1000000 / clockinfo.stathz;
+		else
+			_clock_res_usec = CLOCK_RES_USEC;
+
+		_thr_page_size = getpagesize();
+		_thr_guard_default = _thr_page_size;
+		if (sizeof(void *) == 8) {
+			_thr_stack_default = THR_STACK64_DEFAULT;
+			_thr_stack_initial = THR_STACK64_INITIAL;
+		}
+		else {
+			_thr_stack_default = THR_STACK32_DEFAULT;
+			_thr_stack_initial = THR_STACK32_INITIAL;
+		}
+		_pthread_attr_default.guardsize_attr = _thr_guard_default;
+		_pthread_attr_default.stacksize_attr = _thr_stack_default;
+		TAILQ_INIT(&_thr_atfork_list);
+		init_once = 1;	/* Don't do this again. */
+	} else {
+		/*
+		 * Destroy the locks before creating them.  We don't
+		 * know what state they are in so it is better to just
+		 * recreate them.
+		 */
+		_lock_destroy(&_thread_signal_lock);
+		_lock_destroy(&_mutex_static_lock);
+		_lock_destroy(&_rwlock_static_lock);
+		_lock_destroy(&_keytable_lock);
+	}
+
+	/* Initialize everything else. */
+	TAILQ_INIT(&_thread_list);
+	TAILQ_INIT(&_thread_gc_list);
+	_pthread_mutex_init(&_thr_atfork_mutex, NULL);
+
+	/*
+	 * Initialize the lock for temporary installation of signal
+	 * handlers (to support sigwait() semantics) and for the
+	 * process signal mask and pending signal sets.
+	 */
+	if (_lock_init(&_thread_signal_lock, LCK_ADAPTIVE,
+	    _kse_lock_wait, _kse_lock_wakeup) != 0)
+		PANIC("Cannot initialize _thread_signal_lock");
+	if (_lock_init(&_mutex_static_lock, LCK_ADAPTIVE,
+	    _thr_lock_wait, _thr_lock_wakeup) != 0)
+		PANIC("Cannot initialize mutex static init lock");
+	if (_lock_init(&_rwlock_static_lock, LCK_ADAPTIVE,
+	    _thr_lock_wait, _thr_lock_wakeup) != 0)
+		PANIC("Cannot initialize rwlock static init lock");
+	if (_lock_init(&_keytable_lock, LCK_ADAPTIVE,
+	    _thr_lock_wait, _thr_lock_wakeup) != 0)
+		PANIC("Cannot initialize thread specific keytable lock");
+	_thr_spinlock_init();
+
+	/* Clear pending signals and get the process signal mask. */
+	SIGEMPTYSET(_thr_proc_sigpending);
+
+	/* Are we in M:N mode (default) or 1:1 mode? */
+#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
+	if (getenv("LIBPTHREAD_DEBUG") != NULL)
+		_thr_debug_flags |= DBG_INFO_DUMP;
+
+	/*
+	 * _thread_list_lock and _kse_count are initialized
+	 * by _kse_init()
+	 */
+}
--- /dev/null
+++ lib/libkse/thread/thr_condattr_destroy.c
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 1997 John Birrell <jb at 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. Neither the name of the author nor the names of any 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/libkse/thread/thr_condattr_destroy.c,v 1.10 2007/10/09 13:42:27 obrien Exp $
+ */
+#include <stdlib.h>
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_condattr_destroy);
+LT10_COMPAT_DEFAULT(pthread_condattr_destroy);
+
+__weak_reference(_pthread_condattr_destroy, pthread_condattr_destroy);
+
+int
+_pthread_condattr_destroy(pthread_condattr_t *attr)
+{
+	int	ret;
+	if (attr == NULL || *attr == NULL) {
+		ret = EINVAL;
+	} else {
+		free(*attr);
+		*attr = NULL;
+		ret = 0;
+	}
+	return(ret);
+}
--- /dev/null
+++ lib/libkse/thread/thr_autoinit.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2002 Alfred Perlstein <alfred at freebsd.org>.
+ * Copyright (c) 1995 John Birrell <jb at 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/libkse/thread/thr_autoinit.c,v 1.3 2007/10/09 13:42:27 obrien Exp $
+ */
+
+/*
+ * This module uses GCC extentions to initialize the
+ * threads package at program start-up time.
+ */
+
+#include <pthread.h>
+#include "thr_private.h"
+
+void	_thread_init_hack(void) __attribute__ ((constructor));
+
+void
+_thread_init_hack(void)
+{
+
+	_libpthread_init(NULL);
+}
+
+/*
+ * For the shared version of the threads library, the above is sufficient.
+ * But for the archive version of the library, we need a little bit more.
+ * Namely, we must arrange for this particular module to be pulled in from
+ * the archive library at link time.  To accomplish that, we define and
+ * initialize a variable, "_thread_autoinit_dummy_decl".  This variable is
+ * referenced (as an extern) from libc/stdlib/exit.c. This will always
+ * create a need for this module, ensuring that it is present in the
+ * executable.
+ */
+extern int _thread_autoinit_dummy_decl;
+int _thread_autoinit_dummy_decl = 0;
--- /dev/null
+++ lib/libkse/thread/thr_tcdrain.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2000 Jason Evans <jasone at 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/libkse/thread/thr_tcdrain.c,v 1.10 2007/10/09 13:42:29 obrien Exp $
+ */
+
+#include <termios.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+extern int __tcdrain(int);
+
+LT10_COMPAT_PRIVATE(_tcdrain);
+LT10_COMPAT_DEFAULT(tcdrain);
+
+__weak_reference(_tcdrain, tcdrain);
+
+int
+_tcdrain(int fd)
+{
+	struct pthread *curthread = _get_curthread();
+	int	ret;
+	
+	_thr_cancel_enter(curthread);
+	ret = __tcdrain(fd);
+	_thr_cancel_leave(curthread, 1);
+
+	return (ret);
+}
--- /dev/null
+++ lib/libkse/thread/thr_pspinlock.c
@@ -0,0 +1,174 @@
+/*-
+ * Copyright (c) 2003 David Xu <davidxu at 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/libkse/thread/thr_pspinlock.c,v 1.5 2007/10/09 13:42:29 obrien Exp $
+ */
+
+#include <sys/types.h>
+#include <errno.h>
+#include <pthread.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include "atomic_ops.h"
+#include "thr_private.h"
+
+#define SPIN_COUNT 10000
+
+LT10_COMPAT_PRIVATE(_pthread_spin_init);
+LT10_COMPAT_DEFAULT(pthread_spin_init);
+LT10_COMPAT_PRIVATE(_pthread_spin_destroy);
+LT10_COMPAT_DEFAULT(pthread_spin_destroy);
+LT10_COMPAT_PRIVATE(_pthread_spin_trylock);
+LT10_COMPAT_DEFAULT(pthread_spin_trylock);
+LT10_COMPAT_PRIVATE(_pthread_spin_lock);
+LT10_COMPAT_DEFAULT(pthread_spin_lock);
+LT10_COMPAT_PRIVATE(_pthread_spin_unlock);
+LT10_COMPAT_DEFAULT(pthread_spin_unlock);
+
+__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 {
+		lck->s_lock = 0;
+		lck->s_owner= NULL;
+		*lock = lck;
+		ret = 0;
+	}
+
+	return (ret);
+}
+
+int
+_pthread_spin_destroy(pthread_spinlock_t *lock)
+{
+	int ret;
+
+	if (lock == NULL || *lock == NULL)
+		ret = EINVAL;
+	else if ((*lock)->s_owner != NULL)
+		ret = EBUSY;
+	else {
+		free(*lock);
+		*lock = NULL;
+		ret = 0;
+	}
+
+	return (ret);
+}
+
+int
+_pthread_spin_trylock(pthread_spinlock_t *lock)
+{
+	struct pthread_spinlock	*lck;
+	struct pthread *self = _pthread_self();
+	int oldval, ret;
+
+	if (lock == NULL || (lck = *lock) == NULL)
+		ret = EINVAL;
+	else if (lck->s_owner == self)
+		ret = EDEADLK;
+	else if (lck->s_lock != 0)
+		ret = EBUSY;
+	else {
+		atomic_swap_int((int *)&(lck)->s_lock, 1, &oldval);
+		if (oldval)
+			ret = EBUSY;
+		else {
+			lck->s_owner = _pthread_self();
+			ret = 0;
+		}
+	}
+	return (ret);
+}
+
+int
+_pthread_spin_lock(pthread_spinlock_t *lock)
+{
+	struct pthread_spinlock	*lck;
+	struct pthread *self = _pthread_self();
+	int count, oldval, ret;
+
+	if (lock == NULL || (lck = *lock) == NULL)
+		ret = EINVAL;
+	else if (lck->s_owner == self)
+		ret = EDEADLK;
+	else {
+		do {
+			count = SPIN_COUNT;
+			while (lck->s_lock) {
+#ifdef __i386__
+				/* tell cpu we are spinning */
+				__asm __volatile("pause");
+#endif
+				if (--count <= 0) {
+					count = SPIN_COUNT;
+					_pthread_yield();
+				}
+			}
+			atomic_swap_int((int *)&(lck)->s_lock, 1, &oldval);
+		} while (oldval);
+
+		lck->s_owner = self;
+		ret = 0;
+	}
+
+	return (ret);
+}
+
+int
+_pthread_spin_unlock(pthread_spinlock_t *lock)
+{
+	struct pthread_spinlock	*lck;
+	int ret;
+
+	if (lock == NULL || (lck = *lock) == NULL)
+		ret = EINVAL;
+	else {
+		if (lck->s_owner != _pthread_self())
+			ret = EPERM;
+		else {
+			lck->s_owner = NULL;
+			atomic_swap_int((int *)&lck->s_lock, 0, &ret);
+			ret = 0;
+		}
+	}
+
+	return (ret);
+}
+
--- /dev/null
+++ lib/libkse/thread/thr_attr_get_np.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2002,2003 Alexey Zelkin <phantom at 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/libkse/thread/thr_attr_get_np.c,v 1.6 2007/10/09 13:42:27 obrien Exp $
+ */
+#include <errno.h>
+#include <string.h>
+#include <pthread.h>
+#include <pthread_np.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_attr_get_np);
+LT10_COMPAT_DEFAULT(pthread_attr_get_np);
+
+__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);
+}
--- /dev/null
+++ lib/libkse/thread/thr_read.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 1995-1998 John Birrell <jb at 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. Neither the name of the author nor the names of any 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/libkse/thread/thr_read.c,v 1.21 2007/10/09 13:42:29 obrien Exp $
+ *
+ */
+#include <sys/types.h>
+#include <sys/fcntl.h>
+#include <sys/uio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(__read);
+LT10_COMPAT_DEFAULT(read);
+
+__weak_reference(__read, read);
+
+ssize_t
+__read(int fd, void *buf, size_t nbytes)
+{
+	struct pthread *curthread = _get_curthread();
+	ssize_t	ret;
+
+	_thr_cancel_enter(curthread);
+	ret = __sys_read(fd, buf, nbytes);
+	_thr_cancel_leave(curthread, 1);
+
+	return ret;
+}
--- /dev/null
+++ lib/libkse/thread/thr_find_thread.c
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2003 Daniel Eischen <deischen at freebsd.org>
+ * Copyright (c) 1998 John Birrell <jb at 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. Neither the name of the author nor the names of any 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/libkse/thread/thr_find_thread.c,v 1.16 2007/10/09 13:42:28 obrien Exp $
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+/*
+ * 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)
+{
+	kse_critical_t crit;
+	struct pthread *pthread;
+	struct kse *curkse;
+
+	if (thread == NULL)
+		/* Invalid thread: */
+		return (EINVAL);
+
+	crit = _kse_critical_enter();
+	curkse = _get_curkse();
+	KSE_LOCK_ACQUIRE(curkse, &_thread_list_lock);
+	pthread = _thr_hash_find(thread);
+	if (pthread) {
+		if ((include_dead == 0) &&
+		    ((pthread->state == PS_DEAD) ||
+		    ((pthread->state == PS_DEADLOCK) ||
+		    ((pthread->flags & THR_FLAGS_EXITING) != 0))))
+			pthread = NULL;
+		else {
+			pthread->refcount++;
+			if (curthread != NULL)
+				curthread->critical_count++;
+		}
+	}
+	KSE_LOCK_RELEASE(curkse, &_thread_list_lock);
+	_kse_critical_leave(crit);
+
+	/* Return zero if the thread exists: */
+	return ((pthread != NULL) ? 0 : ESRCH);
+}
+
+void
+_thr_ref_delete(struct pthread *curthread, struct pthread *thread)
+{
+	kse_critical_t crit;
+	struct kse *curkse;
+
+	if (thread != NULL) {
+		crit = _kse_critical_enter();
+		curkse = _get_curkse();
+		KSE_LOCK_ACQUIRE(curkse, &_thread_list_lock);
+		thread->refcount--;
+		if (curthread != NULL)
+			curthread->critical_count--;
+		if ((thread->refcount == 0) &&
+		    (thread->tlflags & TLFLAGS_GC_SAFE) != 0)
+			THR_GCLIST_ADD(thread);
+		KSE_LOCK_RELEASE(curkse, &_thread_list_lock);
+		_kse_critical_leave(crit);
+	}
+}
--- /dev/null
+++ lib/libkse/thread/thr_condattr_pshared.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2005 David Xu <davidxu at freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice unmodified, this list of conditions, and the following
+ *    disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD: src/lib/libkse/thread/thr_condattr_pshared.c,v 1.2 2007/10/09 13:42:27 obrien Exp $
+ *
+ */
+
+#include <errno.h>
+#include "thr_private.h"
+
+__weak_reference(_pthread_condattr_getpshared, pthread_condattr_getpshared);
+__weak_reference(_pthread_condattr_setpshared, pthread_condattr_setpshared);
+
+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);
+}
--- /dev/null
+++ lib/libkse/thread/thr_attr_getinheritsched.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 1998 Daniel Eischen <eischen at 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/libkse/thread/thr_attr_getinheritsched.c,v 1.9 2007/10/09 13:42:27 obrien Exp $
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_attr_getinheritsched);
+LT10_COMPAT_DEFAULT(pthread_attr_getinheritsched);
+
+__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);
+}
--- /dev/null
+++ lib/libkse/thread/thr_kern.c
@@ -0,0 +1,2574 @@
+/*
+ * Copyright (C) 2003 Daniel M. Eischen <deischen at freebsd.org>
+ * Copyright (C) 2002 Jonathon Mini <mini at freebsd.org>
+ * Copyright (c) 1995-1998 John Birrell <jb at cimlogic.com.au>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by John Birrell.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/lib/libkse/thread/thr_kern.c,v 1.125.4.1 2008/02/04 20:03:36 julian Exp $");
+
+#include <sys/types.h>
+#include <sys/kse.h>
+#include <sys/ptrace.h>
+#include <sys/signalvar.h>
+#include <sys/queue.h>
+#include <machine/atomic.h>
+#include <machine/sigframe.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <ucontext.h>
+#include <unistd.h>
+
+#include "atomic_ops.h"
+#include "thr_private.h"
+#include "libc_private.h"
+#ifdef NOTYET
+#include "spinlock.h"
+#endif
+
+/* #define DEBUG_THREAD_KERN */
+#ifdef DEBUG_THREAD_KERN
+#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
+/*
+ * Define high water marks for the maximum number of KSEs and KSE groups
+ * that will be cached. Because we support 1:1 threading, there could have
+ * same number of KSEs and KSE groups as threads. Once these levels are
+ * reached, any extra KSE and KSE groups will be free()'d.
+ */
+#define	MAX_CACHED_KSES		((_thread_scope_system <= 0) ? 50 : 100)
+#define	MAX_CACHED_KSEGS	((_thread_scope_system <= 0) ? 50 : 100)
+
+#define	KSE_SET_MBOX(kse, thrd) \
+	(kse)->k_kcb->kcb_kmbx.km_curthread = &(thrd)->tcb->tcb_tmbx
+
+#define	KSE_SET_EXITED(kse)	(kse)->k_flags |= KF_EXITED
+
+/*
+ * Macros for manipulating the run queues.  The priority queue
+ * routines use the thread's pqe link and also handle the setting
+ * and clearing of the thread's THR_FLAGS_IN_RUNQ flag.
+ */
+#define	KSE_RUNQ_INSERT_HEAD(kse, thrd)			\
+	_pq_insert_head(&(kse)->k_schedq->sq_runq, thrd)
+#define	KSE_RUNQ_INSERT_TAIL(kse, thrd)			\
+	_pq_insert_tail(&(kse)->k_schedq->sq_runq, thrd)
+#define	KSE_RUNQ_REMOVE(kse, thrd)			\
+	_pq_remove(&(kse)->k_schedq->sq_runq, thrd)
+#define	KSE_RUNQ_FIRST(kse)				\
+	((_libkse_debug == 0) ?				\
+	 _pq_first(&(kse)->k_schedq->sq_runq) :		\
+	 _pq_first_debug(&(kse)->k_schedq->sq_runq))
+
+#define KSE_RUNQ_THREADS(kse)	((kse)->k_schedq->sq_runq.pq_threads)
+
+#define THR_NEED_CANCEL(thrd)						\
+	 (((thrd)->cancelflags & THR_CANCELLING) != 0 &&		\
+	  ((thrd)->cancelflags & PTHREAD_CANCEL_DISABLE) == 0 &&	\
+	  (((thrd)->cancelflags & THR_AT_CANCEL_POINT) != 0 ||		\
+	   ((thrd)->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS) != 0))
+
+#define THR_NEED_ASYNC_CANCEL(thrd)					\
+	 (((thrd)->cancelflags & THR_CANCELLING) != 0 &&		\
+	  ((thrd)->cancelflags & PTHREAD_CANCEL_DISABLE) == 0 &&	\
+	  (((thrd)->cancelflags & THR_AT_CANCEL_POINT) == 0 &&		\
+	   ((thrd)->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS) != 0))
+
+/*
+ * 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(, kse)	active_kseq;
+static TAILQ_HEAD(, kse)	free_kseq;
+static TAILQ_HEAD(, kse_group)	free_kse_groupq;
+static TAILQ_HEAD(, kse_group)	active_kse_groupq;
+static TAILQ_HEAD(, kse_group)	gc_ksegq;
+static struct lock		kse_lock;	/* also used for kseg queue */
+static int			free_kse_count = 0;
+static int			free_kseg_count = 0;
+static TAILQ_HEAD(, pthread)	free_threadq;
+static struct lock		thread_lock;
+static int			free_thread_count = 0;
+static int			inited = 0;
+static int			active_kse_count = 0;
+static int			active_kseg_count = 0;
+static u_int64_t		next_uniqueid = 1;
+
+LIST_HEAD(thread_hash_head, pthread);
+#define THREAD_HASH_QUEUES	127
+static struct thread_hash_head	thr_hashtable[THREAD_HASH_QUEUES];
+#define	THREAD_HASH(thrd)	((unsigned long)thrd % THREAD_HASH_QUEUES)
+
+/* Lock for thread tcb constructor/destructor */
+static pthread_mutex_t		_tcb_mutex;
+
+#ifdef DEBUG_THREAD_KERN
+static void	dump_queues(struct kse *curkse);
+#endif
+static void	kse_check_completed(struct kse *kse);
+static void	kse_check_waitq(struct kse *kse);
+static void	kse_fini(struct kse *curkse);
+static void	kse_reinit(struct kse *kse, int sys_scope);
+static void	kse_sched_multi(struct kse_mailbox *kmbx);
+static void	kse_sched_single(struct kse_mailbox *kmbx);
+static void	kse_switchout_thread(struct kse *kse, struct pthread *thread);
+static void	kse_wait(struct kse *kse, struct pthread *td_wait, int sigseq);
+static void	kse_free_unlocked(struct kse *kse);
+static void	kse_destroy(struct kse *kse);
+static void	kseg_free_unlocked(struct kse_group *kseg);
+static void	kseg_init(struct kse_group *kseg);
+static void	kseg_reinit(struct kse_group *kseg);
+static void	kseg_destroy(struct kse_group *kseg);
+static void	kse_waitq_insert(struct pthread *thread);
+static void	kse_wakeup_multi(struct kse *curkse);
+static struct kse_mailbox *kse_wakeup_one(struct pthread *thread);
+static void	thr_cleanup(struct kse *kse, struct pthread *curthread);
+static void	thr_link(struct pthread *thread);
+static void	thr_resume_wrapper(int sig, siginfo_t *, ucontext_t *);
+static void	thr_resume_check(struct pthread *curthread, ucontext_t *ucp);
+static int	thr_timedout(struct pthread *thread, struct timespec *curtime);
+static void	thr_unlink(struct pthread *thread);
+static void	thr_destroy(struct pthread *curthread, struct pthread *thread);
+static void	thread_gc(struct pthread *thread);
+static void	kse_gc(struct pthread *thread);
+static void	kseg_gc(struct pthread *thread);
+
+static void __inline
+thr_accounting(struct pthread *thread)
+{
+	if ((thread->slice_usec != -1) &&
+	    (thread->slice_usec <= TIMESLICE_USEC) &&
+	    (thread->attr.sched_policy != SCHED_FIFO)) {
+		thread->slice_usec += (thread->tcb->tcb_tmbx.tm_uticks
+		    + thread->tcb->tcb_tmbx.tm_sticks) * _clock_res_usec;
+		/* Check for time quantum exceeded: */
+		if (thread->slice_usec > TIMESLICE_USEC)
+			thread->slice_usec = -1;
+	}
+	thread->tcb->tcb_tmbx.tm_uticks = 0;
+	thread->tcb->tcb_tmbx.tm_sticks = 0;
+}
+
+/*
+ * This is called after a fork().
+ * No locks need to be taken here since we are guaranteed to be
+ * single threaded.
+ * 
+ * XXX
+ * POSIX says for threaded process, fork() function is used
+ * only to run new programs, and the effects of calling functions
+ * that require certain resources between the call to fork() and
+ * the call to an exec function are undefined.
+ *
+ * It is not safe to free memory after fork(), because these data
+ * structures may be in inconsistent state.
+ */
+void
+_kse_single_thread(struct pthread *curthread)
+{
+#ifdef NOTYET
+	struct kse *kse;
+	struct kse_group *kseg;
+	struct pthread *thread;
+
+	_thr_spinlock_init();
+	*__malloc_lock = (spinlock_t)_SPINLOCK_INITIALIZER;
+	if (__isthreaded) {
+		_thr_rtld_fini();
+		_thr_signal_deinit();
+	}
+	__isthreaded = 0;
+	/*
+	 * Restore signal mask early, so any memory problems could
+	 * dump core.
+	 */ 
+	__sys_sigprocmask(SIG_SETMASK, &curthread->sigmask, NULL);
+	_thread_active_threads = 1;
+
+	curthread->kse->k_kcb->kcb_kmbx.km_curthread = NULL;
+	curthread->attr.flags &= ~PTHREAD_SCOPE_PROCESS;
+	curthread->attr.flags |= PTHREAD_SCOPE_SYSTEM;
+
+	/*
+	 * Enter a loop to remove and free all threads other than
+	 * the running thread from the active thread list:
+	 */
+	while ((thread = TAILQ_FIRST(&_thread_list)) != NULL) {
+		THR_GCLIST_REMOVE(thread);
+		/*
+		 * Remove this thread from the list (the current
+		 * thread will be removed but re-added by libpthread
+		 * initialization.
+		 */
+		TAILQ_REMOVE(&_thread_list, thread, tle);
+		/* Make sure this isn't the running thread: */
+		if (thread != curthread) {
+			_thr_stack_free(&thread->attr);
+			if (thread->specific != NULL)
+				free(thread->specific);
+			thr_destroy(curthread, thread);
+		}
+	}
+
+	TAILQ_INIT(&curthread->mutexq);		/* initialize mutex queue */
+	curthread->joiner = NULL;		/* no joining threads yet */
+	curthread->refcount = 0;
+	SIGEMPTYSET(curthread->sigpend);	/* clear pending signals */
+
+	/* Don't free thread-specific data as the caller may require it */
+
+	/* Free the free KSEs: */
+	while ((kse = TAILQ_FIRST(&free_kseq)) != NULL) {
+		TAILQ_REMOVE(&free_kseq, kse, k_qe);
+		kse_destroy(kse);
+	}
+	free_kse_count = 0;
+
+	/* Free the active KSEs: */
+	while ((kse = TAILQ_FIRST(&active_kseq)) != NULL) {
+		TAILQ_REMOVE(&active_kseq, kse, k_qe);
+		kse_destroy(kse);
+	}
+	active_kse_count = 0;
+
+	/* Free the free KSEGs: */
+	while ((kseg = TAILQ_FIRST(&free_kse_groupq)) != NULL) {
+		TAILQ_REMOVE(&free_kse_groupq, kseg, kg_qe);
+		kseg_destroy(kseg);
+	}
+	free_kseg_count = 0;
+
+	/* Free the active KSEGs: */
+	while ((kseg = TAILQ_FIRST(&active_kse_groupq)) != NULL) {
+		TAILQ_REMOVE(&active_kse_groupq, kseg, kg_qe);
+		kseg_destroy(kseg);
+	}
+	active_kseg_count = 0;
+
+	/* Free the free threads. */
+	while ((thread = TAILQ_FIRST(&free_threadq)) != NULL) {
+		TAILQ_REMOVE(&free_threadq, thread, tle);
+		thr_destroy(curthread, thread);
+	}
+	free_thread_count = 0;
+
+	/* Free the to-be-gc'd threads. */
+	while ((thread = TAILQ_FIRST(&_thread_gc_list)) != NULL) {
+		TAILQ_REMOVE(&_thread_gc_list, thread, gcle);
+		thr_destroy(curthread, thread);
+	}
+	TAILQ_INIT(&gc_ksegq);
+	_gc_count = 0;
+
+	if (inited != 0) {
+		/*
+		 * Destroy these locks; they'll be recreated to assure they
+		 * are in the unlocked state.
+		 */
+		_lock_destroy(&kse_lock);
+		_lock_destroy(&thread_lock);
+		_lock_destroy(&_thread_list_lock);
+		inited = 0;
+	}
+
+	/* We're no longer part of any lists */
+	curthread->tlflags = 0;
+
+	/*
+	 * After a fork, we are still operating on the thread's original
+	 * stack.  Don't clear the THR_FLAGS_USER from the thread's
+	 * attribute flags.
+	 */
+
+	/* Initialize the threads library. */
+	curthread->kse = NULL;
+	curthread->kseg = NULL;
+	_kse_initial = NULL;
+	_libpthread_init(curthread);
+#else
+	int i;
+
+	/* Reset the current thread and KSE lock data. */
+	for (i = 0; i < curthread->locklevel; i++) {
+		_lockuser_reinit(&curthread->lockusers[i], (void *)curthread);
+	}
+	curthread->locklevel = 0;
+	for (i = 0; i < curthread->kse->k_locklevel; i++) {
+		_lockuser_reinit(&curthread->kse->k_lockusers[i],
+		    (void *)curthread->kse);
+		_LCK_SET_PRIVATE2(&curthread->kse->k_lockusers[i], NULL);
+	}
+	curthread->kse->k_locklevel = 0;
+
+	/*
+	 * Reinitialize the thread and signal locks so that
+	 * sigaction() will work after a fork().
+	 */
+	_lock_reinit(&curthread->lock, LCK_ADAPTIVE, _thr_lock_wait,
+	    _thr_lock_wakeup);
+	_lock_reinit(&_thread_signal_lock, LCK_ADAPTIVE, _kse_lock_wait,
+	    _kse_lock_wakeup);
+
+ 
+	_thr_spinlock_init();
+	if (__isthreaded) {
+		_thr_rtld_fini();
+		_thr_signal_deinit();
+	}
+	__isthreaded = 0;
+	curthread->kse->k_kcb->kcb_kmbx.km_curthread = NULL;
+	curthread->attr.flags |= PTHREAD_SCOPE_SYSTEM;
+
+	/*
+	 * After a fork, it is possible that an upcall occurs in
+	 * the parent KSE that fork()'d before the child process
+	 * is fully created and before its vm space is copied.
+	 * During the upcall, the tcb is set to null or to another
+	 * thread, and this is what gets copied in the child process
+	 * when the vm space is cloned sometime after the upcall
+	 * occurs.  Note that we shouldn't have to set the kcb, but
+	 * we do it for completeness.
+	 */
+	_kcb_set(curthread->kse->k_kcb);
+	_tcb_set(curthread->kse->k_kcb, curthread->tcb);
+ 
+
+	/* After a fork(), there child should have no pending signals. */
+	sigemptyset(&curthread->sigpend);
+
+	/*
+	 * Restore signal mask early, so any memory problems could
+	 * dump core.
+	 */ 
+	sigprocmask(SIG_SETMASK, &curthread->sigmask, NULL);
+	_thread_active_threads = 1;
+#endif
+}
+
+/*
+ * This is used to initialize housekeeping and to initialize the
+ * KSD for the KSE.
+ */
+void
+_kse_init(void)
+{
+	if (inited == 0) {
+		TAILQ_INIT(&active_kseq);
+		TAILQ_INIT(&active_kse_groupq);
+		TAILQ_INIT(&free_kseq);
+		TAILQ_INIT(&free_kse_groupq);
+		TAILQ_INIT(&free_threadq);
+		TAILQ_INIT(&gc_ksegq);
+		if (_lock_init(&kse_lock, LCK_ADAPTIVE,
+		    _kse_lock_wait, _kse_lock_wakeup) != 0)
+			PANIC("Unable to initialize free KSE queue lock");
+		if (_lock_init(&thread_lock, LCK_ADAPTIVE,
+		    _kse_lock_wait, _kse_lock_wakeup) != 0)
+			PANIC("Unable to initialize free thread queue lock");
+		if (_lock_init(&_thread_list_lock, LCK_ADAPTIVE,
+		    _kse_lock_wait, _kse_lock_wakeup) != 0)
+			PANIC("Unable to initialize thread list lock");
+		_pthread_mutex_init(&_tcb_mutex, NULL);
+		active_kse_count = 0;
+		active_kseg_count = 0;
+		_gc_count = 0;
+		inited = 1;
+	}
+}
+
+/*
+ * This is called when the first thread (other than the initial
+ * thread) is created.
+ */
+int
+_kse_setthreaded(int threaded)
+{
+	sigset_t sigset;
+
+	if ((threaded != 0) && (__isthreaded == 0)) {
+		SIGFILLSET(sigset);
+		__sys_sigprocmask(SIG_SETMASK, &sigset, &_thr_initial->sigmask);
+
+		/*
+		 * Tell the kernel to create a KSE for the initial thread
+		 * and enable upcalls in it.
+		 */
+		_kse_initial->k_flags |= KF_STARTED;
+
+		if (_thread_scope_system <= 0) {
+			_thr_initial->attr.flags &= ~PTHREAD_SCOPE_SYSTEM;
+			_kse_initial->k_kseg->kg_flags &= ~KGF_SINGLE_THREAD;
+			_kse_initial->k_kcb->kcb_kmbx.km_curthread = NULL;
+		}
+		else {
+			/*
+			 * For bound thread, kernel reads mailbox pointer
+			 * once, we'd set it here before calling kse_create.
+			 */
+			_tcb_set(_kse_initial->k_kcb, _thr_initial->tcb);
+			KSE_SET_MBOX(_kse_initial, _thr_initial);
+			_kse_initial->k_kcb->kcb_kmbx.km_flags |= KMF_BOUND;
+		}
+
+		/*
+		 * Locking functions in libc are required when there are
+		 * threads other than the initial thread.
+		 */
+		_thr_rtld_init();
+
+		__isthreaded = 1;
+		if (kse_create(&_kse_initial->k_kcb->kcb_kmbx, 0) != 0) {
+			_kse_initial->k_flags &= ~KF_STARTED;
+			__isthreaded = 0;
+			PANIC("kse_create() failed\n");
+			return (-1);
+		}
+		_thr_initial->tcb->tcb_tmbx.tm_lwp = 
+			_kse_initial->k_kcb->kcb_kmbx.km_lwp;
+		_thread_activated = 1;
+
+#ifndef SYSTEM_SCOPE_ONLY
+		if (_thread_scope_system <= 0) {
+			/* Set current thread to initial thread */
+			_tcb_set(_kse_initial->k_kcb, _thr_initial->tcb);
+			KSE_SET_MBOX(_kse_initial, _thr_initial);
+			_thr_start_sig_daemon();
+			_thr_setmaxconcurrency();
+		}
+		else
+#endif
+			__sys_sigprocmask(SIG_SETMASK, &_thr_initial->sigmask,
+			    NULL);
+	}
+	return (0);
+}
+
+/*
+ * Lock wait and wakeup handlers for KSE locks.  These are only used by
+ * KSEs, and should never be used by threads.  KSE locks include the
+ * KSE group lock (used for locking the scheduling queue) and the
+ * kse_lock defined above.
+ *
+ * When a KSE lock attempt blocks, the entire KSE blocks allowing another
+ * KSE to run.  For the most part, it doesn't make much sense to try and
+ * schedule another thread because you need to lock the scheduling queue
+ * in order to do that.  And since the KSE lock is used to lock the scheduling
+ * queue, you would just end up blocking again.
+ */
+void
+_kse_lock_wait(struct lock *lock, struct lockuser *lu)
+{
+	struct kse *curkse = (struct kse *)_LCK_GET_PRIVATE(lu);
+	struct timespec ts;
+	int saved_flags;
+
+	if (curkse->k_kcb->kcb_kmbx.km_curthread != NULL)
+		PANIC("kse_lock_wait does not disable upcall.\n");
+	/*
+	 * Enter a loop to wait until we get the lock.
+	 */
+	ts.tv_sec = 0;
+	ts.tv_nsec = 1000000;  /* 1 sec */
+	while (!_LCK_GRANTED(lu)) {
+		/*
+		 * Yield the kse and wait to be notified when the lock
+		 * is granted.
+		 */
+		saved_flags = curkse->k_kcb->kcb_kmbx.km_flags;
+		curkse->k_kcb->kcb_kmbx.km_flags |= KMF_NOUPCALL |
+		    KMF_NOCOMPLETED;
+		kse_release(&ts);
+		curkse->k_kcb->kcb_kmbx.km_flags = saved_flags;
+	}
+}
+
+void
+_kse_lock_wakeup(struct lock *lock, struct lockuser *lu)
+{
+	struct kse *curkse;
+	struct kse *kse;
+	struct kse_mailbox *mbx;
+
+	curkse = _get_curkse();
+	kse = (struct kse *)_LCK_GET_PRIVATE(lu);
+
+	if (kse == curkse)
+		PANIC("KSE trying to wake itself up in lock");
+	else {
+		mbx = &kse->k_kcb->kcb_kmbx;
+		_lock_grant(lock, lu);
+		/*
+		 * Notify the owning kse that it has the lock.
+		 * It is safe to pass invalid address to kse_wakeup
+		 * even if the mailbox is not in kernel at all,
+		 * and waking up a wrong kse is also harmless.
+		 */
+		kse_wakeup(mbx);
+	}
+}
+
+/*
+ * Thread wait and wakeup handlers for thread locks.  These are only used
+ * by threads, never by KSEs.  Thread locks include the per-thread lock
+ * (defined in its structure), and condition variable and mutex locks.
+ */
+void
+_thr_lock_wait(struct lock *lock, struct lockuser *lu)
+{
+	struct pthread *curthread = (struct pthread *)lu->lu_private;
+
+	do {
+		THR_LOCK_SWITCH(curthread);
+		THR_SET_STATE(curthread, PS_LOCKWAIT);
+		_thr_sched_switch_unlocked(curthread);
+	} while (!_LCK_GRANTED(lu));
+}
+
+void
+_thr_lock_wakeup(struct lock *lock, struct lockuser *lu)
+{
+	struct pthread *thread;
+	struct pthread *curthread;
+	struct kse_mailbox *kmbx;
+
+	curthread = _get_curthread();
+	thread = (struct pthread *)_LCK_GET_PRIVATE(lu);
+
+	THR_SCHED_LOCK(curthread, thread);
+	_lock_grant(lock, lu);
+	kmbx = _thr_setrunnable_unlocked(thread);
+	THR_SCHED_UNLOCK(curthread, thread);
+	if (kmbx != NULL)
+		kse_wakeup(kmbx);
+}
+
+kse_critical_t
+_kse_critical_enter(void)
+{
+	kse_critical_t crit;
+
+	crit = (kse_critical_t)_kcb_critical_enter();
+	return (crit);
+}
+
+void
+_kse_critical_leave(kse_critical_t crit)
+{
+	struct pthread *curthread;
+
+	_kcb_critical_leave((struct kse_thr_mailbox *)crit);
+	if ((crit != NULL) && ((curthread = _get_curthread()) != NULL))
+		THR_YIELD_CHECK(curthread);
+}
+
+int
+_kse_in_critical(void)
+{
+	return (_kcb_in_critical());
+}
+
+void
+_thr_critical_enter(struct pthread *thread)
+{
+	thread->critical_count++;
+}
+
+void
+_thr_critical_leave(struct pthread *thread)
+{
+	thread->critical_count--;
+	THR_YIELD_CHECK(thread);
+}
+
+void
+_thr_sched_switch(struct pthread *curthread)
+{
+	struct kse *curkse;
+
+	(void)_kse_critical_enter();
+	curkse = _get_curkse();
+	KSE_SCHED_LOCK(curkse, curkse->k_kseg);
+	_thr_sched_switch_unlocked(curthread);
+}
+
+/*
+ * XXX - We may need to take the scheduling lock before calling
+ *       this, or perhaps take the lock within here before
+ *       doing anything else.
+ */
+void
+_thr_sched_switch_unlocked(struct pthread *curthread)
+{
+	struct kse *curkse;
+	volatile int resume_once = 0;
+	ucontext_t *uc;
+
+	/* We're in the scheduler, 5 by 5: */
+	curkse = curthread->kse;
+
+	curthread->need_switchout = 1;	/* The thread yielded on its own. */
+	curthread->critical_yield = 0;	/* No need to yield anymore. */
+
+	/* Thread can unlock the scheduler lock. */
+	curthread->lock_switch = 1;
+
+	if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM)
+		kse_sched_single(&curkse->k_kcb->kcb_kmbx);
+	else {
+		if (__predict_false(_libkse_debug != 0)) {
+			/*
+			 * Because debugger saves single step status in thread
+			 * mailbox's tm_dflags, we can safely clear single 
+			 * step status here. the single step status will be
+			 * restored by kse_switchin when the thread is
+			 * switched in again. This also lets uts run in full
+			 * speed.
+			 */
+			 ptrace(PT_CLEARSTEP, curkse->k_kcb->kcb_kmbx.km_lwp,
+				(caddr_t) 1, 0);
+		}
+
+		KSE_SET_SWITCH(curkse);
+		_thread_enter_uts(curthread->tcb, curkse->k_kcb);
+	}
+	
+	/*
+	 * Unlock the scheduling queue and leave the
+	 * critical region.
+	 */
+	/* Don't trust this after a switch! */
+	curkse = curthread->kse;
+
+	curthread->lock_switch = 0;
+	KSE_SCHED_UNLOCK(curkse, curkse->k_kseg);
+	_kse_critical_leave(&curthread->tcb->tcb_tmbx);
+
+	/*
+	 * This thread is being resumed; check for cancellations.
+	 */
+	if (THR_NEED_ASYNC_CANCEL(curthread) && !THR_IN_CRITICAL(curthread)) {
+		uc = alloca(sizeof(ucontext_t));
+		resume_once = 0;
+		THR_GETCONTEXT(uc);
+		if (resume_once == 0) {
+			resume_once = 1;
+			curthread->check_pending = 0;
+			thr_resume_check(curthread, uc);
+		}
+	}
+	THR_ACTIVATE_LAST_LOCK(curthread);
+}
+
+/*
+ * This is the scheduler for a KSE which runs a scope system thread.
+ * The multi-thread KSE scheduler should also work for a single threaded
+ * KSE, but we use a separate scheduler so that it can be fine-tuned
+ * to be more efficient (and perhaps not need a separate stack for
+ * the KSE, allowing it to use the thread's stack).
+ */
+
+static void
+kse_sched_single(struct kse_mailbox *kmbx)
+{
+	struct kse *curkse;
+	struct pthread *curthread;
+	struct timespec ts;
+	sigset_t sigmask;
+	int i, sigseqno, level, first = 0;
+
+	curkse = (struct kse *)kmbx->km_udata;
+	curthread = curkse->k_curthread;
+
+	if (__predict_false((curkse->k_flags & KF_INITIALIZED) == 0)) {
+		/* Setup this KSEs specific data. */
+		_kcb_set(curkse->k_kcb);
+		_tcb_set(curkse->k_kcb, curthread->tcb);
+		curkse->k_flags |= KF_INITIALIZED;
+		first = 1;
+		curthread->active = 1;
+
+		/* Setup kernel signal masks for new thread. */
+		__sys_sigprocmask(SIG_SETMASK, &curthread->sigmask, NULL);
+		/*
+		 * Enter critical region, this is meanless for bound thread,
+		 * It is used to let other code work, those code want mailbox
+		 * to be cleared.
+		 */
+		(void)_kse_critical_enter();
+ 	} else {
+		/*
+		 * Bound thread always has tcb set, this prevent some
+		 * code from blindly setting bound thread tcb to NULL,
+		 * buggy code ?
+		 */
+		_tcb_set(curkse->k_kcb, curthread->tcb);
+	}
+
+	curthread->critical_yield = 0;
+	curthread->need_switchout = 0;
+
+	/*
+	 * Lock the scheduling queue.
+	 *
+	 * There is no scheduling queue for single threaded KSEs,
+	 * but we need a lock for protection regardless.
+	 */
+	if (curthread->lock_switch == 0)
+		KSE_SCHED_LOCK(curkse, curkse->k_kseg);
+
+	/*
+	 * This has to do the job of kse_switchout_thread(), only
+	 * for a single threaded KSE/KSEG.
+	 */
+
+	switch (curthread->state) {
+	case PS_MUTEX_WAIT:
+	case PS_COND_WAIT:
+		if (THR_NEED_CANCEL(curthread)) {
+			curthread->interrupted = 1;
+			curthread->continuation = _thr_finish_cancellation;
+			THR_SET_STATE(curthread, PS_RUNNING);
+		}
+		break;
+
+	case PS_LOCKWAIT:
+		/*
+		 * This state doesn't timeout.
+		 */
+		curthread->wakeup_time.tv_sec = -1;
+		curthread->wakeup_time.tv_nsec = -1;
+		level = curthread->locklevel - 1;
+		if (_LCK_GRANTED(&curthread->lockusers[level]))
+			THR_SET_STATE(curthread, PS_RUNNING);
+		break;
+
+	case PS_DEAD:
+		/* Unlock the scheduling queue and exit the KSE and thread. */
+		thr_cleanup(curkse, curthread);
+		KSE_SCHED_UNLOCK(curkse, curkse->k_kseg);
+		PANIC("bound thread shouldn't get here\n");
+		break;
+
+	case PS_JOIN:
+		if (THR_NEED_CANCEL(curthread)) {
+			curthread->join_status.thread = NULL;
+			THR_SET_STATE(curthread, PS_RUNNING);
+		} else {
+			/*
+			 * This state doesn't timeout.
+			 */
+			curthread->wakeup_time.tv_sec = -1;
+			curthread->wakeup_time.tv_nsec = -1;
+		}
+		break;
+
+	case PS_SUSPENDED:
+		if (THR_NEED_CANCEL(curthread)) {
+			curthread->interrupted = 1;
+			THR_SET_STATE(curthread, PS_RUNNING);
+		} else {
+			/*
+			 * These states don't timeout.
+			 */
+			curthread->wakeup_time.tv_sec = -1;
+			curthread->wakeup_time.tv_nsec = -1;
+		}
+		break;
+
+	case PS_RUNNING:
+		if ((curthread->flags & THR_FLAGS_SUSPENDED) != 0 &&
+		    !THR_NEED_CANCEL(curthread)) {
+			THR_SET_STATE(curthread, PS_SUSPENDED);
+			/*
+			 * These states don't timeout.
+			 */
+			curthread->wakeup_time.tv_sec = -1;
+			curthread->wakeup_time.tv_nsec = -1;
+		}
+		break;
+
+	case PS_SIGWAIT:
+		PANIC("bound thread does not have SIGWAIT state\n");
+
+	case PS_SLEEP_WAIT:
+		PANIC("bound thread does not have SLEEP_WAIT state\n");
+
+	case PS_SIGSUSPEND:
+		PANIC("bound thread does not have SIGSUSPEND state\n");
+	
+	case PS_DEADLOCK:
+		/*
+		 * These states don't timeout and don't need
+		 * to be in the waiting queue.
+		 */
+		curthread->wakeup_time.tv_sec = -1;
+		curthread->wakeup_time.tv_nsec = -1;
+		break;
+
+	default:
+		PANIC("Unknown state\n");
+		break;
+	}
+
+	while (curthread->state != PS_RUNNING) {
+		sigseqno = curkse->k_sigseqno;
+		if (curthread->check_pending != 0) {
+			/*
+			 * Install pending signals into the frame, possible
+			 * cause mutex or condvar backout.
+			 */
+			curthread->check_pending = 0;
+			SIGFILLSET(sigmask);
+
+			/*
+			 * Lock out kernel signal code when we are processing
+			 * signals, and get a fresh copy of signal mask.
+			 */
+			__sys_sigprocmask(SIG_SETMASK, &sigmask,
+					  &curthread->sigmask);
+			for (i = 1; i <= _SIG_MAXSIG; i++) {
+				if (SIGISMEMBER(curthread->sigmask, i))
+					continue;
+				if (SIGISMEMBER(curthread->sigpend, i))
+					(void)_thr_sig_add(curthread, i, 
+					    &curthread->siginfo[i-1]);
+			}
+			__sys_sigprocmask(SIG_SETMASK, &curthread->sigmask,
+				NULL);
+			/* The above code might make thread runnable */
+			if (curthread->state == PS_RUNNING)
+				break;
+		}
+		THR_DEACTIVATE_LAST_LOCK(curthread);
+		kse_wait(curkse, curthread, sigseqno);
+		THR_ACTIVATE_LAST_LOCK(curthread);
+		if (curthread->wakeup_time.tv_sec >= 0) {
+			KSE_GET_TOD(curkse, &ts);
+			if (thr_timedout(curthread, &ts)) {
+				/* Indicate the thread timedout: */
+				curthread->timeout = 1;
+				/* Make the thread runnable. */
+				THR_SET_STATE(curthread, PS_RUNNING);
+			}
+		}
+	}
+
+	if (curthread->lock_switch == 0) {
+		/* Unlock the scheduling queue. */
+		KSE_SCHED_UNLOCK(curkse, curkse->k_kseg);
+	}
+
+	DBG_MSG("Continuing bound thread %p\n", curthread);
+	if (first) {
+		_kse_critical_leave(&curthread->tcb->tcb_tmbx);
+		pthread_exit(curthread->start_routine(curthread->arg));
+	}
+}
+
+#ifdef DEBUG_THREAD_KERN
+static void
+dump_queues(struct kse *curkse)
+{
+	struct pthread *thread;
+
+	DBG_MSG("Threads in waiting queue:\n");
+	TAILQ_FOREACH(thread, &curkse->k_kseg->kg_schedq.sq_waitq, pqe) {
+		DBG_MSG("  thread %p, state %d, blocked %d\n",
+		    thread, thread->state, thread->blocked);
+	}
+}
+#endif
+
+/*
+ * This is the scheduler for a KSE which runs multiple threads.
+ */
+static void
+kse_sched_multi(struct kse_mailbox *kmbx)
+{
+	struct kse *curkse;
+	struct pthread *curthread, *td_wait;
+	int ret;
+
+	curkse = (struct kse *)kmbx->km_udata;
+	THR_ASSERT(curkse->k_kcb->kcb_kmbx.km_curthread == NULL,
+	    "Mailbox not null in kse_sched_multi");
+
+	/* Check for first time initialization: */
+	if (__predict_false((curkse->k_flags & KF_INITIALIZED) == 0)) {
+		/* Setup this KSEs specific data. */
+		_kcb_set(curkse->k_kcb);
+
+		/* Set this before grabbing the context. */
+		curkse->k_flags |= KF_INITIALIZED;
+	}
+
+	/*
+	 * No current thread anymore, calling _get_curthread in UTS
+	 * should dump core
+	 */
+	_tcb_set(curkse->k_kcb, NULL);
+
+	/* If this is an upcall; take the scheduler lock. */
+	if (!KSE_IS_SWITCH(curkse))
+		KSE_SCHED_LOCK(curkse, curkse->k_kseg);
+	else
+		KSE_CLEAR_SWITCH(curkse);
+
+	if (KSE_IS_IDLE(curkse)) {
+		KSE_CLEAR_IDLE(curkse);
+		curkse->k_kseg->kg_idle_kses--;
+	}
+
+	/*
+	 * Now that the scheduler lock is held, get the current
+	 * thread.  The KSE's current thread cannot be safely
+	 * examined without the lock because it could have returned
+	 * as completed on another KSE.  See kse_check_completed().
+	 */
+	curthread = curkse->k_curthread;
+
+	/*
+	 * If the current thread was completed in another KSE, then
+	 * it will be in the run queue.  Don't mark it as being blocked.
+	 */
+	if ((curthread != NULL) &&
+	    ((curthread->flags & THR_FLAGS_IN_RUNQ) == 0) &&
+	    (curthread->need_switchout == 0)) {
+		/*
+		 * Assume the current thread is blocked; when the
+		 * completed threads are checked and if the current
+		 * thread is among the completed, the blocked flag
+		 * will be cleared.
+		 */
+		curthread->blocked = 1;
+		DBG_MSG("Running thread %p is now blocked in kernel.\n",
+		    curthread);
+	}
+
+	/* Check for any unblocked threads in the kernel. */
+	kse_check_completed(curkse);
+
+	/*
+	 * Check for threads that have timed-out.
+	 */
+	kse_check_waitq(curkse);
+
+	/*
+	 * Switchout the current thread, if necessary, as the last step
+	 * so that it is inserted into the run queue (if it's runnable)
+	 * _after_ any other threads that were added to it above.
+	 */
+	if (curthread == NULL)
+		;  /* Nothing to do here. */
+	else if ((curthread->need_switchout == 0) && DBG_CAN_RUN(curthread) &&
+	    (curthread->blocked == 0) && (THR_IN_CRITICAL(curthread))) {
+		/*
+		 * Resume the thread and tell it to yield when
+		 * it leaves the critical region.
+		 */
+		curthread->critical_yield = 1;
+		curthread->active = 1;
+		if ((curthread->flags & THR_FLAGS_IN_RUNQ) != 0)
+			KSE_RUNQ_REMOVE(curkse, curthread);
+		curkse->k_curthread = curthread;
+		curthread->kse = curkse;
+		DBG_MSG("Continuing thread %p in critical region\n",
+		    curthread);
+		kse_wakeup_multi(curkse);
+		KSE_SCHED_UNLOCK(curkse, curkse->k_kseg);
+		ret = _thread_switch(curkse->k_kcb, curthread->tcb, 1);
+		if (ret != 0)
+			PANIC("Can't resume thread in critical region\n");
+	}
+	else if ((curthread->flags & THR_FLAGS_IN_RUNQ) == 0) {
+		curthread->tcb->tcb_tmbx.tm_lwp = 0;
+		kse_switchout_thread(curkse, curthread);
+	}
+	curkse->k_curthread = NULL;
+
+#ifdef DEBUG_THREAD_KERN
+	dump_queues(curkse);
+#endif
+
+	/* Check if there are no threads ready to run: */
+	while (((curthread = KSE_RUNQ_FIRST(curkse)) == NULL) &&
+	    (curkse->k_kseg->kg_threadcount != 0) &&
+	    ((curkse->k_flags & KF_TERMINATED) == 0)) {
+		/*
+		 * Wait for a thread to become active or until there are
+		 * no more threads.
+		 */
+		td_wait = KSE_WAITQ_FIRST(curkse);
+		kse_wait(curkse, td_wait, 0);
+		kse_check_completed(curkse);
+		kse_check_waitq(curkse);
+	}
+
+	/* Check for no more threads: */
+	if ((curkse->k_kseg->kg_threadcount == 0) ||
+	    ((curkse->k_flags & KF_TERMINATED) != 0)) {
+		/*
+		 * Normally this shouldn't return, but it will if there
+		 * are other KSEs running that create new threads that
+		 * are assigned to this KSE[G].  For instance, if a scope
+		 * system thread were to create a scope process thread
+		 * and this kse[g] is the initial kse[g], then that newly
+		 * created thread would be assigned to us (the initial
+		 * kse[g]).
+		 */
+		kse_wakeup_multi(curkse);
+		KSE_SCHED_UNLOCK(curkse, curkse->k_kseg);
+		kse_fini(curkse);
+		/* never returns */
+	}
+
+	THR_ASSERT(curthread != NULL,
+	    "Return from kse_wait/fini without thread.");
+	THR_ASSERT(curthread->state != PS_DEAD,
+	    "Trying to resume dead thread!");
+	KSE_RUNQ_REMOVE(curkse, curthread);
+
+	/*
+	 * Make the selected thread the current thread.
+	 */
+	curkse->k_curthread = curthread;
+
+	/*
+	 * Make sure the current thread's kse points to this kse.
+	 */
+	curthread->kse = curkse;
+
+	/*
+	 * Reset the time slice if this thread is running for the first
+	 * time or running again after using its full time slice allocation.
+	 */
+	if (curthread->slice_usec == -1)
+		curthread->slice_usec = 0;
+
+	/* Mark the thread active. */
+	curthread->active = 1;
+
+	/*
+	 * The thread's current signal frame will only be NULL if it
+	 * is being resumed after being blocked in the kernel.  In
+	 * this case, and if the thread needs to run down pending
+	 * signals or needs a cancellation check, we need to add a
+	 * signal frame to the thread's context.
+	 */
+	if (curthread->lock_switch == 0 && curthread->state == PS_RUNNING &&
+	    (curthread->check_pending != 0 ||
+	     THR_NEED_ASYNC_CANCEL(curthread)) &&
+	    !THR_IN_CRITICAL(curthread)) {
+		curthread->check_pending = 0;
+		signalcontext(&curthread->tcb->tcb_tmbx.tm_context, 0,
+		    (__sighandler_t *)thr_resume_wrapper);
+	}
+	kse_wakeup_multi(curkse);
+	/*
+	 * Continue the thread at its current frame:
+	 */
+	if (curthread->lock_switch != 0) {
+		/*
+		 * This thread came from a scheduler switch; it will
+		 * unlock the scheduler lock and set the mailbox.
+		 */
+		ret = _thread_switch(curkse->k_kcb, curthread->tcb, 0);
+	} else {
+		/* This thread won't unlock the scheduler lock. */
+		KSE_SCHED_UNLOCK(curkse, curkse->k_kseg);
+		ret = _thread_switch(curkse->k_kcb, curthread->tcb, 1);
+	}
+	if (ret != 0)
+		PANIC("Thread has returned from _thread_switch");
+
+	/* This point should not be reached. */
+	PANIC("Thread has returned from _thread_switch");
+}
+
+static void
+thr_resume_wrapper(int sig, siginfo_t *siginfo, ucontext_t *ucp)
+{
+	struct pthread *curthread = _get_curthread();
+	struct kse *curkse;
+	int ret, err_save = errno;
+
+	DBG_MSG(">>> sig wrapper\n");
+	if (curthread->lock_switch)
+		PANIC("thr_resume_wrapper, lock_switch != 0\n");
+	thr_resume_check(curthread, ucp);
+	errno = err_save;
+	_kse_critical_enter();
+	curkse = curthread->kse;
+	curthread->tcb->tcb_tmbx.tm_context = *ucp;
+	ret = _thread_switch(curkse->k_kcb, curthread->tcb, 1);
+	if (ret != 0)
+		PANIC("thr_resume_wrapper: thread has returned "
+		      "from _thread_switch");
+	/* THR_SETCONTEXT(ucp); */ /* not work, why ? */
+}
+
+static void
+thr_resume_check(struct pthread *curthread, ucontext_t *ucp)
+{
+	_thr_sig_rundown(curthread, ucp);
+
+	if (THR_NEED_ASYNC_CANCEL(curthread))
+		pthread_testcancel();
+}
+
+/*
+ * Clean up a thread.  This must be called with the thread's KSE
+ * scheduling lock held.  The thread must be a thread from the
+ * KSE's group.
+ */
+static void
+thr_cleanup(struct kse *curkse, struct pthread *thread)
+{
+	struct pthread *joiner;
+	struct kse_mailbox *kmbx = NULL;
+	int sys_scope;
+
+	thread->active = 0;
+	thread->need_switchout = 0;
+	thread->lock_switch = 0;
+	thread->check_pending = 0;
+
+	if ((joiner = thread->joiner) != NULL) {
+		/* Joinee scheduler lock held; joiner won't leave. */
+		if (joiner->kseg == curkse->k_kseg) {
+			if (joiner->join_status.thread == thread) {
+				joiner->join_status.thread = NULL;
+				joiner->join_status.ret = thread->ret;
+				(void)_thr_setrunnable_unlocked(joiner);
+			}
+		} else {
+			KSE_SCHED_UNLOCK(curkse, curkse->k_kseg);
+			/* The joiner may have removed itself and exited. */
+			if (_thr_ref_add(thread, joiner, 0) == 0) {
+				KSE_SCHED_LOCK(curkse, joiner->kseg);
+				if (joiner->join_status.thread == thread) {
+					joiner->join_status.thread = NULL;
+					joiner->join_status.ret = thread->ret;
+					kmbx = _thr_setrunnable_unlocked(joiner);
+				}
+				KSE_SCHED_UNLOCK(curkse, joiner->kseg);
+				_thr_ref_delete(thread, joiner);
+				if (kmbx != NULL)
+					kse_wakeup(kmbx);
+			}
+			KSE_SCHED_LOCK(curkse, curkse->k_kseg);
+		}
+		thread->attr.flags |= PTHREAD_DETACHED;
+	}
+
+	if (!(sys_scope = (thread->attr.flags & PTHREAD_SCOPE_SYSTEM))) {
+		/*
+		 * Remove the thread from the KSEG's list of threads.
+	 	 */
+		KSEG_THRQ_REMOVE(thread->kseg, thread);
+		/*
+		 * Migrate the thread to the main KSE so that this
+		 * KSE and KSEG can be cleaned when their last thread
+		 * exits.
+		 */
+		thread->kseg = _kse_initial->k_kseg;
+		thread->kse = _kse_initial;
+	}
+
+	/*
+	 * We can't hold the thread list lock while holding the
+	 * scheduler lock.
+	 */
+	KSE_SCHED_UNLOCK(curkse, curkse->k_kseg);
+	DBG_MSG("Adding thread %p to GC list\n", thread);
+	KSE_LOCK_ACQUIRE(curkse, &_thread_list_lock);
+	thread->tlflags |= TLFLAGS_GC_SAFE;
+	THR_GCLIST_ADD(thread);
+	KSE_LOCK_RELEASE(curkse, &_thread_list_lock);
+	if (sys_scope) {
+		/*
+		 * System scope thread is single thread group, 
+		 * when thread is exited, its kse and ksegrp should
+		 * be recycled as well.
+		 * kse upcall stack belongs to thread, clear it here.
+		 */
+		curkse->k_stack.ss_sp = 0;
+		curkse->k_stack.ss_size = 0;
+		kse_exit();
+		PANIC("kse_exit() failed for system scope thread");
+	}
+	KSE_SCHED_LOCK(curkse, curkse->k_kseg);
+}
+
+void
+_thr_gc(struct pthread *curthread)
+{
+	thread_gc(curthread);
+	kse_gc(curthread);
+	kseg_gc(curthread);
+}
+
+static void
+thread_gc(struct pthread *curthread)
+{
+	struct pthread *td, *td_next;
+	kse_critical_t crit;
+	TAILQ_HEAD(, pthread) worklist;
+
+	TAILQ_INIT(&worklist);
+	crit = _kse_critical_enter();
+	KSE_LOCK_ACQUIRE(curthread->kse, &_thread_list_lock);
+
+	/* 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->tlflags & TLFLAGS_GC_SAFE) == 0)
+			continue;
+		else if (((td->attr.flags & PTHREAD_SCOPE_SYSTEM) != 0) &&
+		    ((td->kse->k_kcb->kcb_kmbx.km_flags & KMF_DONE) == 0)) {
+			/*
+			 * The thread and KSE are operating on the same
+			 * stack.  Wait for the KSE to exit before freeing
+			 * the thread's stack as well as everything else.
+			 */
+			continue;
+		}
+		/*
+		 * Remove the thread from the GC list.  If the thread
+		 * isn't yet detached, it will get added back to the
+		 * GC list at a later time.
+		 */
+		THR_GCLIST_REMOVE(td);
+		DBG_MSG("Freeing thread %p stack\n", td);
+		/*
+		 * We can free the thread stack since it's no longer
+		 * in use.
+		 */
+		_thr_stack_free(&td->attr);
+		if (((td->attr.flags & PTHREAD_DETACHED) != 0) &&
+		    (td->refcount == 0)) {
+			/*
+			 * 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);
+		}
+	}
+	KSE_LOCK_RELEASE(curthread->kse, &_thread_list_lock);
+	_kse_critical_leave(crit);
+
+	while ((td = TAILQ_FIRST(&worklist)) != NULL) {
+		TAILQ_REMOVE(&worklist, td, gcle);
+		/*
+		 * XXX we don't free initial thread and its kse
+		 * (if thread is a bound thread), because there might
+		 * have some code referencing initial thread and kse.
+		 */
+		if (td == _thr_initial) {
+			DBG_MSG("Initial thread won't be freed\n");
+			continue;
+		}
+
+		if ((td->attr.flags & PTHREAD_SCOPE_SYSTEM) != 0) {
+			crit = _kse_critical_enter();
+			KSE_LOCK_ACQUIRE(curthread->kse, &kse_lock);
+			kse_free_unlocked(td->kse);
+			kseg_free_unlocked(td->kseg);
+			KSE_LOCK_RELEASE(curthread->kse, &kse_lock);
+			_kse_critical_leave(crit);
+		}
+		DBG_MSG("Freeing thread %p\n", td);
+		_thr_free(curthread, td);
+	}
+}
+
+static void
+kse_gc(struct pthread *curthread)
+{
+	kse_critical_t crit;
+	TAILQ_HEAD(, kse) worklist;
+	struct kse *kse;
+
+	if (free_kse_count <= MAX_CACHED_KSES)
+		return;
+	TAILQ_INIT(&worklist);
+	crit = _kse_critical_enter();
+	KSE_LOCK_ACQUIRE(curthread->kse, &kse_lock);
+	while (free_kse_count > MAX_CACHED_KSES) {
+		kse = TAILQ_FIRST(&free_kseq);
+		TAILQ_REMOVE(&free_kseq, kse, k_qe);
+		TAILQ_INSERT_HEAD(&worklist, kse, k_qe);
+		free_kse_count--;
+	}
+	KSE_LOCK_RELEASE(curthread->kse, &kse_lock);
+	_kse_critical_leave(crit);
+
+	while ((kse = TAILQ_FIRST(&worklist))) {
+		TAILQ_REMOVE(&worklist, kse, k_qe);
+		kse_destroy(kse);
+	}
+}
+
+static void
+kseg_gc(struct pthread *curthread)
+{
+	kse_critical_t crit;
+	TAILQ_HEAD(, kse_group) worklist;
+	struct kse_group *kseg;
+
+	if (free_kseg_count <= MAX_CACHED_KSEGS)
+		return; 
+	TAILQ_INIT(&worklist);
+	crit = _kse_critical_enter();
+	KSE_LOCK_ACQUIRE(curthread->kse, &kse_lock);
+	while (free_kseg_count > MAX_CACHED_KSEGS) {
+		kseg = TAILQ_FIRST(&free_kse_groupq);
+		TAILQ_REMOVE(&free_kse_groupq, kseg, kg_qe);
+		free_kseg_count--;
+		TAILQ_INSERT_HEAD(&worklist, kseg, kg_qe);
+	}
+	KSE_LOCK_RELEASE(curthread->kse, &kse_lock);
+	_kse_critical_leave(crit);
+
+	while ((kseg = TAILQ_FIRST(&worklist))) {
+		TAILQ_REMOVE(&worklist, kseg, kg_qe);
+		kseg_destroy(kseg);
+	}
+}
+
+/*
+ * Only new threads that are running or suspended may be scheduled.
+ */
+int
+_thr_schedule_add(struct pthread *curthread, struct pthread *newthread)
+{
+	kse_critical_t crit;
+	int ret;
+
+	/* Add the new thread. */
+	thr_link(newthread);
+
+	/*
+	 * If this is the first time creating a thread, make sure
+	 * the mailbox is set for the current thread.
+	 */
+	if ((newthread->attr.flags & PTHREAD_SCOPE_SYSTEM) != 0) {
+		/* We use the thread's stack as the KSE's stack. */
+		newthread->kse->k_kcb->kcb_kmbx.km_stack.ss_sp =
+		    newthread->attr.stackaddr_attr;
+		newthread->kse->k_kcb->kcb_kmbx.km_stack.ss_size =
+		    newthread->attr.stacksize_attr;
+
+		/*
+		 * No need to lock the scheduling queue since the
+		 * KSE/KSEG pair have not yet been started.
+		 */
+		KSEG_THRQ_ADD(newthread->kseg, newthread);
+		/* this thread never gives up kse */
+		newthread->active = 1;
+		newthread->kse->k_curthread = newthread;
+		newthread->kse->k_kcb->kcb_kmbx.km_flags = KMF_BOUND;
+		newthread->kse->k_kcb->kcb_kmbx.km_func =
+		    (kse_func_t *)kse_sched_single;
+		newthread->kse->k_kcb->kcb_kmbx.km_quantum = 0;
+		KSE_SET_MBOX(newthread->kse, newthread);
+		/*
+		 * This thread needs a new KSE and KSEG.
+		 */
+		newthread->kse->k_flags &= ~KF_INITIALIZED;
+		newthread->kse->k_flags |= KF_STARTED;
+		/* Fire up! */
+		ret = kse_create(&newthread->kse->k_kcb->kcb_kmbx, 1);
+		if (ret != 0)
+			ret = errno;
+	}
+	else {
+		/*
+		 * Lock the KSE and add the new thread to its list of
+		 * assigned threads.  If the new thread is runnable, also
+		 * add it to the KSE's run queue.
+		 */
+		crit = _kse_critical_enter();
+		KSE_SCHED_LOCK(curthread->kse, newthread->kseg);
+		KSEG_THRQ_ADD(newthread->kseg, newthread);
+		if (newthread->state == PS_RUNNING)
+			THR_RUNQ_INSERT_TAIL(newthread);
+		if ((newthread->kse->k_flags & KF_STARTED) == 0) {
+			/*
+			 * This KSE hasn't been started yet.  Start it
+			 * outside of holding the lock.
+			 */
+			newthread->kse->k_flags |= KF_STARTED;
+			newthread->kse->k_kcb->kcb_kmbx.km_func =
+			    (kse_func_t *)kse_sched_multi;
+			newthread->kse->k_kcb->kcb_kmbx.km_flags = 0;
+			kse_create(&newthread->kse->k_kcb->kcb_kmbx, 0);
+		 } else if ((newthread->state == PS_RUNNING) &&
+		     KSE_IS_IDLE(newthread->kse)) {
+			/*
+			 * The thread is being scheduled on another KSEG.
+			 */
+			kse_wakeup_one(newthread);
+		}
+		KSE_SCHED_UNLOCK(curthread->kse, newthread->kseg);
+		_kse_critical_leave(crit);
+		ret = 0;
+	}
+	if (ret != 0)
+		thr_unlink(newthread);
+
+	return (ret);
+}
+
+void
+kse_waitq_insert(struct pthread *thread)
+{
+	struct pthread *td;
+
+	if (thread->wakeup_time.tv_sec == -1)
+		TAILQ_INSERT_TAIL(&thread->kse->k_schedq->sq_waitq, thread,
+		    pqe);
+	else {
+		td = TAILQ_FIRST(&thread->kse->k_schedq->sq_waitq);
+		while ((td != NULL) && (td->wakeup_time.tv_sec != -1) &&
+		    ((td->wakeup_time.tv_sec < thread->wakeup_time.tv_sec) ||
+		    ((td->wakeup_time.tv_sec == thread->wakeup_time.tv_sec) &&
+		    (td->wakeup_time.tv_nsec <= thread->wakeup_time.tv_nsec))))
+			td = TAILQ_NEXT(td, pqe);
+		if (td == NULL)
+			TAILQ_INSERT_TAIL(&thread->kse->k_schedq->sq_waitq,
+			    thread, pqe);
+		else
+			TAILQ_INSERT_BEFORE(td, thread, pqe);
+	}
+	thread->flags |= THR_FLAGS_IN_WAITQ;
+}
+
+/*
+ * This must be called with the scheduling lock held.
+ */
+static void
+kse_check_completed(struct kse *kse)
+{
+	struct pthread *thread;
+	struct kse_thr_mailbox *completed;
+	int sig;
+
+	if ((completed = kse->k_kcb->kcb_kmbx.km_completed) != NULL) {
+		kse->k_kcb->kcb_kmbx.km_completed = NULL;
+		while (completed != NULL) {
+			thread = completed->tm_udata;
+			DBG_MSG("Found completed thread %p, name %s\n",
+			    thread,
+			    (thread->name == NULL) ? "none" : thread->name);
+			thread->blocked = 0;
+			if (thread != kse->k_curthread) {
+				thr_accounting(thread);
+				if ((thread->flags & THR_FLAGS_SUSPENDED) != 0)
+					THR_SET_STATE(thread, PS_SUSPENDED);
+				else
+					KSE_RUNQ_INSERT_TAIL(kse, thread);
+				if ((thread->kse != kse) &&
+				    (thread->kse->k_curthread == thread)) {
+					/*
+					 * Remove this thread from its
+					 * previous KSE so that it (the KSE)
+					 * doesn't think it is still active.
+					 */
+					thread->kse->k_curthread = NULL;
+					thread->active = 0;
+				}
+			}
+			if ((sig = thread->tcb->tcb_tmbx.tm_syncsig.si_signo)
+			    != 0) {
+				if (SIGISMEMBER(thread->sigmask, sig))
+					SIGADDSET(thread->sigpend, sig);
+				else if (THR_IN_CRITICAL(thread))
+					kse_thr_interrupt(NULL, KSE_INTR_SIGEXIT, sig);
+				else
+					(void)_thr_sig_add(thread, sig,
+					    &thread->tcb->tcb_tmbx.tm_syncsig);
+				thread->tcb->tcb_tmbx.tm_syncsig.si_signo = 0;
+			}
+			completed = completed->tm_next;
+		}
+	}
+}
+
+/*
+ * This must be called with the scheduling lock held.
+ */
+static void
+kse_check_waitq(struct kse *kse)
+{
+	struct pthread	*pthread;
+	struct timespec ts;
+
+	KSE_GET_TOD(kse, &ts);
+
+	/*
+	 * Wake up threads that have timedout.  This has to be
+	 * done before adding the current thread to the run queue
+	 * so that a CPU intensive thread doesn't get preference
+	 * over waiting threads.
+	 */
+	while (((pthread = KSE_WAITQ_FIRST(kse)) != NULL) &&
+	    thr_timedout(pthread, &ts)) {
+		/* Remove the thread from the wait queue: */
+		KSE_WAITQ_REMOVE(kse, pthread);
+		DBG_MSG("Found timedout thread %p in waitq\n", pthread);
+
+		/* Indicate the thread timedout: */
+		pthread->timeout = 1;
+
+		/* Add the thread to the priority queue: */
+		if ((pthread->flags & THR_FLAGS_SUSPENDED) != 0)
+			THR_SET_STATE(pthread, PS_SUSPENDED);
+		else {
+			THR_SET_STATE(pthread, PS_RUNNING);
+			KSE_RUNQ_INSERT_TAIL(kse, pthread);
+		}
+	}
+}
+
+static int
+thr_timedout(struct pthread *thread, struct timespec *curtime)
+{
+	if (thread->wakeup_time.tv_sec < 0)
+		return (0);
+	else if (thread->wakeup_time.tv_sec > curtime->tv_sec)
+		return (0);
+	else if ((thread->wakeup_time.tv_sec == curtime->tv_sec) &&
+	    (thread->wakeup_time.tv_nsec > curtime->tv_nsec))
+		return (0);
+	else
+		return (1);
+}
+
+/*
+ * This must be called with the scheduling lock held.
+ *
+ * Each thread has a time slice, a wakeup time (used when it wants
+ * to wait for a specified amount of time), a run state, and an
+ * active flag.
+ *
+ * When a thread gets run by the scheduler, the active flag is
+ * set to non-zero (1).  When a thread performs an explicit yield
+ * or schedules a state change, it enters the scheduler and the
+ * active flag is cleared.  When the active flag is still seen
+ * set in the scheduler, that means that the thread is blocked in
+ * the kernel (because it is cleared before entering the scheduler
+ * in all other instances).
+ *
+ * The wakeup time is only set for those states that can timeout.
+ * It is set to (-1, -1) for all other instances.
+ *
+ * The thread's run state, aside from being useful when debugging,
+ * is used to place the thread in an appropriate queue.  There
+ * are 2 basic queues:
+ *
+ *   o run queue - queue ordered by priority for all threads
+ *                 that are runnable
+ *   o waiting queue - queue sorted by wakeup time for all threads
+ *                     that are not otherwise runnable (not blocked
+ *                     in kernel, not waiting for locks)
+ *
+ * The thread's time slice is used for round-robin scheduling
+ * (the default scheduling policy).  While a SCHED_RR thread
+ * is runnable it's time slice accumulates.  When it reaches
+ * the time slice interval, it gets reset and added to the end
+ * of the queue of threads at its priority.  When a thread no
+ * longer becomes runnable (blocks in kernel, waits, etc), its
+ * time slice is reset.
+ *
+ * The job of kse_switchout_thread() is to handle all of the above.
+ */
+static void
+kse_switchout_thread(struct kse *kse, struct pthread *thread)
+{
+	int level;
+	int i;
+	int restart;
+	siginfo_t siginfo;
+
+	/*
+	 * Place the currently running thread into the
+	 * appropriate queue(s).
+	 */
+	DBG_MSG("Switching out thread %p, state %d\n", thread, thread->state);
+
+	THR_DEACTIVATE_LAST_LOCK(thread);
+	if (thread->blocked != 0) {
+		thread->active = 0;
+		thread->need_switchout = 0;
+		/* This thread must have blocked in the kernel. */
+		/*
+		 * Check for pending signals and cancellation for
+		 * this thread to see if we need to interrupt it
+		 * in the kernel.
+		 */
+		if (THR_NEED_CANCEL(thread)) {
+			kse_thr_interrupt(&thread->tcb->tcb_tmbx,
+					  KSE_INTR_INTERRUPT, 0);
+		} else if (thread->check_pending != 0) {
+			for (i = 1; i <= _SIG_MAXSIG; ++i) {
+				if (SIGISMEMBER(thread->sigpend, i) &&
+				    !SIGISMEMBER(thread->sigmask, i)) {
+					restart = _thread_sigact[i - 1].sa_flags & SA_RESTART;
+					kse_thr_interrupt(&thread->tcb->tcb_tmbx,
+					    restart ? KSE_INTR_RESTART : KSE_INTR_INTERRUPT, 0);
+					break;
+				}
+			}
+		}
+	}
+	else {
+		switch (thread->state) {
+		case PS_MUTEX_WAIT:
+		case PS_COND_WAIT:
+			if (THR_NEED_CANCEL(thread)) {
+				thread->interrupted = 1;
+				thread->continuation = _thr_finish_cancellation;
+				THR_SET_STATE(thread, PS_RUNNING);
+			} else {
+				/* Insert into the waiting queue: */
+				KSE_WAITQ_INSERT(kse, thread);
+			}
+			break;
+
+		case PS_LOCKWAIT:
+			/*
+			 * This state doesn't timeout.
+			 */
+			thread->wakeup_time.tv_sec = -1;
+			thread->wakeup_time.tv_nsec = -1;
+			level = thread->locklevel - 1;
+			if (!_LCK_GRANTED(&thread->lockusers[level]))
+				KSE_WAITQ_INSERT(kse, thread);
+			else
+				THR_SET_STATE(thread, PS_RUNNING);
+			break;
+
+		case PS_SLEEP_WAIT:
+		case PS_SIGWAIT:
+			if (THR_NEED_CANCEL(thread)) {
+				thread->interrupted = 1;
+				THR_SET_STATE(thread, PS_RUNNING);
+			} else {
+				KSE_WAITQ_INSERT(kse, thread);
+			}
+			break;
+
+		case PS_JOIN:
+			if (THR_NEED_CANCEL(thread)) {
+				thread->join_status.thread = NULL;
+				THR_SET_STATE(thread, PS_RUNNING);
+			} else {
+				/*
+				 * This state doesn't timeout.
+				 */
+				thread->wakeup_time.tv_sec = -1;
+				thread->wakeup_time.tv_nsec = -1;
+
+				/* Insert into the waiting queue: */
+				KSE_WAITQ_INSERT(kse, thread);
+			}
+			break;
+
+		case PS_SIGSUSPEND:
+		case PS_SUSPENDED:
+			if (THR_NEED_CANCEL(thread)) {
+				thread->interrupted = 1;
+				THR_SET_STATE(thread, PS_RUNNING);
+			} else {
+				/*
+				 * These states don't timeout.
+				 */
+				thread->wakeup_time.tv_sec = -1;
+				thread->wakeup_time.tv_nsec = -1;
+
+				/* Insert into the waiting queue: */
+				KSE_WAITQ_INSERT(kse, thread);
+			}
+			break;
+
+		case PS_DEAD:
+			/*
+			 * The scheduler is operating on a different
+			 * stack.  It is safe to do garbage collecting
+			 * here.
+			 */
+			thr_cleanup(kse, thread);
+			return;
+			break;
+
+		case PS_RUNNING:
+			if ((thread->flags & THR_FLAGS_SUSPENDED) != 0 &&
+			    !THR_NEED_CANCEL(thread))
+				THR_SET_STATE(thread, PS_SUSPENDED);
+			break;
+
+		case PS_DEADLOCK:
+			/*
+			 * These states don't timeout.
+			 */
+			thread->wakeup_time.tv_sec = -1;
+			thread->wakeup_time.tv_nsec = -1;
+
+			/* Insert into the waiting queue: */
+			KSE_WAITQ_INSERT(kse, thread);
+			break;
+
+		default:
+			PANIC("Unknown state\n");
+			break;
+		}
+
+		thr_accounting(thread);
+		if (thread->state == PS_RUNNING) {
+			if (thread->slice_usec == -1) {
+				/*
+				 * The thread exceeded its time quantum or
+				 * it yielded the CPU; place it at the tail
+				 * of the queue for its priority.
+				 */
+				KSE_RUNQ_INSERT_TAIL(kse, thread);
+			} else {
+				/*
+				 * The thread hasn't exceeded its interval
+				 * Place it at the head of the queue for its
+				 * priority.
+				 */
+				KSE_RUNQ_INSERT_HEAD(kse, thread);
+			}
+		}
+	}
+	thread->active = 0;
+	thread->need_switchout = 0;
+	if (thread->check_pending != 0) {
+		/* Install pending signals into the frame. */
+		thread->check_pending = 0;
+		KSE_LOCK_ACQUIRE(kse, &_thread_signal_lock);
+		for (i = 1; i <= _SIG_MAXSIG; i++) {
+			if (SIGISMEMBER(thread->sigmask, i))
+				continue;
+			if (SIGISMEMBER(thread->sigpend, i))
+				(void)_thr_sig_add(thread, i,
+				    &thread->siginfo[i-1]);
+			else if (SIGISMEMBER(_thr_proc_sigpending, i) &&
+				_thr_getprocsig_unlocked(i, &siginfo)) {
+				(void)_thr_sig_add(thread, i, &siginfo);
+			}
+		}
+		KSE_LOCK_RELEASE(kse, &_thread_signal_lock);
+	}
+}
+
+/*
+ * This function waits for the smallest timeout value of any waiting
+ * thread, or until it receives a message from another KSE.
+ *
+ * This must be called with the scheduling lock held.
+ */
+static void
+kse_wait(struct kse *kse, struct pthread *td_wait, int sigseqno)
+{
+	struct timespec ts, ts_sleep;
+	int saved_flags;
+
+	if ((td_wait == NULL) || (td_wait->wakeup_time.tv_sec < 0)) {
+		/* Limit sleep to no more than 1 minute. */
+		ts_sleep.tv_sec = 60;
+		ts_sleep.tv_nsec = 0;
+	} else {
+		KSE_GET_TOD(kse, &ts);
+		TIMESPEC_SUB(&ts_sleep, &td_wait->wakeup_time, &ts);
+		if (ts_sleep.tv_sec > 60) {
+			ts_sleep.tv_sec = 60;
+			ts_sleep.tv_nsec = 0;
+		}
+	}
+	/* Don't sleep for negative times. */
+	if ((ts_sleep.tv_sec >= 0) && (ts_sleep.tv_nsec >= 0)) {
+		KSE_SET_IDLE(kse);
+		kse->k_kseg->kg_idle_kses++;
+		KSE_SCHED_UNLOCK(kse, kse->k_kseg);
+		if ((kse->k_kseg->kg_flags & KGF_SINGLE_THREAD) &&
+		    (kse->k_sigseqno != sigseqno))
+			; /* don't sleep */
+		else {
+			saved_flags = kse->k_kcb->kcb_kmbx.km_flags;
+			kse->k_kcb->kcb_kmbx.km_flags |= KMF_NOUPCALL;
+			kse_release(&ts_sleep);
+			kse->k_kcb->kcb_kmbx.km_flags = saved_flags;
+		}
+		KSE_SCHED_LOCK(kse, kse->k_kseg);
+		if (KSE_IS_IDLE(kse)) {
+			KSE_CLEAR_IDLE(kse);
+			kse->k_kseg->kg_idle_kses--;
+		}
+	}
+}
+
+/*
+ * Avoid calling this kse_exit() so as not to confuse it with the
+ * system call of the same name.
+ */
+static void
+kse_fini(struct kse *kse)
+{
+	/* struct kse_group *free_kseg = NULL; */
+	struct timespec ts;
+	struct pthread *td;
+
+	/*
+	 * Check to see if this is one of the main kses.
+	 */
+	if (kse->k_kseg != _kse_initial->k_kseg) {
+		PANIC("shouldn't get here");
+		/* This is for supporting thread groups. */
+#ifdef NOT_YET
+		/* Remove this KSE from the KSEG's list of KSEs. */
+		KSE_SCHED_LOCK(kse, kse->k_kseg);
+		TAILQ_REMOVE(&kse->k_kseg->kg_kseq, kse, k_kgqe);
+		kse->k_kseg->kg_ksecount--;
+		if (TAILQ_EMPTY(&kse->k_kseg->kg_kseq))
+			free_kseg = kse->k_kseg;
+		KSE_SCHED_UNLOCK(kse, kse->k_kseg);
+
+		/*
+		 * Add this KSE to the list of free KSEs along with
+		 * the KSEG if is now orphaned.
+		 */
+		KSE_LOCK_ACQUIRE(kse, &kse_lock);
+		if (free_kseg != NULL)
+			kseg_free_unlocked(free_kseg);
+		kse_free_unlocked(kse);
+		KSE_LOCK_RELEASE(kse, &kse_lock);
+		kse_exit();
+		/* Never returns. */
+		PANIC("kse_exit()");
+#endif
+	} else {
+		/*
+		 * We allow program to kill kse in initial group (by
+		 * lowering the concurrency).
+		 */
+		if ((kse != _kse_initial) &&
+		    ((kse->k_flags & KF_TERMINATED) != 0)) {
+			KSE_SCHED_LOCK(kse, kse->k_kseg);
+			TAILQ_REMOVE(&kse->k_kseg->kg_kseq, kse, k_kgqe);
+			kse->k_kseg->kg_ksecount--;
+			/*
+			 * Migrate thread to  _kse_initial if its lastest
+			 * kse it ran on is the kse.
+			 */
+			td = TAILQ_FIRST(&kse->k_kseg->kg_threadq);
+			while (td != NULL) {
+				if (td->kse == kse)
+					td->kse = _kse_initial;
+				td = TAILQ_NEXT(td, kle);
+			}
+			KSE_SCHED_UNLOCK(kse, kse->k_kseg);
+			KSE_LOCK_ACQUIRE(kse, &kse_lock);
+			kse_free_unlocked(kse);
+			KSE_LOCK_RELEASE(kse, &kse_lock);
+			/* Make sure there is always at least one is awake */
+			KSE_WAKEUP(_kse_initial);
+			kse_exit();
+                        /* Never returns. */
+                        PANIC("kse_exit() failed for initial kseg");
+                }
+		KSE_SCHED_LOCK(kse, kse->k_kseg);
+		KSE_SET_IDLE(kse);
+		kse->k_kseg->kg_idle_kses++;
+		KSE_SCHED_UNLOCK(kse, kse->k_kseg);
+		ts.tv_sec = 120;
+		ts.tv_nsec = 0;
+		kse->k_kcb->kcb_kmbx.km_flags = 0;
+		kse_release(&ts);
+		/* Never reach */
+	}
+}
+
+void
+_thr_set_timeout(const struct timespec *timeout)
+{
+	struct pthread	*curthread = _get_curthread();
+	struct timespec ts;
+
+	/* Reset the timeout flag for the running thread: */
+	curthread->timeout = 0;
+
+	/* Check if the thread is to wait forever: */
+	if (timeout == NULL) {
+		/*
+		 * Set the wakeup time to something that can be recognised as
+		 * different to an actual time of day:
+		 */
+		curthread->wakeup_time.tv_sec = -1;
+		curthread->wakeup_time.tv_nsec = -1;
+	}
+	/* Check if no waiting is required: */
+	else if ((timeout->tv_sec == 0) && (timeout->tv_nsec == 0)) {
+		/* Set the wake up time to 'immediately': */
+		curthread->wakeup_time.tv_sec = 0;
+		curthread->wakeup_time.tv_nsec = 0;
+	} else {
+		/* Calculate the time for the current thread to wakeup: */
+		KSE_GET_TOD(curthread->kse, &ts);
+		TIMESPEC_ADD(&curthread->wakeup_time, &ts, timeout);
+	}
+}
+
+void
+_thr_panic_exit(char *file, int line, char *msg)
+{
+	char buf[256];
+
+	snprintf(buf, sizeof(buf), "(%s:%d) %s\n", file, line, msg);
+	__sys_write(2, buf, strlen(buf));
+	abort();
+}
+
+void
+_thr_setrunnable(struct pthread *curthread, struct pthread *thread)
+{
+	kse_critical_t crit;
+	struct kse_mailbox *kmbx;
+
+	crit = _kse_critical_enter();
+	KSE_SCHED_LOCK(curthread->kse, thread->kseg);
+	kmbx = _thr_setrunnable_unlocked(thread);
+	KSE_SCHED_UNLOCK(curthread->kse, thread->kseg);
+	_kse_critical_leave(crit);
+	if ((kmbx != NULL) && (__isthreaded != 0))
+		kse_wakeup(kmbx);
+}
+
+struct kse_mailbox *
+_thr_setrunnable_unlocked(struct pthread *thread)
+{
+	struct kse_mailbox *kmbx = NULL;
+
+	if ((thread->kseg->kg_flags & KGF_SINGLE_THREAD) != 0) {
+		/* No silly queues for these threads. */
+		if ((thread->flags & THR_FLAGS_SUSPENDED) != 0)
+			THR_SET_STATE(thread, PS_SUSPENDED);
+		else {
+			THR_SET_STATE(thread, PS_RUNNING);
+			kmbx = kse_wakeup_one(thread);
+		}
+
+	} else if (thread->state != PS_RUNNING) {
+		if ((thread->flags & THR_FLAGS_IN_WAITQ) != 0)
+			KSE_WAITQ_REMOVE(thread->kse, thread);
+		if ((thread->flags & THR_FLAGS_SUSPENDED) != 0)
+			THR_SET_STATE(thread, PS_SUSPENDED);
+		else {
+			THR_SET_STATE(thread, PS_RUNNING);
+			if ((thread->blocked == 0) && (thread->active == 0) &&
+			    (thread->flags & THR_FLAGS_IN_RUNQ) == 0)
+				THR_RUNQ_INSERT_TAIL(thread);
+			/*
+			 * XXX - Threads are not yet assigned to specific
+			 *       KSEs; they are assigned to the KSEG.  So
+			 *       the fact that a thread's KSE is waiting
+			 *       doesn't necessarily mean that it will be
+			 *       the KSE that runs the thread after the
+			 *       lock is granted.  But we don't know if the
+			 *       other KSEs within the same KSEG are also
+			 *       in a waiting state or not so we err on the
+			 *       side of caution and wakeup the thread's
+			 *       last known KSE.  We ensure that the
+			 *       threads KSE doesn't change while it's
+			 *       scheduling lock is held so it is safe to
+			 *       reference it (the KSE).  If the KSE wakes
+			 *       up and doesn't find any more work it will
+			 *       again go back to waiting so no harm is
+			 *       done.
+			 */
+			kmbx = kse_wakeup_one(thread);
+		}
+	}
+	return (kmbx);
+}
+
+static struct kse_mailbox *
+kse_wakeup_one(struct pthread *thread)
+{
+	struct kse *ke;
+
+	if (KSE_IS_IDLE(thread->kse)) {
+		KSE_CLEAR_IDLE(thread->kse);
+		thread->kseg->kg_idle_kses--;
+		return (&thread->kse->k_kcb->kcb_kmbx);
+	} else {
+		TAILQ_FOREACH(ke, &thread->kseg->kg_kseq, k_kgqe) {
+			if (KSE_IS_IDLE(ke)) {
+				KSE_CLEAR_IDLE(ke);
+				ke->k_kseg->kg_idle_kses--;
+				return (&ke->k_kcb->kcb_kmbx);
+			}
+		}
+	}
+	return (NULL);
+}
+
+static void
+kse_wakeup_multi(struct kse *curkse)
+{
+	struct kse *ke;
+	int tmp;
+
+	if ((tmp = KSE_RUNQ_THREADS(curkse)) && curkse->k_kseg->kg_idle_kses) {
+		TAILQ_FOREACH(ke, &curkse->k_kseg->kg_kseq, k_kgqe) {
+			if (KSE_IS_IDLE(ke)) {
+				KSE_CLEAR_IDLE(ke);
+				ke->k_kseg->kg_idle_kses--;
+				KSE_WAKEUP(ke);
+				if (--tmp == 0)
+					break;
+			}
+		}
+	}
+}
+
+/*
+ * Allocate a new KSEG.
+ *
+ * We allow the current thread to be NULL in the case that this
+ * is the first time a KSEG is being created (library initialization).
+ * In this case, we don't need to (and can't) take any locks.
+ */
+struct kse_group *
+_kseg_alloc(struct pthread *curthread)
+{
+	struct kse_group *kseg = NULL;
+	kse_critical_t crit;
+
+	if ((curthread != NULL) && (free_kseg_count > 0)) {
+		/* Use the kse lock for the kseg queue. */
+		crit = _kse_critical_enter();
+		KSE_LOCK_ACQUIRE(curthread->kse, &kse_lock);
+		if ((kseg = TAILQ_FIRST(&free_kse_groupq)) != NULL) {
+			TAILQ_REMOVE(&free_kse_groupq, kseg, kg_qe);
+			free_kseg_count--;
+			active_kseg_count++;
+			TAILQ_INSERT_TAIL(&active_kse_groupq, kseg, kg_qe);
+		}
+		KSE_LOCK_RELEASE(curthread->kse, &kse_lock);
+		_kse_critical_leave(crit);
+		if (kseg)
+			kseg_reinit(kseg);
+	}
+
+	/*
+	 * If requested, attempt to allocate a new KSE group only if the
+	 * KSE allocation was successful and a KSE group wasn't found in
+	 * the free list.
+	 */
+	if ((kseg == NULL) &&
+	    ((kseg = (struct kse_group *)malloc(sizeof(*kseg))) != NULL)) {
+		if (_pq_alloc(&kseg->kg_schedq.sq_runq,
+		    THR_MIN_PRIORITY, THR_LAST_PRIORITY) != 0) {
+			free(kseg);
+			kseg = NULL;
+		} else {
+			kseg_init(kseg);
+			/* Add the KSEG to the list of active KSEGs. */
+			if (curthread != NULL) {
+				crit = _kse_critical_enter();
+				KSE_LOCK_ACQUIRE(curthread->kse, &kse_lock);
+				active_kseg_count++;
+				TAILQ_INSERT_TAIL(&active_kse_groupq,
+				    kseg, kg_qe);
+				KSE_LOCK_RELEASE(curthread->kse, &kse_lock);
+				_kse_critical_leave(crit);
+			} else {
+				active_kseg_count++;
+				TAILQ_INSERT_TAIL(&active_kse_groupq,
+				    kseg, kg_qe);
+			}
+		}
+	}
+	return (kseg);
+}
+
+static void
+kseg_init(struct kse_group *kseg)
+{
+	kseg_reinit(kseg);
+	_lock_init(&kseg->kg_lock, LCK_ADAPTIVE, _kse_lock_wait,
+	    _kse_lock_wakeup);
+}
+
+static void
+kseg_reinit(struct kse_group *kseg)
+{
+	TAILQ_INIT(&kseg->kg_kseq);
+	TAILQ_INIT(&kseg->kg_threadq);
+	TAILQ_INIT(&kseg->kg_schedq.sq_waitq);
+	kseg->kg_threadcount = 0;
+	kseg->kg_ksecount = 0;
+	kseg->kg_idle_kses = 0;
+	kseg->kg_flags = 0;
+}
+
+/*
+ * This must be called with the kse lock held and when there are
+ * no more threads that reference it.
+ */
+static void
+kseg_free_unlocked(struct kse_group *kseg)
+{
+	TAILQ_REMOVE(&active_kse_groupq, kseg, kg_qe);
+	TAILQ_INSERT_HEAD(&free_kse_groupq, kseg, kg_qe);
+	free_kseg_count++;
+	active_kseg_count--;
+}
+
+void
+_kseg_free(struct kse_group *kseg)
+{
+	struct kse *curkse;
+	kse_critical_t crit;
+
+	crit = _kse_critical_enter();
+	curkse = _get_curkse();
+	KSE_LOCK_ACQUIRE(curkse, &kse_lock);
+	kseg_free_unlocked(kseg);
+	KSE_LOCK_RELEASE(curkse, &kse_lock);
+	_kse_critical_leave(crit);
+}
+
+static void
+kseg_destroy(struct kse_group *kseg)
+{
+	_lock_destroy(&kseg->kg_lock);
+	_pq_free(&kseg->kg_schedq.sq_runq);
+	free(kseg);
+}
+
+/*
+ * Allocate a new KSE.
+ *
+ * We allow the current thread to be NULL in the case that this
+ * is the first time a KSE is being created (library initialization).
+ * In this case, we don't need to (and can't) take any locks.
+ */
+struct kse *
+_kse_alloc(struct pthread *curthread, int sys_scope)
+{
+	struct kse *kse = NULL;
+	char *stack;
+	kse_critical_t crit;
+	int i;
+
+	if ((curthread != NULL) && (free_kse_count > 0)) {
+		crit = _kse_critical_enter();
+		KSE_LOCK_ACQUIRE(curthread->kse, &kse_lock);
+		/* Search for a finished KSE. */
+		kse = TAILQ_FIRST(&free_kseq);
+		while ((kse != NULL) &&
+		    ((kse->k_kcb->kcb_kmbx.km_flags & KMF_DONE) == 0)) {
+			kse = TAILQ_NEXT(kse, k_qe);
+		}
+		if (kse != NULL) {
+			DBG_MSG("found an unused kse.\n");
+			TAILQ_REMOVE(&free_kseq, kse, k_qe);
+			free_kse_count--;
+			TAILQ_INSERT_TAIL(&active_kseq, kse, k_qe);
+			active_kse_count++;
+		}
+		KSE_LOCK_RELEASE(curthread->kse, &kse_lock);
+		_kse_critical_leave(crit);
+		if (kse != NULL)
+			kse_reinit(kse, sys_scope);
+	}
+	if ((kse == NULL) &&
+	    ((kse = (struct kse *)malloc(sizeof(*kse))) != NULL)) {
+		if (sys_scope != 0)
+			stack = NULL;
+		else if ((stack = malloc(KSE_STACKSIZE)) == NULL) {
+			free(kse);
+			return (NULL);
+		}
+		bzero(kse, sizeof(*kse));
+
+		/* Initialize KCB without the lock. */
+		if ((kse->k_kcb = _kcb_ctor(kse)) == NULL) {
+			if (stack != NULL)
+				free(stack);
+			free(kse);
+			return (NULL);
+		}
+
+		/* Initialize the lockusers. */
+		for (i = 0; i < MAX_KSE_LOCKLEVEL; i++) {
+			_lockuser_init(&kse->k_lockusers[i], (void *)kse);
+			_LCK_SET_PRIVATE2(&kse->k_lockusers[i], NULL);
+		}
+		/* _lock_init(kse->k_lock, ...) */
+
+		if (curthread != NULL) {
+			crit = _kse_critical_enter();
+			KSE_LOCK_ACQUIRE(curthread->kse, &kse_lock);
+		}
+		kse->k_flags = 0;
+		TAILQ_INSERT_TAIL(&active_kseq, kse, k_qe);
+		active_kse_count++;
+		if (curthread != NULL) {
+			KSE_LOCK_RELEASE(curthread->kse, &kse_lock);
+			_kse_critical_leave(crit);
+		}
+		/*
+		 * Create the KSE context.
+		 * Scope system threads (one thread per KSE) are not required
+		 * to have a stack for an unneeded kse upcall.
+		 */
+		if (!sys_scope) {
+			kse->k_kcb->kcb_kmbx.km_func = (kse_func_t *)kse_sched_multi;
+			kse->k_stack.ss_sp = stack;
+			kse->k_stack.ss_size = KSE_STACKSIZE;
+		} else {
+			kse->k_kcb->kcb_kmbx.km_func = (kse_func_t *)kse_sched_single;
+			kse->k_stack.ss_sp = NULL;
+			kse->k_stack.ss_size = 0;
+		}
+		kse->k_kcb->kcb_kmbx.km_udata = (void *)kse;
+		kse->k_kcb->kcb_kmbx.km_quantum = 20000;
+		/*
+		 * We need to keep a copy of the stack in case it
+		 * doesn't get used; a KSE running a scope system
+		 * thread will use that thread's stack.
+		 */
+		kse->k_kcb->kcb_kmbx.km_stack = kse->k_stack;
+	}
+	return (kse);
+}
+
+static void
+kse_reinit(struct kse *kse, int sys_scope)
+{
+	if (!sys_scope) {
+		kse->k_kcb->kcb_kmbx.km_func = (kse_func_t *)kse_sched_multi;
+		if (kse->k_stack.ss_sp == NULL) {
+			/* XXX check allocation failure */
+			kse->k_stack.ss_sp = (char *) malloc(KSE_STACKSIZE);
+			kse->k_stack.ss_size = KSE_STACKSIZE;
+		}
+		kse->k_kcb->kcb_kmbx.km_quantum = 20000;
+	} else {
+		kse->k_kcb->kcb_kmbx.km_func = (kse_func_t *)kse_sched_single;
+		if (kse->k_stack.ss_sp)
+			free(kse->k_stack.ss_sp);
+		kse->k_stack.ss_sp = NULL;
+		kse->k_stack.ss_size = 0;
+		kse->k_kcb->kcb_kmbx.km_quantum = 0;
+	}
+	kse->k_kcb->kcb_kmbx.km_stack = kse->k_stack;
+	kse->k_kcb->kcb_kmbx.km_udata = (void *)kse;
+	kse->k_kcb->kcb_kmbx.km_curthread = NULL;
+	kse->k_kcb->kcb_kmbx.km_flags = 0;
+	kse->k_curthread = NULL;
+	kse->k_kseg = 0;
+	kse->k_schedq = 0;
+	kse->k_locklevel = 0;
+	kse->k_flags = 0;
+	kse->k_error = 0;
+	kse->k_cpu = 0;
+	kse->k_sigseqno = 0;
+}
+
+void
+kse_free_unlocked(struct kse *kse)
+{
+	TAILQ_REMOVE(&active_kseq, kse, k_qe);
+	active_kse_count--;
+	kse->k_kseg = NULL;
+	kse->k_kcb->kcb_kmbx.km_quantum = 20000;
+	kse->k_flags = 0;
+	TAILQ_INSERT_HEAD(&free_kseq, kse, k_qe);
+	free_kse_count++;
+}
+
+void
+_kse_free(struct pthread *curthread, struct kse *kse)
+{
+	kse_critical_t crit;
+
+	if (curthread == NULL)
+		kse_free_unlocked(kse);
+	else {
+		crit = _kse_critical_enter();
+		KSE_LOCK_ACQUIRE(curthread->kse, &kse_lock);
+		kse_free_unlocked(kse);
+		KSE_LOCK_RELEASE(curthread->kse, &kse_lock);
+		_kse_critical_leave(crit);
+	}
+}
+
+static void
+kse_destroy(struct kse *kse)
+{
+	int i;
+
+	if (kse->k_stack.ss_sp != NULL)
+		free(kse->k_stack.ss_sp);
+	_kcb_dtor(kse->k_kcb);
+	for (i = 0; i < MAX_KSE_LOCKLEVEL; ++i)
+		_lockuser_destroy(&kse->k_lockusers[i]);
+	_lock_destroy(&kse->k_lock);
+	free(kse);
+}
+
+struct pthread *
+_thr_alloc(struct pthread *curthread)
+{
+	kse_critical_t	crit;
+	struct pthread	*thread = NULL;
+	int i;
+
+	if (curthread != NULL) {
+		if (GC_NEEDED())
+			_thr_gc(curthread);
+		if (free_thread_count > 0) {
+			crit = _kse_critical_enter();
+			KSE_LOCK_ACQUIRE(curthread->kse, &thread_lock);
+			if ((thread = TAILQ_FIRST(&free_threadq)) != NULL) {
+				TAILQ_REMOVE(&free_threadq, thread, tle);
+				free_thread_count--;
+			}
+			KSE_LOCK_RELEASE(curthread->kse, &thread_lock);
+			_kse_critical_leave(crit);
+		}
+	}
+	if ((thread == NULL) &&
+	    ((thread = malloc(sizeof(struct pthread))) != NULL)) {
+		bzero(thread, sizeof(struct pthread));
+		thread->siginfo = calloc(_SIG_MAXSIG, sizeof(siginfo_t));
+		if (thread->siginfo == NULL) {
+			free(thread);
+			return (NULL);
+		}
+		if (curthread) {
+			_pthread_mutex_lock(&_tcb_mutex);
+			thread->tcb = _tcb_ctor(thread, 0 /* not initial tls */);
+			_pthread_mutex_unlock(&_tcb_mutex);
+		} else {
+			thread->tcb = _tcb_ctor(thread, 1 /* initial tls */);
+		}
+		if (thread->tcb == NULL) {
+			free(thread->siginfo);
+			free(thread);
+			return (NULL);
+		}
+		/*
+		 * Initialize thread locking.
+		 * Lock initializing needs malloc, so don't
+		 * enter critical region before doing this!
+		 */
+		if (_lock_init(&thread->lock, LCK_ADAPTIVE,
+		    _thr_lock_wait, _thr_lock_wakeup) != 0)
+			PANIC("Cannot initialize thread lock");
+		for (i = 0; i < MAX_THR_LOCKLEVEL; i++) {
+			_lockuser_init(&thread->lockusers[i], (void *)thread);
+			_LCK_SET_PRIVATE2(&thread->lockusers[i],
+			    (void *)thread);
+		}
+	}
+	return (thread);
+}
+
+void
+_thr_free(struct pthread *curthread, struct pthread *thread)
+{
+	kse_critical_t crit;
+
+	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. */
+		crit = _kse_critical_enter();
+		KSE_LOCK_ACQUIRE(curthread->kse, &thread_lock);
+		TAILQ_INSERT_TAIL(&free_threadq, thread, tle);
+		free_thread_count++;
+		KSE_LOCK_RELEASE(curthread->kse, &thread_lock);
+		_kse_critical_leave(crit);
+	}
+}
+
+static void
+thr_destroy(struct pthread *curthread, struct pthread *thread)
+{
+	int i;
+
+	for (i = 0; i < MAX_THR_LOCKLEVEL; i++)
+		_lockuser_destroy(&thread->lockusers[i]);
+	_lock_destroy(&thread->lock);
+	if (curthread) {
+		_pthread_mutex_lock(&_tcb_mutex);
+		_tcb_dtor(thread->tcb);
+		_pthread_mutex_unlock(&_tcb_mutex);
+	} else {
+		_tcb_dtor(thread->tcb);
+	}
+	free(thread->siginfo);
+	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.
+ */
+static void
+thr_link(struct pthread *thread)
+{
+	kse_critical_t crit;
+	struct kse *curkse;
+
+	crit = _kse_critical_enter();
+	curkse = _get_curkse();
+	KSE_LOCK_ACQUIRE(curkse, &_thread_list_lock);
+	/*
+	 * 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);
+	_thread_active_threads++;
+	KSE_LOCK_RELEASE(curkse, &_thread_list_lock);
+	_kse_critical_leave(crit);
+}
+
+/*
+ * Remove an active thread.
+ */
+static void
+thr_unlink(struct pthread *thread)
+{
+	kse_critical_t crit;
+	struct kse *curkse;
+
+	crit = _kse_critical_enter();
+	curkse = _get_curkse();
+	KSE_LOCK_ACQUIRE(curkse, &_thread_list_lock);
+	THR_LIST_REMOVE(thread);
+	_thread_active_threads--;
+	KSE_LOCK_RELEASE(curkse, &_thread_list_lock);
+	_kse_critical_leave(crit);
+}
+
+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);
+}
+
+void
+_thr_debug_check_yield(struct pthread *curthread)
+{
+	/*
+	 * Note that TMDF_SUSPEND is set after process is suspended.
+	 * When we are being debugged, every suspension in process
+	 * will cause all KSEs to schedule an upcall in kernel, unless the
+	 * KSE is in critical region.
+	 * If the function is being called, it means the KSE is no longer
+	 * in critical region, if the TMDF_SUSPEND is set by debugger
+	 * before KSE leaves critical region, we will catch it here, else
+	 * if the flag is changed during testing, it also not a problem,
+	 * because the change only occurs after a process suspension event
+	 * occurs. A suspension event will always cause KSE to schedule an
+	 * upcall, in the case, because we are not in critical region,
+	 * upcall will be scheduled sucessfully, the flag will be checked
+	 * again in kse_sched_multi, we won't back until the flag
+	 * is cleared by debugger, the flag will be cleared in next
+	 * suspension event. 
+	 */
+	if (!DBG_CAN_RUN(curthread)) {
+		if ((curthread->attr.flags & PTHREAD_SCOPE_SYSTEM) == 0)
+			_thr_sched_switch(curthread);
+		else
+			kse_thr_interrupt(&curthread->tcb->tcb_tmbx,
+				KSE_INTR_DBSUSPEND, 0);
+	}
+}
--- /dev/null
+++ lib/libkse/thread/thr_atfork.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2003 Daniel Eischen <deischen at 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/libkse/thread/thr_atfork.c,v 1.3 2007/10/09 13:42:27 obrien Exp $
+ */
+#include <errno.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <sys/queue.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_atfork);
+LT10_COMPAT_DEFAULT(pthread_atfork);
+
+__weak_reference(_pthread_atfork, pthread_atfork);
+
+int
+_pthread_atfork(void (*prepare)(void), void (*parent)(void),
+    void (*child)(void))
+{
+	struct pthread_atfork *af;
+
+	if (_thr_initial == NULL)
+		_libpthread_init(NULL);
+
+	if ((af = malloc(sizeof(struct pthread_atfork))) == NULL)
+		return (ENOMEM);
+
+	af->prepare = prepare;
+	af->parent = parent;
+	af->child = child;
+	_pthread_mutex_lock(&_thr_atfork_mutex);
+	TAILQ_INSERT_TAIL(&_thr_atfork_list, af, qe);
+	_pthread_mutex_unlock(&_thr_atfork_mutex);
+	return (0);
+}
+
--- /dev/null
+++ lib/libkse/thread/thr_spec.c
@@ -0,0 +1,244 @@
+/*
+ * Copyright (c) 1995 John Birrell <jb at 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. Neither the name of the author nor the names of any 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/libkse/thread/thr_spec.c,v 1.25.2.1 2007/11/26 02:39:52 davidxu Exp $
+ */
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <pthread.h>
+
+#include "thr_private.h"
+
+
+struct pthread_key _thread_keytable[PTHREAD_KEYS_MAX];
+
+/*
+ * XXX - This breaks the linker if LT10_COMPAT_DEFAULT doesn't
+ * also include a weak reference to the default symbol.
+ */
+LT10_COMPAT_PRIVATE(_thread_keytable);
+
+LT10_COMPAT_PRIVATE(_pthread_key_create);
+LT10_COMPAT_DEFAULT(pthread_key_create);
+LT10_COMPAT_PRIVATE(_pthread_key_delete);
+LT10_COMPAT_DEFAULT(pthread_key_delete);
+LT10_COMPAT_PRIVATE(_pthread_getspecific);
+LT10_COMPAT_DEFAULT(pthread_getspecific);
+LT10_COMPAT_PRIVATE(_pthread_setspecific);
+LT10_COMPAT_DEFAULT(pthread_setspecific);
+
+__weak_reference(_pthread_key_create, pthread_key_create);
+__weak_reference(_pthread_key_delete, pthread_key_delete);
+__weak_reference(_pthread_getspecific, pthread_getspecific);
+__weak_reference(_pthread_setspecific, pthread_setspecific);
+
+
+int
+_pthread_key_create(pthread_key_t *key, void (*destructor) (void *))
+{
+	struct pthread *curthread;
+	int i;
+
+	if (_thr_initial == NULL)
+		_libpthread_init(NULL);
+	curthread = _get_curthread();
+
+	/* Lock the key table: */
+	THR_LOCK_ACQUIRE(curthread, &_keytable_lock);
+	for (i = 0; i < PTHREAD_KEYS_MAX; i++) {
+
+		if (_thread_keytable[i].allocated == 0) {
+			_thread_keytable[i].allocated = 1;
+			_thread_keytable[i].destructor = destructor;
+			_thread_keytable[i].seqno++;
+
+			/* Unlock the key table: */
+			THR_LOCK_RELEASE(curthread, &_keytable_lock);
+			*key = i;
+			return (0);
+		}
+
+	}
+	/* Unlock the key table: */
+	THR_LOCK_RELEASE(curthread, &_keytable_lock);
+	return (EAGAIN);
+}
+
+int
+_pthread_key_delete(pthread_key_t key)
+{
+	struct pthread *curthread = _get_curthread();
+	int ret = 0;
+
+	if ((unsigned int)key < PTHREAD_KEYS_MAX) {
+		/* Lock the key table: */
+		THR_LOCK_ACQUIRE(curthread, &_keytable_lock);
+
+		if (_thread_keytable[key].allocated)
+			_thread_keytable[key].allocated = 0;
+		else
+			ret = EINVAL;
+
+		/* Unlock the key table: */
+		THR_LOCK_RELEASE(curthread, &_keytable_lock);
+	} else
+		ret = EINVAL;
+	return (ret);
+}
+
+void 
+_thread_cleanupspecific(void)
+{
+	struct pthread	*curthread = _get_curthread();
+	void		(*destructor)( void *);
+	void		*data = NULL;
+	int		key;
+	int		i;
+
+	if (curthread->specific == NULL)
+		return;
+
+	/* Lock the key table: */
+	THR_LOCK_ACQUIRE(curthread, &_keytable_lock);
+	for (i = 0; (i < PTHREAD_DESTRUCTOR_ITERATIONS) &&
+	    (curthread->specific_data_count > 0); i++) {
+		for (key = 0; (key < PTHREAD_KEYS_MAX) &&
+		    (curthread->specific_data_count > 0); key++) {
+			destructor = NULL;
+
+			if (_thread_keytable[key].allocated &&
+			    (curthread->specific[key].data != NULL)) {
+				if (curthread->specific[key].seqno ==
+				    _thread_keytable[key].seqno) {
+					data = (void *)
+					    curthread->specific[key].data;
+					destructor = _thread_keytable[key].destructor;
+				}
+				curthread->specific[key].data = NULL;
+				curthread->specific_data_count--;
+			}
+
+			/*
+			 * If there is a destructore, call it
+			 * with the key table entry unlocked:
+			 */
+			if (destructor != NULL) {
+				/*
+				 * Don't hold the lock while calling the
+				 * destructor:
+				 */
+				THR_LOCK_RELEASE(curthread, &_keytable_lock);
+				destructor(data);
+				THR_LOCK_ACQUIRE(curthread, &_keytable_lock);
+			}
+		}
+	}
+	THR_LOCK_RELEASE(curthread, &_keytable_lock);
+	free(curthread->specific);
+	curthread->specific = NULL;
+	if (curthread->specific_data_count > 0)
+		stderr_debug("Thread %p has exited with leftover "
+		    "thread-specific data after %d destructor iterations\n",
+		    curthread, PTHREAD_DESTRUCTOR_ITERATIONS);
+}
+
+static inline struct pthread_specific_elem *
+pthread_key_allocate_data(void)
+{
+	struct pthread_specific_elem *new_data;
+
+	new_data = (struct pthread_specific_elem *)
+	    malloc(sizeof(struct pthread_specific_elem) * PTHREAD_KEYS_MAX);
+	if (new_data != NULL) {
+		memset((void *) new_data, 0,
+		    sizeof(struct pthread_specific_elem) * PTHREAD_KEYS_MAX);
+	}
+	return (new_data);
+}
+
+int 
+_pthread_setspecific(pthread_key_t key, const void *value)
+{
+	struct pthread	*pthread;
+	int		ret = 0;
+
+	/* Point to the running thread: */
+	pthread = _get_curthread();
+
+	if ((pthread->specific) ||
+	    (pthread->specific = pthread_key_allocate_data())) {
+		if ((unsigned int)key < PTHREAD_KEYS_MAX) {
+			if (_thread_keytable[key].allocated) {
+				if (pthread->specific[key].data == NULL) {
+					if (value != NULL)
+						pthread->specific_data_count++;
+				} else if (value == NULL)
+					pthread->specific_data_count--;
+				pthread->specific[key].data = value;
+				pthread->specific[key].seqno =
+				    _thread_keytable[key].seqno;
+				ret = 0;
+			} else
+				ret = EINVAL;
+		} else
+			ret = EINVAL;
+	} else
+		ret = ENOMEM;
+	return (ret);
+}
+
+void *
+_pthread_getspecific(pthread_key_t key)
+{
+	struct pthread	*pthread;
+	void		*data;
+
+	/* Point to the running thread: */
+	pthread = _get_curthread();
+
+	/* Check if there is specific data: */
+	if (pthread->specific != NULL && (unsigned int)key < PTHREAD_KEYS_MAX) {
+		/* Check if this key has been used before: */
+		if (_thread_keytable[key].allocated &&
+		    (pthread->specific[key].seqno == _thread_keytable[key].seqno)) {
+			/* Return the value: */
+			data = (void *) pthread->specific[key].data;
+		} else {
+			/*
+			 * This key has not been used before, so return NULL
+			 * instead: 
+			 */
+			data = NULL;
+		}
+	} else
+		/* No specific data has been created, so just return NULL: */
+		data = NULL;
+	return (data);
+}
--- /dev/null
+++ lib/libkse/thread/thr_attr_setguardsize.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2001 Jason Evans <jasone at freebsd.org>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice(s), this list of conditions and the following disclaimer
+ *    unmodified other than the allowable addition of one or more
+ *    copyright notices.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice(s), this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD: src/lib/libkse/thread/thr_attr_setguardsize.c,v 1.8 2007/10/09 13:42:27 obrien Exp $
+ */
+
+#include <sys/param.h>
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_attr_setguardsize);
+LT10_COMPAT_DEFAULT(pthread_attr_setguardsize);
+
+__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);
+}
--- /dev/null
+++ lib/libkse/thread/thr_wait.c
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2000 Jason Evans <jasone at 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/libkse/thread/thr_wait.c,v 1.10 2007/10/09 13:42:30 obrien Exp $
+ */
+
+#include <pthread.h>
+#include "thr_private.h"
+
+extern int __wait(int *);
+
+LT10_COMPAT_PRIVATE(_wait);
+LT10_COMPAT_DEFAULT(wait);
+
+__weak_reference(_wait, wait);
+
+pid_t
+_wait(int *istat)
+{
+	struct pthread *curthread = _get_curthread();
+	pid_t	ret;
+
+	_thr_cancel_enter(curthread);
+	ret = __wait(istat);
+	_thr_cancel_leave(curthread, 1);
+
+	return ret;
+}
--- /dev/null
+++ lib/libkse/thread/thr_fcntl.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 1995-1998 John Birrell <jb at 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. Neither the name of the author nor the names of any 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/libkse/thread/thr_fcntl.c,v 1.22 2007/10/09 13:42:28 obrien Exp $
+ */
+#include <stdarg.h>
+#include "namespace.h"
+#include <fcntl.h>
+#include "un-namespace.h"
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(__fcntl);
+LT10_COMPAT_DEFAULT(fcntl);
+
+__weak_reference(__fcntl, fcntl);
+
+int
+__fcntl(int fd, int cmd,...)
+{
+	struct pthread *curthread = _get_curthread();
+	int	ret, check = 1;
+	va_list	ap;
+	
+	_thr_cancel_enter(curthread);
+
+	va_start(ap, cmd);
+	switch (cmd) {
+	case F_DUPFD:
+		ret = __sys_fcntl(fd, cmd, va_arg(ap, int));
+		/*
+		 * To avoid possible file handle leak, 
+		 * only check cancellation point if it is failure
+		 */
+		check = (ret == -1);
+		break;
+	case F_SETFD:
+	case F_SETFL:
+		ret = __sys_fcntl(fd, cmd, va_arg(ap, int));
+		break;
+	case F_GETFD:
+	case F_GETFL:
+		ret = __sys_fcntl(fd, cmd);
+		break;
+	default:
+		ret = __sys_fcntl(fd, cmd, va_arg(ap, void *));
+	}
+	va_end(ap);
+
+	_thr_cancel_leave(curthread, check);
+
+	return (ret);
+}
--- /dev/null
+++ lib/libkse/thread/thr_setschedparam.c
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 1998 Daniel Eischen <eischen at 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/libkse/thread/thr_setschedparam.c,v 1.15 2007/10/09 13:42:29 obrien Exp $
+ */
+#include <errno.h>
+#include <sys/param.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_setschedparam);
+LT10_COMPAT_DEFAULT(pthread_setschedparam);
+
+__weak_reference(_pthread_setschedparam, pthread_setschedparam);
+
+int
+_pthread_setschedparam(pthread_t pthread, int policy, 
+	const struct sched_param *param)
+{
+	struct pthread *curthread = _get_curthread();
+	int	in_syncq;
+	int	in_readyq = 0;
+	int	old_prio;
+	int	ret = 0;
+
+	if ((param == NULL) || (policy < SCHED_FIFO) || (policy > SCHED_RR)) {
+		/* Return an invalid argument error: */
+		ret = EINVAL;
+	} else if ((param->sched_priority < THR_MIN_PRIORITY) ||
+	    (param->sched_priority > THR_MAX_PRIORITY)) {
+		/* Return an unsupported value error. */
+		ret = ENOTSUP;
+
+	/* Find the thread in the list of active threads: */
+	} else if ((ret = _thr_ref_add(curthread, pthread, /*include dead*/0))
+	    == 0) {
+		/*
+		 * Lock the threads scheduling queue while we change
+		 * its priority:
+		 */
+		THR_SCHED_LOCK(curthread, pthread);
+		if ((pthread->state == PS_DEAD) ||
+		    (pthread->state == PS_DEADLOCK) ||
+		    ((pthread->flags & THR_FLAGS_EXITING) != 0)) {
+			THR_SCHED_UNLOCK(curthread, pthread);
+			_thr_ref_delete(curthread, pthread);
+			return (ESRCH);
+		}
+		in_syncq = pthread->sflags & THR_FLAGS_IN_SYNCQ;
+
+		/* Set the scheduling policy: */
+		pthread->attr.sched_policy = policy;
+
+		if (param->sched_priority ==
+		    THR_BASE_PRIORITY(pthread->base_priority))
+			/*
+			 * There is nothing to do; unlock the threads
+			 * scheduling queue.
+			 */
+			THR_SCHED_UNLOCK(curthread, pthread);
+		else {
+			/*
+			 * Remove the thread from its current priority
+			 * queue before any adjustments are made to its
+			 * active priority:
+			 */
+			old_prio = pthread->active_priority;
+			if ((pthread->flags & THR_FLAGS_IN_RUNQ) != 0) {
+				in_readyq = 1;
+				THR_RUNQ_REMOVE(pthread);
+			}
+
+			/* Set the thread base priority: */
+			pthread->base_priority &=
+			    (THR_SIGNAL_PRIORITY | THR_RT_PRIORITY);
+			pthread->base_priority = param->sched_priority;
+
+			/* Recalculate the active priority: */
+			pthread->active_priority = MAX(pthread->base_priority,
+			    pthread->inherited_priority);
+
+			if (in_readyq) {
+				if ((pthread->priority_mutex_count > 0) &&
+				    (old_prio > pthread->active_priority)) {
+					/*
+					 * POSIX states that if the priority is
+					 * being lowered, the thread must be
+					 * inserted at the head of the queue for
+					 * its priority if it owns any priority
+					 * protection or inheritence mutexes.
+					 */
+					THR_RUNQ_INSERT_HEAD(pthread);
+				}
+				else
+					THR_RUNQ_INSERT_TAIL(pthread);
+			}
+
+			/* Unlock the threads scheduling queue: */
+			THR_SCHED_UNLOCK(curthread, pthread);
+
+			/*
+			 * Check for any mutex priority adjustments.  This
+			 * includes checking for a priority mutex on which
+			 * this thread is waiting.
+			 */
+			_mutex_notify_priochange(curthread, pthread, in_syncq);
+		}
+		_thr_ref_delete(curthread, pthread);
+	}
+	return (ret);
+}
--- /dev/null
+++ lib/libkse/thread/thr_sigaction.c
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 1995-1998 John Birrell <jb at 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. Neither the name of the author nor the names of any 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/libkse/thread/thr_sigaction.c,v 1.26 2007/10/09 13:42:29 obrien Exp $
+ */
+#include <signal.h>
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_sigaction);
+LT10_COMPAT_DEFAULT(sigaction);
+
+__weak_reference(_sigaction, sigaction);
+
+int
+_sigaction(int sig, const struct sigaction * act, struct sigaction * oact)
+{
+	int ret = 0;
+	int err = 0;
+	struct sigaction newact, oldact;
+	struct pthread *curthread;
+	kse_critical_t crit;
+
+	/* Check if the signal number is out of range: */
+	if (sig < 1 || sig > _SIG_MAXSIG) {
+		/* Return an invalid argument: */
+		errno = EINVAL;
+		ret = -1;
+	} else {
+		if (act)
+			newact = *act;
+
+		crit = _kse_critical_enter();
+		curthread = _get_curthread();
+		KSE_LOCK_ACQUIRE(curthread->kse, &_thread_signal_lock);
+
+		oldact = _thread_sigact[sig - 1];
+
+		/* Check if a signal action was supplied: */
+		if (act != NULL) {
+			/* Set the new signal handler: */
+			_thread_sigact[sig - 1] = newact;
+		}
+
+		/*
+		 * Check if the kernel needs to be advised of a change
+		 * in signal action:
+		 */
+		if (act != NULL) {
+
+			newact.sa_flags |= SA_SIGINFO;
+
+			/*
+			 * Check if the signal handler is being set to
+			 * the default or ignore handlers:
+			 */
+			if (newact.sa_handler != SIG_DFL &&
+			    newact.sa_handler != SIG_IGN) {
+				/*
+				 * Specify the thread kernel signal
+				 * handler:
+				 */
+				newact.sa_handler = (void (*) ())_thr_sig_handler;
+			}
+			/*
+			 * Install libpthread signal handler wrapper
+			 * for SIGINFO signal if threads dump enabled
+			 * even if a user set the signal handler to
+			 * SIG_DFL or SIG_IGN.
+			 */
+			if (sig == SIGINFO && _thr_dump_enabled()) {
+				newact.sa_handler =
+				    (void (*) ())_thr_sig_handler;
+			}
+			/* Change the signal action in the kernel: */
+			if (__sys_sigaction(sig, &newact, NULL) != 0) {
+				_thread_sigact[sig - 1] = oldact;
+				/* errno is in kse, will copy it to thread */
+				err = errno;
+				ret = -1;
+			}
+		}
+		KSE_LOCK_RELEASE(curthread->kse, &_thread_signal_lock);
+		_kse_critical_leave(crit);
+		/*
+		 * Check if the existing signal action structure contents are
+		 * to be returned: 
+		*/
+		if (oact != NULL) {
+			/* Return the existing signal action contents: */
+			*oact = oldact;
+		}
+		if (ret != 0) {
+			/* Return errno to thread */
+			errno = err;
+		}
+	}
+
+	/* Return the completion status: */
+	return (ret);
+}
--- /dev/null
+++ lib/libkse/thread/thr_mattr_pshared.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2005 David Xu <davidxu at freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice unmodified, this list of conditions, and the following
+ *    disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD: src/lib/libkse/thread/thr_mattr_pshared.c,v 1.2 2007/10/09 13:42:28 obrien Exp $
+ *
+ */
+
+#include <errno.h>
+#include "thr_private.h"
+
+__weak_reference(_pthread_mutexattr_getpshared, pthread_mutexattr_getpshared);
+__weak_reference(_pthread_mutexattr_setpshared, pthread_mutexattr_setpshared);
+
+int
+_pthread_mutexattr_getpshared(const pthread_mutexattr_t *attr,
+	int *pshared)
+{
+	if (attr == NULL || *attr == NULL)
+		return (EINVAL);
+
+	pshared = PTHREAD_PROCESS_PRIVATE;
+	return (0);
+}
+
+int
+_pthread_mutexattr_setpshared(pthread_mutexattr_t *attr, int pshared)
+{
+	if (attr == NULL || *attr == NULL)
+		return (EINVAL);
+
+	if  (pshared != PTHREAD_PROCESS_PRIVATE)
+		return (EINVAL);
+	return (0);
+}
--- /dev/null
+++ lib/libkse/thread/thr_write.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 1995-1998 John Birrell <jb at 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. Neither the name of the author nor the names of any 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/libkse/thread/thr_write.c,v 1.27 2007/10/09 13:42:30 obrien Exp $
+ *
+ */
+#include <sys/types.h>
+#include <sys/fcntl.h>
+#include <sys/uio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(__write);
+LT10_COMPAT_DEFAULT(write);
+
+__weak_reference(__write, write);
+
+ssize_t
+__write(int fd, const void *buf, size_t nbytes)
+{
+	struct pthread *curthread = _get_curthread();
+	ssize_t	ret;
+
+	_thr_cancel_enter(curthread);
+	ret = __sys_write(fd, buf, nbytes);
+	_thr_cancel_leave(curthread, 1);
+
+	return ret;
+}
--- /dev/null
+++ lib/libkse/thread/thr_mutexattr_destroy.c
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 1997 John Birrell <jb at 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. Neither the name of the author nor the names of any 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/libkse/thread/thr_mutexattr_destroy.c,v 1.11 2007/10/09 13:42:28 obrien Exp $
+ */
+#include <stdlib.h>
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_mutexattr_destroy);
+LT10_COMPAT_DEFAULT(pthread_mutexattr_destroy);
+
+__weak_reference(_pthread_mutexattr_destroy, pthread_mutexattr_destroy);
+
+int
+_pthread_mutexattr_destroy(pthread_mutexattr_t *attr)
+{
+	int	ret;
+	if (attr == NULL || *attr == NULL) {
+		ret = EINVAL;
+	} else {
+		free(*attr);
+		*attr = NULL;
+		ret = 0;
+	}
+	return(ret);
+}
--- /dev/null
+++ lib/libkse/thread/thr_single_np.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 1996 John Birrell <jb at 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. Neither the name of the author nor the names of any 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/libkse/thread/thr_single_np.c,v 1.9 2007/10/09 13:42:29 obrien Exp $
+ */
+#include <pthread.h>
+#include <pthread_np.h>
+
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_single_np);
+LT10_COMPAT_DEFAULT(pthread_single_np);
+
+__weak_reference(_pthread_single_np, pthread_single_np);
+
+int _pthread_single_np()
+{
+
+	/* Enter single-threaded (non-POSIX) scheduling mode: */
+	pthread_suspend_all_np();
+	/*
+	 * XXX - Do we want to do this?
+	 * __is_threaded = 0;
+	 */
+	return (0);
+}
--- /dev/null
+++ lib/libkse/thread/thr_attr_setcreatesuspend_np.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 1995 John Birrell <jb at 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. Neither the name of the author nor the names of any 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/libkse/thread/thr_attr_setcreatesuspend_np.c,v 1.11 2007/10/09 13:42:27 obrien Exp $
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_attr_setcreatesuspend_np);
+LT10_COMPAT_DEFAULT(pthread_attr_setcreatesuspend_np);
+
+__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);
+}
--- /dev/null
+++ lib/libkse/thread/thr_execve.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2004 Daniel Eischen <deischen at 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/libkse/thread/thr_execve.c,v 1.5 2007/10/09 13:42:27 obrien Exp $
+ */
+
+#include <errno.h>
+#include <pthread.h>
+#include <unistd.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_execve);
+LT10_COMPAT_DEFAULT(execve);
+
+__weak_reference(_execve, execve);
+
+int 
+_execve(const char *name, char *const *argv, char *const *envp)
+{
+	struct kse_execve_args args;
+	struct pthread *curthread = _get_curthread();
+	int ret;
+
+	if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM)
+		ret = __sys_execve(name, argv, envp);
+	else {
+		/*
+		 * When exec'ing, set the kernel signal mask to the thread's
+	 	 * signal mask to satisfy POSIX requirements.
+		 */
+		args.sigmask = curthread->sigmask;
+		args.sigpend = curthread->sigpend;
+		args.path = (char *)name;
+		args.argv = (char **)argv;
+		args.envp = (char **)envp;
+		args.reserved = NULL;
+		ret = kse_thr_interrupt(NULL, KSE_INTR_EXECVE, (long)&args);
+	}
+
+	return (ret);
+}
--- /dev/null
+++ lib/libkse/thread/thr_yield.c
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 1995 John Birrell <jb at 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. Neither the name of the author nor the names of any 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/libkse/thread/thr_yield.c,v 1.18 2007/10/09 13:42:30 obrien Exp $
+ */
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_sched_yield);
+LT10_COMPAT_DEFAULT(sched_yield);
+LT10_COMPAT_PRIVATE(_pthread_yield);
+LT10_COMPAT_DEFAULT(pthread_yield);
+
+__weak_reference(_sched_yield, sched_yield);
+__weak_reference(_pthread_yield, pthread_yield);
+
+int
+_sched_yield(void)
+{
+	struct pthread	*curthread = _get_curthread();
+
+	if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM)
+		return (__sys_sched_yield());
+
+	/* Reset the accumulated time slice value for the current thread: */
+	curthread->slice_usec = -1;
+
+	/* Schedule the next thread: */
+	_thr_sched_switch(curthread);
+	/* Always return no error. */
+	return(0);
+}
+
+/* Draft 4 yield */
+void
+_pthread_yield(void)
+{
+	struct pthread	*curthread = _get_curthread();
+
+	if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM) {
+		__sys_sched_yield();
+		return;
+	}
+
+	/* Reset the accumulated time slice value for the current thread: */
+	curthread->slice_usec = -1;
+
+	/* Schedule the next thread: */
+	_thr_sched_switch(curthread);
+}
--- /dev/null
+++ lib/libkse/thread/thr_attr_getguardsize.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2001 Jason Evans <jasone at freebsd.org>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice(s), this list of conditions and the following disclaimer
+ *    unmodified other than the allowable addition of one or more
+ *    copyright notices.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice(s), this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD: src/lib/libkse/thread/thr_attr_getguardsize.c,v 1.4 2007/10/09 13:42:27 obrien Exp $
+ */
+
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_attr_getguardsize);
+LT10_COMPAT_DEFAULT(pthread_attr_getguardsize);
+
+__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);
+}
--- /dev/null
+++ lib/libkse/thread/thr_create.c
@@ -0,0 +1,345 @@
+/*
+ * Copyright (c) 2003 Daniel M. Eischen <deischen at gdeb.com>
+ * Copyright (c) 1995-1998 John Birrell <jb at 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. Neither the name of the author nor the names of any 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/libkse/thread/thr_create.c,v 1.62 2007/10/09 13:42:27 obrien 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 "thr_private.h"
+#include "libc_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_create);
+LT10_COMPAT_DEFAULT(pthread_create);
+
+static void free_thread(struct pthread *curthread, struct pthread *thread);
+static int  create_stack(struct pthread_attr *pattr);
+static void free_stack(struct pthread_attr *pattr);
+static void thread_start(struct pthread *curthread,
+		void *(*start_routine) (void *), void *arg);
+
+__weak_reference(_pthread_create, pthread_create);
+
+/*
+ * Some notes on new thread creation and first time initializion
+ * to enable multi-threading.
+ *
+ * There are basically two things that need to be done.
+ *
+ *   1) The internal library variables must be initialized.
+ *   2) Upcalls need to be enabled to allow multiple threads
+ *      to be run.
+ *
+ * The first may be done as a result of other pthread functions
+ * being called.  When _thr_initial is null, _libpthread_init is
+ * called to initialize the internal variables; this also creates
+ * or sets the initial thread.  It'd be nice to automatically
+ * have _libpthread_init called on program execution so we don't
+ * have to have checks throughout the library.
+ *
+ * The second part is only triggered by the creation of the first
+ * thread (other than the initial/main thread).  If the thread
+ * being created is a scope system thread, then a new KSE/KSEG
+ * pair needs to be allocated.  Also, if upcalls haven't been
+ * enabled on the initial thread's KSE, they must be now that
+ * there is more than one thread; this could be delayed until
+ * the initial KSEG has more than one thread.
+ */
+int
+_pthread_create(pthread_t * thread, const pthread_attr_t * attr,
+	       void *(*start_routine) (void *), void *arg)
+{
+	struct pthread *curthread, *new_thread;
+	struct kse *kse = NULL;
+	struct kse_group *kseg = NULL;
+	kse_critical_t crit;
+	int ret = 0;
+
+	if (_thr_initial == NULL)
+		_libpthread_init(NULL);
+
+	/*
+	 * Turn on threaded mode, if failed, it is unnecessary to
+	 * do further work.
+	 */
+	if (_kse_isthreaded() == 0 && _kse_setthreaded(1)) {
+		return (EAGAIN);
+	}
+	curthread = _get_curthread();
+
+	/*
+	 * Allocate memory for the thread structure.
+	 * Some functions use malloc, so don't put it
+	 * in a critical region.
+	 */
+	if ((new_thread = _thr_alloc(curthread)) == NULL) {
+		/* Insufficient memory to create a thread: */
+		ret = EAGAIN;
+	} else {
+		/* Check if default thread attributes are required: */
+		if (attr == NULL || *attr == NULL)
+			/* Use the default thread attributes: */
+			new_thread->attr = _pthread_attr_default;
+		else {
+			new_thread->attr = *(*attr);
+			if ((*attr)->sched_inherit == PTHREAD_INHERIT_SCHED) {
+				/* inherit scheduling contention scop */
+				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)
+		    && (thread != &_thr_sig_daemon))
+			new_thread->attr.flags &= ~PTHREAD_SCOPE_SYSTEM;
+		if (create_stack(&new_thread->attr) != 0) {
+			/* Insufficient memory to create a stack: */
+			ret = EAGAIN;
+			_thr_free(curthread, new_thread);
+		}
+		else if (((new_thread->attr.flags & PTHREAD_SCOPE_SYSTEM) != 0) &&
+		    (((kse = _kse_alloc(curthread, 1)) == NULL)
+		    || ((kseg = _kseg_alloc(curthread)) == NULL))) {
+			/* Insufficient memory to create a new KSE/KSEG: */
+			ret = EAGAIN;
+			if (kse != NULL) {
+				kse->k_kcb->kcb_kmbx.km_flags |= KMF_DONE;
+				_kse_free(curthread, kse);
+			}
+			free_stack(&new_thread->attr);
+			_thr_free(curthread, new_thread);
+		}
+		else {
+			if (kseg != NULL) {
+				/* Add the KSE to the KSEG's list of KSEs. */
+				TAILQ_INSERT_HEAD(&kseg->kg_kseq, kse, k_kgqe);
+				kseg->kg_ksecount = 1;
+				kse->k_kseg = kseg;
+				kse->k_schedq = &kseg->kg_schedq;
+			}
+			/*
+			 * Write a magic value to the thread structure
+			 * to help identify valid ones:
+			 */
+			new_thread->magic = THR_MAGIC;
+
+			new_thread->slice_usec = -1;
+			new_thread->start_routine = start_routine;
+			new_thread->arg = arg;
+			new_thread->cancelflags = PTHREAD_CANCEL_ENABLE |
+			    PTHREAD_CANCEL_DEFERRED;
+
+			/* No thread is wanting to join to this one: */
+			new_thread->joiner = NULL;
+
+			/*
+			 * Initialize the machine context.
+			 * Enter a critical region to get consistent context.
+			 */
+			crit = _kse_critical_enter();
+			THR_GETCONTEXT(&new_thread->tcb->tcb_tmbx.tm_context);
+			/* Initialize the thread for signals: */
+			new_thread->sigmask = curthread->sigmask;
+			_kse_critical_leave(crit);
+
+			new_thread->tcb->tcb_tmbx.tm_udata = new_thread;
+			new_thread->tcb->tcb_tmbx.tm_context.uc_sigmask =
+			    new_thread->sigmask;
+			new_thread->tcb->tcb_tmbx.tm_context.uc_stack.ss_size =
+			    new_thread->attr.stacksize_attr;
+			new_thread->tcb->tcb_tmbx.tm_context.uc_stack.ss_sp =
+			    new_thread->attr.stackaddr_attr;
+			makecontext(&new_thread->tcb->tcb_tmbx.tm_context,
+			    (void (*)(void))thread_start, 3, new_thread,
+			    start_routine, arg);
+			/*
+			 * 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_SCHED_LOCK(curthread, curthread);
+				new_thread->base_priority =
+				    curthread->base_priority &
+				    ~THR_SIGNAL_PRIORITY;
+				new_thread->attr.prio =
+				    curthread->base_priority &
+				    ~THR_SIGNAL_PRIORITY;
+				new_thread->attr.sched_policy =
+				    curthread->attr.sched_policy;
+				THR_SCHED_UNLOCK(curthread, 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;
+			new_thread->inherited_priority = 0;
+
+			/* Initialize the mutex queue: */
+			TAILQ_INIT(&new_thread->mutexq);
+
+			/* Initialise hooks in the thread structure: */
+			new_thread->specific = NULL;
+			new_thread->specific_data_count = 0;
+			new_thread->cleanup = NULL;
+			new_thread->flags = 0;
+			new_thread->tlflags = 0;
+			new_thread->sigbackout = NULL;
+			new_thread->continuation = NULL;
+			new_thread->wakeup_time.tv_sec = -1;
+			new_thread->lock_switch = 0;
+			sigemptyset(&new_thread->sigpend);
+			new_thread->check_pending = 0;
+			new_thread->locklevel = 0;
+			new_thread->rdlock_count = 0;
+			new_thread->sigstk.ss_sp = 0;
+			new_thread->sigstk.ss_size = 0;
+			new_thread->sigstk.ss_flags = SS_DISABLE;
+			new_thread->oldsigmask = NULL;
+
+			if (new_thread->attr.suspend == THR_CREATE_SUSPENDED) {
+				new_thread->state = PS_SUSPENDED;
+				new_thread->flags = THR_FLAGS_SUSPENDED;
+			}
+			else
+				new_thread->state = PS_RUNNING;
+
+			/*
+			 * System scope threads have their own kse and
+			 * kseg.  Process scope threads are all hung
+			 * off the main process kseg.
+			 */
+			if ((new_thread->attr.flags & PTHREAD_SCOPE_SYSTEM) == 0) {
+				new_thread->kseg = _kse_initial->k_kseg;
+				new_thread->kse = _kse_initial;
+			}
+			else {
+				kse->k_curthread = NULL;
+				kse->k_kseg->kg_flags |= KGF_SINGLE_THREAD;
+				new_thread->kse = kse;
+				new_thread->kseg = kse->k_kseg;
+				kse->k_kcb->kcb_kmbx.km_udata = kse;
+				kse->k_kcb->kcb_kmbx.km_curthread = NULL;
+			}
+
+			/*
+			 * Schedule the new thread starting a new KSEG/KSE
+			 * pair if necessary.
+			 */
+			ret = _thr_schedule_add(curthread, new_thread);
+			if (ret != 0)
+				free_thread(curthread, new_thread);
+			else {
+				/* Return a pointer to the thread structure: */
+				(*thread) = new_thread;
+			}
+		}
+	}
+
+	/* Return the status: */
+	return (ret);
+}
+
+static void
+free_thread(struct pthread *curthread, struct pthread *thread)
+{
+	free_stack(&thread->attr);
+	if ((thread->attr.flags & PTHREAD_SCOPE_SYSTEM) != 0) {
+		/* Free the KSE and KSEG. */
+		_kseg_free(thread->kseg);
+		_kse_free(curthread, thread->kse);
+	}
+	_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_attr *pattr)
+{
+	struct kse *curkse;
+	kse_critical_t crit;
+
+	if ((pattr->flags & THR_STACK_USER) == 0) {
+		crit = _kse_critical_enter();
+		curkse = _get_curkse();
+		KSE_LOCK_ACQUIRE(curkse, &_thread_list_lock);
+		/* Stack routines don't use malloc/free. */
+		_thr_stack_free(pattr);
+		KSE_LOCK_RELEASE(curkse, &_thread_list_lock);
+		_kse_critical_leave(crit);
+	}
+}
+
+static void
+thread_start(struct pthread *curthread, void *(*start_routine) (void *),
+    void *arg)
+{
+	/* Run the current thread's start routine with argument: */
+	pthread_exit(start_routine(arg));
+
+	/* This point should never be reached. */
+	PANIC("Thread has resumed after exit");
+}
--- /dev/null
+++ lib/libkse/thread/thr_fork.c
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 1995-1998 John Birrell <jb at 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. Neither the name of the author nor the names of any 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/libkse/thread/thr_fork.c,v 1.39 2007/10/09 13:42:28 obrien Exp $
+ */
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <spinlock.h>
+#include <sys/signalvar.h>
+
+#include "libc_private.h"
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_fork);
+LT10_COMPAT_DEFAULT(fork);
+
+__weak_reference(_fork, fork);
+
+pid_t
+_fork(void)
+{
+	sigset_t sigset, oldset;
+	struct pthread *curthread;
+	struct pthread_atfork *af;
+	pid_t ret;
+	int errsave;
+
+	curthread = _get_curthread();
+
+	if (!_kse_isthreaded()) {
+		SIGFILLSET(sigset);
+		__sys_sigprocmask(SIG_SETMASK, &sigset, &oldset);
+		ret = __sys_fork();
+		if (ret == 0)
+			/* Child */
+			__sys_sigprocmask(SIG_SETMASK, &curthread->sigmask,
+			    NULL);
+		else
+			__sys_sigprocmask(SIG_SETMASK, &oldset, NULL);
+		return (ret);
+	}
+
+	/*
+	 * Masks all signals until we reach a safe point in
+	 * _kse_single_thread, and the signal masks will be
+	 * restored in that function, for M:N thread, all 
+	 * signals were already masked in kernel atomically,
+	 * we only need to do this for bound thread.
+	 */
+	if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM) {
+		SIGFILLSET(sigset);
+		__sys_sigprocmask(SIG_SETMASK, &sigset, &oldset);
+	}
+
+	_pthread_mutex_lock(&_thr_atfork_mutex);
+
+	/* Run down atfork prepare handlers. */
+	TAILQ_FOREACH_REVERSE(af, &_thr_atfork_list, atfork_head, qe) {
+		if (af->prepare != NULL)
+			af->prepare();
+	}
+
+	/* Fork a new process: */
+	if (_kse_isthreaded() != 0) {
+		_malloc_prefork();
+	}
+	if ((ret = __sys_fork()) == 0) {
+		/* Child process */
+		errsave = errno; 
+
+		/* Kernel signal mask is restored in _kse_single_thread */
+		_kse_single_thread(curthread);
+
+		/* Run down atfork child handlers. */
+		TAILQ_FOREACH(af, &_thr_atfork_list, qe) {
+			if (af->child != NULL)
+				af->child();
+		}
+		_thr_mutex_reinit(&_thr_atfork_mutex);
+	} else {
+		if (_kse_isthreaded() != 0) {
+			_malloc_postfork();
+		}
+		errsave = errno; 
+		if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM) {
+			__sys_sigprocmask(SIG_SETMASK, &oldset, NULL);
+		}
+		/* Run down atfork parent handlers. */
+		TAILQ_FOREACH(af, &_thr_atfork_list, qe) {
+			if (af->parent != NULL)
+				af->parent();
+		}
+		_pthread_mutex_unlock(&_thr_atfork_mutex);
+	}
+	errno = errsave;
+
+	/* Return the process ID: */
+	return (ret);
+}
--- /dev/null
+++ lib/libkse/thread/thr_join.c
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 1995 John Birrell <jb at 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. Neither the name of the author nor the names of any 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/libkse/thread/thr_join.c,v 1.32 2007/10/09 13:42:28 obrien Exp $
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_join);
+LT10_COMPAT_DEFAULT(pthread_join);
+
+__weak_reference(_pthread_join, pthread_join);
+
+int
+_pthread_join(pthread_t pthread, void **thread_return)
+{
+	struct pthread *curthread = _get_curthread();
+	void *tmp;
+	kse_critical_t crit;
+	int ret = 0;
+ 
+	_thr_cancel_enter(curthread);
+
+	/* Check if the caller has specified an invalid thread: */
+	if (pthread == NULL || pthread->magic != THR_MAGIC) {
+		/* Invalid thread: */
+		_thr_cancel_leave(curthread, 1);
+		return (EINVAL);
+	}
+
+	/* Check if the caller has specified itself: */
+	if (pthread == curthread) {
+		/* Avoid a deadlock condition: */
+		_thr_cancel_leave(curthread, 1);
+		return (EDEADLK);
+	}
+
+	/*
+	 * Find the thread in the list of active threads or in the
+	 * list of dead threads:
+	 */
+	if ((ret = _thr_ref_add(curthread, pthread, /*include dead*/1)) != 0) {
+		/* Return an error: */
+		_thr_cancel_leave(curthread, 1);
+		return (ESRCH);
+	}
+
+	THR_SCHED_LOCK(curthread, pthread);
+	/* Check if this thread has been detached: */
+	if ((pthread->attr.flags & PTHREAD_DETACHED) != 0) {
+		THR_SCHED_UNLOCK(curthread, pthread);
+		/* Remove the reference and return an error: */
+		_thr_ref_delete(curthread, pthread);
+		ret = EINVAL;
+	} else {
+		/* Lock the target thread while checking its state. */
+		if (pthread->state == PS_DEAD) {
+			/* Return the thread's return value: */
+			tmp = pthread->ret;
+
+			/* Detach the thread. */
+			pthread->attr.flags |= PTHREAD_DETACHED;
+
+			/* Unlock the thread. */
+			THR_SCHED_UNLOCK(curthread, pthread);
+
+			/*
+			 * Remove the thread from the list of active
+			 * threads and add it to the GC list.
+			 */
+			crit = _kse_critical_enter();
+			KSE_LOCK_ACQUIRE(curthread->kse, &_thread_list_lock);
+			THR_LIST_REMOVE(pthread);
+			THR_GCLIST_ADD(pthread);
+			KSE_LOCK_RELEASE(curthread->kse, &_thread_list_lock);
+			_kse_critical_leave(crit);
+
+			/* Remove the reference. */
+			_thr_ref_delete(curthread, pthread);
+			if (thread_return != NULL)
+				*thread_return = tmp;
+		}
+		else if (pthread->joiner != NULL) {
+			/* Unlock the thread and remove the reference. */
+			THR_SCHED_UNLOCK(curthread, pthread);
+			_thr_ref_delete(curthread, pthread);
+
+			/* Multiple joiners are not supported. */
+			ret = ENOTSUP;
+		}
+		else {
+			/* Set the running thread to be the joiner: */
+			pthread->joiner = curthread;
+
+			/* Keep track of which thread we're joining to: */
+			curthread->join_status.thread = pthread;
+
+			/* Unlock the thread and remove the reference. */
+			THR_SCHED_UNLOCK(curthread, pthread);
+			_thr_ref_delete(curthread, pthread);
+
+			THR_SCHED_LOCK(curthread, curthread);
+			while (curthread->join_status.thread == pthread) {
+				THR_SET_STATE(curthread, PS_JOIN);
+				THR_SCHED_UNLOCK(curthread, curthread);
+				/* Schedule the next thread: */
+				_thr_sched_switch(curthread);
+				THR_SCHED_LOCK(curthread, curthread);
+			}
+			THR_SCHED_UNLOCK(curthread, curthread);
+
+			if ((curthread->cancelflags & THR_CANCELLING) &&
+			   !(curthread->cancelflags & PTHREAD_CANCEL_DISABLE)) {
+				if (_thr_ref_add(curthread, pthread, 1) == 0) {
+					THR_SCHED_LOCK(curthread, pthread);
+					pthread->joiner = NULL;
+					THR_SCHED_UNLOCK(curthread, pthread);
+					_thr_ref_delete(curthread, pthread);
+				}
+				pthread_exit(PTHREAD_CANCELED);
+			}
+
+			/*
+			 * The thread return value and error are set by the
+			 * thread we're joining to when it exits or detaches:
+			 */
+			ret = curthread->join_status.error;
+			if ((ret == 0) && (thread_return != NULL))
+				*thread_return = curthread->join_status.ret;
+		}
+	}
+	_thr_cancel_leave(curthread, 1);
+
+	/* Return the completion status: */
+	return (ret);
+}
--- /dev/null
+++ lib/libkse/thread/thr_sem.c
@@ -0,0 +1,267 @@
+/*
+ * Copyright (C) 2000 Jason Evans <jasone at 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/libkse/thread/thr_sem.c,v 1.20 2007/10/09 13:42:29 obrien Exp $
+ */
+
+#include "namespace.h"
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <semaphore.h>
+#include <stdlib.h>
+#include <time.h>
+#include <_semaphore.h>
+#include "un-namespace.h"
+#include "libc_private.h"
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_sem_init);
+LT10_COMPAT_DEFAULT(sem_init);
+LT10_COMPAT_PRIVATE(_sem_wait);
+LT10_COMPAT_DEFAULT(sem_wait);
+LT10_COMPAT_PRIVATE(_sem_timedwait);
+LT10_COMPAT_DEFAULT(sem_timedwait);
+LT10_COMPAT_PRIVATE(_sem_post);
+LT10_COMPAT_DEFAULT(sem_post);
+
+__weak_reference(_sem_init, sem_init);
+__weak_reference(_sem_wait, sem_wait);
+__weak_reference(_sem_timedwait, sem_timedwait);
+__weak_reference(_sem_post, sem_post);
+
+
+static inline int
+sem_check_validity(sem_t *sem)
+{
+
+	if ((sem != NULL) && ((*sem)->magic == SEM_MAGIC))
+		return (0);
+	else {
+		errno = EINVAL;
+		return (-1);
+	}
+}
+
+static void
+decrease_nwaiters(void *arg)
+{
+	sem_t *sem = (sem_t *)arg;
+
+	(*sem)->nwaiters--;
+	/*
+	 * this function is called from cancellation point,
+	 * the mutex should already be hold.
+	 */
+	_pthread_mutex_unlock(&(*sem)->lock);
+}
+
+static sem_t
+sem_alloc(unsigned int value, semid_t semid, int system_sem)
+{
+	sem_t sem;
+
+	if (value > SEM_VALUE_MAX) {
+		errno = EINVAL;
+		return (NULL);
+	}
+
+	sem = (sem_t)malloc(sizeof(struct sem));
+	if (sem == NULL) {
+		errno = ENOSPC;
+		return (NULL);
+	}
+
+	/*
+	 * Initialize the semaphore.
+	 */
+	if (_pthread_mutex_init(&sem->lock, NULL) != 0) {
+		free(sem);
+		errno = ENOSPC;
+		return (NULL);
+	}
+
+	if (_pthread_cond_init(&sem->gtzero, NULL) != 0) {
+		_pthread_mutex_destroy(&sem->lock);
+		free(sem);
+		errno = ENOSPC;
+		return (NULL);
+	}
+
+	sem->count = (u_int32_t)value;
+	sem->nwaiters = 0;
+	sem->magic = SEM_MAGIC;
+	sem->semid = semid;
+	sem->syssem = system_sem;
+	return (sem);
+}
+
+int
+_sem_init(sem_t *sem, int pshared, unsigned int value)
+{
+	semid_t semid;
+
+	semid = (semid_t)SEM_USER;
+	if ((pshared != 0) && (ksem_init(&semid, value) != 0))
+		return (-1);
+
+	(*sem) = sem_alloc(value, semid, pshared);
+	if ((*sem) == NULL) {
+		if (pshared != 0)
+			ksem_destroy(semid);
+		return (-1);
+	}
+	return (0);
+}
+
+int
+_sem_wait(sem_t *sem)
+{
+	struct pthread *curthread;
+	int retval;
+
+	if (sem_check_validity(sem) != 0)
+		return (-1);
+
+	curthread = _get_curthread();
+	if ((*sem)->syssem != 0) {
+		_thr_cancel_enter(curthread);
+		retval = ksem_wait((*sem)->semid);
+		_thr_cancel_leave(curthread, retval != 0);
+	}
+	else {
+		_pthread_testcancel();
+		_pthread_mutex_lock(&(*sem)->lock);
+
+		while ((*sem)->count <= 0) {
+			(*sem)->nwaiters++;
+			THR_CLEANUP_PUSH(curthread, decrease_nwaiters, sem);
+			_pthread_cond_wait(&(*sem)->gtzero, &(*sem)->lock);
+			THR_CLEANUP_POP(curthread, 0);
+			(*sem)->nwaiters--;
+		}
+		(*sem)->count--;
+
+		_pthread_mutex_unlock(&(*sem)->lock);
+
+		retval = 0;
+	}
+	return (retval);
+}
+
+int
+_sem_timedwait(sem_t * __restrict sem,
+    const struct timespec * __restrict abs_timeout)
+{
+	struct pthread *curthread;
+	int retval;
+	int timeout_invalid;
+
+	if (sem_check_validity(sem) != 0)
+		return (-1);
+
+	if ((*sem)->syssem != 0) {
+		curthread = _get_curthread();
+		_thr_cancel_enter(curthread);
+		retval = ksem_timedwait((*sem)->semid, abs_timeout);
+		_thr_cancel_leave(curthread, retval != 0);
+	}
+	else {
+		/*
+		 * The timeout argument is only supposed to
+		 * be checked if the thread would have blocked.
+		 * This is checked outside of the lock so a
+		 * segfault on an invalid address doesn't end
+		 * up leaving the mutex locked.
+		 */
+		_pthread_testcancel();
+		timeout_invalid = (abs_timeout->tv_nsec >= 1000000000) ||
+		    (abs_timeout->tv_nsec < 0);
+		_pthread_mutex_lock(&(*sem)->lock);
+
+		if ((*sem)->count <= 0) {
+			if (timeout_invalid) {
+				_pthread_mutex_unlock(&(*sem)->lock);
+				errno = EINVAL;
+				return (-1);
+			}
+			(*sem)->nwaiters++;
+			_pthread_cleanup_push(decrease_nwaiters, sem);
+			_pthread_cond_timedwait(&(*sem)->gtzero,
+			    &(*sem)->lock, abs_timeout);
+			_pthread_cleanup_pop(0);
+			(*sem)->nwaiters--;
+		}
+		if ((*sem)->count == 0) {
+			errno = ETIMEDOUT;
+			retval = -1;
+		}
+		else {
+			(*sem)->count--;
+			retval = 0;
+		}	
+
+		_pthread_mutex_unlock(&(*sem)->lock);
+	}
+
+	return (retval);
+}
+
+int
+_sem_post(sem_t *sem)
+{
+	struct pthread *curthread;
+	int retval;
+	
+	if (sem_check_validity(sem) != 0)
+		return (-1);
+
+	if ((*sem)->syssem != 0)
+		retval = ksem_post((*sem)->semid);
+	else {
+		/*
+		 * sem_post() is required to be safe to call from within
+		 * signal handlers.  Thus, we must enter a critical region.
+		 */
+		curthread = _get_curthread();
+		_thr_critical_enter(curthread);
+		_pthread_mutex_lock(&(*sem)->lock);
+
+		(*sem)->count++;
+		if ((*sem)->nwaiters > 0)
+			_pthread_cond_signal(&(*sem)->gtzero);
+
+		_pthread_mutex_unlock(&(*sem)->lock);
+		_thr_critical_leave(curthread);
+		retval = 0;
+	}
+
+	return (retval);
+}
--- /dev/null
+++ lib/libkse/thread/thr_attr_setschedparam.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 1998 Daniel Eischen <eischen at 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/libkse/thread/thr_attr_setschedparam.c,v 1.12 2007/10/09 13:42:27 obrien Exp $
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_attr_setschedparam);
+LT10_COMPAT_DEFAULT(pthread_attr_setschedparam);
+
+__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);
+}
--- /dev/null
+++ lib/libkse/thread/thr_getschedparam.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 1998 Daniel Eischen <eischen at 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/libkse/thread/thr_getschedparam.c,v 1.12 2007/10/09 13:42:28 obrien Exp $
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_getschedparam);
+LT10_COMPAT_DEFAULT(pthread_getschedparam);
+
+__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_SCHED_LOCK(curthread, curthread);
+		param->sched_priority =
+		    THR_BASE_PRIORITY(pthread->base_priority);
+		tmp = pthread->attr.sched_policy;
+		THR_SCHED_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_SCHED_LOCK(curthread, pthread);
+		param->sched_priority =
+		    THR_BASE_PRIORITY(pthread->base_priority);
+		tmp = pthread->attr.sched_policy;
+		THR_SCHED_UNLOCK(curthread, pthread);
+		_thr_ref_delete(curthread, pthread);
+		*policy = tmp;
+	}
+	return (ret);
+}
--- /dev/null
+++ lib/libkse/thread/thr_resume_np.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 1995 John Birrell <jb at 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. Neither the name of the author nor the names of any 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/libkse/thread/thr_resume_np.c,v 1.21 2007/10/09 13:42:29 obrien Exp $
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+static struct kse_mailbox *resume_common(struct pthread *);
+
+LT10_COMPAT_PRIVATE(_pthread_resume_np);
+LT10_COMPAT_DEFAULT(pthread_resume_np);
+LT10_COMPAT_PRIVATE(_pthread_resume_all_np);
+LT10_COMPAT_DEFAULT(pthread_resume_all_np);
+
+__weak_reference(_pthread_resume_np, pthread_resume_np);
+__weak_reference(_pthread_resume_all_np, pthread_resume_all_np);
+
+
+/* Resume a thread: */
+int
+_pthread_resume_np(pthread_t thread)
+{
+	struct pthread *curthread = _get_curthread();
+	struct kse_mailbox *kmbx;
+	int ret;
+
+	/* Add a reference to the thread: */
+	if ((ret = _thr_ref_add(curthread, thread, /*include dead*/0)) == 0) {
+		/* Lock the threads scheduling queue: */
+		THR_SCHED_LOCK(curthread, thread);
+		kmbx = resume_common(thread);
+		THR_SCHED_UNLOCK(curthread, thread);
+		_thr_ref_delete(curthread, thread);
+		if (kmbx != NULL)
+			kse_wakeup(kmbx);
+	}
+	return (ret);
+}
+
+void
+_pthread_resume_all_np(void)
+{
+	struct pthread *curthread = _get_curthread();
+	struct pthread *thread;
+	struct kse_mailbox *kmbx;
+	kse_critical_t crit;
+
+	/* Take the thread list lock: */
+	crit = _kse_critical_enter();
+	KSE_LOCK_ACQUIRE(curthread->kse, &_thread_list_lock);
+
+	TAILQ_FOREACH(thread, &_thread_list, tle) {
+		if (thread != curthread) {
+			THR_SCHED_LOCK(curthread, thread);
+			kmbx = resume_common(thread);
+			THR_SCHED_UNLOCK(curthread, thread);
+			if (kmbx != NULL)
+				kse_wakeup(kmbx);
+		}
+	}
+
+	/* Release the thread list lock: */
+	KSE_LOCK_RELEASE(curthread->kse, &_thread_list_lock);
+	_kse_critical_leave(crit);
+}
+
+static struct kse_mailbox *
+resume_common(struct pthread *thread)
+{
+	/* Clear the suspend flag: */
+	thread->flags &= ~THR_FLAGS_SUSPENDED;
+
+	/*
+	 * If the thread's state is suspended, that means it is
+	 * now runnable but not in any scheduling queue.  Set the
+	 * state to running and insert it into the run queue.
+	 */
+	if (thread->state == PS_SUSPENDED)
+		return (_thr_setrunnable_unlocked(thread));
+	else
+		return (NULL);
+}
--- /dev/null
+++ lib/libkse/thread/thr_sigprocmask.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 1995 John Birrell <jb at 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. Neither the name of the author nor the names of any 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/libkse/thread/thr_sigprocmask.c,v 1.20 2007/10/09 13:42:29 obrien Exp $
+ */
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/signalvar.h>
+#include <signal.h>
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_sigprocmask);
+LT10_COMPAT_DEFAULT(sigprocmask);
+
+__weak_reference(_sigprocmask, sigprocmask);
+
+int
+_sigprocmask(int how, const sigset_t *set, sigset_t *oset)
+{
+	int ret;
+
+	ret = pthread_sigmask(how, set, oset);
+	if (ret) {
+		errno = ret;
+		ret = -1;
+	}
+	return (ret);
+}
--- /dev/null
+++ lib/libkse/thread/thr_raise.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2003 David Xu<davidxu at 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/libkse/thread/thr_raise.c,v 1.3 2007/10/09 13:42:29 obrien Exp $
+ */
+
+#include <pthread.h>
+#include <errno.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_raise);
+LT10_COMPAT_DEFAULT(raise);
+
+__weak_reference(_raise, raise);
+
+int
+_raise(int sig)
+{
+	int ret;
+
+	if (!_kse_isthreaded())
+		ret = kill(getpid(), sig);
+	else {
+		ret = pthread_kill(pthread_self(), sig);
+		if (ret != 0) {
+			errno = ret;
+			ret = -1;
+		}
+	}
+	return (ret);
+}
--- /dev/null
+++ lib/libkse/thread/thr_main_np.c
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2001 Alfred Perlstein
+ * Author: Alfred Perlstein <alfred at 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/libkse/thread/thr_main_np.c,v 1.7 2007/10/09 13:42:28 obrien Exp $
+ */
+
+#include <pthread.h>
+#include <pthread_np.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_main_np);
+LT10_COMPAT_DEFAULT(pthread_main_np);
+
+__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);
+}
--- /dev/null
+++ lib/libkse/thread/thr_rwlock.c
@@ -0,0 +1,438 @@
+/*-
+ * Copyright (c) 1998 Alex Nash
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/lib/libkse/thread/thr_rwlock.c,v 1.16 2007/10/09 13:42:29 obrien Exp $
+ */
+
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+
+#include "namespace.h"
+#include <pthread.h>
+#include "un-namespace.h"
+#include "thr_private.h"
+
+/* maximum number of times a read lock may be obtained */
+#define	MAX_READ_LOCKS		(INT_MAX - 1)
+
+LT10_COMPAT_PRIVATE(_pthread_rwlock_destroy);
+LT10_COMPAT_DEFAULT(pthread_rwlock_destroy);
+LT10_COMPAT_PRIVATE(_pthread_rwlock_init);
+LT10_COMPAT_DEFAULT(pthread_rwlock_init);
+LT10_COMPAT_PRIVATE(_pthread_rwlock_rdlock);
+LT10_COMPAT_DEFAULT(pthread_rwlock_rdlock);
+LT10_COMPAT_PRIVATE(_pthread_rwlock_timedrdlock);
+LT10_COMPAT_DEFAULT(pthread_rwlock_timedrdlock);
+LT10_COMPAT_PRIVATE(_pthread_rwlock_tryrdlock);
+LT10_COMPAT_DEFAULT(pthread_rwlock_tryrdlock);
+LT10_COMPAT_PRIVATE(_pthread_rwlock_trywrlock);
+LT10_COMPAT_DEFAULT(pthread_rwlock_trywrlock);
+LT10_COMPAT_PRIVATE(_pthread_rwlock_unlock);
+LT10_COMPAT_DEFAULT(pthread_rwlock_unlock);
+LT10_COMPAT_PRIVATE(_pthread_rwlock_wrlock);
+LT10_COMPAT_DEFAULT(pthread_rwlock_wrlock);
+LT10_COMPAT_PRIVATE(_pthread_rwlock_timedwrlock);
+LT10_COMPAT_DEFAULT(pthread_rwlock_timedwrlock);
+
+__weak_reference(_pthread_rwlock_destroy, pthread_rwlock_destroy);
+__weak_reference(_pthread_rwlock_init, pthread_rwlock_init);
+__weak_reference(_pthread_rwlock_rdlock, pthread_rwlock_rdlock);
+__weak_reference(_pthread_rwlock_timedrdlock, pthread_rwlock_timedrdlock);
+__weak_reference(_pthread_rwlock_tryrdlock, pthread_rwlock_tryrdlock);
+__weak_reference(_pthread_rwlock_trywrlock, pthread_rwlock_trywrlock);
+__weak_reference(_pthread_rwlock_unlock, pthread_rwlock_unlock);
+__weak_reference(_pthread_rwlock_wrlock, pthread_rwlock_wrlock);
+__weak_reference(_pthread_rwlock_timedwrlock, pthread_rwlock_timedwrlock);
+
+/*
+ * Prototypes
+ */
+static int init_static(pthread_rwlock_t *rwlock);
+
+
+static int
+init_static(pthread_rwlock_t *rwlock)
+{
+	struct pthread *thread = _get_curthread();
+	int ret;
+
+	THR_LOCK_ACQUIRE(thread, &_rwlock_static_lock);
+
+	if (*rwlock == NULL)
+		ret = _pthread_rwlock_init(rwlock, NULL);
+	else
+		ret = 0;
+
+	THR_LOCK_RELEASE(thread, &_rwlock_static_lock);
+	return (ret);
+}
+
+int
+_pthread_rwlock_destroy (pthread_rwlock_t *rwlock)
+{
+	int ret;
+
+	if (rwlock == NULL)
+		ret = EINVAL;
+	else {
+		pthread_rwlock_t prwlock;
+
+		prwlock = *rwlock;
+
+		_pthread_mutex_destroy(&prwlock->lock);
+		_pthread_cond_destroy(&prwlock->read_signal);
+		_pthread_cond_destroy(&prwlock->write_signal);
+		free(prwlock);
+
+		*rwlock = NULL;
+
+		ret = 0;
+	}
+	return (ret);
+}
+
+int
+_pthread_rwlock_init (pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr)
+{
+	pthread_rwlock_t prwlock;
+	int ret;
+
+	/* allocate rwlock object */
+	prwlock = (pthread_rwlock_t)malloc(sizeof(struct pthread_rwlock));
+
+	if (prwlock == NULL)
+		return (ENOMEM);
+
+	/* initialize the lock */
+	if ((ret = _pthread_mutex_init(&prwlock->lock, NULL)) != 0)
+		free(prwlock);
+	else {
+		/* initialize the read condition signal */
+		ret = _pthread_cond_init(&prwlock->read_signal, NULL);
+
+		if (ret != 0) {
+			_pthread_mutex_destroy(&prwlock->lock);
+			free(prwlock);
+		} else {
+			/* initialize the write condition signal */
+			ret = _pthread_cond_init(&prwlock->write_signal, NULL);
+
+			if (ret != 0) {
+				_pthread_cond_destroy(&prwlock->read_signal);
+				_pthread_mutex_destroy(&prwlock->lock);
+				free(prwlock);
+			} else {
+				/* success */
+				prwlock->state = 0;
+				prwlock->blocked_writers = 0;
+
+				*rwlock = prwlock;
+			}
+		}
+	}
+
+	return (ret);
+}
+
+static int
+rwlock_rdlock_common (pthread_rwlock_t *rwlock, const struct timespec *abstime)
+{
+	pthread_rwlock_t prwlock;
+	struct pthread *curthread;
+	int ret;
+
+	if (rwlock == NULL)
+		return (EINVAL);
+
+	prwlock = *rwlock;
+
+	/* check for static initialization */
+	if (prwlock == NULL) {
+		if ((ret = init_static(rwlock)) != 0)
+			return (ret);
+
+		prwlock = *rwlock;
+	}
+
+	/* grab the monitor lock */
+	if ((ret = _thr_mutex_lock(&prwlock->lock)) != 0)
+		return (ret);
+
+	/* check lock count */
+	if (prwlock->state == MAX_READ_LOCKS) {
+		_thr_mutex_unlock(&prwlock->lock);
+		return (EAGAIN);
+	}
+
+	curthread = _get_curthread();
+	if ((curthread->rdlock_count > 0) && (prwlock->state > 0)) {
+		/*
+		 * To avoid having to track all the rdlocks held by
+		 * a thread or all of the threads that hold a rdlock,
+		 * we keep a simple count of all the rdlocks held by
+		 * a thread.  If a thread holds any rdlocks it is
+		 * possible that it is attempting to take a recursive
+		 * rdlock.  If there are blocked writers and precedence
+		 * is given to them, then that would result in the thread
+		 * deadlocking.  So allowing a thread to take the rdlock
+		 * when it already has one or more rdlocks avoids the
+		 * deadlock.  I hope the reader can follow that logic ;-)
+		 */
+		;	/* nothing needed */
+	} else {
+		/* give writers priority over readers */
+		while (prwlock->blocked_writers || prwlock->state < 0) {
+			if (abstime)
+				ret = _pthread_cond_timedwait
+				    (&prwlock->read_signal,
+				    &prwlock->lock, abstime);
+			else
+				ret = _thr_cond_wait(&prwlock->read_signal,
+			    &prwlock->lock);
+			if (ret != 0) {
+				/* can't do a whole lot if this fails */
+				_thr_mutex_unlock(&prwlock->lock);
+				return (ret);
+			}
+		}
+	}
+
+	curthread->rdlock_count++;
+	prwlock->state++; /* indicate we are locked for reading */
+
+	/*
+	 * Something is really wrong if this call fails.  Returning
+	 * error won't do because we've already obtained the read
+	 * lock.  Decrementing 'state' is no good because we probably
+	 * don't have the monitor lock.
+	 */
+	_thr_mutex_unlock(&prwlock->lock);
+
+	return (ret);
+}
+
+int
+_pthread_rwlock_rdlock (pthread_rwlock_t *rwlock)
+{
+	return (rwlock_rdlock_common(rwlock, NULL));
+}
+
+__strong_reference(_pthread_rwlock_rdlock, _thr_rwlock_rdlock);
+
+int
+_pthread_rwlock_timedrdlock (pthread_rwlock_t *rwlock,
+	 const struct timespec *abstime)
+{
+	return (rwlock_rdlock_common(rwlock, abstime));
+}
+
+int
+_pthread_rwlock_tryrdlock (pthread_rwlock_t *rwlock)
+{
+	struct pthread *curthread;
+	pthread_rwlock_t prwlock;
+	int ret;
+
+	if (rwlock == NULL)
+		return (EINVAL);
+
+	prwlock = *rwlock;
+
+	/* check for static initialization */
+	if (prwlock == NULL) {
+		if ((ret = init_static(rwlock)) != 0)
+			return (ret);
+
+		prwlock = *rwlock;
+	}
+
+	/* grab the monitor lock */
+	if ((ret = _pthread_mutex_lock(&prwlock->lock)) != 0)
+		return (ret);
+
+	curthread = _get_curthread();
+	if (prwlock->state == MAX_READ_LOCKS)
+		ret = EAGAIN;
+	else if ((curthread->rdlock_count > 0) && (prwlock->state > 0)) {
+		/* see comment for pthread_rwlock_rdlock() */
+		curthread->rdlock_count++;
+		prwlock->state++;
+	}
+	/* give writers priority over readers */
+	else if (prwlock->blocked_writers || prwlock->state < 0)
+		ret = EBUSY;
+	else {
+		curthread->rdlock_count++;
+		prwlock->state++; /* indicate we are locked for reading */
+	}
+
+	/* see the comment on this in pthread_rwlock_rdlock */
+	_pthread_mutex_unlock(&prwlock->lock);
+
+	return (ret);
+}
+
+int
+_pthread_rwlock_trywrlock (pthread_rwlock_t *rwlock)
+{
+	pthread_rwlock_t prwlock;
+	int ret;
+
+	if (rwlock == NULL)
+		return (EINVAL);
+
+	prwlock = *rwlock;
+
+	/* check for static initialization */
+	if (prwlock == NULL) {
+		if ((ret = init_static(rwlock)) != 0)
+			return (ret);
+
+		prwlock = *rwlock;
+	}
+
+	/* grab the monitor lock */
+	if ((ret = _pthread_mutex_lock(&prwlock->lock)) != 0)
+		return (ret);
+
+	if (prwlock->state != 0)
+		ret = EBUSY;
+	else
+		/* indicate we are locked for writing */
+		prwlock->state = -1;
+
+	/* see the comment on this in pthread_rwlock_rdlock */
+	_pthread_mutex_unlock(&prwlock->lock);
+
+	return (ret);
+}
+
+int
+_pthread_rwlock_unlock (pthread_rwlock_t *rwlock)
+{
+	struct pthread *curthread;
+	pthread_rwlock_t prwlock;
+	int ret;
+
+	if (rwlock == NULL)
+		return (EINVAL);
+
+	prwlock = *rwlock;
+
+	if (prwlock == NULL)
+		return (EINVAL);
+
+	/* grab the monitor lock */
+	if ((ret = _thr_mutex_lock(&prwlock->lock)) != 0)
+		return (ret);
+
+	curthread = _get_curthread();
+	if (prwlock->state > 0) {
+		curthread->rdlock_count--;
+		prwlock->state--;
+		if (prwlock->state == 0 && prwlock->blocked_writers)
+			ret = _thr_cond_signal(&prwlock->write_signal);
+	} else if (prwlock->state < 0) {
+		prwlock->state = 0;
+
+		if (prwlock->blocked_writers)
+			ret = _thr_cond_signal(&prwlock->write_signal);
+		else
+			ret = _thr_cond_broadcast(&prwlock->read_signal);
+	} else
+		ret = EINVAL;
+
+	/* see the comment on this in pthread_rwlock_rdlock */
+	_thr_mutex_unlock(&prwlock->lock);
+
+	return (ret);
+}
+
+__strong_reference(_pthread_rwlock_unlock, _thr_rwlock_unlock);
+
+static int
+rwlock_wrlock_common (pthread_rwlock_t *rwlock, const struct timespec *abstime)
+{
+	pthread_rwlock_t prwlock;
+	int ret;
+
+	if (rwlock == NULL)
+		return (EINVAL);
+
+	prwlock = *rwlock;
+
+	/* check for static initialization */
+	if (prwlock == NULL) {
+		if ((ret = init_static(rwlock)) != 0)
+			return (ret);
+
+		prwlock = *rwlock;
+	}
+
+	/* grab the monitor lock */
+	if ((ret = _thr_mutex_lock(&prwlock->lock)) != 0)
+		return (ret);
+
+	while (prwlock->state != 0) {
+		prwlock->blocked_writers++;
+
+		if (abstime != NULL)
+			ret = _pthread_cond_timedwait(&prwlock->write_signal,
+			    &prwlock->lock, abstime);
+		else
+			ret = _thr_cond_wait(&prwlock->write_signal,
+			    &prwlock->lock);
+		if (ret != 0) {
+			prwlock->blocked_writers--;
+			_thr_mutex_unlock(&prwlock->lock);
+			return (ret);
+		}
+
+		prwlock->blocked_writers--;
+	}
+
+	/* indicate we are locked for writing */
+	prwlock->state = -1;
+
+	/* see the comment on this in pthread_rwlock_rdlock */
+	_thr_mutex_unlock(&prwlock->lock);
+
+	return (ret);
+}
+
+int
+_pthread_rwlock_wrlock (pthread_rwlock_t *rwlock)
+{
+	return (rwlock_wrlock_common (rwlock, NULL));
+}
+__strong_reference(_pthread_rwlock_wrlock, _thr_rwlock_wrlock);
+
+int
+_pthread_rwlock_timedwrlock (pthread_rwlock_t *rwlock,
+    const struct timespec *abstime)
+{
+	return (rwlock_wrlock_common (rwlock, abstime));
+}
--- /dev/null
+++ lib/libkse/thread/thr_attr_getstackaddr.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 1997 John Birrell <jb at 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. Neither the name of the author nor the names of any 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/libkse/thread/thr_attr_getstackaddr.c,v 1.10 2007/10/09 13:42:27 obrien Exp $
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_attr_getstackaddr);
+LT10_COMPAT_DEFAULT(pthread_attr_getstackaddr);
+
+__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);
+}
--- /dev/null
+++ lib/libkse/thread/thr_attr_setdetachstate.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 1997 John Birrell <jb at 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. Neither the name of the author nor the names of any 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/libkse/thread/thr_attr_setdetachstate.c,v 1.10 2007/10/09 13:42:27 obrien Exp $
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_attr_setdetachstate);
+LT10_COMPAT_DEFAULT(pthread_attr_setdetachstate);
+
+__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);
+}
--- /dev/null
+++ lib/libkse/thread/thr_exit.c
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 1995-1998 John Birrell <jb at 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. Neither the name of the author nor the names of any 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/libkse/thread/thr_exit.c,v 1.42 2007/10/09 13:42:27 obrien 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"
+
+LT10_COMPAT_PRIVATE(_pthread_exit);
+LT10_COMPAT_DEFAULT(pthread_exit);
+
+void	_pthread_exit(void *status);
+
+__weak_reference(_pthread_exit, pthread_exit);
+
+void
+_thr_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();
+	kse_critical_t crit;
+	struct kse *curkse;
+
+	/* Check if this thread is already in the process of exiting: */
+	if ((curthread->flags & THR_FLAGS_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.  Threads should now be prevented
+	 * from joining to this thread.
+	 */
+	THR_SCHED_LOCK(curthread, curthread);
+	curthread->flags |= THR_FLAGS_EXITING;
+	THR_SCHED_UNLOCK(curthread, curthread);
+	
+	/*
+	 * To avoid signal-lost problem, if signals had already been
+	 * delivered to us, handle it. we have already set EXITING flag
+	 * so no new signals should be delivered to us.
+	 * XXX this is not enough if signal was delivered just before
+	 * thread called sigprocmask and masked it! in this case, we
+	 * might have to re-post the signal by kill() if the signal
+	 * is targeting process (not for a specified thread).
+	 * Kernel has same signal-lost problem, a signal may be delivered
+	 * to a thread which is on the way to call sigprocmask or thr_exit()!
+	 */
+	if (curthread->check_pending)
+		_thr_sig_check_pending(curthread);
+	/* 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 (!_kse_isthreaded())
+		exit(0);
+	crit = _kse_critical_enter();
+	curkse = _get_curkse();
+	KSE_LOCK_ACQUIRE(curkse, &_thread_list_lock);
+	/* Use thread_list_lock */
+	_thread_active_threads--;
+	if ((_thread_scope_system <= 0 && _thread_active_threads == 1) ||
+	    (_thread_scope_system > 0 && _thread_active_threads == 0)) {
+		KSE_LOCK_RELEASE(curkse, &_thread_list_lock);
+		_kse_critical_leave(crit);
+		exit(0);
+		/* Never reach! */
+	}
+	KSE_LOCK_RELEASE(curkse, &_thread_list_lock);
+
+	/* This thread will never be re-scheduled. */
+	KSE_LOCK(curkse);
+	THR_SET_STATE(curthread, PS_DEAD);
+	_thr_sched_switch_unlocked(curthread);
+	/* Never reach! */
+
+	/* This point should not be reached. */
+	PANIC("Dead thread has resumed");
+}
--- /dev/null
+++ lib/libkse/thread/thr_priority_queue.c
@@ -0,0 +1,324 @@
+/*
+ * Copyright (c) 1998 Daniel Eischen <eischen at 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/libkse/thread/thr_priority_queue.c,v 1.17 2007/10/09 13:42:28 obrien Exp $
+ */
+#include <stdlib.h>
+#include <sys/queue.h>
+#include <string.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+/* Prototypes: */
+static void pq_insert_prio_list(pq_queue_t *pq, int prio);
+
+#if defined(_PTHREADS_INVARIANTS)
+
+#define PQ_IN_SCHEDQ	(THR_FLAGS_IN_RUNQ | THR_FLAGS_IN_WAITQ)
+
+#define PQ_SET_ACTIVE(pq)		(pq)->pq_flags |= PQF_ACTIVE
+#define PQ_CLEAR_ACTIVE(pq)		(pq)->pq_flags &= ~PQF_ACTIVE
+#define PQ_ASSERT_ACTIVE(pq, msg)	do {		\
+	if (((pq)->pq_flags & PQF_ACTIVE) == 0)		\
+		PANIC(msg);				\
+} while (0)
+#define PQ_ASSERT_INACTIVE(pq, msg)	do {		\
+	if (((pq)->pq_flags & PQF_ACTIVE) != 0)		\
+		PANIC(msg);				\
+} while (0)
+#define PQ_ASSERT_IN_WAITQ(thrd, msg)	do {		\
+	if (((thrd)->flags & THR_FLAGS_IN_WAITQ) == 0) \
+		PANIC(msg);				\
+} while (0)
+#define PQ_ASSERT_IN_RUNQ(thrd, msg)	do {		\
+	if (((thrd)->flags & THR_FLAGS_IN_RUNQ) == 0) \
+		PANIC(msg);				\
+} while (0)
+#define PQ_ASSERT_NOT_QUEUED(thrd, msg) do {		\
+	if (((thrd)->flags & PQ_IN_SCHEDQ) != 0)	\
+		PANIC(msg);				\
+} while (0)
+
+#else
+
+#define PQ_SET_ACTIVE(pq)
+#define PQ_CLEAR_ACTIVE(pq)
+#define PQ_ASSERT_ACTIVE(pq, msg)
+#define PQ_ASSERT_INACTIVE(pq, msg)
+#define PQ_ASSERT_IN_WAITQ(thrd, msg)
+#define PQ_ASSERT_IN_RUNQ(thrd, msg)
+#define PQ_ASSERT_NOT_QUEUED(thrd, msg)
+
+#endif
+
+int
+_pq_alloc(pq_queue_t *pq, int minprio, int maxprio)
+{
+	int ret = 0;
+	int prioslots = maxprio - minprio + 1;
+
+	if (pq == NULL)
+		ret = -1;
+
+	/* Create the priority queue with (maxprio - minprio + 1) slots: */
+	else if	((pq->pq_lists =
+	    (pq_list_t *) malloc(sizeof(pq_list_t) * prioslots)) == NULL)
+		ret = -1;
+
+	else {
+		/* Remember the queue size: */
+		pq->pq_size = prioslots;
+		ret = _pq_init(pq);
+	}
+	return (ret);
+}
+
+void
+_pq_free(pq_queue_t *pq)
+{
+	if ((pq != NULL) && (pq->pq_lists != NULL))
+		free(pq->pq_lists);
+}
+
+int
+_pq_init(pq_queue_t *pq)
+{
+	int i, ret = 0;
+
+	if ((pq == NULL) || (pq->pq_lists == NULL))
+		ret = -1;
+
+	else {
+		/* Initialize the queue for each priority slot: */
+		for (i = 0; i < pq->pq_size; i++) {
+			TAILQ_INIT(&pq->pq_lists[i].pl_head);
+			pq->pq_lists[i].pl_prio = i;
+			pq->pq_lists[i].pl_queued = 0;
+		}
+		/* Initialize the priority queue: */
+		TAILQ_INIT(&pq->pq_queue);
+		pq->pq_flags = 0;
+		pq->pq_threads = 0;
+	}
+	return (ret);
+}
+
+void
+_pq_remove(pq_queue_t *pq, pthread_t pthread)
+{
+	int prio = pthread->active_priority;
+
+	/*
+	 * Make some assertions when debugging is enabled:
+	 */
+	PQ_ASSERT_INACTIVE(pq, "_pq_remove: pq_active");
+	PQ_SET_ACTIVE(pq);
+	PQ_ASSERT_IN_RUNQ(pthread, "_pq_remove: Not in priority queue");
+
+	/*
+	 * Remove this thread from priority list.  Note that if
+	 * the priority list becomes empty, it is not removed
+	 * from the priority queue because another thread may be
+	 * added to the priority list (resulting in a needless
+	 * removal/insertion).  Priority lists are only removed
+	 * from the priority queue when _pq_first is called.
+	 */
+	TAILQ_REMOVE(&pq->pq_lists[prio].pl_head, pthread, pqe);
+	pq->pq_threads--;
+	/* This thread is now longer in the priority queue. */
+	pthread->flags &= ~THR_FLAGS_IN_RUNQ;
+	
+	PQ_CLEAR_ACTIVE(pq);
+}
+
+
+void
+_pq_insert_head(pq_queue_t *pq, pthread_t pthread)
+{
+	int prio;
+
+	/*
+	 * Make some assertions when debugging is enabled:
+	 */
+	PQ_ASSERT_INACTIVE(pq, "_pq_insert_head: pq_active");
+	PQ_SET_ACTIVE(pq);
+	PQ_ASSERT_NOT_QUEUED(pthread,
+	    "_pq_insert_head: Already in priority queue");
+
+	prio = pthread->active_priority;
+	TAILQ_INSERT_HEAD(&pq->pq_lists[prio].pl_head, pthread, pqe);
+	if (pq->pq_lists[prio].pl_queued == 0)
+		/* Insert the list into the priority queue: */
+		pq_insert_prio_list(pq, prio);
+	pq->pq_threads++;
+	/* Mark this thread as being in the priority queue. */
+	pthread->flags |= THR_FLAGS_IN_RUNQ;
+
+	PQ_CLEAR_ACTIVE(pq);
+}
+
+
+void
+_pq_insert_tail(pq_queue_t *pq, pthread_t pthread)
+{
+	int prio;
+
+	/*
+	 * Make some assertions when debugging is enabled:
+	 */
+	PQ_ASSERT_INACTIVE(pq, "_pq_insert_tail: pq_active");
+	PQ_SET_ACTIVE(pq);
+	PQ_ASSERT_NOT_QUEUED(pthread,
+	    "_pq_insert_tail: Already in priority queue");
+
+	prio = pthread->active_priority;
+	TAILQ_INSERT_TAIL(&pq->pq_lists[prio].pl_head, pthread, pqe);
+	if (pq->pq_lists[prio].pl_queued == 0)
+		/* Insert the list into the priority queue: */
+		pq_insert_prio_list(pq, prio);
+	pq->pq_threads++;
+	/* Mark this thread as being in the priority queue. */
+	pthread->flags |= THR_FLAGS_IN_RUNQ;
+
+	PQ_CLEAR_ACTIVE(pq);
+}
+
+
+pthread_t
+_pq_first(pq_queue_t *pq)
+{
+	pq_list_t *pql;
+	pthread_t pthread = NULL;
+
+	/*
+	 * Make some assertions when debugging is enabled:
+	 */
+	PQ_ASSERT_INACTIVE(pq, "_pq_first: pq_active");
+	PQ_SET_ACTIVE(pq);
+
+	while (((pql = TAILQ_FIRST(&pq->pq_queue)) != NULL) &&
+	    (pthread == NULL)) {
+		if ((pthread = TAILQ_FIRST(&pql->pl_head)) == NULL) {
+			/*
+			 * The priority list is empty; remove the list
+			 * from the queue.
+			 */
+			TAILQ_REMOVE(&pq->pq_queue, pql, pl_link);
+
+			/* Mark the list as not being in the queue: */
+			pql->pl_queued = 0;
+		}
+	}
+
+	PQ_CLEAR_ACTIVE(pq);
+	return (pthread);
+}
+
+/*
+ * Select a thread which is allowed to run by debugger, we probably
+ * should merge the function into _pq_first if that function is only
+ * used by scheduler to select a thread.
+ */
+pthread_t
+_pq_first_debug(pq_queue_t *pq)
+{
+	pq_list_t *pql, *pqlnext = NULL;
+	pthread_t pthread = NULL;
+
+	/*
+	 * Make some assertions when debugging is enabled:
+	 */
+	PQ_ASSERT_INACTIVE(pq, "_pq_first: pq_active");
+	PQ_SET_ACTIVE(pq);
+
+	for (pql = TAILQ_FIRST(&pq->pq_queue);
+	     pql != NULL && pthread == NULL; pql = pqlnext) {
+		if ((pthread = TAILQ_FIRST(&pql->pl_head)) == NULL) {
+			/*
+			 * The priority list is empty; remove the list
+			 * from the queue.
+			 */
+			pqlnext = TAILQ_NEXT(pql, pl_link);
+			TAILQ_REMOVE(&pq->pq_queue, pql, pl_link);
+
+			/* Mark the list as not being in the queue: */
+			pql->pl_queued = 0;
+		} else {
+			/*
+			 * note there may be a suspension event during this
+			 * test, If TMDF_SUSPEND is set after we tested it,
+			 * we will run the thread, this seems be a problem,
+			 * fortunatly, when we are being debugged, all context
+			 * switch will be done by kse_switchin, that is a
+			 * syscall, kse_switchin will check the flag again,
+			 * the thread will be returned via upcall, so next
+			 * time, UTS won't run the thread.
+			 */ 
+			while (pthread != NULL && !DBG_CAN_RUN(pthread)) {
+				pthread = TAILQ_NEXT(pthread, pqe);
+			}
+			if (pthread == NULL)
+				pqlnext = TAILQ_NEXT(pql, pl_link);
+		}
+	}
+
+	PQ_CLEAR_ACTIVE(pq);
+	return (pthread);
+}
+
+static void
+pq_insert_prio_list(pq_queue_t *pq, int prio)
+{
+	pq_list_t *pql;
+
+	/*
+	 * Make some assertions when debugging is enabled:
+	 */
+	PQ_ASSERT_ACTIVE(pq, "pq_insert_prio_list: pq_active");
+
+	/*
+	 * The priority queue is in descending priority order.  Start at
+	 * the beginning of the queue and find the list before which the
+	 * new list should be inserted.
+	 */
+	pql = TAILQ_FIRST(&pq->pq_queue);
+	while ((pql != NULL) && (pql->pl_prio > prio))
+		pql = TAILQ_NEXT(pql, pl_link);
+
+	/* Insert the list: */
+	if (pql == NULL)
+		TAILQ_INSERT_TAIL(&pq->pq_queue, &pq->pq_lists[prio], pl_link);
+	else
+		TAILQ_INSERT_BEFORE(pql, &pq->pq_lists[prio], pl_link);
+
+	/* Mark this list as being in the queue: */
+	pq->pq_lists[prio].pl_queued = 1;
+}
--- /dev/null
+++ lib/libkse/thread/thr_mutex_prioceiling.c
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 1998 Daniel Eischen <eischen at 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/libkse/thread/thr_mutex_prioceiling.c,v 1.10 2007/10/09 13:42:28 obrien Exp $
+ */
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_mutexattr_getprioceiling);
+LT10_COMPAT_DEFAULT(pthread_mutexattr_getprioceiling);
+LT10_COMPAT_PRIVATE(_pthread_mutexattr_setprioceiling);
+LT10_COMPAT_DEFAULT(pthread_mutexattr_setprioceiling);
+LT10_COMPAT_PRIVATE(_pthread_mutex_getprioceiling);
+LT10_COMPAT_DEFAULT(pthread_mutex_getprioceiling);
+LT10_COMPAT_PRIVATE(_pthread_mutex_setprioceiling);
+LT10_COMPAT_DEFAULT(pthread_mutex_setprioceiling);
+
+__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);
+}
--- /dev/null
+++ lib/libkse/thread/thr_attr_setscope.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 1998 Daniel Eischen <eischen at 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/libkse/thread/thr_attr_setscope.c,v 1.12 2007/10/09 13:42:27 obrien Exp $
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_attr_setscope);
+LT10_COMPAT_DEFAULT(pthread_attr_setscope);
+
+__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);
+}
--- /dev/null
+++ lib/libkse/thread/thr_info.c
@@ -0,0 +1,244 @@
+/*
+ * Copyright (c) 1995-1998 John Birrell <jb at 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. Neither the name of the author nor the names of any 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/libkse/thread/thr_info.c,v 1.31 2007/10/09 13:42:28 obrien 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
+
+LT10_COMPAT_PRIVATE(_pthread_set_name_np);
+LT10_COMPAT_DEFAULT(pthread_set_name_np);
+
+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_LOCKWAIT    , "Waiting on an internal lock"},
+	{PS_MUTEX_WAIT	, "Waiting on a mutex"},
+	{PS_COND_WAIT	, "Waiting on a condition variable"},
+	{PS_SLEEP_WAIT	, "Sleeping"},
+	{PS_SIGSUSPEND	, "Suspended, waiting for a signal"},
+	{PS_SIGWAIT	, "Waiting for a signal"},
+	{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, blocked %s, state %s [%s:%d]\n",
+	    pthread, (pthread->name == NULL) ? "" : pthread->name,
+	    pthread->attr.flags & PTHREAD_SCOPE_SYSTEM ? "system" : "process",
+	    pthread->active_priority, (pthread->blocked != 0) ? "yes" : "no",
+	    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) {
+		case PS_SIGWAIT:
+			snprintf(s, sizeof(s), "sigmask (hi) ");
+			__sys_write(fd, s, strlen(s));
+			for (i = _SIG_WORDS - 1; i >= 0; i--) {
+				snprintf(s, sizeof(s), "%08x ",
+				    pthread->sigmask.__bits[i]);
+				__sys_write(fd, s, strlen(s));
+			}
+			snprintf(s, sizeof(s), "(lo)\n");
+			__sys_write(fd, s, strlen(s));
+
+			snprintf(s, sizeof(s), "waitset (hi) ");
+			__sys_write(fd, s, strlen(s));
+			for (i = _SIG_WORDS - 1; i >= 0; i--) {
+				snprintf(s, sizeof(s), "%08x ",
+				    pthread->data.sigwait->waitset->__bits[i]);
+				__sys_write(fd, s, strlen(s));
+			}
+			snprintf(s, sizeof(s), "(lo)\n");
+			__sys_write(fd, s, strlen(s));
+			break;
+		/*
+		 * Trap other states that are not explicitly
+		 * coded to dump information:
+		 */
+		default:
+			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)
+{
+	struct pthread *curthread = _get_curthread();
+	char *new_name;
+	char *prev_name;
+	int ret;
+
+	new_name = strdup(name);
+	/* Add a reference to the target thread. */
+	if (_thr_ref_add(curthread, thread, 0) != 0) {
+		free(new_name);
+		ret = ESRCH;
+	}
+	else {
+		THR_THREAD_LOCK(curthread, thread);
+		prev_name = thread->name;
+		thread->name = new_name;
+		THR_THREAD_UNLOCK(curthread, thread);
+		_thr_ref_delete(curthread, thread);
+		if (prev_name != NULL) {
+			/* Free space for previous name. */
+			free(prev_name);
+		}
+		ret = 0;
+	}
+#if 0
+	/* XXX - Should return error code. */
+	return (ret);
+#endif
+}
--- /dev/null
+++ lib/libkse/thread/thr_multi_np.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 1996 John Birrell <jb at 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. Neither the name of the author nor the names of any 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/libkse/thread/thr_multi_np.c,v 1.10 2007/10/09 13:42:28 obrien Exp $
+ */
+#include <pthread.h>
+#include <pthread_np.h>
+
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_multi_np);
+LT10_COMPAT_DEFAULT(pthread_multi_np);
+
+__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);
+}
--- /dev/null
+++ lib/libkse/thread/thr_sigaltstack.c
@@ -0,0 +1,110 @@
+/*-
+ * Copyright (c) 2003 David Xu <davidxu at 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/lib/libkse/thread/thr_sigaltstack.c,v 1.4 2007/10/09 13:42:29 obrien Exp $");
+
+#include <errno.h>
+#include <signal.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_sigaltstack);
+LT10_COMPAT_DEFAULT(sigaltstack);
+
+__weak_reference(_sigaltstack, sigaltstack);
+
+int
+_sigaltstack(stack_t *_ss, stack_t *_oss)
+{
+	struct pthread *curthread = _get_curthread();
+	stack_t ss, oss;
+	int oonstack, errsave, ret;
+	kse_critical_t crit;
+
+	if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM) {
+		crit = _kse_critical_enter();
+		ret = __sys_sigaltstack(_ss, _oss);
+		errsave = errno;
+		/* Get a copy */
+		if (ret == 0 && _ss != NULL)
+			curthread->sigstk = *_ss;
+		_kse_critical_leave(crit);
+		errno = errsave;
+		return (ret);
+	}
+
+	if (_ss)
+		ss = *_ss;
+	if (_oss)
+		oss = *_oss;
+
+	/* Should get and set stack in atomic way */
+	crit = _kse_critical_enter();
+	oonstack = _thr_sigonstack(&ss);
+	if (_oss != NULL) {
+		oss = curthread->sigstk;
+		oss.ss_flags = (curthread->sigstk.ss_flags & SS_DISABLE)
+		    ? SS_DISABLE : ((oonstack) ? SS_ONSTACK : 0);
+	}
+
+	if (_ss != NULL) {
+		if (oonstack) {
+			_kse_critical_leave(crit);
+			errno = EPERM;
+			return (-1);
+		}
+		if ((ss.ss_flags & ~SS_DISABLE) != 0) {
+			_kse_critical_leave(crit);
+			errno = EINVAL;
+			return (-1);
+		}
+		if (!(ss.ss_flags & SS_DISABLE)) {
+			if (ss.ss_size < MINSIGSTKSZ) {
+				_kse_critical_leave(crit);
+				errno = ENOMEM;
+				return (-1);
+			}
+			curthread->sigstk = ss;
+		} else {
+			curthread->sigstk.ss_flags |= SS_DISABLE;
+		}
+	}
+	_kse_critical_leave(crit);
+	if (_oss != NULL)
+		*_oss = oss;
+	return (0);
+}
+
+int
+_thr_sigonstack(void *sp)
+{
+	struct pthread *curthread = _get_curthread();
+
+	return ((curthread->sigstk.ss_flags & SS_DISABLE) == 0 ?
+	    (((size_t)sp - (size_t)curthread->sigstk.ss_sp) < curthread->sigstk.ss_size)
+	    : 0);
+}
+
--- /dev/null
+++ lib/libkse/thread/thr_attr_destroy.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 1996 John Birrell <jb at 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. Neither the name of the author nor the names of any 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/libkse/thread/thr_attr_destroy.c,v 1.10 2007/10/09 13:42:27 obrien Exp $
+ */
+#include <stdlib.h>
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_attr_destroy);
+LT10_COMPAT_DEFAULT(pthread_attr_destroy);
+
+__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);
+}
--- /dev/null
+++ lib/libkse/thread/thr_pselect.c
@@ -0,0 +1,60 @@
+/*-
+ * Copyright (c) 2002 Daniel M. Eischen <deischen at 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.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/lib/libkse/thread/thr_pselect.c,v 1.7 2007/10/09 13:42:29 obrien Exp $");
+
+#include <sys/select.h>
+#include <sys/time.h>
+
+#include <errno.h>
+#include <signal.h>
+#include <pthread.h>
+
+#include "thr_private.h"
+
+extern int __pselect(int count, fd_set *rfds, fd_set *wfds, fd_set *efds, 
+		const struct timespec *timo, const sigset_t *mask);
+
+LT10_COMPAT_PRIVATE(_pselect);
+LT10_COMPAT_DEFAULT(pselect);
+
+__weak_reference(_pselect, pselect);
+
+int 
+_pselect(int count, fd_set *rfds, fd_set *wfds, fd_set *efds, 
+	const struct timespec *timo, const sigset_t *mask)
+{
+	struct pthread *curthread = _get_curthread();
+	int ret;
+
+	_thr_cancel_enter(curthread);
+	ret = __pselect(count, rfds, wfds, efds, timo, mask);
+	_thr_cancel_leave(curthread, 1);
+
+	return (ret);
+}
--- /dev/null
+++ lib/libkse/thread/thr_switch_np.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 1998 Daniel Eischen <eischen at 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/libkse/thread/thr_switch_np.c,v 1.9 2007/10/09 13:42:29 obrien Exp $
+ */
+#include <errno.h>
+#include <pthread.h>
+#include <pthread_np.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_switch_add_np);
+LT10_COMPAT_DEFAULT(pthread_switch_add_np);
+LT10_COMPAT_PRIVATE(_pthread_switch_delete_np);
+LT10_COMPAT_DEFAULT(pthread_switch_delete_np);
+
+__weak_reference(_pthread_switch_add_np, pthread_switch_add_np);
+__weak_reference(_pthread_switch_delete_np, pthread_switch_delete_np);
+
+int
+_pthread_switch_add_np(pthread_switch_routine_t routine)
+{
+	return (ENOTSUP);
+}
+
+int
+_pthread_switch_delete_np(pthread_switch_routine_t routine)
+{
+	return (ENOTSUP);
+}
--- /dev/null
+++ lib/libkse/thread/thr_kill.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 1997 John Birrell <jb at 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. Neither the name of the author nor the names of any 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/libkse/thread/thr_kill.c,v 1.19 2007/10/09 13:42:28 obrien Exp $
+ */
+#include <errno.h>
+#include <signal.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_kill);
+LT10_COMPAT_DEFAULT(pthread_kill);
+
+__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) &&
+		    (_thread_sigact[sig - 1].sa_handler != SIG_IGN))
+			_thr_sig_send(pthread, sig);
+		_thr_ref_delete(curthread, pthread);
+	}
+
+	/* Return the completion status: */
+	return (ret);
+}
--- /dev/null
+++ lib/libkse/thread/thr_open.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 1995-1998 John Birrell <jb at 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. Neither the name of the author nor the names of any 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/libkse/thread/thr_open.c,v 1.19 2007/10/09 13:42:28 obrien Exp $
+ *
+ */
+#include <stdarg.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(__open);
+LT10_COMPAT_DEFAULT(open);
+
+__weak_reference(__open, open);
+
+int
+__open(const char *path, int flags,...)
+{
+	struct pthread *curthread = _get_curthread();
+	int	ret;
+	int	mode = 0;
+	va_list	ap;
+
+	_thr_cancel_enter(curthread);
+	
+	/* Check if the file is being created: */
+	if (flags & O_CREAT) {
+		/* Get the creation mode: */
+		va_start(ap, flags);
+		mode = va_arg(ap, int);
+		va_end(ap);
+	}
+	
+	ret = __sys_open(path, flags, mode);
+	/*
+	 * To avoid possible file handle leak, 
+	 * only check cancellation point if it is failure
+	 */
+	_thr_cancel_leave(curthread, (ret == -1));
+
+	return ret;
+}
--- /dev/null
+++ lib/libkse/thread/thr_attr_setstacksize.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 1996 John Birrell <jb at 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. Neither the name of the author nor the names of any 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/libkse/thread/thr_attr_setstacksize.c,v 1.11 2007/10/09 13:42:27 obrien Exp $
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_attr_setstacksize);
+LT10_COMPAT_DEFAULT(pthread_attr_setstacksize);
+
+__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);
+}
--- /dev/null
+++ lib/libkse/thread/thr_pause.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2000 Jason Evans <jasone at 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/libkse/thread/thr_pause.c,v 1.10 2007/10/09 13:42:28 obrien Exp $
+ */
+
+#include <unistd.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+extern int __pause(void);
+
+LT10_COMPAT_PRIVATE(_pause);
+LT10_COMPAT_DEFAULT(pause);
+
+__weak_reference(_pause, pause);
+
+int
+_pause(void)
+{
+	struct pthread *curthread = _get_curthread();
+	int	ret;
+
+	_thr_cancel_enter(curthread);
+	ret = __pause();
+	_thr_cancel_leave(curthread, 1);
+	
+	return ret;
+}
--- /dev/null
+++ lib/libkse/thread/thr_attr_getstack.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2003 Craig Rodrigues <rodrigc at 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.
+ *
+ * $FreeBSD: src/lib/libkse/thread/thr_attr_getstack.c,v 1.3 2007/10/09 13:42:27 obrien Exp $
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_attr_getstack);
+LT10_COMPAT_DEFAULT(pthread_attr_getstack);
+
+__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);
+}
+
--- /dev/null
+++ lib/libkse/thread/thr_condattr_init.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 1997 John Birrell <jb at 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. Neither the name of the author nor the names of any 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/libkse/thread/thr_condattr_init.c,v 1.11 2007/10/09 13:42:27 obrien Exp $
+ */
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_condattr_init);
+LT10_COMPAT_DEFAULT(pthread_condattr_init);
+
+__weak_reference(_pthread_condattr_init, pthread_condattr_init);
+
+int
+_pthread_condattr_init(pthread_condattr_t *attr)
+{
+	int ret;
+	pthread_condattr_t pattr;
+
+	if ((pattr = (pthread_condattr_t)
+	    malloc(sizeof(struct pthread_cond_attr))) == NULL) {
+		ret = ENOMEM;
+	} else {
+		memcpy(pattr, &_pthread_condattr_default,
+		    sizeof(struct pthread_cond_attr));
+		*attr = pattr;
+		ret = 0;
+	}
+	return (ret);
+}
--- /dev/null
+++ lib/libkse/thread/thr_sigmask.c
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 1997 John Birrell <jb at 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. Neither the name of the author nor the names of any 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/libkse/thread/thr_sigmask.c,v 1.22 2007/10/09 13:42:29 obrien Exp $
+ */
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/signalvar.h>
+#include <errno.h>
+#include <signal.h>
+#include <string.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_sigmask);
+LT10_COMPAT_DEFAULT(pthread_sigmask);
+
+__weak_reference(_pthread_sigmask, pthread_sigmask);
+
+int
+_pthread_sigmask(int how, const sigset_t *set, sigset_t *oset)
+{
+	struct pthread *curthread = _get_curthread();
+	sigset_t oldset, newset;
+	int ret;
+
+	if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM) {
+		ret = __sys_sigprocmask(how, set, oset);
+		if (ret != 0)
+			ret = errno;
+		/* Get a fresh copy */
+		__sys_sigprocmask(SIG_SETMASK, NULL, &curthread->sigmask);
+		return (ret);
+	}
+
+	if (set)
+		newset = *set;
+
+	THR_SCHED_LOCK(curthread, curthread);
+
+	ret = 0;
+	if (oset != NULL)
+		/* Return the current mask: */
+		oldset = curthread->sigmask;
+
+	/* Check if a new signal set was provided by the caller: */
+	if (set != NULL) {
+		/* Process according to what to do: */
+		switch (how) {
+		/* Block signals: */
+		case SIG_BLOCK:
+			/* Add signals to the existing mask: */
+			SIGSETOR(curthread->sigmask, newset);
+			break;
+
+		/* Unblock signals: */
+		case SIG_UNBLOCK:
+			/* Clear signals from the existing mask: */
+			SIGSETNAND(curthread->sigmask, newset);
+			break;
+
+		/* Set the signal process mask: */
+		case SIG_SETMASK:
+			/* Set the new mask: */
+			curthread->sigmask = newset;
+			break;
+
+		/* Trap invalid actions: */
+		default:
+			/* Return an invalid argument: */
+			ret = EINVAL;
+			break;
+		}
+		SIG_CANTMASK(curthread->sigmask);
+		THR_SCHED_UNLOCK(curthread, curthread);
+
+		/*
+		 * Run down any pending signals:
+		 */
+		if (ret == 0)
+		    _thr_sig_check_pending(curthread);
+	} else
+		THR_SCHED_UNLOCK(curthread, curthread);
+
+	if (ret == 0 && oset != NULL)
+		*oset = oldset;
+	return (ret);
+}
--- /dev/null
+++ lib/libkse/thread/thr_self.c
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 1995 John Birrell <jb at 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. Neither the name of the author nor the names of any 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/libkse/thread/thr_self.c,v 1.10 2007/10/09 13:42:29 obrien Exp $
+ */
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_self);
+LT10_COMPAT_DEFAULT(pthread_self);
+
+__weak_reference(_pthread_self, pthread_self);
+
+pthread_t
+_pthread_self(void)
+{
+	if (_thr_initial == NULL)
+		_libpthread_init(NULL);
+
+	/* Return the running thread pointer: */
+	return (_get_curthread());
+}
--- /dev/null
+++ lib/libkse/thread/thr_readv.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 1995-1998 John Birrell <jb at 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. Neither the name of the author nor the names of any 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/libkse/thread/thr_readv.c,v 1.22 2007/10/09 13:42:29 obrien Exp $
+ *
+ */
+#include <sys/types.h>
+#include <sys/fcntl.h>
+#include <sys/uio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(__readv);
+LT10_COMPAT_DEFAULT(readv);
+
+__weak_reference(__readv, readv);
+
+ssize_t
+__readv(int fd, const struct iovec *iov, int iovcnt)
+{
+	struct pthread *curthread = _get_curthread();
+	ssize_t ret;
+
+	_thr_cancel_enter(curthread);
+	ret = __sys_readv(fd, iov, iovcnt);
+	_thr_cancel_leave(curthread, 1);
+
+	return ret;
+}
--- /dev/null
+++ lib/libkse/thread/thr_mattr_init.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 1996 Jeffrey Hsu <hsu at freebsd.org>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by John Birrell.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/lib/libkse/thread/thr_mattr_init.c,v 1.11 2007/10/09 13:42:28 obrien Exp $
+ */
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_mutexattr_init);
+LT10_COMPAT_DEFAULT(pthread_mutexattr_init);
+
+__weak_reference(_pthread_mutexattr_init, pthread_mutexattr_init);
+
+int
+_pthread_mutexattr_init(pthread_mutexattr_t *attr)
+{
+	int ret;
+	pthread_mutexattr_t pattr;
+
+	if ((pattr = (pthread_mutexattr_t)
+	    malloc(sizeof(struct pthread_mutex_attr))) == NULL) {
+		ret = ENOMEM;
+	} else {
+		memcpy(pattr, &_pthread_mutexattr_default,
+		    sizeof(struct pthread_mutex_attr));
+		*attr = pattr;
+		ret = 0;
+	}
+	return (ret);
+}
--- /dev/null
+++ lib/libkse/thread/thr_attr_setstack.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2003 Craig Rodrigues <rodrigc at 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.
+ *
+ * $FreeBSD: src/lib/libkse/thread/thr_attr_setstack.c,v 1.3 2007/10/09 13:42:27 obrien Exp $
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_attr_setstack);
+LT10_COMPAT_DEFAULT(pthread_attr_setstack);
+
+__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);
+}
+
--- /dev/null
+++ lib/libkse/thread/thr_close.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 1995-1998 John Birrell <jb at 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. Neither the name of the author nor the names of any 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/libkse/thread/thr_close.c,v 1.20 2007/10/09 13:42:27 obrien Exp $
+ */
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(__close);
+LT10_COMPAT_DEFAULT(close);
+
+__weak_reference(__close, close);
+
+int
+__close(int fd)
+{
+	struct pthread	*curthread = _get_curthread();
+	int	ret;
+
+	_thr_cancel_enter(curthread);
+	ret = __sys_close(fd);
+	_thr_cancel_leave(curthread, 1);
+	
+	return (ret);
+}
--- /dev/null
+++ lib/libkse/thread/thr_sigsuspend.c
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 1995 John Birrell <jb at 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. Neither the name of the author nor the names of any 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/libkse/thread/thr_sigsuspend.c,v 1.30 2007/10/09 13:42:29 obrien Exp $
+ */
+
+#include <sys/types.h>
+#include <sys/signalvar.h>
+#include <errno.h>
+#include <pthread.h>
+#include <signal.h>
+#include <string.h>
+
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(__sigsuspend);
+LT10_COMPAT_PRIVATE(_sigsuspend);
+LT10_COMPAT_DEFAULT(sigsuspend);
+
+__weak_reference(__sigsuspend, sigsuspend);
+
+int
+_sigsuspend(const sigset_t *set)
+{
+	struct pthread	*curthread = _get_curthread();
+	sigset_t	oldmask, newmask, tempset;
+	int             ret = -1;
+
+	if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM)
+		return (__sys_sigsuspend(set));
+
+	/* Check if a new signal set was provided by the caller: */
+	if (set != NULL) {
+		newmask = *set;
+		SIG_CANTMASK(newmask);
+		THR_LOCK_SWITCH(curthread);
+
+		/* Save current sigmask: */
+		oldmask = curthread->sigmask;
+		curthread->oldsigmask = &oldmask;
+
+		/* Change the caller's mask: */
+		curthread->sigmask = newmask;
+		tempset = curthread->sigpend;
+		SIGSETNAND(tempset, newmask);
+		if (SIGISEMPTY(tempset)) {
+			THR_SET_STATE(curthread, PS_SIGSUSPEND);
+			/* Wait for a signal: */
+			_thr_sched_switch_unlocked(curthread);
+		} else {
+			curthread->check_pending = 1;
+			THR_UNLOCK_SWITCH(curthread);
+			/* check pending signal I can handle: */
+			_thr_sig_check_pending(curthread);
+		}
+		if ((curthread->cancelflags & THR_CANCELLING) != 0)
+			curthread->oldsigmask = NULL;
+		else {
+			THR_ASSERT(curthread->oldsigmask == NULL,
+		 	          "oldsigmask is not cleared");
+		}
+
+		/* Always return an interrupted error: */
+		errno = EINTR;
+	} else {
+		/* Return an invalid argument error: */
+		errno = EINVAL;
+	}
+
+	/* Return the completion status: */
+	return (ret);
+}
+
+int
+__sigsuspend(const sigset_t * set)
+{
+	struct pthread *curthread = _get_curthread();
+	int		ret;
+
+	_thr_cancel_enter(curthread);
+	ret = _sigsuspend(set);
+	_thr_cancel_leave(curthread, 1);
+
+	return (ret);
+}
--- /dev/null
+++ lib/libkse/thread/thr_wait4.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 1995-1998 John Birrell <jb at 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. Neither the name of the author nor the names of any 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/libkse/thread/thr_wait4.c,v 1.22 2007/10/09 13:42:30 obrien Exp $
+ */
+#include <sys/types.h>
+
+#include "namespace.h"
+#include <errno.h>
+#include <sys/wait.h>
+#include <pthread.h>
+#include "un-namespace.h"
+
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(__wait4);
+LT10_COMPAT_DEFAULT(wait4);
+
+__weak_reference(__wait4, wait4);
+
+pid_t
+__wait4(pid_t pid, int *istat, int options, struct rusage *rusage)
+{
+	struct pthread *curthread = _get_curthread();
+	pid_t ret;
+
+	_thr_cancel_enter(curthread);
+	ret = _wait4(pid, istat, options, rusage);
+	_thr_cancel_leave(curthread, 1);
+
+	return ret;
+}
--- /dev/null
+++ lib/libkse/thread/thr_attr_getschedpolicy.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 1998 Daniel Eischen <eischen at 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/libkse/thread/thr_attr_getschedpolicy.c,v 1.9 2007/10/09 13:42:27 obrien Exp $
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_attr_getschedpolicy);
+LT10_COMPAT_DEFAULT(pthread_attr_getschedpolicy);
+
+__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);
+}
--- /dev/null
+++ lib/libkse/thread/thr_stack.c
@@ -0,0 +1,258 @@
+/*
+ * Copyright (c) 2001 Daniel Eischen <deischen at freebsd.org>
+ * Copyright (c) 2000-2001 Jason Evans <jasone at freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/lib/libkse/thread/thr_stack.c,v 1.11 2007/10/09 13:42:29 obrien Exp $
+ */
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/queue.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+/* Spare thread stack. */
+struct stack {
+	LIST_ENTRY(stack)	qe;		/* Stack queue linkage. */
+	size_t			stacksize;	/* Stack size (rounded up). */
+	size_t			guardsize;	/* Guard size. */
+	void			*stackaddr;	/* Stack address. */
+};
+
+/*
+ * Default sized (stack and guard) spare stack queue.  Stacks are cached
+ * to avoid additional complexity managing mmap()ed stack regions.  Spare
+ * stacks are used in LIFO order to increase cache locality.
+ */
+static LIST_HEAD(, stack)	dstackq = LIST_HEAD_INITIALIZER(dstackq);
+
+/*
+ * Miscellaneous sized (non-default stack and/or guard) spare stack queue.
+ * Stacks are cached to avoid additional complexity managing mmap()ed
+ * stack regions.  This list is unordered, since ordering on both stack
+ * size and guard size would be more trouble than it's worth.  Stacks are
+ * allocated from this cache on a first size match basis.
+ */
+static LIST_HEAD(, stack)	mstackq = LIST_HEAD_INITIALIZER(mstackq);
+
+/**
+ * Base address of the last stack allocated (including its red zone, if
+ * there is one).  Stacks are allocated contiguously, starting beyond the
+ * top of the main stack.  When a new stack is created, a red zone is
+ * typically created (actually, the red zone is mapped with PROT_NONE) above
+ * the top of the stack, such that the stack will not be able to grow all
+ * the way to the bottom of the next stack.  This isn't fool-proof.  It is
+ * possible for a stack to grow by a large amount, such that it grows into
+ * the next stack, and as long as the memory within the red zone is never
+ * accessed, nothing will prevent one thread stack from trouncing all over
+ * the next.
+ *
+ * low memory
+ *     . . . . . . . . . . . . . . . . . . 
+ *    |                                   |
+ *    |             stack 3               | start of 3rd thread stack
+ *    +-----------------------------------+
+ *    |                                   |
+ *    |       Red Zone (guard page)       | red zone for 2nd thread
+ *    |                                   |
+ *    +-----------------------------------+
+ *    |  stack 2 - PTHREAD_STACK_DEFAULT  | top of 2nd thread stack
+ *    |                                   |
+ *    |                                   |
+ *    |                                   |
+ *    |                                   |
+ *    |             stack 2               |
+ *    +-----------------------------------+ <-- start of 2nd thread stack
+ *    |                                   |
+ *    |       Red Zone                    | red zone for 1st thread
+ *    |                                   |
+ *    +-----------------------------------+
+ *    |  stack 1 - PTHREAD_STACK_DEFAULT  | top of 1st thread stack
+ *    |                                   |
+ *    |                                   |
+ *    |                                   |
+ *    |                                   |
+ *    |             stack 1               |
+ *    +-----------------------------------+ <-- start of 1st thread stack
+ *    |                                   |   (initial value of last_stack)
+ *    |       Red Zone                    |
+ *    |                                   | red zone for main thread
+ *    +-----------------------------------+
+ *    | USRSTACK - PTHREAD_STACK_INITIAL  | top of main thread stack
+ *    |                                   | ^
+ *    |                                   | |
+ *    |                                   | |
+ *    |                                   | | stack growth
+ *    |                                   |
+ *    +-----------------------------------+ <-- start of main thread stack
+ *                                              (USRSTACK)
+ * high memory
+ *
+ */
+static void *last_stack = NULL;
+
+/*
+ * Round size up to the nearest multiple of
+ * _thr_page_size.
+ */
+static inline size_t
+round_up(size_t size)
+{
+	if (size % _thr_page_size != 0)
+		size = ((size / _thr_page_size) + 1) *
+		    _thr_page_size;
+	return size;
+}
+
+int
+_thr_stack_alloc(struct pthread_attr *attr)
+{
+	struct stack *spare_stack;
+	struct kse *curkse;
+	kse_critical_t crit;
+	size_t stacksize;
+	size_t guardsize;
+	char *stackaddr;
+
+	/*
+	 * Round up stack size to nearest multiple of _thr_page_size so
+	 * that mmap() * will work.  If the stack size is not an even
+	 * multiple, we end up initializing things such that there is
+	 * unused space above the beginning of the stack, so the stack
+	 * sits snugly against its guard.
+	 */
+	stacksize = round_up(attr->stacksize_attr);
+	guardsize = round_up(attr->guardsize_attr);
+
+	attr->stackaddr_attr = NULL;
+	attr->flags &= ~THR_STACK_USER;
+
+	/*
+	 * Use the garbage collector lock for synchronization of the
+	 * spare stack lists and allocations from usrstack.
+	 */
+	crit = _kse_critical_enter();
+	curkse = _get_curkse();
+	KSE_LOCK_ACQUIRE(curkse, &_thread_list_lock);
+	/*
+	 * If the stack and guard sizes are default, try to allocate a stack
+	 * from the default-size stack cache:
+	 */
+	if ((stacksize == _thr_stack_default) &&
+	    (guardsize == _thr_guard_default)) {
+		if ((spare_stack = LIST_FIRST(&dstackq)) != NULL) {
+			/* Use the spare stack. */
+			LIST_REMOVE(spare_stack, qe);
+			attr->stackaddr_attr = spare_stack->stackaddr;
+		}
+	}
+	/*
+	 * The user specified a non-default stack and/or guard size, so try to
+	 * allocate a stack from the non-default size stack cache, using the
+	 * rounded up stack size (stack_size) in the search:
+	 */
+	else {
+		LIST_FOREACH(spare_stack, &mstackq, qe) {
+			if (spare_stack->stacksize == stacksize &&
+			    spare_stack->guardsize == guardsize) {
+				LIST_REMOVE(spare_stack, qe);
+				attr->stackaddr_attr = spare_stack->stackaddr;
+				break;
+			}
+		}
+	}
+	if (attr->stackaddr_attr != NULL) {
+		/* A cached stack was found.  Release the lock. */
+		KSE_LOCK_RELEASE(curkse, &_thread_list_lock);
+		_kse_critical_leave(crit);
+	}
+	else {
+		/* Allocate a stack from usrstack. */
+		if (last_stack == NULL)
+			last_stack = _usrstack - _thr_stack_initial -
+			    _thr_guard_default;
+
+		/* Allocate a new stack. */
+		stackaddr = last_stack - stacksize - guardsize;
+
+		/*
+		 * Even if stack allocation fails, we don't want to try to
+		 * use this location again, so unconditionally decrement
+		 * last_stack.  Under normal operating conditions, the most
+		 * likely reason for an mmap() error is a stack overflow of
+		 * the adjacent thread stack.
+		 */
+		last_stack -= (stacksize + guardsize);
+
+		/* Release the lock before mmap'ing it. */
+		KSE_LOCK_RELEASE(curkse, &_thread_list_lock);
+		_kse_critical_leave(crit);
+
+		/* Map the stack and guard page together, and split guard
+		   page from allocated space: */
+		if ((stackaddr = mmap(stackaddr, stacksize+guardsize,
+		     PROT_READ | PROT_WRITE, MAP_STACK,
+		     -1, 0)) != MAP_FAILED &&
+		    (guardsize == 0 ||
+		     mprotect(stackaddr, guardsize, PROT_NONE) == 0)) {
+			stackaddr += guardsize;
+		} else {
+			if (stackaddr != MAP_FAILED)
+				munmap(stackaddr, stacksize + guardsize);
+			stackaddr = NULL;
+		}
+		attr->stackaddr_attr = stackaddr;
+	}
+	if (attr->stackaddr_attr != NULL)
+		return (0);
+	else
+		return (-1);
+}
+
+/* This function must be called with _thread_list_lock held. */
+void
+_thr_stack_free(struct pthread_attr *attr)
+{
+	struct stack *spare_stack;
+
+	if ((attr != NULL) && ((attr->flags & THR_STACK_USER) == 0)
+	    && (attr->stackaddr_attr != NULL)) {
+		spare_stack = (attr->stackaddr_attr + attr->stacksize_attr
+		    - sizeof(struct stack));
+		spare_stack->stacksize = round_up(attr->stacksize_attr);
+		spare_stack->guardsize = round_up(attr->guardsize_attr);
+		spare_stack->stackaddr = attr->stackaddr_attr;
+
+		if (spare_stack->stacksize == _thr_stack_default &&
+		    spare_stack->guardsize == _thr_guard_default) {
+			/* Default stack/guard size. */
+			LIST_INSERT_HEAD(&dstackq, spare_stack, qe);
+		} else {
+			/* Non-default stack/guard size. */
+			LIST_INSERT_HEAD(&mstackq, spare_stack, qe);
+		}
+		attr->stackaddr_attr = NULL;
+	}
+}
--- /dev/null
+++ lib/libkse/thread/thr_attr_getstacksize.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 1997 John Birrell <jb at 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. Neither the name of the author nor the names of any 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/libkse/thread/thr_attr_getstacksize.c,v 1.10 2007/10/09 13:42:27 obrien Exp $
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_attr_getstacksize);
+LT10_COMPAT_DEFAULT(pthread_attr_getstacksize);
+
+__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);
+}
--- /dev/null
+++ lib/libkse/thread/thr_aio_suspend.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2000 Jason Evans <jasone at 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/libkse/thread/thr_aio_suspend.c,v 1.10 2007/10/09 13:42:27 obrien Exp $
+ */
+
+#include <aio.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_aio_suspend);
+LT10_COMPAT_DEFAULT(aio_suspend);
+
+__weak_reference(_aio_suspend, aio_suspend);
+
+int
+_aio_suspend(const struct aiocb * const iocbs[], int niocb, const struct
+    timespec *timeout)
+{
+	struct pthread *curthread = _get_curthread();
+	int ret;
+
+	_thr_cancel_enter(curthread);
+	ret = __sys_aio_suspend(iocbs, niocb, timeout);
+	_thr_cancel_leave(curthread, 1);
+
+	return (ret);
+}
+
--- /dev/null
+++ lib/libkse/thread/thr_suspend_np.c
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 1995-1998 John Birrell <jb at 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. Neither the name of the author nor the names of any 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/libkse/thread/thr_suspend_np.c,v 1.22 2007/10/09 13:42:29 obrien Exp $
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+static void suspend_common(struct pthread *thread);
+
+LT10_COMPAT_PRIVATE(_pthread_suspend_np);
+LT10_COMPAT_DEFAULT(pthread_suspend_np);
+LT10_COMPAT_PRIVATE(_pthread_suspend_all_np);
+LT10_COMPAT_DEFAULT(pthread_suspend_all_np);
+
+__weak_reference(_pthread_suspend_np, pthread_suspend_np);
+__weak_reference(_pthread_suspend_all_np, pthread_suspend_all_np);
+
+/* Suspend a thread: */
+int
+_pthread_suspend_np(pthread_t thread)
+{
+	struct pthread *curthread = _get_curthread();
+	int ret;
+
+	/* Suspending the current thread doesn't make sense. */
+	if (thread == _get_curthread())
+		ret = EDEADLK;
+
+	/* Add a reference to the thread: */
+	else if ((ret = _thr_ref_add(curthread, thread, /*include dead*/0))
+	    == 0) {
+		/* Lock the threads scheduling queue: */
+		THR_SCHED_LOCK(curthread, thread);
+		suspend_common(thread);
+		/* Unlock the threads scheduling queue: */
+		THR_SCHED_UNLOCK(curthread, thread);
+
+		/* Don't forget to remove the reference: */
+		_thr_ref_delete(curthread, thread);
+	}
+	return (ret);
+}
+
+void
+_pthread_suspend_all_np(void)
+{
+	struct pthread	*curthread = _get_curthread();
+	struct pthread	*thread;
+	kse_critical_t crit;
+
+	/* Take the thread list lock: */
+	crit = _kse_critical_enter();
+	KSE_LOCK_ACQUIRE(curthread->kse, &_thread_list_lock);
+
+	TAILQ_FOREACH(thread, &_thread_list, tle) {
+		if (thread != curthread) {
+			THR_SCHED_LOCK(curthread, thread);
+			suspend_common(thread);
+			THR_SCHED_UNLOCK(curthread, thread);
+		}
+	}
+
+	/* Release the thread list lock: */
+	KSE_LOCK_RELEASE(curthread->kse, &_thread_list_lock);
+	_kse_critical_leave(crit);
+}
+
+void
+suspend_common(struct pthread *thread)
+{
+	if ((thread->state != PS_DEAD) &&
+	    (thread->state != PS_DEADLOCK) &&
+	    ((thread->flags & THR_FLAGS_EXITING) == 0)) {
+		thread->flags |= THR_FLAGS_SUSPENDED;
+		if ((thread->flags & THR_FLAGS_IN_RUNQ) != 0) {
+			THR_RUNQ_REMOVE(thread);
+			THR_SET_STATE(thread, PS_SUSPENDED);
+		}
+#ifdef NOT_YET
+		if ((thread->attr.flags & PTHREAD_SCOPE_SYSTEM) != 0)
+			/* ??? */
+#endif
+	}
+}
--- /dev/null
+++ lib/libkse/thread/thr_sleep.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2000 Jason Evans <jasone at 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/libkse/thread/thr_sleep.c,v 1.11 2007/10/09 13:42:29 obrien Exp $
+ */
+
+#include <unistd.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+extern unsigned int	__sleep(unsigned int);
+extern int		__usleep(useconds_t);
+
+LT10_COMPAT_PRIVATE(_sleep);
+LT10_COMPAT_DEFAULT(sleep);
+LT10_COMPAT_PRIVATE(_usleep);
+LT10_COMPAT_DEFAULT(usleep);
+
+__weak_reference(_sleep, sleep);
+__weak_reference(_usleep, usleep);
+
+unsigned int
+_sleep(unsigned int seconds)
+{
+	struct pthread *curthread = _get_curthread();
+	unsigned int	ret;
+
+	_thr_cancel_enter(curthread);
+	ret = __sleep(seconds);
+	_thr_cancel_leave(curthread, 1);
+	
+	return (ret);
+}
+
+int
+_usleep(useconds_t useconds)
+{
+	struct pthread *curthread = _get_curthread();
+	unsigned int	ret;
+
+	_thr_cancel_enter(curthread);
+	ret = __usleep(useconds);
+	_thr_cancel_leave(curthread, 1);
+	
+	return (ret);
+}
--- /dev/null
+++ lib/libkse/thread/thr_accept.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2003 Daniel Eischen <deischen at 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/lib/libkse/thread/thr_accept.c,v 1.4 2007/10/09 13:42:27 obrien Exp $");
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(__accept);
+LT10_COMPAT_DEFAULT(accept);
+
+__weak_reference(__accept, accept);
+
+int
+__accept(int s, struct sockaddr *addr, socklen_t *addrlen)
+{
+	struct pthread *curthread;
+	int ret;
+
+	curthread = _get_curthread();
+	_thr_cancel_enter(curthread);
+	ret = __sys_accept(s, addr, addrlen);
+	_thr_cancel_leave(curthread, ret == -1);
+
+ 	return (ret);
+}
--- /dev/null
+++ lib/libkse/thread/thr_attr_setschedpolicy.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 1998 Daniel Eischen <eischen at 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/libkse/thread/thr_attr_setschedpolicy.c,v 1.9 2007/10/09 13:42:27 obrien Exp $
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_attr_setschedpolicy);
+LT10_COMPAT_DEFAULT(pthread_attr_setschedpolicy);
+
+__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);
+}
--- /dev/null
+++ lib/libkse/thread/thr_symbols.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2004 David Xu <davidxu at 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. Neither the name of the author nor the names of any 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/libkse/thread/thr_symbols.c,v 1.6 2007/10/09 13:42:29 obrien Exp $
+ */
+
+#include <sys/types.h>
+#include <stddef.h>
+#include <pthread.h>
+#include <rtld.h>
+
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_thread_off_tcb);
+LT10_COMPAT_PRIVATE(_thread_off_tmbx);
+LT10_COMPAT_PRIVATE(_thread_off_next);
+LT10_COMPAT_PRIVATE(_thread_off_attr_flags);
+LT10_COMPAT_PRIVATE(_thread_off_kse);
+LT10_COMPAT_PRIVATE(_thread_off_kse_locklevel);
+LT10_COMPAT_PRIVATE(_thread_off_thr_locklevel);
+LT10_COMPAT_PRIVATE(_thread_off_linkmap);
+LT10_COMPAT_PRIVATE(_thread_off_tlsindex);
+LT10_COMPAT_PRIVATE(_thread_size_key);
+LT10_COMPAT_PRIVATE(_thread_off_key_allocated);
+LT10_COMPAT_PRIVATE(_thread_off_key_destructor);
+LT10_COMPAT_PRIVATE(_thread_max_keys);
+LT10_COMPAT_PRIVATE(_thread_off_dtv);
+LT10_COMPAT_PRIVATE(_thread_off_state);
+LT10_COMPAT_PRIVATE(_thread_state_running);
+LT10_COMPAT_PRIVATE(_thread_state_zoombie);
+
+/* A collection of symbols needed by debugger */
+
+/* int _libkse_debug */
+int _thread_off_tcb = offsetof(struct pthread, tcb);
+int _thread_off_tmbx = offsetof(struct tcb, tcb_tmbx);
+int _thread_off_next = offsetof(struct pthread, tle.tqe_next);
+int _thread_off_attr_flags = offsetof(struct pthread, attr.flags);
+int _thread_off_kse = offsetof(struct pthread, kse);
+int _thread_off_kse_locklevel = offsetof(struct kse, k_locklevel);
+int _thread_off_thr_locklevel = offsetof(struct pthread, locklevel);
+int _thread_off_linkmap = offsetof(Obj_Entry, linkmap);
+int _thread_off_tlsindex = offsetof(Obj_Entry, tlsindex);
+int _thread_size_key = sizeof(struct pthread_key);
+int _thread_off_key_allocated = offsetof(struct pthread_key, allocated);
+int _thread_off_key_destructor = offsetof(struct pthread_key, destructor);
+int _thread_max_keys = PTHREAD_KEYS_MAX;
+int _thread_off_dtv = DTV_OFFSET;
+int _thread_off_state = offsetof(struct pthread, state);
+int _thread_state_running = PS_RUNNING;
+int _thread_state_zoombie = PS_DEAD;
+int _thread_off_sigmask = offsetof(struct pthread, sigmask);
+int _thread_off_sigpend = offsetof(struct pthread, sigpend);
--- /dev/null
+++ lib/libkse/thread/thr_sig.c
@@ -0,0 +1,1250 @@
+/*
+ * Copyright (c) 1995-1998 John Birrell <jb at 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. Neither the name of the author nor the names of any 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/libkse/thread/thr_sig.c,v 1.87 2007/10/09 13:42:29 obrien Exp $
+ */
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/signalvar.h>
+#include <signal.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+/* Prototypes: */
+static inline void build_siginfo(siginfo_t *info, int signo);
+#ifndef SYSTEM_SCOPE_ONLY
+static struct pthread *thr_sig_find(struct kse *curkse, int sig,
+		    siginfo_t *info);
+#endif
+static inline void thr_sigframe_restore(struct pthread *thread,
+	struct pthread_sigframe *psf);
+static inline void thr_sigframe_save(struct pthread *thread,
+	struct pthread_sigframe *psf);
+
+#define SA_KILL         0x01            /* terminates process by default */
+#define	SA_STOP		0x02
+#define	SA_CONT		0x04
+
+static int sigproptbl[NSIG] = {
+	SA_KILL,	/* SIGHUP */
+	SA_KILL,	/* SIGINT */
+	SA_KILL,	/* SIGQUIT */
+	SA_KILL,	/* SIGILL */
+	SA_KILL,	/* SIGTRAP */
+	SA_KILL,	/* SIGABRT */
+	SA_KILL,	/* SIGEMT */
+	SA_KILL,	/* SIGFPE */
+	SA_KILL,	/* SIGKILL */
+	SA_KILL,	/* SIGBUS */
+	SA_KILL,	/* SIGSEGV */
+	SA_KILL,	/* SIGSYS */
+	SA_KILL,	/* SIGPIPE */
+	SA_KILL,	/* SIGALRM */
+	SA_KILL,	/* SIGTERM */
+	0,		/* SIGURG */
+	SA_STOP,	/* SIGSTOP */
+	SA_STOP,	/* SIGTSTP */
+	SA_CONT,	/* SIGCONT */
+	0,		/* SIGCHLD */
+	SA_STOP,	/* SIGTTIN */
+	SA_STOP,	/* SIGTTOU */
+	0,		/* SIGIO */
+	SA_KILL,	/* SIGXCPU */
+	SA_KILL,	/* SIGXFSZ */
+	SA_KILL,	/* SIGVTALRM */
+	SA_KILL,	/* SIGPROF */
+	0,		/* SIGWINCH  */
+	0,		/* SIGINFO */
+	SA_KILL,	/* SIGUSR1 */
+	SA_KILL		/* SIGUSR2 */
+};
+
+/* #define DEBUG_SIGNAL */
+#ifdef DEBUG_SIGNAL
+#define DBG_MSG		stdout_debug
+#else
+#define DBG_MSG(x...)
+#endif
+
+/*
+ * Signal setup and delivery.
+ *
+ * 1) Delivering signals to threads in the same KSE.
+ *    These signals are sent by upcall events and are set in the
+ *    km_sigscaught field of the KSE mailbox.  Since these signals
+ *    are received while operating on the KSE stack, they can be
+ *    delivered either by using signalcontext() to add a stack frame
+ *    to the target thread's stack, or by adding them in the thread's
+ *    pending set and having the thread run them down after it 
+ * 2) Delivering signals to threads in other KSEs/KSEGs.
+ * 3) Delivering signals to threads in critical regions.
+ * 4) Delivering signals to threads after they change their signal masks.
+ *
+ * Methods of delivering signals.
+ *
+ *   1) Add a signal frame to the thread's saved context.
+ *   2) Add the signal to the thread structure, mark the thread as
+ *  	having signals to handle, and let the thread run them down
+ *  	after it resumes from the KSE scheduler.
+ *
+ * Problem with 1).  You can't do this to a running thread or a
+ * thread in a critical region.
+ *
+ * Problem with 2).  You can't do this to a thread that doesn't
+ * yield in some way (explicitly enters the scheduler).  A thread
+ * blocked in the kernel or a CPU hungry thread will not see the
+ * signal without entering the scheduler.
+ *
+ * The solution is to use both 1) and 2) to deliver signals:
+ *
+ *   o Thread in critical region - use 2).  When the thread
+ *     leaves the critical region it will check to see if it
+ *     has pending signals and run them down.
+ *
+ *   o Thread enters scheduler explicitly - use 2).  The thread
+ *     can check for pending signals after it returns from the
+ *     the scheduler.
+ *
+ *   o Thread is running and not current thread - use 2).  When the
+ *     thread hits a condition specified by one of the other bullets,
+ *     the signal will be delivered.
+ *
+ *   o Thread is running and is current thread (e.g., the thread
+ *     has just changed its signal mask and now sees that it has
+ *     pending signals) - just run down the pending signals.
+ *
+ *   o Thread is swapped out due to quantum expiration - use 1)
+ *
+ *   o Thread is blocked in kernel - kse_thr_wakeup() and then
+ *     use 1)
+ */
+
+/*
+ * Rules for selecting threads for signals received:
+ *
+ *   1) If the signal is a sychronous signal, it is delivered to
+ *      the generating (current thread).  If the thread has the
+ *      signal masked, it is added to the threads pending signal
+ *      set until the thread unmasks it.
+ *
+ *   2) A thread in sigwait() where the signal is in the thread's
+ *      waitset.
+ *
+ *   3) A thread in sigsuspend() where the signal is not in the
+ *      thread's suspended signal mask.
+ *
+ *   4) Any thread (first found/easiest to deliver) that has the
+ *      signal unmasked.
+ */
+
+#ifndef SYSTEM_SCOPE_ONLY
+
+static void *
+sig_daemon(void *arg /* Unused */)
+{
+	int i;
+	kse_critical_t crit;
+	struct timespec ts;
+	sigset_t set;
+	struct kse *curkse;
+	struct pthread *curthread = _get_curthread();
+
+	DBG_MSG("signal daemon started(%p)\n", curthread);
+	
+	curthread->name = strdup("signal thread");
+	crit = _kse_critical_enter();
+	curkse = _get_curkse();
+
+	/*
+	 * Daemon thread is a bound thread and we must be created with
+	 * all signals masked
+	 */
+#if 0	
+	SIGFILLSET(set);
+	__sys_sigprocmask(SIG_SETMASK, &set, NULL);
+#endif	
+	__sys_sigpending(&set);
+	ts.tv_sec = 0;
+	ts.tv_nsec = 0;
+	while (1) {
+		KSE_LOCK_ACQUIRE(curkse, &_thread_signal_lock);
+		_thr_proc_sigpending = set;
+		KSE_LOCK_RELEASE(curkse, &_thread_signal_lock);
+		for (i = 1; i <= _SIG_MAXSIG; i++) {
+			if (SIGISMEMBER(set, i) != 0)
+				_thr_sig_dispatch(curkse, i,
+				    NULL /* no siginfo */);
+		}
+		ts.tv_sec = 30;
+		ts.tv_nsec = 0;
+		curkse->k_kcb->kcb_kmbx.km_flags =
+		    KMF_NOUPCALL | KMF_NOCOMPLETED | KMF_WAITSIGEVENT;
+		kse_release(&ts);
+		curkse->k_kcb->kcb_kmbx.km_flags = 0;
+		set = curkse->k_kcb->kcb_kmbx.km_sigscaught;
+	}
+	return (0);
+}
+
+
+/* Utility function to create signal daemon thread */
+int
+_thr_start_sig_daemon(void)
+{
+	pthread_attr_t attr;
+	sigset_t sigset, oldset;
+
+	SIGFILLSET(sigset);
+	pthread_sigmask(SIG_SETMASK, &sigset, &oldset);
+	pthread_attr_init(&attr);
+	pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
+	attr->flags |= THR_SIGNAL_THREAD;
+	/* sigmask will be inherited */
+	if (pthread_create(&_thr_sig_daemon, &attr, sig_daemon, NULL))
+		PANIC("can not create signal daemon thread!\n");
+	pthread_attr_destroy(&attr);
+	pthread_sigmask(SIG_SETMASK, &oldset, NULL);
+	return (0);
+}
+
+/*
+ * This signal handler only delivers asynchronous signals.
+ * This must be called with upcalls disabled and without
+ * holding any locks.
+ */
+void
+_thr_sig_dispatch(struct kse *curkse, int sig, siginfo_t *info)
+{
+	struct kse_mailbox *kmbx;
+	struct pthread *thread;
+
+	DBG_MSG(">>> _thr_sig_dispatch(%d)\n", sig);
+
+	/* Check if the signal requires a dump of thread information: */
+	if (_thr_dump_enabled() && (sig == SIGINFO)) {
+		/* Dump thread information to file: */
+		_thread_dump_info();
+	}
+
+	while ((thread = thr_sig_find(curkse, sig, info)) != NULL) {
+		/*
+		 * Setup the target thread to receive the signal:
+		 */
+		DBG_MSG("Got signal %d, selecting thread %p\n", sig, thread);
+		KSE_SCHED_LOCK(curkse, thread->kseg);
+		if ((thread->state == PS_DEAD) ||
+		    (thread->state == PS_DEADLOCK) ||
+		    THR_IS_EXITING(thread) || THR_IS_SUSPENDED(thread)) {
+			KSE_SCHED_UNLOCK(curkse, thread->kseg);
+			_thr_ref_delete(NULL, thread);
+		} else if (SIGISMEMBER(thread->sigmask, sig)) {
+			KSE_SCHED_UNLOCK(curkse, thread->kseg);
+			_thr_ref_delete(NULL, thread);
+		} else {
+			kmbx = _thr_sig_add(thread, sig, info);
+			KSE_SCHED_UNLOCK(curkse, thread->kseg);
+			_thr_ref_delete(NULL, thread);
+			if (kmbx != NULL)
+				kse_wakeup(kmbx);
+			break;
+		}
+	}
+	DBG_MSG("<<< _thr_sig_dispatch\n");
+}
+
+#endif /* ! SYSTEM_SCOPE_ONLY */
+
+static __inline int
+sigprop(int sig)
+{
+
+	if (sig > 0 && sig < NSIG)
+                return (sigproptbl[_SIG_IDX(sig)]);
+        return (0);
+}
+
+typedef void (*ohandler)(int sig, int code,
+	struct sigcontext *scp, char *addr, __sighandler_t *catcher);
+
+void
+_thr_sig_handler(int sig, siginfo_t *info, ucontext_t *ucp)
+{
+	struct pthread_sigframe psf;
+	__siginfohandler_t *sigfunc;
+	struct pthread *curthread;
+	struct kse *curkse;
+	struct sigaction act;
+	int sa_flags, err_save;
+
+	err_save = errno;
+
+	DBG_MSG(">>> _thr_sig_handler(%d)\n", sig);
+
+	curthread = _get_curthread();
+	if (curthread == NULL)
+		PANIC("No current thread.\n");
+	if (!(curthread->attr.flags & PTHREAD_SCOPE_SYSTEM))
+		PANIC("Thread is not system scope.\n");
+	if (curthread->flags & THR_FLAGS_EXITING) {
+		errno = err_save;
+		return;
+	}
+
+	curkse = _get_curkse();
+	/*
+	 * If thread is in critical region or if thread is on
+	 * the way of state transition, then latch signal into buffer.
+	 */
+	if (_kse_in_critical() || THR_IN_CRITICAL(curthread) ||
+	    curthread->state != PS_RUNNING) {
+		DBG_MSG(">>> _thr_sig_handler(%d) in critical\n", sig);
+		curthread->siginfo[sig-1] = *info;
+		curthread->check_pending = 1;
+		curkse->k_sigseqno++;
+		SIGADDSET(curthread->sigpend, sig);
+		/* 
+		 * If the kse is on the way to idle itself, but
+		 * we have signal ready, we should prevent it
+		 * to sleep, kernel will latch the wakeup request,
+		 * so kse_release will return from kernel immediately.
+		 */
+		if (KSE_IS_IDLE(curkse))
+			kse_wakeup(&curkse->k_kcb->kcb_kmbx);
+		errno = err_save;
+		return;
+	}
+
+	/* Check if the signal requires a dump of thread information: */
+	if (_thr_dump_enabled() && (sig == SIGINFO)) {
+		/* Dump thread information to file: */
+		_thread_dump_info();
+	}
+
+	/* Check the threads previous state: */
+	curthread->critical_count++;
+	if (curthread->sigbackout != NULL)
+		curthread->sigbackout((void *)curthread);
+	curthread->critical_count--;
+	thr_sigframe_save(curthread, &psf);
+	THR_ASSERT(!(curthread->sigbackout), "sigbackout was not cleared.");
+
+	_kse_critical_enter();
+	/* Get a fresh copy of signal mask */
+	__sys_sigprocmask(SIG_BLOCK, NULL, &curthread->sigmask);
+	KSE_LOCK_ACQUIRE(curkse, &_thread_signal_lock);
+	sigfunc = _thread_sigact[sig - 1].sa_sigaction;
+	sa_flags = _thread_sigact[sig - 1].sa_flags;
+	if (sa_flags & SA_RESETHAND) {
+		act.sa_handler = SIG_DFL;
+		act.sa_flags = SA_RESTART;
+		SIGEMPTYSET(act.sa_mask);
+		__sys_sigaction(sig, &act, NULL);
+		__sys_sigaction(sig, NULL, &_thread_sigact[sig - 1]);
+	}
+	KSE_LOCK_RELEASE(curkse, &_thread_signal_lock);
+	_kse_critical_leave(&curthread->tcb->tcb_tmbx);
+
+	/* Now invoke real handler */
+	if (((__sighandler_t *)sigfunc != SIG_DFL) &&
+	    ((__sighandler_t *)sigfunc != SIG_IGN) && 
+	    (sigfunc != (__siginfohandler_t *)_thr_sig_handler)) {
+		if ((sa_flags & SA_SIGINFO) != 0 || info == NULL)
+			(*(sigfunc))(sig, info, ucp);
+		else {
+			((ohandler)(*sigfunc))(
+				sig, info->si_code, (struct sigcontext *)ucp,
+				info->si_addr, (__sighandler_t *)sigfunc);
+		}
+	} else {
+		if ((__sighandler_t *)sigfunc == SIG_DFL) {
+			if (sigprop(sig) & SA_KILL) {
+				if (_kse_isthreaded())
+					kse_thr_interrupt(NULL,
+						 KSE_INTR_SIGEXIT, sig);
+				else
+					kill(getpid(), sig);
+			}
+#ifdef NOTYET
+			else if (sigprop(sig) & SA_STOP)
+				kse_thr_interrupt(NULL, KSE_INTR_JOBSTOP, sig);
+#endif
+		}
+	}
+	_kse_critical_enter();
+	curthread->sigmask = ucp->uc_sigmask;
+	SIG_CANTMASK(curthread->sigmask);
+	_kse_critical_leave(&curthread->tcb->tcb_tmbx);
+
+	thr_sigframe_restore(curthread, &psf);
+
+	DBG_MSG("<<< _thr_sig_handler(%d)\n", sig);
+
+	errno = err_save;
+}
+
+struct sighandle_info {
+	__siginfohandler_t *sigfunc;
+	int sa_flags;
+	int sig;
+	siginfo_t *info;
+	ucontext_t *ucp;
+};
+
+static void handle_signal(struct pthread *curthread,
+	struct sighandle_info *shi);
+static void handle_signal_altstack(struct pthread *curthread,
+	struct sighandle_info *shi);
+
+/* Must be called with signal lock and schedule lock held in order */
+static void
+thr_sig_invoke_handler(struct pthread *curthread, int sig, siginfo_t *info,
+    ucontext_t *ucp)
+{
+	__siginfohandler_t *sigfunc;
+	sigset_t sigmask;
+	int sa_flags;
+	int onstack;
+	struct sigaction act;
+	struct kse *curkse;
+	struct sighandle_info shi;
+
+	/*
+	 * Invoke the signal handler without going through the scheduler:
+	 */
+	DBG_MSG("Got signal %d, calling handler for current thread %p\n",
+	    sig, curthread);
+
+	if (!_kse_in_critical())
+		PANIC("thr_sig_invoke_handler without in critical\n");
+	curkse = curthread->kse;
+	/*
+	 * Check that a custom handler is installed and if
+	 * the signal is not blocked:
+	 */
+	sigfunc = _thread_sigact[sig - 1].sa_sigaction;
+	sa_flags = _thread_sigact[sig - 1].sa_flags;
+	sigmask = curthread->sigmask;
+	SIGSETOR(curthread->sigmask, _thread_sigact[sig - 1].sa_mask);
+	if (!(sa_flags & (SA_NODEFER | SA_RESETHAND)))
+		SIGADDSET(curthread->sigmask, sig);
+	if ((sig != SIGILL) && (sa_flags & SA_RESETHAND)) {
+		act.sa_handler = SIG_DFL;
+		act.sa_flags = SA_RESTART;
+		SIGEMPTYSET(act.sa_mask);
+		__sys_sigaction(sig, &act, NULL);
+		__sys_sigaction(sig, NULL, &_thread_sigact[sig - 1]);
+	}
+	KSE_LOCK_RELEASE(curkse, &_thread_signal_lock);
+	KSE_SCHED_UNLOCK(curkse, curkse->k_kseg);
+	/*
+	 * We are processing buffered signals, synchronize working
+	 * signal mask into kernel.
+	 */
+	if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM)
+		__sys_sigprocmask(SIG_SETMASK, &curthread->sigmask, NULL);
+	onstack = _thr_sigonstack(&sigfunc);
+	ucp->uc_stack = curthread->sigstk;
+	ucp->uc_stack.ss_flags = (curthread->sigstk.ss_flags & SS_DISABLE)
+		? SS_DISABLE : ((onstack) ? SS_ONSTACK : 0);
+	if (curthread->oldsigmask) {
+		ucp->uc_sigmask = *(curthread->oldsigmask);
+		curthread->oldsigmask = NULL;
+	} else
+		ucp->uc_sigmask = sigmask;
+	shi.sigfunc = sigfunc;
+	shi.sig = sig;
+	shi.sa_flags = sa_flags;
+	shi.info = info;
+	shi.ucp = ucp;
+	if ((curthread->sigstk.ss_flags & SS_DISABLE) == 0) {
+		/* Deliver signal on alternative stack */
+		if (sa_flags & SA_ONSTACK && !onstack)
+			handle_signal_altstack(curthread, &shi);
+		else
+			handle_signal(curthread, &shi);
+	} else {
+		handle_signal(curthread, &shi);
+	}
+
+	_kse_critical_enter();
+	/* Don't trust after critical leave/enter */
+	curkse = curthread->kse;
+
+	/*
+	 * Restore the thread's signal mask.
+	 */
+	curthread->sigmask = ucp->uc_sigmask;
+	SIG_CANTMASK(curthread->sigmask);
+	if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM)
+		__sys_sigprocmask(SIG_SETMASK, &ucp->uc_sigmask, NULL);
+	KSE_SCHED_LOCK(curkse, curkse->k_kseg);
+	KSE_LOCK_ACQUIRE(curkse, &_thread_signal_lock);
+	
+	DBG_MSG("Got signal %d, handler returned %p\n", sig, curthread);
+}
+
+static void
+handle_signal(struct pthread *curthread, struct sighandle_info *shi)
+{
+	_kse_critical_leave(&curthread->tcb->tcb_tmbx);
+
+	/* Check if the signal requires a dump of thread information: */
+	if (_thr_dump_enabled() && (shi->sig == SIGINFO)) {
+		/* Dump thread information to file: */
+		_thread_dump_info();
+	}
+
+	if (((__sighandler_t *)shi->sigfunc != SIG_DFL) &&
+	    ((__sighandler_t *)shi->sigfunc != SIG_IGN)) {
+		if ((shi->sa_flags & SA_SIGINFO) != 0 || shi->info == NULL)
+			(*(shi->sigfunc))(shi->sig, shi->info, shi->ucp);
+		else {
+			((ohandler)(*shi->sigfunc))(
+				shi->sig, shi->info->si_code,
+				(struct sigcontext *)shi->ucp,
+				shi->info->si_addr,
+				(__sighandler_t *)shi->sigfunc);
+		}
+	} else {
+		if ((__sighandler_t *)shi->sigfunc == SIG_DFL) {
+			if (sigprop(shi->sig) & SA_KILL) {
+				if (_kse_isthreaded())
+					kse_thr_interrupt(NULL,
+						 KSE_INTR_SIGEXIT, shi->sig);
+				else
+					kill(getpid(), shi->sig);
+			}
+#ifdef NOTYET
+			else if (sigprop(shi->sig) & SA_STOP)
+				kse_thr_interrupt(NULL, KSE_INTR_JOBSTOP,
+					shi->sig);
+#endif
+		}
+	}
+}
+
+static void
+handle_signal_wrapper(struct pthread *curthread, ucontext_t *ret_uc,
+	struct sighandle_info *shi)
+{
+	shi->ucp->uc_stack.ss_flags = SS_ONSTACK;
+	handle_signal(curthread, shi);
+	if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM)
+		setcontext(ret_uc);
+	else {
+		/* Work around for ia64, THR_SETCONTEXT does not work */
+		_kse_critical_enter();
+        	curthread->tcb->tcb_tmbx.tm_context = *ret_uc;
+        	_thread_switch(curthread->kse->k_kcb, curthread->tcb, 1);
+		/* THR_SETCONTEXT */
+	}
+}
+
+/*
+ * Jump to stack set by sigaltstack before invoking signal handler
+ */
+static void
+handle_signal_altstack(struct pthread *curthread, struct sighandle_info *shi)
+{
+	volatile int once;
+	ucontext_t uc1, *uc2;
+
+	THR_ASSERT(_kse_in_critical(), "Not in critical");
+
+	once = 0;
+	THR_GETCONTEXT(&uc1);
+	if (once == 0) {
+		once = 1;
+		/* XXX
+		 * We are still in critical region, it is safe to operate thread
+		 * context
+		 */
+		uc2 = &curthread->tcb->tcb_tmbx.tm_context;
+		uc2->uc_stack = curthread->sigstk;
+		makecontext(uc2, (void (*)(void))handle_signal_wrapper,
+			3, curthread, &uc1, shi);
+		if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM)
+			setcontext(uc2);
+		else {
+			_thread_switch(curthread->kse->k_kcb, curthread->tcb, 1);
+			/* THR_SETCONTEXT(uc2); */
+		}
+	}
+}
+
+int
+_thr_getprocsig(int sig, siginfo_t *siginfo)
+{
+	kse_critical_t crit;
+	struct kse *curkse;
+	int ret;
+
+	DBG_MSG(">>> _thr_getprocsig\n");
+
+	crit = _kse_critical_enter();
+	curkse = _get_curkse();
+	KSE_LOCK_ACQUIRE(curkse, &_thread_signal_lock);
+	ret = _thr_getprocsig_unlocked(sig, siginfo);
+	KSE_LOCK_RELEASE(curkse, &_thread_signal_lock);
+	_kse_critical_leave(crit);
+
+	DBG_MSG("<<< _thr_getprocsig\n");
+	return (ret);
+}
+
+int
+_thr_getprocsig_unlocked(int sig, siginfo_t *siginfo)
+{
+	sigset_t sigset;
+	struct timespec ts;
+
+	/* try to retrieve signal from kernel */
+	SIGEMPTYSET(sigset);
+	SIGADDSET(sigset, sig);
+	ts.tv_sec = 0;
+	ts.tv_nsec = 0;
+	SIGDELSET(_thr_proc_sigpending, sig);
+	if (__sys_sigtimedwait(&sigset, siginfo, &ts) > 0)
+		return (sig);
+	return (0);
+}
+
+#ifndef SYSTEM_SCOPE_ONLY
+/*
+ * Find a thread that can handle the signal.  This must be called
+ * with upcalls disabled.
+ */
+struct pthread *
+thr_sig_find(struct kse *curkse, int sig, siginfo_t *info)
+{
+	struct kse_mailbox *kmbx = NULL;
+	struct pthread	*pthread;
+	struct pthread	*suspended_thread, *signaled_thread;
+	__siginfohandler_t *sigfunc;
+	siginfo_t si;
+
+	DBG_MSG("Looking for thread to handle signal %d\n", sig);
+
+	/*
+	 * Enter a loop to look for threads that have the signal
+	 * unmasked.  POSIX specifies that a thread in a sigwait
+	 * will get the signal over any other threads.  Second
+	 * preference will be threads in in a sigsuspend.  Third
+	 * preference will be the current thread.  If none of the
+	 * above, then the signal is delivered to the first thread
+	 * that is found.  Note that if a custom handler is not
+	 * installed, the signal only affects threads in sigwait.
+	 */
+	suspended_thread = NULL;
+	signaled_thread = NULL;
+
+	KSE_LOCK_ACQUIRE(curkse, &_thread_list_lock);
+	TAILQ_FOREACH(pthread, &_thread_list, tle) {
+		if (pthread == _thr_sig_daemon)
+			continue;
+		/* Signal delivering to bound thread is done by kernel */
+		if (pthread->attr.flags & PTHREAD_SCOPE_SYSTEM)
+			continue;
+		/* Take the scheduling lock. */
+		KSE_SCHED_LOCK(curkse, pthread->kseg);
+		if ((pthread->state == PS_DEAD)		||
+		    (pthread->state == PS_DEADLOCK)	||
+		    THR_IS_EXITING(pthread)		||
+		    THR_IS_SUSPENDED(pthread)) {
+			; /* Skip this thread. */
+		} else if (pthread->state == PS_SIGWAIT &&
+			   SIGISMEMBER(*(pthread->data.sigwait->waitset), sig)) {
+			/*
+			 * retrieve signal from kernel, if it is job control
+			 * signal, and sigaction is SIG_DFL, then we will
+			 * be stopped in kernel, we hold lock here, but that 
+			 * does not matter, because that's job control, and
+			 * whole process should be stopped.
+			 */
+			if (_thr_getprocsig(sig, &si)) {
+				DBG_MSG("Waking thread %p in sigwait"
+					" with signal %d\n", pthread, sig);
+				/*  where to put siginfo ? */
+				*(pthread->data.sigwait->siginfo) = si;
+				kmbx = _thr_setrunnable_unlocked(pthread);
+			}
+			KSE_SCHED_UNLOCK(curkse, pthread->kseg);
+			/*
+			 * POSIX doesn't doesn't specify which thread
+			 * will get the signal if there are multiple
+			 * waiters, so we give it to the first thread
+			 * we find.
+			 *
+			 * Do not attempt to deliver this signal
+			 * to other threads and do not add the signal
+			 * to the process pending set.
+			 */
+			KSE_LOCK_RELEASE(curkse, &_thread_list_lock);
+			if (kmbx != NULL)
+				kse_wakeup(kmbx);
+			if (suspended_thread != NULL)
+				_thr_ref_delete(NULL, suspended_thread);
+			if (signaled_thread != NULL)
+				_thr_ref_delete(NULL, signaled_thread);
+			return (NULL);
+		} else if (!SIGISMEMBER(pthread->sigmask, sig)) {
+			/*
+			 * If debugger is running, we don't quick exit,
+			 * and give it a chance to check the signal.
+			 */  
+			if (_libkse_debug == 0) {
+				sigfunc = _thread_sigact[sig - 1].sa_sigaction;
+				if ((__sighandler_t *)sigfunc == SIG_DFL) {
+					if (sigprop(sig) & SA_KILL) {
+						kse_thr_interrupt(NULL,
+							 KSE_INTR_SIGEXIT, sig);
+						/* Never reach */
+					}
+				}
+			}
+			if (pthread->state == PS_SIGSUSPEND) {
+				if (suspended_thread == NULL) {
+					suspended_thread = pthread;
+					suspended_thread->refcount++;
+				}
+			} else if (signaled_thread == NULL) {
+				signaled_thread = pthread;
+				signaled_thread->refcount++;
+			}
+		}
+		KSE_SCHED_UNLOCK(curkse, pthread->kseg);
+	}
+	KSE_LOCK_RELEASE(curkse, &_thread_list_lock);
+
+	if (suspended_thread != NULL) {
+		pthread = suspended_thread;
+		if (signaled_thread)
+			_thr_ref_delete(NULL, signaled_thread);
+	} else if (signaled_thread) {
+		pthread = signaled_thread;
+	} else {
+		pthread = NULL;
+	}
+	return (pthread);
+}
+#endif /* ! SYSTEM_SCOPE_ONLY */
+
+static inline void
+build_siginfo(siginfo_t *info, int signo)
+{
+	bzero(info, sizeof(*info));
+	info->si_signo = signo;
+	info->si_pid = _thr_pid;
+}
+
+/*
+ * This is called by a thread when it has pending signals to deliver.
+ * It should only be called from the context of the thread.
+ */
+void
+_thr_sig_rundown(struct pthread *curthread, ucontext_t *ucp)
+{
+	struct pthread_sigframe psf;
+	siginfo_t siginfo;
+	int i, err_save;
+	kse_critical_t crit;
+	struct kse *curkse;
+	sigset_t sigmask;
+
+	err_save = errno;
+
+	DBG_MSG(">>> thr_sig_rundown (%p)\n", curthread);
+
+	/* Check the threads previous state: */
+	curthread->critical_count++;
+	if (curthread->sigbackout != NULL)
+		curthread->sigbackout((void *)curthread);
+	curthread->critical_count--;
+
+	THR_ASSERT(!(curthread->sigbackout), "sigbackout was not cleared.");
+	THR_ASSERT((curthread->state == PS_RUNNING), "state is not PS_RUNNING");
+
+	thr_sigframe_save(curthread, &psf);
+	/*
+	 * Lower the priority before calling the handler in case
+	 * it never returns (longjmps back):
+	 */
+	crit = _kse_critical_enter();
+	curkse = curthread->kse;
+	KSE_SCHED_LOCK(curkse, curkse->k_kseg);
+	KSE_LOCK_ACQUIRE(curkse, &_thread_signal_lock);
+	curthread->active_priority &= ~THR_SIGNAL_PRIORITY;
+	SIGFILLSET(sigmask);
+	while (1) {
+		/*
+		 * For bound thread, we mask all signals and get a fresh
+		 * copy of signal mask from kernel
+		 */
+		if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM) {
+			__sys_sigprocmask(SIG_SETMASK, &sigmask,
+				 &curthread->sigmask);
+		}
+		for (i = 1; i <= _SIG_MAXSIG; i++) {
+			if (SIGISMEMBER(curthread->sigmask, i))
+				continue;
+			if (SIGISMEMBER(curthread->sigpend, i)) {
+				SIGDELSET(curthread->sigpend, i);
+				siginfo = curthread->siginfo[i-1];
+				break;
+			}
+			if (!(curthread->attr.flags & PTHREAD_SCOPE_SYSTEM) 
+			    && SIGISMEMBER(_thr_proc_sigpending, i)) {
+				if (_thr_getprocsig_unlocked(i, &siginfo))
+					break;
+			}
+		}
+		if (i <= _SIG_MAXSIG)
+			thr_sig_invoke_handler(curthread, i, &siginfo, ucp);
+		else {
+			if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM) {
+				__sys_sigprocmask(SIG_SETMASK,
+						 &curthread->sigmask, NULL);
+			}
+			break;
+		}
+	}
+
+	/* Don't trust after signal handling */
+	curkse = curthread->kse;
+	KSE_LOCK_RELEASE(curkse, &_thread_signal_lock);
+	KSE_SCHED_UNLOCK(curkse, curkse->k_kseg);
+	_kse_critical_leave(&curthread->tcb->tcb_tmbx);
+	/* repost masked signal to kernel, it hardly happens in real world */
+	if ((curthread->attr.flags & PTHREAD_SCOPE_SYSTEM) &&
+	    !SIGISEMPTY(curthread->sigpend)) { /* dirty read */
+		__sys_sigprocmask(SIG_SETMASK, &sigmask, &curthread->sigmask);
+		for (i = 1; i <= _SIG_MAXSIG; ++i) {
+			if (SIGISMEMBER(curthread->sigpend, i)) {
+				SIGDELSET(curthread->sigpend, i);
+				if (!_kse_isthreaded())
+					kill(getpid(), i);
+				else
+					kse_thr_interrupt(
+						&curthread->tcb->tcb_tmbx,
+						KSE_INTR_SENDSIG,
+						i);
+			}
+		}
+		__sys_sigprocmask(SIG_SETMASK, &curthread->sigmask, NULL);
+	}
+	DBG_MSG("<<< thr_sig_rundown (%p)\n", curthread);
+
+	thr_sigframe_restore(curthread, &psf);
+	errno = err_save;
+}
+
+/*
+ * This checks pending signals for the current thread.  It should be
+ * called whenever a thread changes its signal mask.  Note that this
+ * is called from a thread (using its stack).
+ *
+ * XXX - We might want to just check to see if there are pending
+ *       signals for the thread here, but enter the UTS scheduler
+ *       to actually install the signal handler(s).
+ */
+void
+_thr_sig_check_pending(struct pthread *curthread)
+{
+	ucontext_t uc;
+	volatile int once;
+	int errsave;
+
+	/*
+	 * If the thread is in critical region, delay processing signals.
+	 * If the thread state is not PS_RUNNING, it might be switching
+	 * into UTS and but a THR_LOCK_RELEASE saw check_pending, and it
+	 * goes here, in the case we delay processing signals, lets UTS
+	 * process complicated things, normally UTS will call _thr_sig_add
+	 * to resume the thread, so we needn't repeat doing it here.
+	 */
+	if (THR_IN_CRITICAL(curthread) || curthread->state != PS_RUNNING)
+		return;
+
+	errsave = errno;
+	once = 0;
+	THR_GETCONTEXT(&uc);
+	if (once == 0) {
+		once = 1;
+		curthread->check_pending = 0;
+		_thr_sig_rundown(curthread, &uc);
+	}
+	errno = errsave;
+}
+
+/*
+ * Perform thread specific actions in response to a signal.
+ * This function is only called if there is a handler installed
+ * for the signal, and if the target thread has the signal
+ * unmasked.
+ *
+ * This must be called with the thread's scheduling lock held.
+ */
+struct kse_mailbox *
+_thr_sig_add(struct pthread *pthread, int sig, siginfo_t *info)
+{
+	siginfo_t siginfo;
+	struct kse *curkse;
+	struct kse_mailbox *kmbx = NULL;
+	struct pthread *curthread = _get_curthread();
+	int	restart;
+	int	suppress_handler = 0;
+	int	fromproc = 0;
+	__sighandler_t *sigfunc;
+
+	DBG_MSG(">>> _thr_sig_add %p (%d)\n", pthread, sig);
+
+	curkse = _get_curkse();
+	restart = _thread_sigact[sig - 1].sa_flags & SA_RESTART;
+	sigfunc = _thread_sigact[sig - 1].sa_handler;
+	fromproc = (curthread == _thr_sig_daemon);
+
+	if (pthread->state == PS_DEAD || pthread->state == PS_DEADLOCK ||
+	    pthread->state == PS_STATE_MAX)
+	    	return (NULL); /* return false */
+
+	if ((pthread->attr.flags & PTHREAD_SCOPE_SYSTEM) &&
+	    (curthread != pthread)) {
+	    	PANIC("Please use _thr_send_sig for bound thread");
+		return (NULL);
+	}
+
+	if (pthread->state != PS_SIGWAIT &&
+	    SIGISMEMBER(pthread->sigmask, sig)) {
+		/* signal is masked, just add signal to thread. */
+		if (!fromproc) {
+			SIGADDSET(pthread->sigpend, sig);
+			if (info == NULL)
+				build_siginfo(&pthread->siginfo[sig-1], sig);
+			else if (info != &pthread->siginfo[sig-1])
+				memcpy(&pthread->siginfo[sig-1], info,
+					 sizeof(*info));
+		} else {
+			if (!_thr_getprocsig(sig, &pthread->siginfo[sig-1]))
+				return (NULL);
+			SIGADDSET(pthread->sigpend, sig);
+		}
+	}
+	else {
+		/* if process signal not exists, just return */
+		if (fromproc) {
+			if (!_thr_getprocsig(sig, &siginfo))
+				return (NULL);
+			info = &siginfo;
+		}
+
+		if (pthread->state != PS_SIGWAIT && sigfunc == SIG_DFL &&
+		    (sigprop(sig) & SA_KILL)) {
+			kse_thr_interrupt(NULL, KSE_INTR_SIGEXIT, sig);
+			/* Never reach */
+		}
+
+		/*
+		 * Process according to thread state:
+		 */
+		switch (pthread->state) {
+		case PS_DEAD:
+		case PS_DEADLOCK:
+		case PS_STATE_MAX:
+			return (NULL);	/* XXX return false */
+		case PS_LOCKWAIT:
+		case PS_SUSPENDED:
+			/*
+			 * You can't call a signal handler for threads in these
+			 * states.
+			 */
+			suppress_handler = 1;
+			break;
+		case PS_RUNNING:
+			if ((pthread->flags & THR_FLAGS_IN_RUNQ)) {
+				THR_RUNQ_REMOVE(pthread);
+				pthread->active_priority |= THR_SIGNAL_PRIORITY;
+				THR_RUNQ_INSERT_TAIL(pthread);
+			} else {
+				/* Possible not in RUNQ and has curframe ? */
+				pthread->active_priority |= THR_SIGNAL_PRIORITY;
+			}
+			break;
+		/*
+		 * States which cannot be interrupted but still require the
+		 * signal handler to run:
+		 */
+		case PS_COND_WAIT:
+		case PS_MUTEX_WAIT:
+			break;
+
+		case PS_SLEEP_WAIT:
+			/*
+			 * Unmasked signals always cause sleep to terminate
+			 * early regardless of SA_RESTART:
+			 */
+			pthread->interrupted = 1;
+			break;
+
+		case PS_JOIN:
+			break;
+
+		case PS_SIGSUSPEND:
+			pthread->interrupted = 1;
+			break;
+
+		case PS_SIGWAIT:
+			if (info == NULL)
+				build_siginfo(&pthread->siginfo[sig-1], sig);
+			else if (info != &pthread->siginfo[sig-1])
+				memcpy(&pthread->siginfo[sig-1], info,
+					sizeof(*info));
+			/*
+			 * The signal handler is not called for threads in
+			 * SIGWAIT.
+			 */
+			suppress_handler = 1;
+			/* Wake up the thread if the signal is not blocked. */
+			if (SIGISMEMBER(*(pthread->data.sigwait->waitset), sig)) {
+				/* Return the signal number: */
+				*(pthread->data.sigwait->siginfo) = pthread->siginfo[sig-1];
+				/* Make the thread runnable: */
+				kmbx = _thr_setrunnable_unlocked(pthread);
+			} else {
+				/* Increment the pending signal count. */
+				SIGADDSET(pthread->sigpend, sig);
+				if (!SIGISMEMBER(pthread->sigmask, sig)) {
+					if (sigfunc == SIG_DFL &&
+					    sigprop(sig) & SA_KILL) {
+						kse_thr_interrupt(NULL,
+							 KSE_INTR_SIGEXIT,
+							 sig);
+						/* Never reach */
+					}
+					pthread->check_pending = 1;
+					pthread->interrupted = 1;
+					kmbx = _thr_setrunnable_unlocked(pthread);
+				}
+			}
+			return (kmbx);
+		}
+
+		SIGADDSET(pthread->sigpend, sig);
+		if (info == NULL)
+			build_siginfo(&pthread->siginfo[sig-1], sig);
+		else if (info != &pthread->siginfo[sig-1])
+			memcpy(&pthread->siginfo[sig-1], info, sizeof(*info));
+		pthread->check_pending = 1;
+		if (!(pthread->attr.flags & PTHREAD_SCOPE_SYSTEM) &&
+		    (pthread->blocked != 0) && !THR_IN_CRITICAL(pthread))
+			kse_thr_interrupt(&pthread->tcb->tcb_tmbx,
+			    restart ? KSE_INTR_RESTART : KSE_INTR_INTERRUPT, 0);
+		if (suppress_handler == 0) {
+			/*
+			 * Setup a signal frame and save the current threads
+			 * state:
+			 */
+			if (pthread->state != PS_RUNNING) {
+				if (pthread->flags & THR_FLAGS_IN_RUNQ)
+					THR_RUNQ_REMOVE(pthread);
+				pthread->active_priority |= THR_SIGNAL_PRIORITY;
+				kmbx = _thr_setrunnable_unlocked(pthread);
+			}
+		}
+	}
+	return (kmbx);
+}
+
+/*
+ * Send a signal to a specific thread (ala pthread_kill):
+ */
+void
+_thr_sig_send(struct pthread *pthread, int sig)
+{
+	struct pthread *curthread = _get_curthread();
+	struct kse_mailbox *kmbx;
+
+	if (pthread->attr.flags & PTHREAD_SCOPE_SYSTEM) {
+		kse_thr_interrupt(&pthread->tcb->tcb_tmbx, KSE_INTR_SENDSIG, sig);
+		return;
+	}
+
+	/* Lock the scheduling queue of the target thread. */
+	THR_SCHED_LOCK(curthread, pthread);
+	if (_thread_sigact[sig - 1].sa_handler != SIG_IGN) {
+		kmbx = _thr_sig_add(pthread, sig, NULL);
+		/* Add a preemption point. */
+		if (kmbx == NULL && (curthread->kseg == pthread->kseg) &&
+		    (pthread->active_priority > curthread->active_priority))
+			curthread->critical_yield = 1;
+		THR_SCHED_UNLOCK(curthread, pthread);
+		if (kmbx != NULL)
+			kse_wakeup(kmbx);
+		/* XXX
+		 * If thread sent signal to itself, check signals now.
+		 * It is not really needed, _kse_critical_leave should
+		 * have already checked signals.
+		 */
+		if (pthread == curthread && curthread->check_pending)
+			_thr_sig_check_pending(curthread);
+
+	} else  {
+		THR_SCHED_UNLOCK(curthread, pthread);
+	}
+}
+
+static inline void
+thr_sigframe_restore(struct pthread *curthread, struct pthread_sigframe *psf)
+{
+	kse_critical_t crit;
+	struct kse *curkse;
+
+	THR_THREAD_LOCK(curthread, curthread);
+	curthread->cancelflags = psf->psf_cancelflags;
+	crit = _kse_critical_enter();
+	curkse = curthread->kse;
+	KSE_SCHED_LOCK(curkse, curthread->kseg);
+	curthread->flags = psf->psf_flags;
+	curthread->interrupted = psf->psf_interrupted;
+	curthread->timeout = psf->psf_timeout;
+	curthread->data = psf->psf_wait_data;
+	curthread->wakeup_time = psf->psf_wakeup_time;
+	curthread->continuation = psf->psf_continuation;
+	KSE_SCHED_UNLOCK(curkse, curthread->kseg);
+	_kse_critical_leave(crit);
+	THR_THREAD_UNLOCK(curthread, curthread);
+}
+
+static inline void
+thr_sigframe_save(struct pthread *curthread, struct pthread_sigframe *psf)
+{
+	kse_critical_t crit;
+	struct kse *curkse;
+
+	THR_THREAD_LOCK(curthread, curthread);
+	psf->psf_cancelflags = curthread->cancelflags;
+	crit = _kse_critical_enter();
+	curkse = curthread->kse;
+	KSE_SCHED_LOCK(curkse, curthread->kseg);
+	/* This has to initialize all members of the sigframe. */
+	psf->psf_flags = (curthread->flags & (THR_FLAGS_PRIVATE | THR_FLAGS_EXITING));
+	psf->psf_interrupted = curthread->interrupted;
+	psf->psf_timeout = curthread->timeout;
+	psf->psf_wait_data = curthread->data;
+	psf->psf_wakeup_time = curthread->wakeup_time;
+	psf->psf_continuation = curthread->continuation;
+	KSE_SCHED_UNLOCK(curkse, curthread->kseg);
+	_kse_critical_leave(crit);
+	THR_THREAD_UNLOCK(curthread, curthread);
+}
+
+void
+_thr_signal_init(void)
+{
+	struct sigaction act;
+	__siginfohandler_t *sigfunc;
+	int i;
+	sigset_t sigset;
+
+	SIGFILLSET(sigset);
+	__sys_sigprocmask(SIG_SETMASK, &sigset, &_thr_initial->sigmask);
+	/* Enter a loop to get the existing signal status: */
+	for (i = 1; i <= _SIG_MAXSIG; i++) {
+		/* Get the signal handler details: */
+		if (__sys_sigaction(i, NULL, &_thread_sigact[i - 1]) != 0) {
+			/*
+			 * Abort this process if signal
+			 * initialisation fails:
+			 */
+			PANIC("Cannot read signal handler info");
+		}
+		/* Intall wrapper if handler was set */
+		sigfunc = _thread_sigact[i - 1].sa_sigaction;
+		if (((__sighandler_t *)sigfunc) != SIG_DFL &&
+		    ((__sighandler_t *)sigfunc) != SIG_IGN) {
+		    	act = _thread_sigact[i - 1];
+			act.sa_flags |= SA_SIGINFO;
+			act.sa_sigaction =
+				(__siginfohandler_t *)_thr_sig_handler;
+			__sys_sigaction(i, &act, NULL);
+		}
+	}
+	if (_thr_dump_enabled()) {
+		/*
+		 * Install the signal handler for SIGINFO.  It isn't
+		 * really needed, but it is nice to have for debugging
+		 * purposes.
+		 */
+		_thread_sigact[SIGINFO - 1].sa_flags = SA_SIGINFO | SA_RESTART;
+		SIGEMPTYSET(act.sa_mask);
+		act.sa_flags = SA_SIGINFO | SA_RESTART;
+		act.sa_sigaction = (__siginfohandler_t *)&_thr_sig_handler;
+		if (__sys_sigaction(SIGINFO, &act, NULL) != 0) {
+			__sys_sigprocmask(SIG_SETMASK, &_thr_initial->sigmask,
+			    NULL);
+			/*
+			 * Abort this process if signal initialisation fails:
+			 */
+			PANIC("Cannot initialize signal handler");
+		}
+	}
+	__sys_sigprocmask(SIG_SETMASK, &_thr_initial->sigmask, NULL);
+	__sys_sigaltstack(NULL, &_thr_initial->sigstk);
+}
+
+void
+_thr_signal_deinit(void)
+{
+	int i;
+	struct pthread *curthread = _get_curthread();
+
+	/* Clear process pending signals. */
+	sigemptyset(&_thr_proc_sigpending);
+
+	/* Enter a loop to get the existing signal status: */
+	for (i = 1; i <= _SIG_MAXSIG; i++) {
+		/* Check for signals which cannot be trapped: */
+		if (i == SIGKILL || i == SIGSTOP) {
+		}
+
+		/* Set the signal handler details: */
+		else if (__sys_sigaction(i, &_thread_sigact[i - 1],
+			 NULL) != 0) {
+			/*
+			 * Abort this process if signal
+			 * initialisation fails:
+			 */
+			PANIC("Cannot set signal handler info");
+		}
+	}
+	__sys_sigaltstack(&curthread->sigstk, NULL);
+}
+
--- /dev/null
+++ lib/libkse/thread/thr_rwlockattr.c
@@ -0,0 +1,107 @@
+/*-
+ * Copyright (c) 1998 Alex Nash
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/lib/libkse/thread/thr_rwlockattr.c,v 1.10 2007/10/09 13:42:29 obrien Exp $
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_rwlockattr_destroy);
+LT10_COMPAT_DEFAULT(pthread_rwlockattr_destroy);
+LT10_COMPAT_PRIVATE(_pthread_rwlockattr_getpshared);
+LT10_COMPAT_DEFAULT(pthread_rwlockattr_getpshared);
+LT10_COMPAT_PRIVATE(_pthread_rwlockattr_init);
+LT10_COMPAT_DEFAULT(pthread_rwlockattr_init);
+LT10_COMPAT_PRIVATE(_pthread_rwlockattr_setpshared);
+LT10_COMPAT_DEFAULT(pthread_rwlockattr_setpshared);
+
+__weak_reference(_pthread_rwlockattr_destroy, pthread_rwlockattr_destroy);
+__weak_reference(_pthread_rwlockattr_getpshared, pthread_rwlockattr_getpshared);
+__weak_reference(_pthread_rwlockattr_init, pthread_rwlockattr_init);
+__weak_reference(_pthread_rwlockattr_setpshared, pthread_rwlockattr_setpshared);
+
+int
+_pthread_rwlockattr_destroy(pthread_rwlockattr_t *rwlockattr)
+{
+	pthread_rwlockattr_t prwlockattr;
+
+	if (rwlockattr == NULL)
+		return(EINVAL);
+
+	prwlockattr = *rwlockattr;
+
+	if (prwlockattr == NULL)
+		return(EINVAL);
+
+	free(prwlockattr);
+
+	return(0);
+}
+
+int
+_pthread_rwlockattr_getpshared(const pthread_rwlockattr_t *rwlockattr,
+	int *pshared)
+{
+	*pshared = (*rwlockattr)->pshared;
+
+	return(0);
+}
+
+int
+_pthread_rwlockattr_init(pthread_rwlockattr_t *rwlockattr)
+{
+	pthread_rwlockattr_t prwlockattr;
+
+	if (rwlockattr == NULL)
+		return(EINVAL);
+
+	prwlockattr = (pthread_rwlockattr_t)
+		malloc(sizeof(struct pthread_rwlockattr));
+
+	if (prwlockattr == NULL)
+		return(ENOMEM);
+
+	prwlockattr->pshared 	= PTHREAD_PROCESS_PRIVATE;
+	*rwlockattr		= prwlockattr;
+
+	return(0);
+}
+
+int
+_pthread_rwlockattr_setpshared(pthread_rwlockattr_t *rwlockattr, int pshared)
+{
+	/* Only PTHREAD_PROCESS_PRIVATE is supported. */
+	if (pshared != PTHREAD_PROCESS_PRIVATE)
+		return(EINVAL);
+
+	(*rwlockattr)->pshared = pshared;
+
+	return(0);
+}
+
--- /dev/null
+++ lib/libkse/thread/thr_private.h
@@ -0,0 +1,1324 @@
+/*
+ * Copyright (c) 1995-1998 John Birrell <jb at 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. Neither the name of the author nor the names of any 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/libkse/thread/thr_private.h,v 1.131 2007/10/09 13:42:28 obrien Exp $
+ */
+
+#ifndef _THR_PRIVATE_H
+#define _THR_PRIVATE_H
+
+/*
+ * Include files.
+ */
+#include <setjmp.h>
+#include <signal.h>
+#include <stdio.h>
+#include <sys/queue.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/cdefs.h>
+#include <sys/kse.h>
+#include <sched.h>
+#include <ucontext.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <pthread_np.h>
+
+#ifndef LIBTHREAD_DB
+#include "lock.h"
+#include "pthread_md.h"
+#endif
+
+/*
+ * Unfortunately, libpthread had symbol versioning before libc.
+ * But now libc has symbol versioning, we need to occupy the
+ * same version namespace in order to override some libc functions.
+ * So in order to avoid breaking binaries requiring symbols from
+ * LIBTHREAD_1_0, we need to provide a compatible interface for
+ * those symbols.
+ */
+#if 0
+#define	SYM_LT10(sym)			__CONCAT(sym, _lt10)
+#define	SYM_FB10(sym)			__CONCAT(sym, _fb10)
+#define	SYM_FBP10(sym)			__CONCAT(sym, _fbp10)
+#define	WEAK_REF(sym, alias)		__weak_reference(sym, alias)
+#define	SYM_COMPAT(sym, impl, ver)	__sym_compat(sym, impl, ver)
+#define	SYM_DEFAULT(sym, impl, ver)	__sym_default(sym, impl, ver)
+
+#define	LT10_COMPAT(sym)				\
+	WEAK_REF(sym, SYM_LT10(sym));			\
+	SYM_COMPAT(sym, SYM_LT10(sym), LIBTHREAD_1_0)
+
+#define	LT10_COMPAT_DEFAULT(sym)			\
+	LT10_COMPAT(sym);				\
+	WEAK_REF(sym, SYM_FB10(sym));			\
+	SYM_DEFAULT(sym, SYM_FB10(sym), FBSD_1.0)
+
+#define	LT10_COMPAT_PRIVATE(sym)			\
+	LT10_COMPAT(sym);				\
+	WEAK_REF(sym, SYM_FBP10(sym));			\
+	SYM_DEFAULT(sym, SYM_FBP10(sym), FBSDprivate_1.0)
+#else
+#define	LT10_COMPAT_DEFAULT(sym)
+#define	LT10_COMPAT_PRIVATE(sym)
+#endif
+
+/*
+ * 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
+
+/*
+ * Kernel fatal error handler macro.
+ */
+#define PANIC(string)   _thr_exit(__FILE__, __LINE__, string)
+
+
+/* Output debug messages like this: */
+#ifdef STDOUT_FILENO
+#define stdout_debug(...)	_thread_printf(STDOUT_FILENO, __VA_ARGS__)
+#endif
+#ifdef STDERR_FILENO
+#define stderr_debug(...)	_thread_printf(STDERR_FILENO, __VA_ARGS__)
+#endif
+
+#define	DBG_MUTEX	0x0001
+#define	DBG_SIG		0x0002
+#define	DBG_INFO_DUMP	0x0004
+
+#ifdef _PTHREADS_INVARIANTS
+#define THR_ASSERT(cond, msg) do {	\
+	if (!(cond))			\
+		PANIC(msg);		\
+} while (0)
+#else
+#define THR_ASSERT(cond, msg)
+#endif
+
+/*
+ * State change macro without scheduling queue change:
+ */
+#define THR_SET_STATE(thrd, newstate) do {				\
+	(thrd)->state = newstate;					\
+	(thrd)->fname = __FILE__;					\
+	(thrd)->lineno = __LINE__;					\
+} while (0)
+
+
+#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)
+
+/*
+ * Priority queues.
+ *
+ * XXX It'd be nice if these were contained in uthread_priority_queue.[ch].
+ */
+typedef struct pq_list {
+	TAILQ_HEAD(, pthread)	pl_head; /* list of threads at this priority */
+	TAILQ_ENTRY(pq_list)	pl_link; /* link for queue of priority lists */
+	int			pl_prio; /* the priority of this list */
+	int			pl_queued; /* is this in the priority queue */
+} pq_list_t;
+
+typedef struct pq_queue {
+	TAILQ_HEAD(, pq_list)	 pq_queue; /* queue of priority lists */
+	pq_list_t		*pq_lists; /* array of all priority lists */
+	int			 pq_size;  /* number of priority lists */
+#define	PQF_ACTIVE	0x0001
+	int			 pq_flags;
+	int			 pq_threads;
+} pq_queue_t;
+
+/*
+ * Each KSEG has a scheduling queue.  For now, threads that exist in their
+ * own KSEG (system scope) will get a full priority queue.  In the future
+ * this can be optimized for the single thread per KSEG case.
+ */
+struct sched_queue {
+	pq_queue_t		sq_runq;
+	TAILQ_HEAD(, pthread)	sq_waitq;	/* waiting in userland */
+};
+
+typedef struct kse_thr_mailbox *kse_critical_t;
+
+struct kse_group;
+
+#define	MAX_KSE_LOCKLEVEL	5	
+struct kse {
+	/* -- location and order specific items for gdb -- */
+	struct kcb		*k_kcb;
+	struct pthread		*k_curthread;	/* current thread */
+	struct kse_group	*k_kseg;	/* parent KSEG */
+	struct sched_queue	*k_schedq;	/* scheduling queue */
+	/* -- end of location and order specific items -- */
+	TAILQ_ENTRY(kse)	k_qe;		/* KSE list link entry */
+	TAILQ_ENTRY(kse)	k_kgqe;		/* KSEG's KSE list entry */
+	/*
+	 * Items that are only modified by the kse, or that otherwise
+	 * don't need to be locked when accessed
+	 */
+	struct lock		k_lock;
+	struct lockuser		k_lockusers[MAX_KSE_LOCKLEVEL];
+	int			k_locklevel;
+	stack_t			k_stack;
+	int			k_flags;
+#define	KF_STARTED			0x0001	/* kernel kse created */
+#define	KF_INITIALIZED			0x0002	/* initialized on 1st upcall */
+#define	KF_TERMINATED			0x0004	/* kse is terminated */
+#define	KF_IDLE				0x0008	/* kse is idle */
+#define	KF_SWITCH			0x0010	/* thread switch in UTS */
+	int			k_error;	/* syscall errno in critical */
+	int			k_cpu;		/* CPU ID when bound */
+	int			k_sigseqno;	/* signal buffered count */
+};
+
+#define	KSE_SET_IDLE(kse)	((kse)->k_flags |= KF_IDLE)
+#define	KSE_CLEAR_IDLE(kse)	((kse)->k_flags &= ~KF_IDLE)
+#define	KSE_IS_IDLE(kse)	(((kse)->k_flags & KF_IDLE) != 0)
+#define	KSE_SET_SWITCH(kse)	((kse)->k_flags |= KF_SWITCH)
+#define	KSE_CLEAR_SWITCH(kse)	((kse)->k_flags &= ~KF_SWITCH)
+#define	KSE_IS_SWITCH(kse)	(((kse)->k_flags & KF_SWITCH) != 0)
+
+/*
+ * Each KSE group contains one or more KSEs in which threads can run.
+ * At least for now, there is one scheduling queue per KSE group; KSEs
+ * within the same KSE group compete for threads from the same scheduling
+ * queue.  A scope system thread has one KSE in one KSE group; the group
+ * does not use its scheduling queue.
+ */
+struct kse_group {
+	TAILQ_HEAD(, kse)	kg_kseq;	/* list of KSEs in group */
+	TAILQ_HEAD(, pthread)	kg_threadq;	/* list of threads in group */
+	TAILQ_ENTRY(kse_group)  kg_qe;		/* link entry */
+	struct sched_queue	kg_schedq;	/* scheduling queue */
+	struct lock		kg_lock;
+	int			kg_threadcount;	/* # of assigned threads */
+	int			kg_ksecount;	/* # of assigned KSEs */
+	int			kg_idle_kses;
+	int			kg_flags;
+#define	KGF_SINGLE_THREAD		0x0001	/* scope system kse group */
+#define	KGF_SCHEDQ_INITED		0x0002	/* has an initialized schedq */
+};
+
+/*
+ * Add/remove threads from a KSE's scheduling queue.
+ * For now the scheduling queue is hung off the KSEG.
+ */
+#define	KSEG_THRQ_ADD(kseg, thr)			\
+do {							\
+	TAILQ_INSERT_TAIL(&(kseg)->kg_threadq, thr, kle);\
+	(kseg)->kg_threadcount++;			\
+} while (0)
+
+#define	KSEG_THRQ_REMOVE(kseg, thr)			\
+do {							\
+	TAILQ_REMOVE(&(kseg)->kg_threadq, thr, kle);	\
+	(kseg)->kg_threadcount--;			\
+} while (0)
+
+
+/*
+ * Lock acquire and release for KSEs.
+ */
+#define	KSE_LOCK_ACQUIRE(kse, lck)					\
+do {									\
+	if ((kse)->k_locklevel < MAX_KSE_LOCKLEVEL) {			\
+		(kse)->k_locklevel++;					\
+		_lock_acquire((lck),					\
+		    &(kse)->k_lockusers[(kse)->k_locklevel - 1], 0);	\
+	}								\
+	else 								\
+		PANIC("Exceeded maximum lock level");			\
+} while (0)
+
+#define	KSE_LOCK_RELEASE(kse, lck)					\
+do {									\
+	if ((kse)->k_locklevel > 0) {					\
+		_lock_release((lck),					\
+		    &(kse)->k_lockusers[(kse)->k_locklevel - 1]);	\
+		(kse)->k_locklevel--;					\
+	}								\
+} while (0)
+
+/*
+ * Lock our own KSEG.
+ */
+#define	KSE_LOCK(curkse)		\
+	KSE_LOCK_ACQUIRE(curkse, &(curkse)->k_kseg->kg_lock)
+#define	KSE_UNLOCK(curkse)		\
+	KSE_LOCK_RELEASE(curkse, &(curkse)->k_kseg->kg_lock)
+
+/*
+ * Lock a potentially different KSEG.
+ */
+#define	KSE_SCHED_LOCK(curkse, kseg)	\
+	KSE_LOCK_ACQUIRE(curkse, &(kseg)->kg_lock)
+#define	KSE_SCHED_UNLOCK(curkse, kseg)	\
+	KSE_LOCK_RELEASE(curkse, &(kseg)->kg_lock)
+
+/*
+ * Waiting queue manipulation macros (using pqe link):
+ */
+#define KSE_WAITQ_REMOVE(kse, thrd) \
+do { \
+	if (((thrd)->flags & THR_FLAGS_IN_WAITQ) != 0) { \
+		TAILQ_REMOVE(&(kse)->k_schedq->sq_waitq, thrd, pqe); \
+		(thrd)->flags &= ~THR_FLAGS_IN_WAITQ; \
+	} \
+} while (0)
+#define KSE_WAITQ_INSERT(kse, thrd)	kse_waitq_insert(thrd)
+#define	KSE_WAITQ_FIRST(kse)		TAILQ_FIRST(&(kse)->k_schedq->sq_waitq)
+
+#define	KSE_WAKEUP(kse)		kse_wakeup(&(kse)->k_kcb->kcb_kmbx)
+
+/*
+ * TailQ initialization values.
+ */
+#define TAILQ_INITIALIZER	{ NULL, NULL }
+
+/*
+ * lock initialization values.
+ */
+#define	LCK_INITIALIZER		{ NULL, NULL, LCK_DEFAULT }
+
+struct pthread_mutex {
+	/*
+	 * Lock for accesses to this structure.
+	 */
+	struct lock			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;
+};
+
+/*
+ * Flags for mutexes. 
+ */
+#define MUTEX_FLAGS_PRIVATE	0x01
+#define MUTEX_FLAGS_INITED	0x02
+#define MUTEX_FLAGS_BUSY	0x04
+
+/*
+ * Static mutex initialization values. 
+ */
+#define PTHREAD_MUTEX_STATIC_INITIALIZER				\
+	{ LCK_INITIALIZER, PTHREAD_MUTEX_DEFAULT, PTHREAD_PRIO_NONE,	\
+	TAILQ_INITIALIZER, NULL, MUTEX_FLAGS_PRIVATE, 0, 0, 0, 0,	\
+	TAILQ_INITIALIZER }
+
+struct pthread_mutex_attr {
+	enum pthread_mutextype	m_type;
+	int			m_protocol;
+	int			m_ceiling;
+	long			m_flags;
+};
+
+#define PTHREAD_MUTEXATTR_STATIC_INITIALIZER \
+	{ PTHREAD_MUTEX_DEFAULT, PTHREAD_PRIO_NONE, 0, MUTEX_FLAGS_PRIVATE }
+
+/* 
+ * Condition variable definitions.
+ */
+enum pthread_cond_type {
+	COND_TYPE_FAST,
+	COND_TYPE_MAX
+};
+
+struct pthread_cond {
+	/*
+	 * Lock for accesses to this structure.
+	 */
+	struct lock			c_lock;
+	enum pthread_cond_type		c_type;
+	TAILQ_HEAD(cond_head, pthread)	c_queue;
+	struct pthread_mutex		*c_mutex;
+	long				c_flags;
+	long				c_seqno;
+};
+
+struct pthread_cond_attr {
+	enum pthread_cond_type	c_type;
+	long			c_flags;
+};
+
+struct pthread_barrier {
+	pthread_mutex_t	b_lock;
+	pthread_cond_t	b_cond;
+	int		b_count;
+	int		b_waiters;
+	int		b_generation;
+};
+
+struct pthread_barrierattr {
+	int		pshared;
+};
+
+struct pthread_spinlock {
+	volatile int	s_lock;
+	pthread_t	s_owner;
+};
+
+/*
+ * Flags for condition variables.
+ */
+#define COND_FLAGS_PRIVATE	0x01
+#define COND_FLAGS_INITED	0x02
+#define COND_FLAGS_BUSY		0x04
+
+/*
+ * Static cond initialization values. 
+ */
+#define PTHREAD_COND_STATIC_INITIALIZER				\
+	{ LCK_INITIALIZER, COND_TYPE_FAST, TAILQ_INITIALIZER,	\
+	NULL, NULL, 0, 0 }
+
+/*
+ * Cleanup definitions.
+ */
+struct pthread_cleanup {
+	struct pthread_cleanup	*next;
+	void			(*routine) (void *);
+	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> */
+#define	THR_SIGNAL_THREAD	0x200	/* This is a signal thread */
+	int	flags;
+	void	*arg_attr;
+	void	(*cleanup_attr) (void *);
+	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_STACK32_DEFAULT			(1 * 1024 * 1024)
+#define THR_STACK64_DEFAULT			(2 * 1024 * 1024)
+
+/*
+ * Maximum size of initial thread's stack.  This perhaps deserves to be larger
+ * than the stacks of other threads, since many applications are likely to run
+ * almost entirely on this stack.
+ */
+#define THR_STACK32_INITIAL			(2 * 1024 * 1024)
+#define THR_STACK64_INITIAL			(4 * 1024 * 1024)
+
+/*
+ * 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)
+
+/*
+ * Clock resolution in microseconds.
+ */
+#define CLOCK_RES_USEC				10000
+
+/*
+ * Time slice period in microseconds.
+ */
+#define TIMESLICE_USEC				20000
+
+/*
+ * XXX - Define a thread-safe macro to get the current time of day
+ *       which is updated at regular intervals by something.
+ *
+ * For now, we just make the system call to get the time.
+ */
+#define	KSE_GET_TOD(curkse, tsp) \
+do {							\
+	*tsp = (curkse)->k_kcb->kcb_kmbx.km_timeofday;	\
+	if ((tsp)->tv_sec == 0)				\
+		clock_gettime(CLOCK_REALTIME, tsp);	\
+} while (0)
+
+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_LOCKWAIT,
+	PS_MUTEX_WAIT,
+	PS_COND_WAIT,
+	PS_SLEEP_WAIT,
+	PS_SIGSUSPEND,
+	PS_SIGWAIT,
+	PS_JOIN,
+	PS_SUSPENDED,
+	PS_DEAD,
+	PS_DEADLOCK,
+	PS_STATE_MAX
+};
+
+struct sigwait_data {
+	sigset_t	*waitset;
+	siginfo_t	*siginfo;	/* used to save siginfo for sigwaitinfo() */
+};
+
+union pthread_wait_data {
+	pthread_mutex_t	mutex;
+	pthread_cond_t	cond;
+	struct lock	*lock;
+	struct sigwait_data *sigwait;
+};
+
+/*
+ * Define a continuation routine that can be used to perform a
+ * transfer of control:
+ */
+typedef void	(*thread_continuation_t) (void *);
+
+/*
+ * This stores a thread's state prior to running a signal handler.
+ * It is used when a signal is delivered to a thread blocked in
+ * userland.  If the signal handler returns normally, the thread's
+ * state is restored from here.
+ */
+struct pthread_sigframe {
+	int			psf_valid;
+	int			psf_flags;
+	int			psf_cancelflags;
+	int			psf_interrupted;
+	int			psf_timeout;
+	int			psf_signo;
+	enum pthread_state	psf_state;
+	union pthread_wait_data psf_wait_data;
+	struct timespec		psf_wakeup_time;
+	sigset_t		psf_sigset;
+	sigset_t		psf_sigmask;
+	int			psf_seqno;
+	thread_continuation_t	psf_continuation;
+};
+
+struct join_status {
+	struct pthread	*thread;
+	void		*ret;
+	int		error;
+};
+
+struct pthread_specific_elem {
+	const void	*data;
+	int		seqno;
+};
+
+struct pthread_key {
+	volatile int	allocated;
+	volatile int	count;
+	int		seqno;
+	void            (*destructor) (void *);
+};
+
+#define	MAX_THR_LOCKLEVEL	5	
+/*
+ * Thread structure.
+ */
+struct pthread {
+	/* Thread control block */
+	struct tcb		*tcb;
+
+	/*
+	 * 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 */
+
+	/* Queue entry for list of all threads: */
+	TAILQ_ENTRY(pthread)	tle;	/* link for all threads in process */
+	TAILQ_ENTRY(pthread)	kle;	/* link for all threads in KSE/KSEG */
+
+	/* Queue entry for GC lists: */
+	TAILQ_ENTRY(pthread)	gcle;
+
+	/* Hash queue entry */
+	LIST_ENTRY(pthread)	hle;
+
+	/*
+	 * Lock for accesses to this thread structure.
+	 */
+	struct lock		lock;
+	struct lockuser		lockusers[MAX_THR_LOCKLEVEL];
+	int			locklevel;
+	kse_critical_t		critical[MAX_KSE_LOCKLEVEL];
+	struct kse		*kse;
+	struct kse_group	*kseg;
+
+	/*
+	 * Thread start routine, argument, stack pointer and thread
+	 * attributes.
+	 */
+	void			*(*start_routine)(void *);
+	void			*arg;
+	struct pthread_attr	attr;
+
+	int			active;		/* thread running */
+	int			blocked;	/* thread blocked in kernel */
+	int			need_switchout;
+
+	/*
+	 * Used for tracking delivery of signal handlers.
+	 */
+	siginfo_t		*siginfo;
+	thread_continuation_t	sigbackout;
+
+ 	/*
+	 * Cancelability flags - the lower 2 bits are used by cancel
+	 * definitions in pthread.h
+	 */
+#define THR_AT_CANCEL_POINT		0x0004
+#define THR_CANCELLING			0x0008
+#define THR_CANCEL_NEEDED		0x0010
+	int			cancelflags;
+
+	thread_continuation_t	continuation;
+
+	/*
+	 * The thread's base and pending signal masks.  The active
+	 * signal mask is stored in the thread's context (in mailbox).
+	 */
+	sigset_t		sigmask;
+	sigset_t		sigpend;
+	sigset_t		*oldsigmask;
+	volatile int		check_pending;
+	int			refcount;
+
+	/* Thread state: */
+	enum pthread_state	state;
+	volatile int		lock_switch;
+
+	/*
+	 * Number of microseconds accumulated by this thread when
+	 * time slicing is active.
+	 */
+	long			slice_usec;
+
+	/*
+	 * Time to wake up thread. This is used for sleeping threads and
+	 * for any operation which may time out (such as select).
+	 */
+	struct timespec		wakeup_time;
+
+	/* TRUE if operation has timed out. */
+	int			timeout;
+
+	/*
+	 * Error variable used instead of errno. The function __error()
+	 * returns a pointer to this. 
+	 */
+	int			error;
+
+	/*
+	 * The joiner is the thread that is joining to this thread.  The
+	 * join status keeps track of a join operation to another thread.
+	 */
+	struct pthread		*joiner;
+	struct join_status	join_status;
+
+	/*
+	 * The current thread can belong to only one scheduling queue at
+	 * a time (ready or waiting queue).  It can also belong to:
+	 *
+	 *   o A queue of threads waiting for a mutex
+	 *   o A queue of threads waiting for a condition variable
+	 *
+	 * It is possible for a thread to belong to more than one of the
+	 * above queues if it is handling a signal.  A thread may only
+	 * enter a mutex or condition variable queue when it is not
+	 * being called from a signal handler.  If a thread is a member
+	 * of one of these queues when a signal handler is invoked, it
+	 * must be removed from the queue before invoking the handler
+	 * and then added back to the queue after return from the handler.
+	 *
+	 * Use pqe for the scheduling queue link (both ready and waiting),
+	 * sqe for synchronization (mutex, condition variable, and join)
+	 * queue links, and qe for all other links.
+	 */
+	TAILQ_ENTRY(pthread)	pqe;	/* priority, wait queues link */
+	TAILQ_ENTRY(pthread)	sqe;	/* synchronization queue link */
+
+	/* Wait data. */
+	union pthread_wait_data data;
+
+	/*
+	 * Set to TRUE if a blocking operation was
+	 * interrupted by a signal:
+	 */
+	int			interrupted;
+
+	/*
+	 * Set to non-zero when this thread has entered a critical
+	 * region.  We allow for recursive entries into critical regions.
+	 */
+	int			critical_count;
+
+	/*
+	 * Set to TRUE if this thread should yield after leaving a
+	 * critical region to check for signals, messages, etc.
+	 */
+	int			critical_yield;
+
+	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_IN_WAITQ	0x0002	/* in waiting queue using pqe link */
+#define THR_FLAGS_IN_RUNQ	0x0004	/* in run queue using pqe link */
+#define	THR_FLAGS_EXITING	0x0008	/* thread is exiting */
+#define	THR_FLAGS_SUSPENDED	0x0010	/* thread is suspended */
+
+	/* Thread list flags; only set with thread list lock held. */
+#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 */
+	int			tlflags;
+
+	/*
+	 * 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;
+
+	/* Number rwlocks rdlocks held. */
+	int			rdlock_count;
+
+	/*
+	 * Queue of currently owned mutexes.
+	 */
+	TAILQ_HEAD(, pthread_mutex)	mutexq;
+
+	void				*ret;
+	struct pthread_specific_elem	*specific;
+	int				specific_data_count;
+
+	/* Alternative stack for sigaltstack() */
+	stack_t				sigstk;
+
+	/*
+	 * Current locks bitmap for rtld.
+	 */
+	int	rtld_bits;
+
+	/* Cleanup handlers Link List */
+	struct pthread_cleanup *cleanup;
+	char			*fname;	/* Ptr to source file name  */
+	int			lineno;	/* Source line number.      */
+};
+
+/*
+ * Critical regions can also be detected by looking at the threads
+ * current lock level.  Ensure these macros increment and decrement
+ * the lock levels such that locks can not be held with a lock level
+ * of 0.
+ */
+#define	THR_IN_CRITICAL(thrd)					\
+	(((thrd)->locklevel > 0) ||				\
+	((thrd)->critical_count > 0))
+
+#define	THR_YIELD_CHECK(thrd)					\
+do {								\
+	if (!THR_IN_CRITICAL(thrd)) {				\
+		if (__predict_false(_libkse_debug))		\
+			_thr_debug_check_yield(thrd);		\
+		if ((thrd)->critical_yield != 0)		\
+			_thr_sched_switch(thrd);		\
+		if ((thrd)->check_pending != 0) 		\
+			_thr_sig_check_pending(thrd);		\
+	}							\
+} while (0)
+
+#define	THR_LOCK_ACQUIRE(thrd, lck)				\
+do {								\
+	if ((thrd)->locklevel < MAX_THR_LOCKLEVEL) {		\
+		THR_DEACTIVATE_LAST_LOCK(thrd);			\
+		(thrd)->locklevel++;				\
+		_lock_acquire((lck),				\
+		    &(thrd)->lockusers[(thrd)->locklevel - 1],	\
+		    (thrd)->active_priority);			\
+	} else 							\
+		PANIC("Exceeded maximum lock level");		\
+} while (0)
+
+#define	THR_LOCK_RELEASE(thrd, lck)				\
+do {								\
+	if ((thrd)->locklevel > 0) {				\
+		_lock_release((lck),				\
+		    &(thrd)->lockusers[(thrd)->locklevel - 1]);	\
+		(thrd)->locklevel--;				\
+		THR_ACTIVATE_LAST_LOCK(thrd);			\
+		if ((thrd)->locklevel == 0)			\
+			THR_YIELD_CHECK(thrd);			\
+	}							\
+} while (0)
+
+#define THR_ACTIVATE_LAST_LOCK(thrd)					\
+do {									\
+	if ((thrd)->locklevel > 0)					\
+		_lockuser_setactive(					\
+		    &(thrd)->lockusers[(thrd)->locklevel - 1], 1);	\
+} while (0)
+
+#define	THR_DEACTIVATE_LAST_LOCK(thrd)					\
+do {									\
+	if ((thrd)->locklevel > 0)					\
+		_lockuser_setactive(					\
+		    &(thrd)->lockusers[(thrd)->locklevel - 1], 0);	\
+} while (0)
+
+/*
+ * For now, threads will have their own lock separate from their
+ * KSE scheduling lock.
+ */
+#define	THR_LOCK(thr)			THR_LOCK_ACQUIRE(thr, &(thr)->lock)
+#define	THR_UNLOCK(thr)			THR_LOCK_RELEASE(thr, &(thr)->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)
+
+/*
+ * Priority queue manipulation macros (using pqe link).  We use
+ * the thread's kseg link instead of the kse link because a thread
+ * does not (currently) have a statically assigned kse.
+ */
+#define THR_RUNQ_INSERT_HEAD(thrd)	\
+	_pq_insert_head(&(thrd)->kseg->kg_schedq.sq_runq, thrd)
+#define THR_RUNQ_INSERT_TAIL(thrd)	\
+	_pq_insert_tail(&(thrd)->kseg->kg_schedq.sq_runq, thrd)
+#define THR_RUNQ_REMOVE(thrd)		\
+	_pq_remove(&(thrd)->kseg->kg_schedq.sq_runq, thrd)
+
+/*
+ * 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()	(atomic_load_acq_int(&_gc_count) >= 5)
+
+/*
+ * Locking the scheduling queue for another thread uses that thread's
+ * KSEG lock.
+ */
+#define	THR_SCHED_LOCK(curthr, thr) do {		\
+	(curthr)->critical[(curthr)->locklevel] = _kse_critical_enter(); \
+	(curthr)->locklevel++;				\
+	KSE_SCHED_LOCK((curthr)->kse, (thr)->kseg);	\
+} while (0)
+
+#define	THR_SCHED_UNLOCK(curthr, thr) do {		\
+	KSE_SCHED_UNLOCK((curthr)->kse, (thr)->kseg);	\
+	(curthr)->locklevel--;				\
+	_kse_critical_leave((curthr)->critical[(curthr)->locklevel]); \
+} while (0)
+
+/* Take the scheduling lock with the intent to call the scheduler. */
+#define	THR_LOCK_SWITCH(curthr) do {			\
+	(void)_kse_critical_enter();			\
+	KSE_SCHED_LOCK((curthr)->kse, (curthr)->kseg);	\
+} while (0)
+#define	THR_UNLOCK_SWITCH(curthr) do {			\
+	KSE_SCHED_UNLOCK((curthr)->kse, (curthr)->kseg);\
+} while (0)
+
+#define	THR_CRITICAL_ENTER(thr)		(thr)->critical_count++
+#define	THR_CRITICAL_LEAVE(thr)	do {		\
+	(thr)->critical_count--;		\
+	if (((thr)->critical_yield != 0) &&	\
+	    ((thr)->critical_count == 0)) {	\
+		(thr)->critical_yield = 0;	\
+		_thr_sched_switch(thr);		\
+	}					\
+} while (0)
+
+#define	THR_IS_ACTIVE(thrd) \
+	((thrd)->kse != NULL) && ((thrd)->kse->k_curthread == (thrd))
+
+#define	THR_IN_SYNCQ(thrd)	(((thrd)->sflags & THR_FLAGS_IN_SYNCQ) != 0)
+
+#define	THR_IS_SUSPENDED(thrd) \
+	(((thrd)->state == PS_SUSPENDED) || \
+	(((thrd)->flags & THR_FLAGS_SUSPENDED) != 0))
+#define	THR_IS_EXITING(thrd)	(((thrd)->flags & THR_FLAGS_EXITING) != 0)
+#define DBG_CAN_RUN(thrd) (((thrd)->tcb->tcb_tmbx.tm_dflags & \
+	TMDF_SUSPEND) == 0)
+
+extern int __isthreaded;
+
+static inline int
+_kse_isthreaded(void)
+{
+	return (__isthreaded != 0);
+}
+
+/*
+ * Global variables for the pthread kernel.
+ */
+
+SCLASS void		*_usrstack	SCLASS_PRESET(NULL);
+SCLASS struct kse	*_kse_initial	SCLASS_PRESET(NULL);
+SCLASS struct pthread	*_thr_initial	SCLASS_PRESET(NULL);
+/* For debugger */
+SCLASS int		_libkse_debug		SCLASS_PRESET(0);
+SCLASS int		_thread_activated	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 pthread_mutex_t		_thr_atfork_mutex;
+
+/* Default thread attributes: */
+SCLASS struct pthread_attr _pthread_attr_default
+    SCLASS_PRESET({
+	SCHED_RR, 0, TIMESLICE_USEC, THR_DEFAULT_PRIORITY,
+	THR_CREATE_RUNNING,	PTHREAD_CREATE_JOINABLE, NULL,
+	NULL, NULL, /* stacksize */0, /* guardsize */0
+    });
+
+/* Default mutex attributes: */
+SCLASS struct pthread_mutex_attr _pthread_mutexattr_default
+    SCLASS_PRESET({PTHREAD_MUTEX_DEFAULT, PTHREAD_PRIO_NONE, 0, 0 });
+
+/* Default condition variable attributes: */
+SCLASS struct pthread_cond_attr _pthread_condattr_default
+    SCLASS_PRESET({COND_TYPE_FAST, 0});
+
+/* Clock resolution in usec.	*/
+SCLASS int		_clock_res_usec		SCLASS_PRESET(CLOCK_RES_USEC);
+
+/* Array of signal actions for this process: */
+SCLASS struct sigaction	_thread_sigact[_SIG_MAXSIG];
+
+/*
+ * Lock for above count of dummy handlers and for the process signal
+ * mask and pending signal sets.
+ */
+SCLASS struct lock	_thread_signal_lock;
+
+/* Pending signals and mask for this process: */
+SCLASS sigset_t		_thr_proc_sigpending;
+SCLASS siginfo_t	_thr_proc_siginfo[_SIG_MAXSIG];
+
+SCLASS pid_t		_thr_pid		SCLASS_PRESET(0);
+
+/* Garbage collector lock. */
+SCLASS struct lock	_gc_lock;
+SCLASS int		_gc_check		SCLASS_PRESET(0);
+SCLASS int		_gc_count		SCLASS_PRESET(0);
+
+SCLASS struct lock	_mutex_static_lock;
+SCLASS struct lock	_rwlock_static_lock;
+SCLASS struct lock	_keytable_lock;
+SCLASS struct lock	_thread_list_lock;
+SCLASS int		_thr_guard_default;
+SCLASS int		_thr_stack_default;
+SCLASS int		_thr_stack_initial;
+SCLASS int		_thr_page_size;
+SCLASS pthread_t	_thr_sig_daemon;
+SCLASS int		_thr_debug_flags	SCLASS_PRESET(0);
+
+/* Undefine the storage class and preset specifiers: */
+#undef  SCLASS
+#undef	SCLASS_PRESET
+
+
+/*
+ * Function prototype definitions.
+ */
+__BEGIN_DECLS
+int	_cond_reinit(pthread_cond_t *);
+struct kse *_kse_alloc(struct pthread *, int sys_scope);
+kse_critical_t _kse_critical_enter(void);
+void	_kse_critical_leave(kse_critical_t);
+int	_kse_in_critical(void);
+void	_kse_free(struct pthread *, struct kse *);
+void	_kse_init(void);
+struct kse_group *_kseg_alloc(struct pthread *);
+void	_kse_lock_wait(struct lock *, struct lockuser *lu);
+void	_kse_lock_wakeup(struct lock *, struct lockuser *lu);
+void	_kse_single_thread(struct pthread *);
+int	_kse_setthreaded(int);
+void	_kseg_free(struct kse_group *);
+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(struct pthread_mutex *);
+void	_mutex_unlock_private(struct pthread *);
+void	_libpthread_init(struct pthread *);
+int	_pq_alloc(struct pq_queue *, int, int);
+void	_pq_free(struct pq_queue *);
+int	_pq_init(struct pq_queue *);
+void	_pq_remove(struct pq_queue *pq, struct pthread *);
+void	_pq_insert_head(struct pq_queue *pq, struct pthread *);
+void	_pq_insert_tail(struct pq_queue *pq, struct pthread *);
+struct pthread *_pq_first(struct pq_queue *pq);
+struct pthread *_pq_first_debug(struct pq_queue *pq);
+void	*_pthread_getspecific(pthread_key_t);
+int	_pthread_key_create(pthread_key_t *, void (*) (void *));
+int	_pthread_key_delete(pthread_key_t);
+int	_pthread_mutex_destroy(pthread_mutex_t *);
+int	_pthread_mutex_init(pthread_mutex_t *, const pthread_mutexattr_t *);
+int	_pthread_mutex_lock(pthread_mutex_t *);
+int	_pthread_mutex_trylock(pthread_mutex_t *);
+int	_pthread_mutex_unlock(pthread_mutex_t *);
+int	_pthread_mutexattr_init(pthread_mutexattr_t *);
+int	_pthread_mutexattr_destroy(pthread_mutexattr_t *);
+int	_pthread_mutexattr_settype(pthread_mutexattr_t *, int);
+int	_pthread_once(pthread_once_t *, void (*) (void));
+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_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	_thr_exit(char *, int, char *);
+void	_thr_exit_cleanup(void);
+void	_thr_lock_wait(struct lock *lock, struct lockuser *lu);
+void	_thr_lock_wakeup(struct lock *lock, struct lockuser *lu);
+void	_thr_mutex_reinit(pthread_mutex_t *);
+int	_thr_ref_add(struct pthread *, struct pthread *, int);
+void	_thr_ref_delete(struct pthread *, struct pthread *);
+void	_thr_rtld_init(void);
+void	_thr_rtld_fini(void);
+int	_thr_schedule_add(struct pthread *, struct pthread *);
+void	_thr_schedule_remove(struct pthread *, struct pthread *);
+void	_thr_setrunnable(struct pthread *curthread, struct pthread *thread);
+struct kse_mailbox *_thr_setrunnable_unlocked(struct pthread *thread);
+struct kse_mailbox *_thr_sig_add(struct pthread *, int, siginfo_t *);
+void	_thr_sig_dispatch(struct kse *, int, siginfo_t *);
+int	_thr_stack_alloc(struct pthread_attr *);
+void	_thr_stack_free(struct pthread_attr *);
+void    _thr_exit_cleanup(void);
+void	_thr_free(struct pthread *, struct pthread *);
+void	_thr_gc(struct pthread *);
+void    _thr_panic_exit(char *, int, char *);
+void    _thread_cleanupspecific(void);
+void    _thread_dump_info(void);
+void	_thread_printf(int, const char *, ...);
+void	_thr_sched_switch(struct pthread *);
+void	_thr_sched_switch_unlocked(struct pthread *);
+void    _thr_set_timeout(const struct timespec *);
+void	_thr_seterrno(struct pthread *, int);
+void    _thr_sig_handler(int, siginfo_t *, ucontext_t *);
+void    _thr_sig_check_pending(struct pthread *);
+void	_thr_sig_rundown(struct pthread *, ucontext_t *);
+void	_thr_sig_send(struct pthread *pthread, int sig);
+void	_thr_sigframe_restore(struct pthread *thread, struct pthread_sigframe *psf);
+void	_thr_spinlock_init(void);
+void	_thr_cancel_enter(struct pthread *);
+void	_thr_cancel_leave(struct pthread *, int);
+int	_thr_setconcurrency(int new_level);
+int	_thr_setmaxconcurrency(void);
+void	_thr_critical_enter(struct pthread *);
+void	_thr_critical_leave(struct pthread *);
+int	_thr_start_sig_daemon(void);
+int	_thr_getprocsig(int sig, siginfo_t *siginfo);
+int	_thr_getprocsig_unlocked(int sig, siginfo_t *siginfo);
+void	_thr_signal_init(void);
+void	_thr_signal_deinit(void);
+void	_thr_hash_add(struct pthread *);
+void	_thr_hash_remove(struct pthread *);
+struct pthread *_thr_hash_find(struct pthread *);
+void	_thr_finish_cancellation(void *arg);
+int	_thr_sigonstack(void *sp);
+void	_thr_debug_check_yield(struct pthread *);
+
+/*
+ * 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);
+int	__sys_sendfile(int, int, off_t, size_t, struct sf_hdtr *,
+	    off_t *, int);
+#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(sigset_t *, siginfo_t *, struct timespec *);
+#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_dump_enabled(void)
+{
+
+	return ((_thr_debug_flags & DBG_INFO_DUMP) != 0);
+}
+
+#endif  /* !_THR_PRIVATE_H */
--- /dev/null
+++ lib/libkse/thread/thr_once.c
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 1995 John Birrell <jb at 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. Neither the name of the author nor the names of any 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/libkse/thread/thr_once.c,v 1.13 2007/10/09 13:42:28 obrien Exp $
+ */
+#include "namespace.h"
+#include <pthread.h>
+#include "un-namespace.h"
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_once);
+LT10_COMPAT_DEFAULT(pthread_once);
+
+__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))
+{
+	struct pthread *curthread;
+	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);
+		curthread = _get_curthread();
+		THR_CLEANUP_PUSH(curthread, once_cancel_handler, once_control);
+		init_routine();
+		THR_CLEANUP_POP(curthread, 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);
+}
+
--- /dev/null
+++ lib/libkse/thread/thr_connect.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2003 Daniel Eischen <deischen at 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/lib/libkse/thread/thr_connect.c,v 1.4 2007/10/09 13:42:27 obrien Exp $");
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(__connect);
+LT10_COMPAT_DEFAULT(connect);
+
+__weak_reference(__connect, connect);
+
+int
+__connect(int fd, const struct sockaddr *name, socklen_t namelen)
+{
+	struct pthread *curthread;
+	int ret;
+
+	curthread = _get_curthread();
+	_thr_cancel_enter(curthread);
+	ret = __sys_connect(fd, name, namelen);
+	_thr_cancel_leave(curthread, ret == -1);
+
+ 	return (ret);
+}
--- /dev/null
+++ lib/libkse/thread/thr_poll.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 1999 Daniel Eischen <eischen at 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/libkse/thread/thr_poll.c,v 1.18 2007/10/09 13:42:28 obrien Exp $
+ */
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <poll.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/fcntl.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(__poll);
+LT10_COMPAT_DEFAULT(poll);
+
+__weak_reference(__poll, poll);
+
+int
+__poll(struct pollfd *fds, unsigned int nfds, int timeout)
+{
+	struct pthread *curthread = _get_curthread();
+	int ret;
+
+	_thr_cancel_enter(curthread);
+	ret = __sys_poll(fds, nfds, timeout);
+	_thr_cancel_leave(curthread, 1);
+
+	return ret;
+}
--- /dev/null
+++ lib/libkse/thread/thr_attr_setstackaddr.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 1997 John Birrell <jb at 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. Neither the name of the author nor the names of any 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/libkse/thread/thr_attr_setstackaddr.c,v 1.10 2007/10/09 13:42:27 obrien Exp $
+ */
+#include <errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_attr_setstackaddr);
+LT10_COMPAT_DEFAULT(pthread_attr_setstackaddr);
+
+__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);
+}
--- /dev/null
+++ lib/libkse/thread/thr_equal.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 1995 John Birrell <jb at 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. Neither the name of the author nor the names of any 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/libkse/thread/thr_equal.c,v 1.9 2007/10/09 13:42:27 obrien Exp $
+ */
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_equal);
+LT10_COMPAT_DEFAULT(pthread_equal);
+
+__weak_reference(_pthread_equal, pthread_equal);
+
+int
+_pthread_equal(pthread_t t1, pthread_t t2)
+{
+	/* Compare the two thread pointers: */
+	return (t1 == t2);
+}
--- /dev/null
+++ lib/libkse/thread/thr_waitpid.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2000 Jason Evans <jasone at 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/libkse/thread/thr_waitpid.c,v 1.10 2007/10/09 13:42:30 obrien Exp $
+ */
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_waitpid);
+LT10_COMPAT_DEFAULT(waitpid);
+
+extern int __waitpid(pid_t, int *, int);
+
+__weak_reference(_waitpid, waitpid);
+
+pid_t
+_waitpid(pid_t wpid, int *status, int options)
+{
+	struct pthread *curthread = _get_curthread();
+	pid_t	ret;
+
+	_thr_cancel_enter(curthread);
+	ret = __waitpid(wpid, status, options);
+	_thr_cancel_leave(curthread, 1);
+	
+	return ret;
+}
--- /dev/null
+++ lib/libkse/thread/thr_spinlock.c
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 1997 John Birrell <jb at 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. Neither the name of the author nor the names of any 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/libkse/thread/thr_spinlock.c,v 1.26 2007/10/09 13:42:29 obrien Exp $
+ *
+ */
+
+#include <sys/types.h>
+#include <machine/atomic.h>
+
+#include <libc_private.h>
+#include "spinlock.h"
+#include "thr_private.h"
+
+#define	MAX_SPINLOCKS	72
+
+struct spinlock_extra {
+	spinlock_t	*owner;
+	pthread_mutex_t	lock;
+};
+
+static void	init_spinlock(spinlock_t *lck);
+
+static struct pthread_mutex_attr static_mutex_attr =
+    PTHREAD_MUTEXATTR_STATIC_INITIALIZER;
+static pthread_mutexattr_t	static_mattr = &static_mutex_attr;
+
+static pthread_mutex_t		spinlock_static_lock;
+static struct spinlock_extra	extra[MAX_SPINLOCKS];
+static int			spinlock_count = 0;
+static int			initialized = 0;
+
+LT10_COMPAT_PRIVATE(_spinlock);
+LT10_COMPAT_PRIVATE(_spinlock_debug);
+LT10_COMPAT_PRIVATE(_spinunlock);
+
+/*
+ * These are for compatability only.  Spinlocks of this type
+ * are deprecated.
+ */
+
+void
+_spinunlock(spinlock_t *lck)
+{
+	struct spinlock_extra *extra;
+
+	extra = (struct spinlock_extra *)lck->fname;
+	_pthread_mutex_unlock(&extra->lock);
+}
+
+/*
+ * Lock a location for the running thread. Yield to allow other
+ * threads to run if this thread is blocked because the lock is
+ * not available. Note that this function does not sleep. It
+ * assumes that the lock will be available very soon.
+ */
+void
+_spinlock(spinlock_t *lck)
+{
+	struct spinlock_extra *extra;
+
+	if (!__isthreaded)
+		PANIC("Spinlock called when not threaded.");
+	if (!initialized)
+		PANIC("Spinlocks not initialized.");
+	/*
+	 * Try to grab the lock and loop if another thread grabs
+	 * it before we do.
+	 */
+	if (lck->fname == NULL)
+		init_spinlock(lck);
+	extra = (struct spinlock_extra *)lck->fname;
+	_pthread_mutex_lock(&extra->lock);
+}
+
+/*
+ * Lock a location for the running thread. Yield to allow other
+ * threads to run if this thread is blocked because the lock is
+ * not available. Note that this function does not sleep. It
+ * assumes that the lock will be available very soon.
+ *
+ * This function checks if the running thread has already locked the
+ * location, warns if this occurs and creates a thread dump before
+ * returning.
+ */
+void
+_spinlock_debug(spinlock_t *lck, char *fname, int lineno)
+{
+	_spinlock(lck);
+}
+
+static void
+init_spinlock(spinlock_t *lck)
+{
+	_pthread_mutex_lock(&spinlock_static_lock);
+	if ((lck->fname == NULL) && (spinlock_count < MAX_SPINLOCKS)) {
+		lck->fname = (char *)&extra[spinlock_count];
+		extra[spinlock_count].owner = lck;
+		spinlock_count++;
+	}
+	_pthread_mutex_unlock(&spinlock_static_lock);
+	if (lck->fname == NULL)
+		PANIC("Exceeded max spinlocks");
+}
+
+void
+_thr_spinlock_init(void)
+{
+	int i;
+
+	if (initialized != 0) {
+		_thr_mutex_reinit(&spinlock_static_lock);
+		for (i = 0; i < spinlock_count; i++)
+			_thr_mutex_reinit(&extra[i].lock);
+	} else {
+		if (_pthread_mutex_init(&spinlock_static_lock, &static_mattr))
+			PANIC("Cannot initialize spinlock_static_lock");
+		for (i = 0; i < MAX_SPINLOCKS; i++) {
+			if (_pthread_mutex_init(&extra[i].lock, &static_mattr))
+				PANIC("Cannot initialize spinlock extra");
+		}
+		initialized = 1;
+	}
+}
--- /dev/null
+++ lib/libkse/thread/thr_barrierattr.c
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2003 David Xu <davidxu at 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/libkse/thread/thr_barrierattr.c,v 1.3 2007/10/09 13:42:27 obrien Exp $
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_barrierattr_destroy);
+LT10_COMPAT_DEFAULT(pthread_barrierattr_destroy);
+LT10_COMPAT_PRIVATE(_pthread_barrierattr_init);
+LT10_COMPAT_DEFAULT(pthread_barrierattr_init);
+LT10_COMPAT_PRIVATE(_pthread_barrierattr_setpshared);
+LT10_COMPAT_DEFAULT(pthread_barrierattr_setpshared);
+LT10_COMPAT_PRIVATE(_pthread_barrierattr_getpshared);
+LT10_COMPAT_DEFAULT(pthread_barrierattr_getpshared);
+
+__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);
+}
--- /dev/null
+++ lib/libkse/thread/Makefile.inc
@@ -0,0 +1,117 @@
+# $FreeBSD: src/lib/libkse/thread/Makefile.inc,v 1.51 2007/10/09 13:42:27 obrien Exp $
+
+# thr sources
+.PATH: ${.CURDIR}/thread
+
+SRCS+= \
+	thr_accept.c \
+	thr_aio_suspend.c \
+	thr_atfork.c \
+	thr_attr_destroy.c \
+	thr_attr_init.c \
+	thr_attr_get_np.c \
+	thr_attr_getdetachstate.c \
+	thr_attr_getguardsize.c \
+	thr_attr_getinheritsched.c \
+	thr_attr_getschedparam.c \
+	thr_attr_getschedpolicy.c \
+	thr_attr_getscope.c \
+	thr_attr_getstack.c \
+	thr_attr_getstackaddr.c \
+	thr_attr_getstacksize.c \
+	thr_attr_setcreatesuspend_np.c \
+	thr_attr_setdetachstate.c \
+	thr_attr_setguardsize.c \
+	thr_attr_setinheritsched.c \
+	thr_attr_setschedparam.c \
+	thr_attr_setschedpolicy.c \
+	thr_attr_setscope.c \
+	thr_attr_setstack.c \
+	thr_attr_setstackaddr.c \
+	thr_attr_setstacksize.c \
+	thr_autoinit.c \
+	thr_barrier.c \
+	thr_barrierattr.c \
+	thr_cancel.c \
+	thr_clean.c \
+	thr_close.c \
+	thr_concurrency.c \
+	thr_cond.c \
+	thr_condattr_destroy.c \
+	thr_condattr_init.c \
+	thr_condattr_pshared.c \
+	thr_connect.c \
+	thr_creat.c \
+	thr_create.c \
+	thr_detach.c \
+	thr_equal.c \
+	thr_execve.c \
+	thr_exit.c \
+	thr_fcntl.c \
+	thr_find_thread.c \
+	thr_fork.c \
+	thr_fsync.c \
+	thr_getprio.c \
+	thr_getschedparam.c \
+	thr_info.c \
+	thr_init.c \
+	thr_join.c \
+	thr_kern.c \
+	thr_kill.c \
+	thr_main_np.c \
+	thr_mattr_init.c \
+	thr_mattr_kind_np.c \
+	thr_mattr_pshared.c \
+	thr_msync.c \
+	thr_multi_np.c \
+	thr_mutex.c \
+	thr_mutex_prioceiling.c \
+	thr_mutex_protocol.c \
+	thr_mutexattr_destroy.c \
+	thr_nanosleep.c \
+	thr_once.c \
+	thr_open.c \
+	thr_pause.c \
+	thr_poll.c \
+	thr_printf.c \
+	thr_priority_queue.c \
+	thr_pselect.c \
+	thr_pspinlock.c \
+	thr_raise.c \
+	thr_read.c \
+	thr_readv.c \
+	thr_resume_np.c \
+	thr_rtld.c \
+	thr_rwlock.c \
+	thr_rwlockattr.c \
+	thr_select.c \
+	thr_self.c \
+	thr_sem.c \
+	thr_seterrno.c \
+	thr_setprio.c \
+	thr_setschedparam.c \
+	thr_sig.c \
+	thr_sigaction.c \
+	thr_sigaltstack.c \
+	thr_sigmask.c \
+	thr_sigpending.c \
+	thr_sigprocmask.c \
+	thr_sigsuspend.c \
+	thr_sigwait.c \
+	thr_single_np.c \
+	thr_sleep.c \
+	thr_spec.c \
+	thr_spinlock.c \
+	thr_stack.c \
+	thr_suspend_np.c \
+	thr_switch_np.c \
+	thr_system.c \
+	thr_symbols.c \
+	thr_tcdrain.c \
+	thr_vfork.c \
+	thr_wait.c \
+	thr_wait4.c \
+	thr_waitpid.c \
+	thr_write.c \
+	thr_writev.c \
+	thr_yield.c
--- /dev/null
+++ lib/libkse/thread/thr_cancel.c
@@ -0,0 +1,311 @@
+/*
+ * David Leonard <d at openbsd.org>, 1999. Public domain.
+ * $FreeBSD: src/lib/libkse/thread/thr_cancel.c,v 1.34 2007/10/09 13:42:27 obrien Exp $
+ */
+#include <sys/errno.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_cancel);
+LT10_COMPAT_DEFAULT(pthread_cancel);
+LT10_COMPAT_PRIVATE(_pthread_setcancelstate);
+LT10_COMPAT_DEFAULT(pthread_setcancelstate);
+LT10_COMPAT_PRIVATE(_pthread_setcanceltype);
+LT10_COMPAT_DEFAULT(pthread_setcanceltype);
+LT10_COMPAT_PRIVATE(_pthread_testcancel);
+LT10_COMPAT_DEFAULT(pthread_testcancel);
+
+__weak_reference(_pthread_cancel, pthread_cancel);
+__weak_reference(_pthread_setcancelstate, pthread_setcancelstate);
+__weak_reference(_pthread_setcanceltype, pthread_setcanceltype);
+__weak_reference(_pthread_testcancel, pthread_testcancel);
+
+static inline int
+checkcancel(struct pthread *curthread)
+{
+	if ((curthread->cancelflags & THR_CANCELLING) != 0) {
+		/*
+		 * It is possible for this thread to be swapped out
+		 * while performing cancellation; do not allow it
+		 * to be cancelled again.
+		 */
+		if ((curthread->flags & THR_FLAGS_EXITING) != 0) {
+			/*
+			 * This may happen once, but after this, it
+			 * shouldn't happen again.
+			 */
+			curthread->cancelflags &= ~THR_CANCELLING;
+			return (0);
+		}
+		if ((curthread->cancelflags & PTHREAD_CANCEL_DISABLE) == 0) {
+			curthread->cancelflags &= ~THR_CANCELLING;
+			return (1);
+		}
+	}
+	return (0);
+}
+
+static inline void
+testcancel(struct pthread *curthread)
+{
+	if (checkcancel(curthread) != 0) {
+		/* Unlock before exiting: */
+		THR_THREAD_UNLOCK(curthread, curthread);
+
+		_thr_exit_cleanup();
+		pthread_exit(PTHREAD_CANCELED);
+		PANIC("cancel");
+	}
+}
+
+int
+_pthread_cancel(pthread_t pthread)
+{
+	struct pthread *curthread = _get_curthread();
+	struct pthread *joinee = NULL;
+	struct kse_mailbox *kmbx = NULL;
+	int ret;
+
+	if ((ret = _thr_ref_add(curthread, pthread, /*include dead*/0)) == 0) {
+		/*
+		 * Take the thread's lock while we change the cancel flags.
+		 */
+		THR_THREAD_LOCK(curthread, pthread);
+		THR_SCHED_LOCK(curthread, pthread);
+		if (pthread->flags & THR_FLAGS_EXITING) {
+			THR_SCHED_UNLOCK(curthread, pthread);
+			THR_THREAD_UNLOCK(curthread, pthread);
+			_thr_ref_delete(curthread, pthread);
+			return (ESRCH);
+		}
+		if (((pthread->cancelflags & PTHREAD_CANCEL_DISABLE) != 0) ||
+		    (((pthread->cancelflags & THR_AT_CANCEL_POINT) == 0) &&
+		    ((pthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS) == 0)))
+			/* Just mark it for cancellation: */
+			pthread->cancelflags |= THR_CANCELLING;
+		else {
+			/*
+			 * Check if we need to kick it back into the
+			 * run queue:
+			 */
+			switch (pthread->state) {
+			case PS_RUNNING:
+				/* No need to resume: */
+				pthread->cancelflags |= THR_CANCELLING;
+				break;
+
+			case PS_LOCKWAIT:
+				/*
+				 * These can't be removed from the queue.
+				 * Just mark it as cancelling and tell it
+				 * to yield once it leaves the critical
+				 * region.
+				 */
+				pthread->cancelflags |= THR_CANCELLING;
+				pthread->critical_yield = 1;
+				break;
+
+			case PS_SLEEP_WAIT:
+			case PS_SIGSUSPEND:
+			case PS_SIGWAIT:
+				/* Interrupt and resume: */
+				pthread->interrupted = 1;
+				pthread->cancelflags |= THR_CANCELLING;
+				kmbx = _thr_setrunnable_unlocked(pthread);
+				break;
+
+			case PS_JOIN:
+				/* Disconnect the thread from the joinee: */
+				joinee = pthread->join_status.thread;
+				pthread->join_status.thread = NULL;
+				pthread->cancelflags |= THR_CANCELLING;
+				kmbx = _thr_setrunnable_unlocked(pthread);
+				if ((joinee != NULL) &&
+				    (pthread->kseg == joinee->kseg)) {
+					/* Remove the joiner from the joinee. */
+					joinee->joiner = NULL;
+					joinee = NULL;
+				}
+				break;
+
+			case PS_SUSPENDED:
+			case PS_MUTEX_WAIT:
+			case PS_COND_WAIT:
+				/*
+				 * Threads in these states may be in queues.
+				 * In order to preserve queue integrity, the
+				 * cancelled thread must remove itself from the
+				 * queue.  Mark the thread as interrupted and
+				 * needing cancellation, and set the state to
+				 * running.  When the thread resumes, it will
+				 * remove itself from the queue and call the
+				 * cancellation completion routine.
+				 */
+				pthread->interrupted = 1;
+				pthread->cancelflags |= THR_CANCEL_NEEDED;
+				kmbx = _thr_setrunnable_unlocked(pthread);
+				pthread->continuation =
+					_thr_finish_cancellation;
+				break;
+
+			case PS_DEAD:
+			case PS_DEADLOCK:
+			case PS_STATE_MAX:
+				/* Ignore - only here to silence -Wall: */
+				break;
+			}
+			if ((pthread->cancelflags & THR_AT_CANCEL_POINT) &&
+			    (pthread->blocked != 0 ||
+			     pthread->attr.flags & PTHREAD_SCOPE_SYSTEM))
+				kse_thr_interrupt(&pthread->tcb->tcb_tmbx,
+					KSE_INTR_INTERRUPT, 0);
+		}
+
+		/*
+		 * Release the thread's lock and remove the
+		 * reference:
+		 */
+		THR_SCHED_UNLOCK(curthread, pthread);
+		THR_THREAD_UNLOCK(curthread, pthread);
+		_thr_ref_delete(curthread, pthread);
+		if (kmbx != NULL)
+			kse_wakeup(kmbx);
+
+		if ((joinee != NULL) &&
+		    (_thr_ref_add(curthread, joinee, /* include dead */1) == 0)) {
+			/* Remove the joiner from the joinee. */
+			THR_SCHED_LOCK(curthread, joinee);
+			joinee->joiner = NULL;
+			THR_SCHED_UNLOCK(curthread, joinee);
+			_thr_ref_delete(curthread, joinee);
+		}
+	}
+	return (ret);
+}
+
+int
+_pthread_setcancelstate(int state, int *oldstate)
+{
+	struct pthread	*curthread = _get_curthread();
+	int ostate;
+	int ret;
+	int need_exit = 0;
+
+	/* Take the thread's lock while fiddling with the state: */
+	THR_THREAD_LOCK(curthread, curthread);
+
+	ostate = curthread->cancelflags & PTHREAD_CANCEL_DISABLE;
+
+	switch (state) {
+	case PTHREAD_CANCEL_ENABLE:
+		curthread->cancelflags &= ~PTHREAD_CANCEL_DISABLE;
+		if ((curthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS) != 0)
+			need_exit = checkcancel(curthread);
+		ret = 0;
+		break;
+	case PTHREAD_CANCEL_DISABLE:
+		curthread->cancelflags |= PTHREAD_CANCEL_DISABLE;
+		ret = 0;
+		break;
+	default:
+		ret = EINVAL;
+	}
+
+	THR_THREAD_UNLOCK(curthread, curthread);
+	if (need_exit != 0) {
+		_thr_exit_cleanup();
+		pthread_exit(PTHREAD_CANCELED);
+		PANIC("cancel");
+	}
+	if (ret == 0 && oldstate != NULL)
+		*oldstate = ostate;
+
+	return (ret);
+}
+
+int
+_pthread_setcanceltype(int type, int *oldtype)
+{
+	struct pthread	*curthread = _get_curthread();
+	int otype;
+	int ret;
+	int need_exit = 0;
+
+	/* Take the thread's lock while fiddling with the state: */
+	THR_THREAD_LOCK(curthread, curthread);
+
+	otype = curthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS;
+	switch (type) {
+	case PTHREAD_CANCEL_ASYNCHRONOUS:
+		curthread->cancelflags |= PTHREAD_CANCEL_ASYNCHRONOUS;
+		need_exit = checkcancel(curthread);
+		ret = 0;
+		break;
+	case PTHREAD_CANCEL_DEFERRED:
+		curthread->cancelflags &= ~PTHREAD_CANCEL_ASYNCHRONOUS;
+		ret = 0;
+		break;
+	default:
+		ret = EINVAL;
+	}
+
+	THR_THREAD_UNLOCK(curthread, curthread);
+	if (need_exit != 0) {
+		_thr_exit_cleanup();
+		pthread_exit(PTHREAD_CANCELED);
+		PANIC("cancel");
+	}
+	if (ret == 0 && oldtype != NULL)
+		*oldtype = otype;
+
+	return (ret);
+}
+
+void
+_pthread_testcancel(void)
+{
+	struct pthread	*curthread = _get_curthread();
+
+	THR_THREAD_LOCK(curthread, curthread);
+	testcancel(curthread);
+	THR_THREAD_UNLOCK(curthread, curthread);
+}
+
+void
+_thr_cancel_enter(struct pthread *thread)
+{
+	/* Look for a cancellation before we block: */
+	THR_THREAD_LOCK(thread, thread);
+	testcancel(thread);
+	thread->cancelflags |= THR_AT_CANCEL_POINT;
+	THR_THREAD_UNLOCK(thread, thread);
+}
+
+void
+_thr_cancel_leave(struct pthread *thread, int check)
+{
+	THR_THREAD_LOCK(thread, thread);
+	thread->cancelflags &= ~THR_AT_CANCEL_POINT;
+	/* Look for a cancellation after we unblock: */
+	if (check)
+		testcancel(thread);
+	THR_THREAD_UNLOCK(thread, thread);
+}
+
+void
+_thr_finish_cancellation(void *arg)
+{
+	struct pthread	*curthread = _get_curthread();
+
+	curthread->continuation = NULL;
+	curthread->interrupted = 0;
+
+	THR_THREAD_LOCK(curthread, curthread);
+	if ((curthread->cancelflags & THR_CANCEL_NEEDED) != 0) {
+		curthread->cancelflags &= ~THR_CANCEL_NEEDED;
+		THR_THREAD_UNLOCK(curthread, curthread);
+		_thr_exit_cleanup();
+		pthread_exit(PTHREAD_CANCELED);
+	}
+	THR_THREAD_UNLOCK(curthread, curthread);
+}
--- /dev/null
+++ lib/libkse/thread/thr_clean.c
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 1995 John Birrell <jb at 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. Neither the name of the author nor the names of any 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/libkse/thread/thr_clean.c,v 1.12 2007/10/09 13:42:27 obrien Exp $
+ */
+#include <signal.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+LT10_COMPAT_PRIVATE(_pthread_cleanup_push);
+LT10_COMPAT_DEFAULT(pthread_cleanup_push);
+LT10_COMPAT_PRIVATE(_pthread_cleanup_pop);
+LT10_COMPAT_DEFAULT(pthread_cleanup_pop);
+
+__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);
+	}
+}
--- lib/libncurses/termcap.c
+++ /dev/null
@@ -1,267 +0,0 @@
-/* A portion of this file is from ncurses: */
-/***************************************************************************
-*                            COPYRIGHT NOTICE                              *
-****************************************************************************
-*                ncurses is copyright (C) 1992-1995                        *
-*                          Zeyd M. Ben-Halim                               *
-*                          zmbenhal at netcom.com                             *
-*                          Eric S. Raymond                                 *
-*                          esr at snark.thyrsus.com                           *
-*                                                                          *
-*        Permission is hereby granted to reproduce and distribute ncurses  *
-*        by any means and for any fee, whether alone or as part of a       *
-*        larger distribution, in source or in binary form, PROVIDED        *
-*        this notice is included with any such distribution, and is not    *
-*        removed from any of its header files. Mention of ncurses in any   *
-*        applications linked with it is highly appreciated.                *
-*                                                                          *
-*        ncurses comes AS IS with no warranty, implied or expressed.       *
-*                                                                          *
-***************************************************************************/
-
-#include <curses.priv.h>
-
-#include <string.h>
-#include <term.h>
-#include <tic.h>
-#include <term_entry.h>
-
-/* The rest is from BSD */
-/*
- * Copyright (c) 1980, 1993
- *	The Regents of the University of California.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *	This product includes software developed by the University of
- *	California, Berkeley and its contributors.
- * 4. Neither the name of the University 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 REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED 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.
- */
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/lib/libncurses/termcap.c,v 1.6 2002/08/12 19:13:22 ru Exp $");
-
-#ifndef lint
-static const char sccsid[] = "@(#)termcap.c	8.1 (Berkeley) 6/4/93";
-#endif /* not lint */
-
-#include <stdio.h>
-#include <ctype.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/param.h>
-#include "pathnames.h"
-
-#define	PBUFSIZ	MAXPATHLEN	/* max length of filename path */
-#define	PVECSIZ	32		/* max number of names in path */
-#define	TBUFSIZ 1024		/* max length of _nc_tgetent buffer */
-
-char _nc_termcap[TBUFSIZ + 1]; /* Last getcap, provided to tgetent() emul */
-
-/*
- * termcap - routines for dealing with the terminal capability data base
- *
- * BUG:		Should use a "last" pointer in tbuf, so that searching
- *		for capabilities alphabetically would not be a n**2/2
- *		process when large numbers of capabilities are given.
- * Note:	If we add a last pointer now we will screw up the
- *		tc capability. We really should compile termcap.
- *
- * Essentially all the work here is scanning and decoding escapes
- * in string capabilities.  We don't use stdio because the editor
- * doesn't, and because living w/o it is not hard.
- */
-
-/*
- * Get an entry for terminal name in buffer _nc_termcap from the termcap
- * file.
- */
-int
-_nc_read_termcap_entry(const char *const name, TERMTYPE *const tp)
-{
-	ENTRY	*ep;
-	char *p;
-	char *cp;
-	char  *dummy;
-	char **fname;
-	char  *home;
-	int    i;
-	char   pathbuf[PBUFSIZ];	/* holds raw path of filenames */
-	char  *pathvec[PVECSIZ];	/* to point to names in pathbuf */
-	char **pvec;			/* holds usable tail of path vector */
-	char  *termpath;
-
-	_nc_termcap[0] = '\0';		/* in case */
-	dummy = NULL;
-	fname = pathvec;
-	pvec = pathvec;
-	p = pathbuf;
-	cp = getenv("TERMCAP");
-	/*
-	 * TERMCAP can have one of two things in it. It can be the
-	 * name of a file to use instead of /etc/termcap. In this
-	 * case it better start with a "/". Or it can be an entry to
-	 * use so we don't have to read the file. In this case it
-	 * has to already have the newlines crunched out.  If TERMCAP
-	 * does not hold a file name then a path of names is searched
-	 * instead.  The path is found in the TERMPATH variable, or
-	 * becomes "$HOME/.termcap /etc/termcap" if no TERMPATH exists.
-	 */
-	if (!cp || *cp != '/') {	/* no TERMCAP or it holds an entry */
-		if ( (termpath = getenv("TERMPATH")) )
-			strncpy(pathbuf, termpath, PBUFSIZ);
-		else {
-			if ( (home = getenv("HOME")) ) {/* set up default */
-				strncpy(pathbuf, home, PBUFSIZ - 1); /* $HOME first */
-				pathbuf[PBUFSIZ - 2] = '\0'; /* -2 because we add a slash */
-				p += strlen(pathbuf);	/* path, looking in */
-				*p++ = '/';
-			}	/* if no $HOME look in current directory */
-			strncpy(p, _PATH_DEF, PBUFSIZ - (p - pathbuf));
-		}
-	}
-	else				/* user-defined name in TERMCAP */
-		strncpy(pathbuf, cp, PBUFSIZ);	/* still can be tokenized */
-
-	/* For safety */
-	if (issetugid())
-		strcpy(pathbuf, _PATH_DEF_SEC);
-
-	pathbuf[PBUFSIZ - 1] = '\0';
-
-	*fname++ = pathbuf;	/* tokenize path into vector of names */
-	while (*++p)
-		if (*p == ' ' || *p == ':') {
-			*p = '\0';
-			while (*++p)
-				if (*p != ' ' && *p != ':')
-					break;
-			if (*p == '\0')
-				break;
-			*fname++ = p;
-			if (fname >= pathvec + PVECSIZ) {
-				fname--;
-				break;
-			}
-		}
-	*fname = (char *) 0;			/* mark end of vector */
-	if (cp && *cp && *cp != '/')
-		if (cgetset(cp) < 0)
-			return(-2);
-
-	i = cgetent(&dummy, pathvec, (char *)name);
-
-	if (i == 0) {
-		char *pd, *ps, *tok, *s, *tcs;
-		size_t len;
-
-		pd = _nc_termcap;
-		ps = dummy;
-		if ((tok = strchr(ps, ':')) == NULL) {
-			len = strlen(ps);
-			if (len >= TBUFSIZ)
-				i = -1;
-			else
-				strcpy(pd, ps);
-			goto done;
-		}
-		len = tok - ps + 1;
-		if (pd + len + 1 - _nc_termcap >= TBUFSIZ) {
-			i = -1;
-			goto done;
-		}
-		memcpy(pd, ps, len);
-		ps += len;
-		pd += len;
-		*pd = '\0';
-		tcs = pd - 1;
-		for (;;) {
-			while ((tok = strsep(&ps, ":")) != NULL &&
-			       *(tok - 2) != '\\' &&
-			       (*tok == '\0' || *tok == '\\' || !isgraph(*tok)))
-				;
-			if (tok == NULL)
-				break;
-			for (s = tcs; s != NULL && s[1] != '\0';
-			     s = strchr(s, ':')) {
-				s++;
-				if (s[0] == tok[0] && s[1] == tok[1])
-					goto skip_it;
-			}
-			len = strlen(tok);
-			if (pd + len + 1 - _nc_termcap >= TBUFSIZ) {
-				i = -1;
-				break;
-			}
-			memcpy(pd, tok, len);
-			pd += len;
-			*pd++ = ':';
-			*pd = '\0';
-		skip_it: ;
-		}
-	}
-done:
-	if (dummy)
-		free(dummy);
-
-
-/*
- * From here on is ncurses-specific glue code
- */
-
-	if (i < 0)
-		return(ERR);
-
-	_nc_set_source("TERMCAP");
-	_nc_read_entry_source((FILE *)NULL, _nc_termcap, FALSE, TRUE, NULLHOOK);
-
-	if (_nc_head == (ENTRY *)NULL)
-		return(ERR);
-
-	/* resolve all use references */
-	_nc_resolve_uses(TRUE);
-
-	for_entry_list(ep)
-		if (_nc_name_match(ep->tterm.term_names, name, "|:"))
-		{
-			/*
-			 * Make a local copy of the terminal capabilities. free
-			 * all entry storage except the string table for the
-			 * loaded type (which we disconnected from the list by
-			 * NULLing out ep->tterm.str_table above).
-			 */
-			memcpy(tp, &ep->tterm, sizeof(TERMTYPE));
-			ep->tterm.str_table = (char *)NULL;
-			_nc_free_entries(_nc_head);
-			_nc_head = _nc_tail = NULL;	/* do not reuse! */
-
-			return 1;	/* OK */
-		}
-
-	_nc_free_entries(_nc_head);
-	_nc_head = _nc_tail = NULL;	/* do not reuse! */
-	return(0);	/* not found */
-}
--- lib/libncurses/ncurses_cfg.h
+++ /dev/null
@@ -1,155 +0,0 @@
-/* include/ncurses_cfg.h.  Generated automatically by configure.  */
-/****************************************************************************
- * Copyright (c) 1998 Free Software Foundation, Inc.                        *
- *                                                                          *
- * Permission is hereby granted, free of charge, to any person obtaining a  *
- * copy of this software and associated documentation files (the            *
- * "Software"), to deal in the Software without restriction, including      *
- * without limitation the rights to use, copy, modify, merge, publish,      *
- * distribute, distribute with modifications, sublicense, and/or sell       *
- * copies of the Software, and to permit persons to whom the Software is    *
- * furnished to do so, subject to the following conditions:                 *
- *                                                                          *
- * The above copyright notice and this permission notice shall be included  *
- * in all copies or substantial portions of the Software.                   *
- *                                                                          *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
- * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
- * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
- * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
- * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
- * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
- *                                                                          *
- * Except as contained in this notice, the name(s) of the above copyright   *
- * holders shall not be used in advertising or otherwise to promote the     *
- * sale, use or other dealings in this Software without prior written       *
- * authorization.                                                           *
- ****************************************************************************/
-
-/****************************************************************************
- *  Author: Thomas E. Dickey <dickey at clark.net> 1997                        *
- ****************************************************************************/
-/*
- * $Id: ncurses_cfg.hin,v 1.3 2000/09/02 17:13:32 tom Exp $
- *
- * This is a template-file used to generate the "ncurses_cfg.h" file.
- *
- * Rather than list every definition, the configuration script substitutes the
- * definitions that it finds using 'sed'.  You need a patch (original date
- * 971222) to autoconf 2.12 or 2.13 to do this.
- *
- * See:
- *	http://dickey.his.com/autoconf/
- *	ftp://dickey.his.com/autoconf/
- */
-
-/* $FreeBSD: src/lib/libncurses/ncurses_cfg.h,v 1.5 2002/05/21 05:40:28 peter Exp $ */
-
-#ifndef NC_CONFIG_H
-#define NC_CONFIG_H
-
-#define BSD_TPUTS 1
-#define CC_HAS_INLINE_FUNCS 1
-#define CC_HAS_PROTOS 1
-#define GCC_NORETURN __dead2
-#define GCC_PRINTF 1
-#define GCC_SCANF 1
-#define GCC_UNUSED __unused
-#define HAVE_BIG_CORE 1
-#define HAVE_BSD_CGETENT 1
-#define HAVE_CURSES_VERSION 1
-#define HAVE_DIRENT_H 1
-#define HAVE_ERRNO 1
-#define HAVE_FCNTL_H 1
-#define HAVE_FORM_H 1
-#define HAVE_GETCWD 1
-#define HAVE_GETEGID 1
-#define HAVE_GETEUID 1
-#define HAVE_GETTIMEOFDAY 1
-#define HAVE_GETTTYNAM 1
-#define HAVE_HAS_KEY 1
-#define HAVE_ISASCII 1
-#define HAVE_ISSETUGID 1
-#define HAVE_LIBFORM 1
-#define HAVE_LIBMENU 1
-#define HAVE_LIBPANEL 1
-#define HAVE_LIMITS_H 1
-#define HAVE_LINK 1
-#define HAVE_LOCALE_H 1
-#define HAVE_LONG_FILE_NAMES 1
-#define HAVE_MEMCCPY 1
-#define HAVE_MENU_H 1
-#define HAVE_MKSTEMP 1
-#define HAVE_NANOSLEEP 1
-#define HAVE_NC_ALLOC_H 1
-#define HAVE_PANEL_H 1
-#define HAVE_POLL 1
-#define HAVE_POLL_H 1
-#define HAVE_REGEX_H_FUNCS 1
-#define HAVE_REMOVE 1
-#define HAVE_REMOVE 1
-#define HAVE_RESIZETERM 1
-#define HAVE_SELECT 1
-#define HAVE_SETBUF 1
-#define HAVE_SETBUFFER 1
-#define HAVE_SETVBUF 1
-#define HAVE_SIGACTION 1
-#define HAVE_SIGVEC 1
-#define HAVE_SIZECHANGE 1
-#define HAVE_STRDUP 1
-#define HAVE_STRSTR 1
-#define HAVE_SYMLINK 1
-#define HAVE_SYS_IOCTL_H 1
-#define HAVE_SYS_PARAM_H 1
-#define HAVE_SYS_POLL_H 1
-#define HAVE_SYS_SELECT_H 1
-#define HAVE_SYS_TIMES_H 1
-#define HAVE_SYS_TIME_H 1
-#define HAVE_SYS_TIME_SELECT 1
-#define HAVE_TCGETATTR 1
-#define HAVE_TCGETPGRP 1
-#define HAVE_TERMIOS_H 1
-#define HAVE_TIMES 1
-#define HAVE_TTYENT_H 1
-#define HAVE_UNISTD_H 1
-#define HAVE_UNISTD_H 1
-#define HAVE_UNLINK 1
-#define HAVE_USE_DEFAULT_COLORS 1
-#define HAVE_VSNPRINTF 1
-#define HAVE_VSSCANF 1
-#define HAVE_WORKING_POLL 1
-#define HAVE_WRESIZE 1
-#define MIXEDCASE_FILENAMES 1
-#define NCURSES_EXT_FUNCS 1
-#define NCURSES_NO_PADDING 1
-#define NCURSES_PATHSEP ':'
-#define NDEBUG 1
-#define RETSIGTYPE void
-#define STDC_HEADERS 1
-#define SYSTEM_NAME "FreeBSD"
-#define TERMINFO "/usr/share/misc/terminfo"
-#define TERMINFO_DIRS "/usr/share/misc/terminfo"
-#define TIME_WITH_SYS_TIME 1
-#define TYPEOF_CHTYPE long
-#define USE_ASSUMED_COLOR 1
-#define USE_COLORFGBG 1
-#define USE_DATABASE 1
-#define USE_GETCAP 1
-#define USE_HASHMAP 1
-#define USE_SIGWINCH 1
-
-#include <ncurses_def.h>
-
-	/* The C compiler may not treat these properly but C++ has to */
-#ifdef __cplusplus
-#undef const
-#undef inline
-#else
-#if defined(lint) || defined(TRACE)
-#undef inline
-#define inline /* nothing */
-#endif
-#endif
-
-#endif /* NC_CONFIG_H */
--- lib/libncurses/Makefile
+++ /dev/null
@@ -1,561 +0,0 @@
-# $FreeBSD: src/lib/libncurses/Makefile,v 1.78.2.1 2005/07/22 17:29:06 kensmith Exp $
-
-NCURSES=${.CURDIR}/../../contrib/ncurses
-
-LIB=	ncurses
-SHLIBDIR?= /lib
-SHLIB_MAJOR=6
-
-# Should be elsewhere
-AWK?=	awk
-TERMINFODIR?=	${SHAREDIR}/misc
-
-NCURSES_MAJOR!=egrep 'NCURSES_MAJOR[ 	]*=' ${NCURSES}/dist.mk | sed -e 's%^[^0-9]*%%'
-NCURSES_MINOR!=egrep 'NCURSES_MINOR[ 	]*=' ${NCURSES}/dist.mk | sed -e 's%^[^0-9]*%%'
-NCURSES_PATCH!=egrep 'NCURSES_PATCH[ 	]*=' ${NCURSES}/dist.mk | sed -e 's%^[^0-9]*%%'
-
-# From autoconf (!)
-NCURSES_CONST=		const
-NCURSES_XNAMES=		1
-NCURSES_OSPEED=		short
-NCURSES_CH_T=		chtype
-NCURSES_EXT_FUNCS=	1
-NCURSES_LIBUTF8=	0
-NCURSES_MBSTATE_T=	0
-BROKEN_LINKER=		0
-BUILTIN_BOOL=		1
-BOOL_TYPE=		0
-HAVE_VSSCANF=		1
-HEADER_STDBOOL=		1
-TYPE_OF_BOOL=		unsigned char
-TYPEOF_CHTYPE=		long
-WIDEC_SHIFT=		8
-SHIFT_LIMIT=		32
-ONEUL=			1UL
-
-.PATH:  ${NCURSES}/ncurses
-.PATH:  ${NCURSES}/ncurses/base
-.PATH:  ${NCURSES}/ncurses/tinfo
-.PATH:  ${NCURSES}/ncurses/tty
-.PATH:  ${NCURSES}/ncurses/trace
-.PATH:  ${NCURSES}/include
-.PATH:  ${NCURSES}/man
-
-CFLAGS+=-I. -I${.CURDIR} -I${NCURSES}/ncurses -I${NCURSES}/include
-CFLAGS+=-Wall -DFREEBSD_NATIVE -DNDEBUG -DHAVE_CONFIG_H -DTERMIOS
-
-GENSRC= \
-	codes.c \
-	expanded.c \
-	fallback.c \
-	lib_gen.c \
-	lib_keyname.c \
-	names.c \
-	unctrl.c
-
-GENHDR= \
-	curses.h \
-	hashsize.h \
-	init_keytry.h \
-	ncurses_def.h \
-	nomacros.h \
-	parametrized.h \
-	term.h \
-	termcap.h \
-	unctrl.h
-
-# Installed
-HEADERS=curses.h term.h termcap.h unctrl.h
-SRCHDRS=ncurses_dll.h
-INCS=	${HEADERS} ${SRCHDRS}
-INCSLINKS= curses.h ${INCLUDEDIR}/ncurses.h
-
-# Components of names.c and codes.c
-NAMESRC=boolnames boolfnames numnames numfnames strnames strfnames
-CODESRC=boolcodes numcodes strcodes
-
-SRCS=	${GENHDR} ${GENSRC} \
-	access.c \
-	add_tries.c \
-	alloc_entry.c \
-	alloc_ttype.c \
-	captoinfo.c \
-	comp_captab.c \
-	comp_error.c \
-	comp_expand.c \
-	comp_hash.c \
-	comp_parse.c \
-	comp_scan.c \
-	define_key.c \
-	doalloc.c \
-	free_ttype.c \
-	getenv_num.c \
-	hardscroll.c \
-	hashmap.c \
-	home_terminfo.c \
-	init_keytry.c \
-	keybound.c \
-	keyok.c \
-	lib_acs.c \
-	lib_addch.c \
-	lib_addstr.c \
-	lib_baudrate.c \
-	lib_beep.c \
-	lib_bkgd.c \
-	lib_box.c \
-	lib_chgat.c \
-	lib_clear.c \
-	lib_clearok.c \
-	lib_clrbot.c \
-	lib_clreol.c \
-	lib_color.c \
-	lib_colorset.c \
-	lib_cur_term.c \
-	lib_data.c \
-	lib_delch.c \
-	lib_delwin.c \
-	lib_dft_fgbg.c \
-	lib_echo.c \
-	lib_endwin.c \
-	lib_erase.c \
-	lib_flash.c \
-	lib_freeall.c \
-	lib_getch.c \
-	lib_getstr.c \
-	lib_has_cap.c \
-	lib_hline.c \
-	lib_immedok.c \
-	lib_inchstr.c \
-	lib_initscr.c \
-	lib_insch.c \
-	lib_insdel.c \
-	lib_insstr.c \
-	lib_instr.c \
-	lib_isendwin.c \
-	lib_kernel.c \
-	lib_leaveok.c \
-	lib_longname.c \
-	lib_mouse.c \
-	lib_move.c \
-	lib_mvcur.c \
-	lib_mvwin.c \
-	lib_napms.c \
-	lib_newterm.c \
-	lib_newwin.c \
-	lib_nl.c \
-	lib_options.c \
-	lib_overlay.c \
-	lib_pad.c \
-	lib_print.c \
-	lib_printw.c \
-	lib_raw.c \
-	lib_redrawln.c \
-	lib_refresh.c \
-	lib_restart.c \
-	lib_scanw.c \
-	lib_screen.c \
-	lib_scroll.c \
-	lib_scrollok.c \
-	lib_scrreg.c \
-	lib_set_term.c \
-	lib_setup.c \
-	lib_slk.c \
-	lib_slkatr_set.c \
-	lib_slkatrof.c \
-	lib_slkatron.c \
-	lib_slkatrset.c \
-	lib_slkattr.c \
-	lib_slkclear.c \
-	lib_slkcolor.c \
-	lib_slkinit.c \
-	lib_slklab.c \
-	lib_slkrefr.c \
-	lib_slkset.c \
-	lib_slktouch.c \
-	lib_termcap.c \
-	lib_termname.c \
-	lib_tgoto.c \
-	lib_ti.c \
-	lib_touch.c \
-	lib_tparm.c \
-	lib_tputs.c \
-	lib_trace.c \
-	lib_tstp.c \
-	lib_ttyflags.c \
-	lib_twait.c \
-	lib_ungetch.c \
-	lib_vidattr.c \
-	lib_vline.c \
-	lib_wattroff.c \
-	lib_wattron.c \
-	lib_winch.c \
-	lib_window.c \
-	memmove.c \
-	name_match.c \
-	nc_panel.c \
-	parse_entry.c \
-	read_entry.c \
-	resizeterm.c \
-	safe_sprintf.c \
-	setbuf.c \
-	sigaction.c \
-	strings.c \
-	tries.c \
-	tty_update.c \
-	varargs.c \
-	version.c \
-	visbuf.c \
-	vsscanf.c \
-	wresize.c \
-	write_entry.c
-
-# Currently unused, for debugging libncurses itself.
-DBGSRCS=lib_traceatr.c \
-	lib_tracebits.c \
-	lib_tracechr.c \
-	lib_tracedmp.c \
-	lib_tracemse.c \
-	trace_buf.c \
-	trace_tries.c \
-	trace_xnames.c
-
-# From our old libtermcap.
-# Used instead of the hideous read_termcap.c abomination.
-SRCS+=	termcap.c
-
-CLEANFILES+=	${GENSRC} ${GENHDR} keys.list make_hash term.h.new \
-	make_keys MKterm.h.awk comp_captab.c curses.head \
-	namehdr nameftr codeftr ${NAMESRC} ${CODESRC}
-
-.if !defined(NO_INSTALLLIB)
-SYMLINKS+=libncurses.a ${LIBDIR}/libcurses.a
-SYMLINKS+=libncurses.a ${LIBDIR}/libtermcap.a
-SYMLINKS+=libncurses.a ${LIBDIR}/libtermlib.a
-SYMLINKS+=libncurses.a ${LIBDIR}/libmytinfo.a
-SYMLINKS+=libncurses.a ${LIBDIR}/libtinfo.a
-.endif
-.if !defined(NO_PIC)
-# no need for major at all, it's an ld-time redirection only
-SYMLINKS+=libncurses.so ${LIBDIR}/libcurses.so
-SYMLINKS+=libncurses.so ${LIBDIR}/libtermcap.so
-SYMLINKS+=libncurses.so ${LIBDIR}/libtermlib.so
-SYMLINKS+=libncurses.so ${LIBDIR}/libmytinfo.so
-SYMLINKS+=libncurses.so ${LIBDIR}/libtinfo.so
-.endif
-.if !defined(NO_PROFILE)
-SYMLINKS+=libncurses_p.a ${LIBDIR}/libcurses_p.a
-SYMLINKS+=libncurses_p.a ${LIBDIR}/libtermcap_p.a
-SYMLINKS+=libncurses_p.a ${LIBDIR}/libtermlib_p.a
-SYMLINKS+=libncurses_p.a ${LIBDIR}/libmytinfo_p.a
-SYMLINKS+=libncurses_p.a ${LIBDIR}/libtinfo_p.a
-.endif
-
-DOCSDIR= /usr/share/doc/ncurses
-DOCS=	ncurses-intro.html hackguide.html
-
-.if !defined(NO_HTML)
-.PATH: ${NCURSES}/doc/html
-FILESGROUPS=	DOCS
-.endif
-
-# Generated source
-namehdr nameftr codeftr ${NAMESRC} ${CODESRC}: MKnames.awk Caps
-	${AWK} -f ${NCURSES}/ncurses/tinfo/MKnames.awk ${NCURSES}/include/Caps
-
-.ORDER: namehdr ${NAMESRC} ${CODESRC} nameftr codeftr names.c codes.c
-
-names.c:	 namehdr ${NAMESRC} nameftr
-	cat namehdr ${NAMESRC} nameftr > $@
-
-codes.c:	 namehdr ${CODESRC} codeftr
-	cat namehdr ${CODESRC} codeftr > $@
-
-lib_gen.c:	MKlib_gen.sh curses.h
-	LC_ALL=C sh ${NCURSES}/ncurses/base/MKlib_gen.sh "${CC} -E ${CFLAGS}" \
-	    "${AWK}" generated < curses.h >$@
-
-lib_keyname.c:	keys.list MKkeyname.awk
-	${AWK} -f ${NCURSES}/ncurses/base/MKkeyname.awk keys.list > lib_keyname.c
-
-unctrl.c:	MKunctrl.awk
-	echo | ${AWK} -f ${NCURSES}/ncurses/base/MKunctrl.awk > unctrl.c
-
-comp_captab.c:	MKcaptab.awk Caps make_hash
-	sh ${NCURSES}/ncurses/tinfo/MKcaptab.awk "${AWK}" \
-	    ${NCURSES}/include/Caps > comp_captab.c
-
-expanded.c:	MKexpanded.sh
-	sh ${NCURSES}/ncurses/tty/MKexpanded.sh "${CC} -E" ${CFLAGS} >expanded.c
-
-fallback.c:	MKfallback.sh
-	sh ${NCURSES}/ncurses/tinfo/MKfallback.sh > fallback.c
-
-# Generated headers
-ncurses_def.h:	MKncurses_def.sh ncurses_defs
-	AWK=${AWK} sh ${NCURSES}/include/MKncurses_def.sh \
-	    ${NCURSES}/include/ncurses_defs > ncurses_def.h
-
-nomacros.h:	MKlib_gen.sh curses.h
-	LC_ALL=C sh ${NCURSES}/ncurses/base/MKlib_gen.sh "${CC} -E ${CFLAGS}" \
-	    "${AWK}" generated < curses.h | fgrep undef > $@
-
-init_keytry.h:	keys.list make_keys
-	./make_keys keys.list > init_keytry.h
-
-hashsize.h:	MKhashsize.sh Caps
-	sh ${NCURSES}/include/MKhashsize.sh ${NCURSES}/include/Caps > $@
-
-parametrized.h:	MKparametrized.sh Caps
-	AWK=${AWK} sh ${NCURSES}/include/MKparametrized.sh \
-	    ${NCURSES}/include/Caps > $@
-
-term.h:		MKterm.h.awk edit_cfg.sh Caps
-	${AWK} -f MKterm.h.awk ${NCURSES}/include/Caps > $@.new
-	sh ${NCURSES}/include/edit_cfg.sh ${.CURDIR}/ncurses_cfg.h $@.new
-	mv -f $@.new $@
-
-curses.h:	curses.head MKkey_defs.sh Caps
-	cat curses.head > $@.new
-	AWK=${AWK} _POSIX2_VERSION=199209 sh ${NCURSES}/include/MKkey_defs.sh \
-	    ${NCURSES}/include/Caps >> $@.new
-	cat ${NCURSES}/include/curses.tail >> $@.new
-	mv -f $@.new $@
-
-# Generated intermediate files
-keys.list:	MKkeys_list.sh Caps
-	AWK=${AWK} sh ${NCURSES}/ncurses/tinfo/MKkeys_list.sh \
-	    ${NCURSES}/include/Caps | LC_ALL=C sort > keys.list
-
-# Build tools
-build-tools: make_hash make_keys
-
-make_keys:	make_keys.c names.c ncurses_def.h ${HEADERS}
-	${CC} -o $@ ${CFLAGS} ${NCURSES}/ncurses/tinfo/make_keys.c
-
-make_hash:	comp_hash.c hashsize.h ncurses_def.h ${HEADERS}
-	${CC} -o $@ ${CFLAGS} -DMAIN_PROGRAM \
-		${NCURSES}/ncurses/tinfo/comp_hash.c
-
-# ./configure generated
-MKterm.h.awk:	MKterm.h.awk.in
-	sed <${NCURSES}/include/MKterm.h.awk.in >$@ \
-	    -e "/@NCURSES_MAJOR@/s%%${NCURSES_MAJOR}%" \
-	    -e "/@NCURSES_MINOR@/s%%${NCURSES_MINOR}%" \
-	    -e "/@NCURSES_CONST@/s%%${NCURSES_CONST}%" \
-	    -e "/@NCURSES_XNAMES@/s%%${NCURSES_XNAMES}%"
-
-termcap.h:	termcap.h.in
-	sed <${NCURSES}/include/termcap.h.in >$@ \
-	    -e "/@NCURSES_MAJOR@/s%%${NCURSES_MAJOR}%" \
-	    -e "/@NCURSES_MINOR@/s%%${NCURSES_MINOR}%" \
-	    -e "/@NCURSES_CONST@/s%%${NCURSES_CONST}%" \
-	    -e "/@NCURSES_OSPEED@/s%%${NCURSES_OSPEED}%"
-
-curses.head:	curses.h.in
-	sed <${NCURSES}/include/curses.h.in >$@ \
-	    -e "/@BROKEN_LINKER@/s%%${BROKEN_LINKER}%" \
-	    -e "/@HAVE_VSSCANF@/s%%${HAVE_VSSCANF}%" \
-	    -e "/@NCURSES_CONST@/s%%${NCURSES_CONST}%" \
-	    -e "/@NCURSES_MAJOR@/s%%${NCURSES_MAJOR}%" \
-	    -e "/@NCURSES_MINOR@/s%%${NCURSES_MINOR}%" \
-	    -e "/@NCURSES_PATCH@/s%%${NCURSES_PATCH}%" \
-	    -e "/@NCURSES_CH_T@/s%%${NCURSES_CH_T}%" \
-	    -e "/@NCURSES_EXT_FUNCS@/s%%${NCURSES_EXT_FUNCS}%" \
-	    -e "/@NCURSES_LIBUTF8@/s%%${NCURSES_LIBUTF8}%" \
-	    -e "/@NCURSES_MBSTATE_T@/s%%${NCURSES_MBSTATE_T}%" \
-	    -e "s%@cf_cv_1UL@%${ONEUL}%g" \
-	    -e "s%@cf_cv_builtin_bool@%${BUILTIN_BOOL}%g" \
-	    -e "s%@cf_cv_cc_bool_type@%${BOOL_TYPE}%g" \
-	    -e "s%@cf_cv_shift_limit@%${SHIFT_LIMIT}%g" \
-	    -e "s%@cf_cv_header_stdbool_h@%${HEADER_STDBOOL}%g" \
-	    -e "s%@cf_cv_type_of_bool@%${TYPE_OF_BOOL}%g" \
-	    -e "s%@cf_cv_typeof_chtype@%${TYPEOF_CHTYPE}%g" \
-	    -e "s%@cf_cv_widec_shift@%${WIDEC_SHIFT}%g" \
-	    -e "s/ _WCHAR_T/ __wchar_t/g" \
-	    -e "s/ _WINT_T/ __wint_t/g" \
-
-unctrl.h:	unctrl.h.in
-	sed <${NCURSES}/include/$@.in >$@ \
-	    -e "/@NCURSES_MAJOR@/s%%${NCURSES_MAJOR}%" \
-	    -e "/@NCURSES_MINOR@/s%%${NCURSES_MINOR}%"
-
-# MAN page gunk
-terminfo.5:	MKterminfo.sh terminfo.head Caps
-	sh ${NCURSES}/man/MKterminfo.sh ${NCURSES}/man/terminfo.head \
-	    ${NCURSES}/include/Caps ${NCURSES}/man/terminfo.tail >$@
-
-CLEANFILES+=	terminfo.5
-MANFILTER=      sed -e 's%@TERMINFO@%${TERMINFODIR}/terminfo%g' \
-		    -e 's%@NCURSES_OSPEED@%${NCURSES_OSPEED}%g'
-
-MANx=	curs_addch.3x curs_addchstr.3x curs_addstr.3x curs_attr.3x \
-	curs_beep.3x curs_bkgd.3x curs_border.3x curs_clear.3x curs_color.3x \
-	curs_delch.3x curs_deleteln.3x curs_extend.3x curs_getch.3x \
-	curs_getstr.3x \
-	curs_getyx.3x curs_inch.3x curs_inchstr.3x curs_initscr.3x \
-	curs_inopts.3x curs_insch.3x curs_insstr.3x curs_instr.3x \
-	curs_kernel.3x curs_mouse.3x curs_move.3x curs_outopts.3x \
-	curs_overlay.3x curs_pad.3x curs_print.3x curs_printw.3x \
-	curs_refresh.3x curs_scanw.3x curs_scr_dump.3x curs_scroll.3x \
-	curs_slk.3x curs_termattrs.3x curs_termcap.3x curs_terminfo.3x \
-	curs_touch.3x curs_trace.3x curs_util.3x curs_window.3x \
-	default_colors.3x define_key.3x \
-	keybound.3x keyok.3x ncurses.3x resizeterm.3x wresize.3x
-MAN=	term.5 terminfo.5
-MAN+=	term.7
-
-# Generate the MAN list from MANx
-.for page in ${MANx}
-CLEANFILES+=${page:T:S/x$//g}
-MAN+=${page:T:S/x$//g}
-${page:T:S/x$//g}: ${page}
-	cat ${.ALLSRC} > ${.TARGET}
-.endfor
-
-MLINKS+=ncurses.3 curses.3
-MLINKS+=curs_addch.3 addch.3 curs_addch.3 echochar.3 curs_addch.3 mvaddch.3 \
-	curs_addch.3 mvwaddch.3 curs_addch.3 waddch.3 curs_addch.3 wechochar.3
-MLINKS+=curs_addchstr.3 addchnstr.3 curs_addchstr.3 addchstr.3 \
-	curs_addchstr.3 mvaddchnstr.3 curs_addchstr.3 mvaddchstr.3 \
-	curs_addchstr.3 mvwaddchnstr.3 curs_addchstr.3 mvwaddchstr.3 \
-	curs_addchstr.3 waddchnstr.3 curs_addchstr.3 waddchstr.3
-MLINKS+=curs_addstr.3 addnstr.3 curs_addstr.3 addstr.3 \
-	curs_addstr.3 mvaddnstr.3 curs_addstr.3 mvaddstr.3 \
-	curs_addstr.3 mvwaddnstr.3 curs_addstr.3 mvwaddstr.3 \
-	curs_addstr.3 waddnstr.3 curs_addstr.3 waddstr.3
-MLINKS+=curs_attr.3 PAIR_NUMBER.3 \
-	curs_attr.3 attr_get.3 curs_attr.3 attr_off.3 curs_attr.3 attr_on.3 \
-	curs_attr.3 attr_set.3 curs_attr.3 attroff.3 curs_attr.3 attron.3 \
-	curs_attr.3 attrset.3 curs_attr.3 chgat.3 curs_attr.3 color_set.3 \
-	curs_attr.3 mvchgat.3 curs_attr.3 mvwchgat.3 curs_attr.3 standend.3 \
-	curs_attr.3 standout.3 curs_attr.3 wattr_get.3 curs_attr.3 wattr_off.3 \
-	curs_attr.3 wattr_on.3 curs_attr.3 wattr_set.3 curs_attr.3 wattroff.3 \
-	curs_attr.3 wattron.3 curs_attr.3 wattrset.3 curs_attr.3 wchgat.3 \
-	curs_attr.3 wcolor_set.3 curs_attr.3 wstandend.3 \
-	curs_attr.3 wstandout.3
-MLINKS+=curs_beep.3 beep.3 curs_beep.3 flash.3
-MLINKS+=curs_bkgd.3 bkgd.3 curs_bkgd.3 bkgdset.3 curs_bkgd.3 getbkgd.3 \
-	curs_bkgd.3 wbkgd.3 curs_bkgd.3 wbkgdset.3
-MLINKS+=curs_border.3 border.3 curs_border.3 box.3 curs_border.3 hline.3 \
-	curs_border.3 mvhline.3 curs_border.3 mvvline.3 \
-	curs_border.3 mvwhline.3 \
-	curs_border.3 mvwvline.3 curs_border.3 vline.3 curs_border.3 wborder.3 \
-	curs_border.3 whline.3 curs_border.3 wvline.3
-MLINKS+=curs_clear.3 clear.3 curs_clear.3 clrtobot.3 curs_clear.3 clrtoeol.3 \
-	curs_clear.3 erase.3 curs_clear.3 wclear.3 curs_clear.3 wclrtobot.3 \
-	curs_clear.3 wclrtoeol.3 curs_clear.3 werase.3
-MLINKS+=curs_color.3 COLOR_PAIR.3 \
-	curs_color.3 can_change_color.3 curs_color.3 color_content.3 \
-	curs_color.3 has_colors.3 curs_color.3 init_color.3 \
-	curs_color.3 init_pair.3 curs_color.3 pair_content.3 \
-	curs_color.3 start_color.3
-MLINKS+=curs_delch.3 delch.3 curs_delch.3 mvdelch.3 curs_delch.3 mvwdelch.3 \
-	curs_delch.3 wdelch.3
-MLINKS+=curs_deleteln.3 deleteln.3 curs_deleteln.3 insdelln.3 \
-	curs_deleteln.3 insertln.3 curs_deleteln.3 wdeleteln.3 \
-	curs_deleteln.3 winsdelln.3 curs_deleteln.3 winsertln.3
-MLINKS+=curs_extend.3 curses_version.3 curs_extend.3 use_extended_names.3
-MLINKS+=curs_getch.3 getch.3 curs_getch.3 has_key.3 curs_getch.3 mvgetch.3 \
-	curs_getch.3 mvwgetch.3 curs_getch.3 ungetch.3 curs_getch.3 wgetch.3
-MLINKS+=curs_getstr.3 getnstr.3 curs_getstr.3 getstr.3 \
-	curs_getstr.3 mvgetnstr.3 curs_getstr.3 mvgetstr.3 \
-	curs_getstr.3 mvwgetnstr.3 curs_getstr.3 mvwgetstr.3 \
-	curs_getstr.3 wgetnstr.3 curs_getstr.3 wgetstr.3
-MLINKS+=curs_getyx.3 getbegyx.3 curs_getyx.3 getmaxyx.3 \
-	curs_getyx.3 getparyx.3 curs_getyx.3 getyx.3
-MLINKS+=curs_inch.3 inch.3 curs_inch.3 mvinch.3 curs_inch.3 mvwinch.3 \
-	curs_inch.3 winch.3
-MLINKS+=curs_inchstr.3 inchnstr.3 curs_inchstr.3 inchstr.3 \
-	curs_inchstr.3 mvinchnstr.3 curs_inchstr.3 mvinchstr.3 \
-	curs_inchstr.3 mvwinchnstr.3 curs_inchstr.3 mvwinchstr.3 \
-	curs_inchstr.3 winchnstr.3 curs_inchstr.3 winchstr.3
-MLINKS+=curs_initscr.3 delscreen.3 curs_initscr.3 endwin.3 \
-	curs_initscr.3 initscr.3 curs_initscr.3 isendwin.3 \
-	curs_initscr.3 newterm.3 curs_initscr.3 set_term.3
-MLINKS+=curs_inopts.3 cbreak.3 curs_inopts.3 echo.3 curs_inopts.3 halfdelay.3 \
-	curs_inopts.3 intrflush.3 curs_inopts.3 keypad.3 curs_inopts.3 meta.3 \
-	curs_inopts.3 nocbreak.3 curs_inopts.3 nodelay.3 \
-	curs_inopts.3 noecho.3 curs_inopts.3 noqiflush.3 curs_inopts.3 noraw.3 \
-	curs_inopts.3 notimeout.3 curs_inopts.3 qiflush.3 curs_inopts.3 raw.3 \
-	curs_inopts.3 timeout.3 curs_inopts.3 typeahead.3 \
-	curs_inopts.3 wtimeout.3
-MLINKS+=curs_insch.3 insch.3 curs_insch.3 mvinsch.3 curs_insch.3 mvwinsch.3 \
-	curs_insch.3 winsch.3
-MLINKS+=curs_insstr.3 insnstr.3 curs_insstr.3 insstr.3 \
-	curs_insstr.3 mvinsnstr.3 curs_insstr.3 mvinsstr.3 \
-	curs_insstr.3 mvwinsnstr.3 curs_insstr.3 mvwinsstr.3 \
-	curs_insstr.3 winsnstr.3 curs_insstr.3 winsstr.3
-MLINKS+=curs_instr.3 innstr.3 curs_instr.3 instr.3 curs_instr.3 mvinnstr.3 \
-	curs_instr.3 mvinstr.3 curs_instr.3 mvwinnstr.3 \
-	curs_instr.3 mvwinstr.3 curs_instr.3 winnstr.3 curs_instr.3 winstr.3
-MLINKS+=curs_kernel.3 curs_set.3 curs_kernel.3 def_prog_mode.3 \
-	curs_kernel.3 def_shell_mode.3 curs_kernel.3 getsyx.3 \
-	curs_kernel.3 napms.3 curs_kernel.3 reset_prog_mode.3 \
-	curs_kernel.3 reset_shell_mode.3 curs_kernel.3 resetty.3 \
-	curs_kernel.3 ripoffline.3 curs_kernel.3 savetty.3 \
-	curs_kernel.3 setsyx.3
-MLINKS+=curs_mouse.3 getmouse.3 curs_mouse.3 mouse_trafo.3 \
-	curs_mouse.3 mouseinterval.3 \
-	curs_mouse.3 mousemask.3 curs_mouse.3 ungetmouse.3 \
-	curs_mouse.3 wenclose.3 curs_mouse.3 wmouse_trafo.3
-MLINKS+=curs_move.3 move.3 curs_move.3 wmove.3
-MLINKS+=curs_outopts.3 clearok.3 curs_outopts.3 idcok.3 curs_outopts.3 idlok.3 \
-	curs_outopts.3 immedok.3 curs_outopts.3 leaveok.3 curs_outopts.3 nl.3 \
-	curs_outopts.3 nonl.3 curs_outopts.3 scrollok.3 \
-	curs_outopts.3 setscrreg.3 curs_outopts.3 wsetscrreg.3
-MLINKS+=curs_overlay.3 copywin.3 curs_overlay.3 overlay.3 \
-	curs_overlay.3 overwrite.3
-MLINKS+=curs_pad.3 newpad.3 curs_pad.3 pechochar.3 curs_pad.3 pnoutrefresh.3 \
-	curs_pad.3 prefresh.3 curs_pad.3 subpad.3
-MLINKS+=curs_print.3 mcprint.3
-MLINKS+=curs_printw.3 mvprintw.3 curs_printw.3 mvwprintw.3 \
-	curs_printw.3 printw.3 curs_printw.3 vw_printw.3 \
-	curs_printw.3 vwprintw.3 curs_printw.3 wprintw.3
-MLINKS+=curs_refresh.3 doupdate.3 curs_refresh.3 redrawwin.3 \
-	curs_refresh.3 refresh.3 curs_refresh.3 wnoutrefresh.3 \
-	curs_refresh.3 wredrawln.3 curs_refresh.3 wrefresh.3
-MLINKS+=curs_scanw.3 mvscanw.3 curs_scanw.3 mvwscanw.3 curs_scanw.3 scanw.3 \
-	curs_scanw.3 vw_scanw.3 curs_scanw.3 vwscanw.3 curs_scanw.3 wscanw.3
-MLINKS+=curs_scr_dump.3 scr_dump.3 curs_scr_dump.3 scr_init.3 \
-	curs_scr_dump.3 scr_restore.3 curs_scr_dump.3 scr_set.3
-MLINKS+=curs_scroll.3 scrl.3 curs_scroll.3 scroll.3 curs_scroll.3 wscrl.3
-MLINKS+=curs_slk.3 slk_attr.3 curs_slk.3 slk_attr_off.3 \
-	curs_slk.3 slk_attr_on.3 curs_slk.3 slk_attr_set.3 \
-	curs_slk.3 slk_attroff.3 curs_slk.3 slk_attron.3 \
-	curs_slk.3 slk_attrset.3 curs_slk.3 slk_clear.3 \
-	curs_slk.3 slk_color.3 curs_slk.3 slk_init.3 curs_slk.3 slk_label.3 \
-	curs_slk.3 slk_noutrefresh.3 curs_slk.3 slk_refresh.3 \
-	curs_slk.3 slk_restore.3 curs_slk.3 slk_set.3 curs_slk.3 slk_touch.3
-MLINKS+=curs_termattrs.3 baudrate.3 curs_termattrs.3 erasechar.3 \
-	curs_termattrs.3 has_ic.3 curs_termattrs.3 has_il.3 \
-	curs_termattrs.3 killchar.3 curs_termattrs.3 longname.3 \
-	curs_termattrs.3 termattrs.3 curs_termattrs.3 termname.3
-MLINKS+=curs_termcap.3 termcap.3 curs_termcap.3 tgetent.3 \
-	curs_termcap.3 tgetflag.3 curs_termcap.3 tgetnum.3 \
-	curs_termcap.3 tgetstr.3 curs_termcap.3 tgoto.3 \
-	curs_termcap.3 tputs.3
-MLINKS+=curs_terminfo.3 del_curterm.3 curs_terminfo.3 mvcur.3 \
-	curs_terminfo.3 putp.3 curs_terminfo.3 restartterm.3 \
-	curs_terminfo.3 set_curterm.3 curs_terminfo.3 setterm.3 \
-	curs_terminfo.3 setupterm.3 curs_terminfo.3 tigetflag.3 \
-	curs_terminfo.3 tigetnum.3 curs_terminfo.3 tigetstr.3 \
-	curs_terminfo.3 tparm.3 curs_terminfo.3 tputs.3 \
-	curs_terminfo.3 vidattr.3 curs_terminfo.3 vidputs.3
-MLINKS+=curs_touch.3 is_linetouched.3 curs_touch.3 is_wintouched.3 \
-	curs_touch.3 touchline.3 curs_touch.3 touchwin.3 \
-	curs_touch.3 untouchwin.3 curs_touch.3 wtouchln.3
-MLINKS+=curs_util.3 delay_output.3 curs_util.3 filter.3 \
-	curs_util.3 flushinp.3 curs_util.3 getwin.3 \
-	curs_util.3 keyname.3 curs_util.3 putwin.3 \
-	curs_util.3 unctrl.3 curs_util.3 use_env.3
-MLINKS+=curs_window.3 delwin.3 curs_window.3 derwin.3 curs_window.3 dupwin.3 \
-	curs_window.3 mvderwin.3 curs_window.3 mvwin.3 curs_window.3 newwin.3 \
-	curs_window.3 subwin.3 curs_window.3 syncok.3 \
-	curs_window.3 wcursyncup.3 curs_window.3 wsyncdown.3 \
-	curs_window.3 wsyncup.3
-MLINKS+=default_colors.3 assume_default_colors.3 \
-	default_colors.3 use_default_colors.3
-
-NO_LINT=
-
-.include <bsd.lib.mk>
--- lib/libncurses/pathnames.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (c) 1989, 1993
- *	The Regents of the University of California.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *	This product includes software developed by the University of
- *	California, Berkeley and its contributors.
- * 4. Neither the name of the University 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 REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED 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.
- *
- *	@(#)pathnames.h	8.1 (Berkeley) 6/4/93
- * $FreeBSD: src/lib/libncurses/pathnames.h,v 1.1 1999/08/30 07:57:50 peter Exp $
- */
-
-#define	_PATH_DEF	".termcap /usr/share/misc/termcap"
-#define	_PATH_DEF_SEC	"/usr/share/misc/termcap"
--- /dev/null
+++ lib/ncurses/panel/Makefile
@@ -0,0 +1,67 @@
+# $FreeBSD: src/lib/ncurses/panel/Makefile,v 1.15 2007/05/25 02:27:46 rafan Exp $
+
+.include "${.CURDIR}/../config.mk"
+
+SRCDIR=	${NCURSES_DIR}/panel
+
+LIB=	panel${LIB_SUFFIX}
+
+.PATH: ${SRCDIR}
+SRCS=	\
+	ncurses_def.h \
+	p_above.c \
+	p_below.c \
+	p_bottom.c \
+	p_delete.c \
+	p_hidden.c \
+	p_hide.c \
+	p_move.c \
+	p_new.c \
+	p_replace.c \
+	p_show.c \
+	p_top.c \
+	p_update.c \
+	p_user.c \
+	p_win.c \
+	panel.c
+
+CLEANFILES=	ncurses_def.h
+
+CFLAGS+=	-I${SRCDIR}
+
+DPADD=	${LIBNCURSES${LIB_SUFFIX:U}}
+LDADD=	-lncurses${LIB_SUFFIX}
+
+.if defined(ENABLE_WIDEC)
+INCS=	panel.h
+.endif
+
+# generate MAN
+.PATH: ${NCURSES_DIR}/man
+MAN=	\
+	panel.3
+
+CLEANFILES+=	${MAN:M*.3}
+
+MLINKS=	panel.3 bottom_panel.3 \
+	panel.3 del_panel.3 \
+	panel.3 hide_panel.3 \
+	panel.3 move_panel.3 \
+	panel.3 new_panel.3 \
+	panel.3 panel_above.3 \
+	panel.3 panel_below.3 \
+	panel.3 panel_hidden.3 \
+	panel.3 panel_userptr.3 \
+	panel.3 panel_window.3 \
+	panel.3 replace_panel.3 \
+	panel.3 set_panel_userptr.3 \
+	panel.3 show_panel.3 \
+	panel.3 top_panel.3 \
+	panel.3 update_panels.3
+	
+.include <bsd.lib.mk>
+
+# Keep the .SUFFIXES line after the include of bsd.lib.mk
+.SUFFIXES: .3 .3x
+.3x.3:
+	cat ${.IMPSRC} > ${.TARGET}
--- /dev/null
+++ lib/ncurses/panelw/Makefile
@@ -0,0 +1,5 @@
+# $FreeBSD: src/lib/ncurses/panelw/Makefile,v 1.1 2007/03/09 12:11:58 rafan Exp $
+
+ENABLE_WIDEC=
+
+.include "${.CURDIR}/../panel/Makefile"


More information about the Midnightbsd-cvs mailing list