[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,
+ ¶m) == 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, ¶m) == 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, ¶m) == 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,
+ ¶m) == 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,
+ ¶m) == 0);
+ param.sched_priority = states[4].priority;
+ assert (pthread_setschedparam (states[4].tid, SCHED_FIFO,
+ ¶m) == 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,
+ ¶m) == 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,
+ ¶m) == 0);
+ param.sched_priority = states[4].priority;
+ assert (pthread_setschedparam (states[4].tid, SCHED_RR,
+ ¶m) == 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, ¶m) == 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,
+ ¶m) == 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, ¶m)) == 0) {
+ param.sched_priority = prio;
+ ret = pthread_setschedparam(pthread, policy, ¶m);
+ }
+
+ /* 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, ¶m)) == 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