Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 3 Sep 2007 19:31:52 -0700
From:      Alfred Perlstein <alfred@freebsd.org>
To:        smp@freebsd.org
Cc:        attilio@freebsd.org
Subject:   take 2: request for review: backport of sx and rwlocks from 7.0 to 6-stable
Message-ID:  <20070904023152.GZ87451@elvis.mu.org>

next in thread | raw e-mail | index | archive | help

--SnV5plBeK2Ge1I9g
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

Updated patch attached:

sizeof(struct sx) should be the same.
garbage removed from kern_sx.c.
alignment of "struct thread" set to constant rather than magic number.
uma_zalloc of "struct thread" fixed to use constant.



-- 
- Alfred Perlstein

--SnV5plBeK2Ge1I9g
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="netsmp_rwlock_freebsd6_09032007.diff"

Index: conf/NOTES
===================================================================
RCS file: /cvs/ncvs/src/sys/conf/NOTES,v
retrieving revision 1.1325.2.36
diff -c -r1.1325.2.36 NOTES
*** conf/NOTES	8 Jul 2007 15:30:28 -0000	1.1325.2.36
--- conf/NOTES	31 Aug 2007 00:39:59 -0000
***************
*** 189,200 ****
--- 189,214 ----
  # to disable it.
  options 	NO_ADAPTIVE_MUTEXES
  
+ # ADAPTIVE_RWLOCKS changes the behavior of reader/writer locks to spin
+ # if the thread that currently owns the rwlock is executing on another
+ # CPU.  This behaviour is enabled by default, so this option can be used
+ # to disable it.
+ options         NO_ADAPTIVE_RWLOCKS
+ 
+ 
  # ADAPTIVE_GIANT causes the Giant lock to also be made adaptive when
  # running without NO_ADAPTIVE_MUTEXES.  Normally, because Giant is assumed
  # to be held for extended periods, contention on Giant will cause a thread
  # to sleep rather than spinning.
  options 	ADAPTIVE_GIANT
  
+  
+ # ADAPTIVE_SX changes the behavior of sx locks to spin if the thread
+ # that currently owns the lock is executing on another CPU.  Note that
+ # in addition to enabling this option, individual sx locks must be
+ # initialized with the SX_ADAPTIVESPIN flag.
+ options   ADAPTIVE_SX
+ 
  # MUTEX_NOINLINE forces mutex operations to call functions to perform each
  # operation rather than inlining the simple cases.  This can be used to
  # shrink the size of the kernel text segment.  Note that this behavior is
***************
*** 207,212 ****
--- 221,240 ----
  # priority waiter.
  options 	MUTEX_WAKE_ALL
  
+ # RWLOCK_NOINLINE forces rwlock operations to call functions to perform each
+ # operation rather than inlining the simple cases.  This can be used to
+ # shrink the size of the kernel text segment.  Note that this behavior is
+ # already implied by the INVARIANT_SUPPORT, INVARIANTS, KTR, LOCK_PROFILING,
+ # and WITNESS options.
+ options         RWLOCK_NOINLINE
+ 
+ # SX_NOINLINE forces sx lock operations to call functions to perform each
+ # operation rather than inlining the simple cases.  This can be used to
+ # shrink the size of the kernel text segment.  Note that this behavior is
+ # already implied by the INVARIANT_SUPPORT, INVARIANTS, KTR, LOCK_PROFILING,
+ # and WITNESS options.
+ options    SX_NOINLINE
+ 
  # SMP Debugging Options:
  #
  # PREEMPTION allows the threads that are in the kernel to be preempted
Index: conf/files
===================================================================
RCS file: /cvs/ncvs/src/sys/conf/files,v
retrieving revision 1.1031.2.67
diff -c -r1.1031.2.67 files
*** conf/files	23 Aug 2007 22:30:14 -0000	1.1031.2.67
--- conf/files	31 Aug 2007 00:39:59 -0000
***************
*** 1312,1317 ****
--- 1312,1318 ----
  kern/kern_proc.c		standard
  kern/kern_prot.c		standard
  kern/kern_resource.c		standard
+ kern/kern_rwlock.c		standard
  kern/kern_sema.c		standard
  kern/kern_shutdown.c		standard
  kern/kern_sig.c			standard
Index: conf/options
===================================================================
RCS file: /cvs/ncvs/src/sys/conf/options,v
retrieving revision 1.510.2.21
diff -c -r1.510.2.21 options
*** conf/options	8 Jul 2007 15:30:28 -0000	1.510.2.21
--- conf/options	31 Aug 2007 00:39:59 -0000
***************
*** 60,66 ****
--- 60,68 ----
  
  # Miscellaneous options.
  ADAPTIVE_GIANT	opt_adaptive_mutexes.h
+ ADAPTIVE_SX
  NO_ADAPTIVE_MUTEXES	opt_adaptive_mutexes.h
+ NO_ADAPTIVE_RWLOCKS
  ALQ
  AUDIT		opt_global.h
  CODA_COMPAT_5	opt_coda.h
***************
*** 517,522 ****
--- 519,526 ----
  MSIZE			opt_global.h
  REGRESSION		opt_global.h
  RESTARTABLE_PANICS	opt_global.h
+ RWLOCK_NOINLINE		opt_global.h
+ SX_NOINLINE		opt_global.h
  VFS_BIO_DEBUG		opt_global.h
  
  # These are VM related options
Index: dev/acpica/acpi_ec.c
===================================================================
RCS file: /cvs/ncvs/src/sys/dev/acpica/acpi_ec.c,v
retrieving revision 1.65.2.2
diff -c -r1.65.2.2 acpi_ec.c
*** dev/acpica/acpi_ec.c	11 May 2006 17:41:00 -0000	1.65.2.2
--- dev/acpica/acpi_ec.c	31 Aug 2007 01:20:08 -0000
***************
*** 144,149 ****
--- 144,150 ----
  #include <sys/bus.h>
  #include <sys/malloc.h>
  #include <sys/module.h>
+ #include <sys/lock.h>
  #include <sys/sx.h>
  
  #include <machine/bus.h>
Index: kern/kern_ktrace.c
===================================================================
RCS file: /cvs/ncvs/src/sys/kern/kern_ktrace.c,v
retrieving revision 1.101.2.5
diff -c -r1.101.2.5 kern_ktrace.c
*** kern/kern_ktrace.c	6 Sep 2006 21:43:59 -0000	1.101.2.5
--- kern/kern_ktrace.c	31 Aug 2007 00:39:59 -0000
***************
*** 53,58 ****
--- 53,59 ----
  #include <sys/vnode.h>
  #include <sys/ktrace.h>
  #include <sys/sx.h>
+ #include <sys/condvar.h>
  #include <sys/sysctl.h>
  #include <sys/syslog.h>
  #include <sys/sysproto.h>
Index: kern/kern_rwlock.c
===================================================================
RCS file: kern/kern_rwlock.c
diff -N kern/kern_rwlock.c
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- kern/kern_rwlock.c	31 Aug 2007 03:25:24 -0000
***************
*** 0 ****
--- 1,943 ----
+ /*-
+  * Copyright (c) 2006 John Baldwin <jhb@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 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.
+  */
+ 
+ /*
+  * Machine independent bits of reader/writer lock implementation.
+  */
+ 
+ #include <sys/cdefs.h>
+ __FBSDID("$FreeBSD: src/sys/kern/kern_rwlock.c,v 1.27 2007/06/26 21:31:56 attilio Exp $");
+ 
+ #include "opt_ddb.h"
+ 
+ #include <sys/param.h>
+ #include <sys/ktr.h>
+ #include <sys/lock.h>
+ #include <sys/mutex.h>
+ #include <sys/proc.h>
+ #include <sys/rwlock.h>
+ #include <sys/systm.h>
+ #include <sys/turnstile.h>
+ #include <sys/lock_profile.h>
+ #include <machine/cpu.h>
+ 
+ CTASSERT((RW_RECURSE & LO_CLASSFLAGS) == RW_RECURSE);
+ 
+ #if defined(SMP) && !defined(NO_ADAPTIVE_RWLOCKS)
+ #define	ADAPTIVE_RWLOCKS
+ #endif
+ 
+ #ifdef DDB
+ #include <ddb/ddb.h>
+ 
+ static void	db_show_rwlock(struct lock_object *lock);
+ #endif
+ 
+ struct lock_class lock_class_rw = {
+ 	.lc_name = "rw",
+ 	.lc_flags = LC_SLEEPLOCK | LC_RECURSABLE | LC_UPGRADABLE,
+ #ifdef DDB
+ 	.lc_ddb_show = db_show_rwlock,
+ #endif
+ };
+ 
+ /*
+  * Return a pointer to the owning thread if the lock is write-locked or
+  * NULL if the lock is unlocked or read-locked.
+  */
+ #define	rw_wowner(rw)							\
+ 	((rw)->rw_lock & RW_LOCK_READ ? NULL :				\
+ 	    (struct thread *)RW_OWNER((rw)->rw_lock))
+ 
+ /*
+  * Returns if a write owner is recursed.  Write ownership is not assured
+  * here and should be previously checked.
+  */
+ #define	rw_recursed(rw)		((rw)->rw_recurse != 0)
+ 
+ /*
+  * Return true if curthread helds the lock.
+  */
+ #define	rw_wlocked(rw)		(rw_wowner((rw)) == curthread)
+ 
+ /*
+  * Return a pointer to the owning thread for this lock who should receive
+  * any priority lent by threads that block on this lock.  Currently this
+  * is identical to rw_wowner().
+  */
+ #define	rw_owner(rw)		rw_wowner(rw)
+ 
+ #ifndef INVARIANTS
+ #define	_rw_assert(rw, what, file, line)
+ #endif
+ 
+ void
+ rw_init_flags(struct rwlock *rw, const char *name, int opts)
+ {
+ 	struct lock_object *lock;
+ 	int flags;
+ 
+ 	MPASS((opts & ~(RW_DUPOK | RW_NOPROFILE | RW_NOWITNESS | RW_QUIET |
+ 	    RW_RECURSE)) == 0);
+ 
+ 	flags = LO_UPGRADABLE | LO_RECURSABLE;
+ 	if (opts & RW_DUPOK)
+ 		flags |= LO_DUPOK;
+ 	if (!(opts & RW_NOWITNESS))
+ 		flags |= LO_WITNESS;
+ 	if (opts & RW_QUIET)
+ 		flags |= LO_QUIET;
+ 	flags |= opts & RW_RECURSE;
+ 
+ 	rw->rw_lock = RW_UNLOCKED;
+ 	rw->rw_recurse = 0;
+ 	lock = &rw->lock_object;
+ 	lock->lo_class = &lock_class_rw;
+ 	lock->lo_flags = flags;
+ 	lock->lo_name = lock->lo_type = name;
+ 	LOCK_LOG_INIT(lock, opts);
+ 	WITNESS_INIT(lock);
+ }
+ 
+ void
+ rw_destroy(struct rwlock *rw)
+ {
+ 
+ 	LOCK_LOG_DESTROY(&rw->lock_object, 0);
+ 	KASSERT(rw->rw_lock == RW_UNLOCKED, ("rw lock not unlocked"));
+ 	KASSERT(rw->rw_recurse == 0, ("rw lock still recursed"));
+ 	rw->rw_lock = RW_DESTROYED;
+ 	WITNESS_DESTROY(&rw->lock_object);
+ }
+ 
+ void
+ rw_sysinit(void *arg)
+ {
+ 	struct rw_args *args = arg;
+ 
+ 	rw_init(args->ra_rw, args->ra_desc);
+ }
+ 
+ int
+ rw_wowned(struct rwlock *rw)
+ {
+ 
+ 	return (rw_wowner(rw) == curthread);
+ }
+ 
+ void
+ _rw_wlock(struct rwlock *rw, const char *file, int line)
+ {
+ 
+ 	MPASS(curthread != NULL);
+ 	KASSERT(rw->rw_lock != RW_DESTROYED,
+ 	    ("rw_wlock() of destroyed rwlock @ %s:%d", file, line));
+ 	KASSERT(rw_wowner(rw) != curthread,
+ 	    ("%s (%s): wlock already held @ %s:%d", __func__,
+ 	    rw->lock_object.lo_name, file, line));
+ 	WITNESS_CHECKORDER(&rw->lock_object, LOP_NEWORDER | LOP_EXCLUSIVE, file,
+ 	    line);
+ 	__rw_wlock(rw, curthread, file, line);
+ 	LOCK_LOG_LOCK("WLOCK", &rw->lock_object, 0, rw->rw_recurse, file, line);
+ 	WITNESS_LOCK(&rw->lock_object, LOP_EXCLUSIVE, file, line);
+ 	curthread->td_locks++;
+ }
+ 
+ void
+ _rw_wunlock(struct rwlock *rw, const char *file, int line)
+ {
+ 
+ 	MPASS(curthread != NULL);
+ 	KASSERT(rw->rw_lock != RW_DESTROYED,
+ 	    ("rw_wunlock() of destroyed rwlock @ %s:%d", file, line));
+ 	_rw_assert(rw, RA_WLOCKED, file, line);
+ 	curthread->td_locks--;
+ 	WITNESS_UNLOCK(&rw->lock_object, LOP_EXCLUSIVE, file, line);
+ 	LOCK_LOG_LOCK("WUNLOCK", &rw->lock_object, 0, rw->rw_recurse, file,
+ 	    line);
+ 	if (!rw_recursed(rw))
+ 		lock_profile_release_lock(&rw->lock_object);
+ 	__rw_wunlock(rw, curthread, file, line);
+ }
+ 
+ void
+ _rw_rlock(struct rwlock *rw, const char *file, int line)
+ {
+ #ifdef ADAPTIVE_RWLOCKS
+ 	volatile struct thread *owner;
+ #endif
+ 	//uint64_t waittime = 0; /* XXX: notsup */
+ 	//int contested = 0; /* XXX: notsup */
+ 	uintptr_t x;
+ 
+ 	KASSERT(rw->rw_lock != RW_DESTROYED,
+ 	    ("rw_rlock() of destroyed rwlock @ %s:%d", file, line));
+ 	KASSERT(rw_wowner(rw) != curthread,
+ 	    ("%s (%s): wlock already held @ %s:%d", __func__,
+ 	    rw->lock_object.lo_name, file, line));
+ 	WITNESS_CHECKORDER(&rw->lock_object, LOP_NEWORDER, file, line);
+ 
+ 	/*
+ 	 * Note that we don't make any attempt to try to block read
+ 	 * locks once a writer has blocked on the lock.  The reason is
+ 	 * that we currently allow for read locks to recurse and we
+ 	 * don't keep track of all the holders of read locks.  Thus, if
+ 	 * we were to block readers once a writer blocked and a reader
+ 	 * tried to recurse on their reader lock after a writer had
+ 	 * blocked we would end up in a deadlock since the reader would
+ 	 * be blocked on the writer, and the writer would be blocked
+ 	 * waiting for the reader to release its original read lock.
+ 	 */
+ 	for (;;) {
+ 		/*
+ 		 * Handle the easy case.  If no other thread has a write
+ 		 * lock, then try to bump up the count of read locks.  Note
+ 		 * that we have to preserve the current state of the
+ 		 * RW_LOCK_WRITE_WAITERS flag.  If we fail to acquire a
+ 		 * read lock, then rw_lock must have changed, so restart
+ 		 * the loop.  Note that this handles the case of a
+ 		 * completely unlocked rwlock since such a lock is encoded
+ 		 * as a read lock with no waiters.
+ 		 */
+ 		x = rw->rw_lock;
+ 		if (x & RW_LOCK_READ) {
+ 
+ 			/*
+ 			 * The RW_LOCK_READ_WAITERS flag should only be set
+ 			 * if another thread currently holds a write lock,
+ 			 * and in that case RW_LOCK_READ should be clear.
+ 			 */
+ 			MPASS((x & RW_LOCK_READ_WAITERS) == 0);
+ 			if (atomic_cmpset_acq_ptr(&rw->rw_lock, x,
+ 			    x + RW_ONE_READER)) {
+ 				if (LOCK_LOG_TEST(&rw->lock_object, 0))
+ 					CTR4(KTR_LOCK,
+ 					    "%s: %p succeed %p -> %p", __func__,
+ 					    rw, (void *)x,
+ 					    (void *)(x + RW_ONE_READER));
+ 				if (RW_READERS(x) == 0)
+ 					lock_profile_obtain_lock_success(
+ 					    &rw->lock_object, contested, waittime,
+ 					    file, line);
+ 				break;
+ 			}
+ 			cpu_spinwait();
+ 			continue;
+ 		}
+ 		lock_profile_obtain_lock_failed(&rw->lock_object, &contested,
+ 		    &waittime);
+ 
+ 		/*
+ 		 * Okay, now it's the hard case.  Some other thread already
+ 		 * has a write lock, so acquire the turnstile lock so we can
+ 		 * begin the process of blocking.
+ 		 */
+ 		turnstile_lock(&rw->lock_object);
+ 
+ 		/*
+ 		 * The lock might have been released while we spun, so
+ 		 * recheck its state and restart the loop if there is no
+ 		 * longer a write lock.
+ 		 */
+ 		x = rw->rw_lock;
+ 		if (x & RW_LOCK_READ) {
+ 			turnstile_release(&rw->lock_object);
+ 			cpu_spinwait();
+ 			continue;
+ 		}
+ 
+ 		/*
+ 		 * Ok, it's still a write lock.  If the RW_LOCK_READ_WAITERS
+ 		 * flag is already set, then we can go ahead and block.  If
+ 		 * it is not set then try to set it.  If we fail to set it
+ 		 * drop the turnstile lock and restart the loop.
+ 		 */
+ 		if (!(x & RW_LOCK_READ_WAITERS)) {
+ 			if (!atomic_cmpset_ptr(&rw->rw_lock, x,
+ 			    x | RW_LOCK_READ_WAITERS)) {
+ 				turnstile_release(&rw->lock_object);
+ 				cpu_spinwait();
+ 				continue;
+ 			}
+ 			if (LOCK_LOG_TEST(&rw->lock_object, 0))
+ 				CTR2(KTR_LOCK, "%s: %p set read waiters flag",
+ 				    __func__, rw);
+ 		}
+ 
+ #ifdef ADAPTIVE_RWLOCKS
+ 		owner = (struct thread *)RW_OWNER(x);
+ 		/*
+ 		 * If the owner is running on another CPU, spin until
+ 		 * the owner stops running or the state of the lock
+ 		 * changes.
+ 		 */
+ 		if (TD_IS_RUNNING(owner)) {
+ 			turnstile_release(&rw->lock_object);
+ 			if (LOCK_LOG_TEST(&rw->lock_object, 0))
+ 				CTR3(KTR_LOCK, "%s: spinning on %p held by %p",
+ 				    __func__, rw, owner);
+ 			while ((struct thread*)RW_OWNER(rw->rw_lock)== owner &&
+ 			    TD_IS_RUNNING(owner))
+ 				cpu_spinwait();
+ 			continue;
+ 		}
+ #endif
+ 
+ 		/*
+ 		 * We were unable to acquire the lock and the read waiters
+ 		 * flag is set, so we must block on the turnstile.
+ 		 */
+ 		if (LOCK_LOG_TEST(&rw->lock_object, 0))
+ 			CTR2(KTR_LOCK, "%s: %p blocking on turnstile", __func__,
+ 			    rw);
+ 		turnstile_wait_queue(&rw->lock_object, rw_owner(rw),
+ 		    TS_SHARED_QUEUE);
+ 		if (LOCK_LOG_TEST(&rw->lock_object, 0))
+ 			CTR2(KTR_LOCK, "%s: %p resuming from turnstile",
+ 			    __func__, rw);
+ 	}
+ 
+ 	/*
+ 	 * TODO: acquire "owner of record" here.  Here be turnstile dragons
+ 	 * however.  turnstiles don't like owners changing between calls to
+ 	 * turnstile_wait() currently.
+ 	 */
+ 
+ 	LOCK_LOG_LOCK("RLOCK", &rw->lock_object, 0, 0, file, line);
+ 	WITNESS_LOCK(&rw->lock_object, 0, file, line);
+ 	curthread->td_locks++;
+ }
+ 
+ void
+ _rw_runlock(struct rwlock *rw, const char *file, int line)
+ {
+ 	struct turnstile *ts;
+ 	uintptr_t x;
+ 
+ 	KASSERT(rw->rw_lock != RW_DESTROYED,
+ 	    ("rw_runlock() of destroyed rwlock @ %s:%d", file, line));
+ 	_rw_assert(rw, RA_RLOCKED, file, line);
+ 	curthread->td_locks--;
+ 	WITNESS_UNLOCK(&rw->lock_object, 0, file, line);
+ 	LOCK_LOG_LOCK("RUNLOCK", &rw->lock_object, 0, 0, file, line);
+ 
+ 	/* TODO: drop "owner of record" here. */
+ 
+ 	for (;;) {
+ 		/*
+ 		 * See if there is more than one read lock held.  If so,
+ 		 * just drop one and return.
+ 		 */
+ 		x = rw->rw_lock;
+ 		if (RW_READERS(x) > 1) {
+ 			if (atomic_cmpset_ptr(&rw->rw_lock, x,
+ 			    x - RW_ONE_READER)) {
+ 				if (LOCK_LOG_TEST(&rw->lock_object, 0))
+ 					CTR4(KTR_LOCK,
+ 					    "%s: %p succeeded %p -> %p",
+ 					    __func__, rw, (void *)x,
+ 					    (void *)(x - RW_ONE_READER));
+ 				break;
+ 			}
+ 			continue;
+ 		}
+ 
+ 
+ 		/*
+ 		 * We should never have read waiters while at least one
+ 		 * thread holds a read lock.  (See note above)
+ 		 */
+ 		KASSERT(!(x & RW_LOCK_READ_WAITERS),
+ 		    ("%s: waiting readers", __func__));
+ 
+ 		/*
+ 		 * If there aren't any waiters for a write lock, then try
+ 		 * to drop it quickly.
+ 		 */
+ 		if (!(x & RW_LOCK_WRITE_WAITERS)) {
+ 
+ 			/*
+ 			 * There shouldn't be any flags set and we should
+ 			 * be the only read lock.  If we fail to release
+ 			 * the single read lock, then another thread might
+ 			 * have just acquired a read lock, so go back up
+ 			 * to the multiple read locks case.
+ 			 */
+ 			MPASS(x == RW_READERS_LOCK(1));
+ 			if (atomic_cmpset_ptr(&rw->rw_lock, RW_READERS_LOCK(1),
+ 			    RW_UNLOCKED)) {
+ 				if (LOCK_LOG_TEST(&rw->lock_object, 0))
+ 					CTR2(KTR_LOCK, "%s: %p last succeeded",
+ 					    __func__, rw);
+ 				break;
+ 			}
+ 			continue;
+ 		}
+ 
+ 		/*
+ 		 * There should just be one reader with one or more
+ 		 * writers waiting.
+ 		 */
+ 		MPASS(x == (RW_READERS_LOCK(1) | RW_LOCK_WRITE_WAITERS));
+ 
+ 		/*
+ 		 * Ok, we know we have a waiting writer and we think we
+ 		 * are the last reader, so grab the turnstile lock.
+ 		 */
+ 		turnstile_lock(&rw->lock_object);
+ 
+ 		/*
+ 		 * Try to drop our lock leaving the lock in a unlocked
+ 		 * state.
+ 		 *
+ 		 * If you wanted to do explicit lock handoff you'd have to
+ 		 * do it here.  You'd also want to use turnstile_signal()
+ 		 * and you'd have to handle the race where a higher
+ 		 * priority thread blocks on the write lock before the
+ 		 * thread you wakeup actually runs and have the new thread
+ 		 * "steal" the lock.  For now it's a lot simpler to just
+ 		 * wakeup all of the waiters.
+ 		 *
+ 		 * As above, if we fail, then another thread might have
+ 		 * acquired a read lock, so drop the turnstile lock and
+ 		 * restart.
+ 		 */
+ 		if (!atomic_cmpset_ptr(&rw->rw_lock,
+ 		    RW_READERS_LOCK(1) | RW_LOCK_WRITE_WAITERS, RW_UNLOCKED)) {
+ 			turnstile_release(&rw->lock_object);
+ 			continue;
+ 		}
+ 		if (LOCK_LOG_TEST(&rw->lock_object, 0))
+ 			CTR2(KTR_LOCK, "%s: %p last succeeded with waiters",
+ 			    __func__, rw);
+ 
+ 		/*
+ 		 * Ok.  The lock is released and all that's left is to
+ 		 * wake up the waiters.  Note that the lock might not be
+ 		 * free anymore, but in that case the writers will just
+ 		 * block again if they run before the new lock holder(s)
+ 		 * release the lock.
+ 		 */
+ 		ts = turnstile_lookup(&rw->lock_object);
+ 		MPASS(ts != NULL);
+ 		turnstile_broadcast_queue(ts, TS_EXCLUSIVE_QUEUE);
+ 		turnstile_unpend_queue(ts, TS_SHARED_LOCK);
+ 		turnstile_release(&rw->lock_object);
+ 		break;
+ 	}
+ 	lock_profile_release_lock(&rw->lock_object);
+ }
+ 
+ /*
+  * This function is called when we are unable to obtain a write lock on the
+  * first try.  This means that at least one other thread holds either a
+  * read or write lock.
+  */
+ void
+ _rw_wlock_hard(struct rwlock *rw, uintptr_t tid, const char *file, int line)
+ {
+ 	//struct turnstile *ts;
+ #ifdef ADAPTIVE_RWLOCKS
+ 	volatile struct thread *owner;
+ #endif
+ 	uintptr_t v;
+ 
+ 	if (rw_wlocked(rw)) {
+ 		KASSERT(rw->lock_object.lo_flags & RW_RECURSE,
+ 		    ("%s: recursing but non-recursive rw %s @ %s:%d\n",
+ 		    __func__, rw->lock_object.lo_name, file, line));
+ 		rw->rw_recurse++;
+ 		atomic_set_ptr(&rw->rw_lock, RW_LOCK_RECURSED);
+ 		if (LOCK_LOG_TEST(&rw->lock_object, 0))
+ 			CTR2(KTR_LOCK, "%s: %p recursing", __func__, rw);
+ 		return;
+ 	}
+ 
+ 	if (LOCK_LOG_TEST(&rw->lock_object, 0))
+ 		CTR5(KTR_LOCK, "%s: %s contested (lock=%p) at %s:%d", __func__,
+ 		    rw->lock_object.lo_name, (void *)rw->rw_lock, file, line);
+ 
+ 	while (!_rw_write_lock(rw, tid)) {
+ 		turnstile_lock(&rw->lock_object);
+ 		v = rw->rw_lock;
+ 
+ 		/*
+ 		 * If the lock was released while spinning on the
+ 		 * turnstile chain lock, try again.
+ 		 */
+ 		if (v == RW_UNLOCKED) {
+ 			turnstile_release(&rw->lock_object);
+ 			cpu_spinwait();
+ 			continue;
+ 		}
+ 
+ 		/*
+ 		 * If the lock was released by a writer with both readers
+ 		 * and writers waiting and a reader hasn't woken up and
+ 		 * acquired the lock yet, rw_lock will be set to the
+ 		 * value RW_UNLOCKED | RW_LOCK_WRITE_WAITERS.  If we see
+ 		 * that value, try to acquire it once.  Note that we have
+ 		 * to preserve the RW_LOCK_WRITE_WAITERS flag as there are
+ 		 * other writers waiting still.  If we fail, restart the
+ 		 * loop.
+ 		 */
+ 		if (v == (RW_UNLOCKED | RW_LOCK_WRITE_WAITERS)) {
+ 			if (atomic_cmpset_acq_ptr(&rw->rw_lock,
+ 			    RW_UNLOCKED | RW_LOCK_WRITE_WAITERS,
+ 			    tid | RW_LOCK_WRITE_WAITERS)) {
+ 				turnstile_claim(&rw->lock_object);
+ 				CTR2(KTR_LOCK, "%s: %p claimed by new writer",
+ 				    __func__, rw);
+ 				break;
+ 			}
+ 			turnstile_release(&rw->lock_object);
+ 			cpu_spinwait();
+ 			continue;
+ 		}
+ 
+ 		/*
+ 		 * If the RW_LOCK_WRITE_WAITERS flag isn't set, then try to
+ 		 * set it.  If we fail to set it, then loop back and try
+ 		 * again.
+ 		 */
+ 		if (!(v & RW_LOCK_WRITE_WAITERS)) {
+ 			if (!atomic_cmpset_ptr(&rw->rw_lock, v,
+ 			    v | RW_LOCK_WRITE_WAITERS)) {
+ 				turnstile_release(&rw->lock_object);
+ 				cpu_spinwait();
+ 				continue;
+ 			}
+ 			if (LOCK_LOG_TEST(&rw->lock_object, 0))
+ 				CTR2(KTR_LOCK, "%s: %p set write waiters flag",
+ 				    __func__, rw);
+ 		}
+ 
+ #ifdef ADAPTIVE_RWLOCKS
+ 		/*
+ 		 * If the lock is write locked and the owner is
+ 		 * running on another CPU, spin until the owner stops
+ 		 * running or the state of the lock changes.
+ 		 */
+ 		owner = (struct thread *)RW_OWNER(v);
+ 		if (!(v & RW_LOCK_READ) && TD_IS_RUNNING(owner)) {
+ 			turnstile_release(&rw->lock_object);
+ 			if (LOCK_LOG_TEST(&rw->lock_object, 0))
+ 				CTR3(KTR_LOCK, "%s: spinning on %p held by %p",
+ 				    __func__, rw, owner);
+ 			while ((struct thread*)RW_OWNER(rw->rw_lock)== owner &&
+ 			    TD_IS_RUNNING(owner))
+ 				cpu_spinwait();
+ 			continue;
+ 		}
+ #endif
+ 
+ 		/*
+ 		 * We were unable to acquire the lock and the write waiters
+ 		 * flag is set, so we must block on the turnstile.
+ 		 */
+ 		if (LOCK_LOG_TEST(&rw->lock_object, 0))
+ 			CTR2(KTR_LOCK, "%s: %p blocking on turnstile", __func__,
+ 			    rw);
+ 		turnstile_wait_queue(&rw->lock_object, rw_owner(rw),
+ 		    TS_EXCLUSIVE_QUEUE);
+ 		if (LOCK_LOG_TEST(&rw->lock_object, 0))
+ 			CTR2(KTR_LOCK, "%s: %p resuming from turnstile",
+ 			    __func__, rw);
+ 	}
+ }
+ 
+ /*
+  * This function is called if the first try at releasing a write lock failed.
+  * This means that one of the 2 waiter bits must be set indicating that at
+  * least one thread is waiting on this lock.
+  */
+ void
+ _rw_wunlock_hard(struct rwlock *rw, uintptr_t tid, const char *file, int line)
+ {
+ 	struct turnstile *ts;
+ 	uintptr_t v;
+ 	int queue;
+ 
+ 	if (rw_wlocked(rw) && rw_recursed(rw)) {
+ 		if ((--rw->rw_recurse) == 0)
+ 			atomic_clear_ptr(&rw->rw_lock, RW_LOCK_RECURSED);
+ 		if (LOCK_LOG_TEST(&rw->lock_object, 0))
+ 			CTR2(KTR_LOCK, "%s: %p unrecursing", __func__, rw);
+ 		return;
+ 	}
+ 
+ 	KASSERT(rw->rw_lock & (RW_LOCK_READ_WAITERS | RW_LOCK_WRITE_WAITERS),
+ 	    ("%s: neither of the waiter flags are set", __func__));
+ 
+ 	if (LOCK_LOG_TEST(&rw->lock_object, 0))
+ 		CTR2(KTR_LOCK, "%s: %p contested", __func__, rw);
+ 
+ 	turnstile_lock(&rw->lock_object);
+ 	ts = turnstile_lookup(&rw->lock_object);
+ 
+ #ifdef ADAPTIVE_RWLOCKS
+ 	/*
+ 	 * There might not be a turnstile for this lock if all of
+ 	 * the waiters are adaptively spinning.  In that case, just
+ 	 * reset the lock to the unlocked state and return.
+ 	 */
+ 	if (ts == NULL) {
+ 		atomic_store_rel_ptr(&rw->rw_lock, RW_UNLOCKED);
+ 		if (LOCK_LOG_TEST(&rw->lock_object, 0))
+ 			CTR2(KTR_LOCK, "%s: %p no sleepers", __func__, rw);
+ 		turnstile_release(&rw->lock_object);
+ 		return;
+ 	}
+ #else
+ 	MPASS(ts != NULL);
+ #endif
+ 
+ 	/*
+ 	 * Use the same algo as sx locks for now.  Prefer waking up shared
+ 	 * waiters if we have any over writers.  This is probably not ideal.
+ 	 *
+ 	 * 'v' is the value we are going to write back to rw_lock.  If we
+ 	 * have waiters on both queues, we need to preserve the state of
+ 	 * the waiter flag for the queue we don't wake up.  For now this is
+ 	 * hardcoded for the algorithm mentioned above.
+ 	 *
+ 	 * In the case of both readers and writers waiting we wakeup the
+ 	 * readers but leave the RW_LOCK_WRITE_WAITERS flag set.  If a
+ 	 * new writer comes in before a reader it will claim the lock up
+ 	 * above.  There is probably a potential priority inversion in
+ 	 * there that could be worked around either by waking both queues
+ 	 * of waiters or doing some complicated lock handoff gymnastics.
+ 	 *
+ 	 * Note that in the ADAPTIVE_RWLOCKS case, if both flags are
+ 	 * set, there might not be any actual writers on the turnstile
+ 	 * as they might all be spinning.  In that case, we don't want
+ 	 * to preserve the RW_LOCK_WRITE_WAITERS flag as the turnstile
+ 	 * is going to go away once we wakeup all the readers.
+ 	 */
+ 	v = RW_UNLOCKED;
+ 	if (rw->rw_lock & RW_LOCK_READ_WAITERS) {
+ 		queue = TS_SHARED_QUEUE;
+ #ifdef ADAPTIVE_RWLOCKS
+ 		if (rw->rw_lock & RW_LOCK_WRITE_WAITERS &&
+ 		    !turnstile_empty_queue(ts, TS_EXCLUSIVE_QUEUE))
+ 			v |= RW_LOCK_WRITE_WAITERS;
+ #else
+ 		v |= (rw->rw_lock & RW_LOCK_WRITE_WAITERS);
+ #endif
+ 	} else
+ 		queue = TS_EXCLUSIVE_QUEUE;
+ 
+ #ifdef ADAPTIVE_RWLOCKS
+ 	/*
+ 	 * We have to make sure that we actually have waiters to
+ 	 * wakeup.  If they are all spinning, then we just need to
+ 	 * disown the turnstile and return.
+ 	 */
+ 	if (turnstile_empty_queue(ts, queue)) {
+ 		if (LOCK_LOG_TEST(&rw->lock_object, 0))
+ 			CTR2(KTR_LOCK, "%s: %p no sleepers 2", __func__, rw);
+ 		atomic_store_rel_ptr(&rw->rw_lock, v);
+ 		turnstile_disown(ts);
+ 		turnstile_release(&rw->lock_object);
+ 		return;
+ 	}
+ #endif
+ 
+ 	/* Wake up all waiters for the specific queue. */
+ 	if (LOCK_LOG_TEST(&rw->lock_object, 0))
+ 		CTR3(KTR_LOCK, "%s: %p waking up %s waiters", __func__, rw,
+ 		    queue == TS_SHARED_QUEUE ? "read" : "write");
+ 	turnstile_broadcast_queue(ts, queue);
+ 	atomic_store_rel_ptr(&rw->rw_lock, v);
+ 	turnstile_unpend_queue(ts, TS_EXCLUSIVE_LOCK);
+ 	turnstile_release(&rw->lock_object);
+ }
+ 
+ /*
+  * Attempt to do a non-blocking upgrade from a read lock to a write
+  * lock.  This will only succeed if this thread holds a single read
+  * lock.  Returns true if the upgrade succeeded and false otherwise.
+  */
+ int
+ _rw_try_upgrade(struct rwlock *rw, const char *file, int line)
+ {
+ 	uintptr_t v, tid;
+ 	int success;
+ 
+ 	KASSERT(rw->rw_lock != RW_DESTROYED,
+ 	    ("rw_try_upgrade() of destroyed rwlock @ %s:%d", file, line));
+ 	_rw_assert(rw, RA_RLOCKED, file, line);
+ 
+ 	/*
+ 	 * Attempt to switch from one reader to a writer.  If there
+ 	 * are any write waiters, then we will have to lock the
+ 	 * turnstile first to prevent races with another writer
+ 	 * calling turnstile_wait() before we have claimed this
+ 	 * turnstile.  So, do the simple case of no waiters first.
+ 	 */
+ 	tid = (uintptr_t)curthread;
+ 	if (!(rw->rw_lock & RW_LOCK_WRITE_WAITERS)) {
+ 		success = atomic_cmpset_ptr(&rw->rw_lock, RW_READERS_LOCK(1),
+ 		    tid);
+ 		goto out;
+ 	}
+ 
+ 	/*
+ 	 * Ok, we think we have write waiters, so lock the
+ 	 * turnstile.
+ 	 */
+ 	turnstile_lock(&rw->lock_object);
+ 
+ 	/*
+ 	 * Try to switch from one reader to a writer again.  This time
+ 	 * we honor the current state of the RW_LOCK_WRITE_WAITERS
+ 	 * flag.  If we obtain the lock with the flag set, then claim
+ 	 * ownership of the turnstile.  In the ADAPTIVE_RWLOCKS case
+ 	 * it is possible for there to not be an associated turnstile
+ 	 * even though there are waiters if all of the waiters are
+ 	 * spinning.
+ 	 */
+ 	v = rw->rw_lock & RW_LOCK_WRITE_WAITERS;
+ 	success = atomic_cmpset_ptr(&rw->rw_lock, RW_READERS_LOCK(1) | v,
+ 	    tid | v);
+ #ifdef ADAPTIVE_RWLOCKS
+ 	if (success && v && turnstile_lookup(&rw->lock_object) != NULL)
+ #else
+ 	if (success && v)
+ #endif
+ 		turnstile_claim(&rw->lock_object);
+ 	else
+ 		turnstile_release(&rw->lock_object);
+ out:
+ 	LOCK_LOG_TRY("WUPGRADE", &rw->lock_object, 0, success, file, line);
+ 	if (success)
+ 		WITNESS_UPGRADE(&rw->lock_object, LOP_EXCLUSIVE | LOP_TRYLOCK,
+ 		    file, line);
+ 	return (success);
+ }
+ 
+ /*
+  * Downgrade a write lock into a single read lock.
+  */
+ void
+ _rw_downgrade(struct rwlock *rw, const char *file, int line)
+ {
+ 	struct turnstile *ts;
+ 	uintptr_t tid, v;
+ 
+ 	KASSERT(rw->rw_lock != RW_DESTROYED,
+ 	    ("rw_downgrade() of destroyed rwlock @ %s:%d", file, line));
+ 	_rw_assert(rw, RA_WLOCKED | RA_NOTRECURSED, file, line);
+ #ifndef INVARIANTS
+ 	if (rw_recursed(rw))
+ 		panic("downgrade of a recursed lock");
+ #endif
+ 
+ 	WITNESS_DOWNGRADE(&rw->lock_object, 0, file, line);
+ 
+ 	/*
+ 	 * Convert from a writer to a single reader.  First we handle
+ 	 * the easy case with no waiters.  If there are any waiters, we
+ 	 * lock the turnstile, "disown" the lock, and awaken any read
+ 	 * waiters.
+ 	 */
+ 	tid = (uintptr_t)curthread;
+ 	if (atomic_cmpset_rel_ptr(&rw->rw_lock, tid, RW_READERS_LOCK(1)))
+ 		goto out;
+ 
+ 	/*
+ 	 * Ok, we think we have waiters, so lock the turnstile so we can
+ 	 * read the waiter flags without any races.
+ 	 */
+ 	turnstile_lock(&rw->lock_object);
+ 	v = rw->rw_lock;
+ 	MPASS(v & (RW_LOCK_READ_WAITERS | RW_LOCK_WRITE_WAITERS));
+ 
+ 	/*
+ 	 * Downgrade from a write lock while preserving
+ 	 * RW_LOCK_WRITE_WAITERS and give up ownership of the
+ 	 * turnstile.  If there are any read waiters, wake them up.
+ 	 *
+ 	 * For ADAPTIVE_RWLOCKS, we have to allow for the fact that
+ 	 * all of the read waiters might be spinning.  In that case,
+ 	 * act as if RW_LOCK_READ_WAITERS is not set.  Also, only
+ 	 * preserve the RW_LOCK_WRITE_WAITERS flag if at least one
+ 	 * writer is blocked on the turnstile.
+ 	 */
+ 	ts = turnstile_lookup(&rw->lock_object);
+ #ifdef ADAPTIVE_RWLOCKS
+ 	if (ts == NULL)
+ 		v &= ~(RW_LOCK_READ_WAITERS | RW_LOCK_WRITE_WAITERS);
+ 	else if (v & RW_LOCK_READ_WAITERS &&
+ 	    turnstile_empty_queue(ts, TS_SHARED_QUEUE))
+ 		v &= ~RW_LOCK_READ_WAITERS;
+ 	else if (v & RW_LOCK_WRITE_WAITERS &&
+ 	    turnstile_empty_queue(ts, TS_EXCLUSIVE_QUEUE))
+ 		v &= ~RW_LOCK_WRITE_WAITERS;
+ #else
+ 	MPASS(ts != NULL);
+ #endif
+ 	if (v & RW_LOCK_READ_WAITERS)
+ 		turnstile_broadcast_queue(ts, TS_SHARED_QUEUE);
+ 	atomic_store_rel_ptr(&rw->rw_lock, RW_READERS_LOCK(1) |
+ 	    (v & RW_LOCK_WRITE_WAITERS));
+ 	if (v & RW_LOCK_READ_WAITERS)
+ 		turnstile_unpend_queue(ts, TS_EXCLUSIVE_LOCK);
+ 	else if (ts)
+ 		turnstile_disown(ts);
+ 	turnstile_release(&rw->lock_object);
+ out:
+ 	LOCK_LOG_LOCK("WDOWNGRADE", &rw->lock_object, 0, 0, file, line);
+ }
+ 
+ #ifdef INVARIANT_SUPPORT
+ #ifndef INVARIANTS
+ #undef _rw_assert
+ #endif
+ 
+ /*
+  * In the non-WITNESS case, rw_assert() can only detect that at least
+  * *some* thread owns an rlock, but it cannot guarantee that *this*
+  * thread owns an rlock.
+  */
+ void
+ _rw_assert(struct rwlock *rw, int what, const char *file, int line)
+ {
+ 
+ 	if (panicstr != NULL)
+ 		return;
+ 	switch (what) {
+ 	case RA_LOCKED:
+ 	case RA_LOCKED | RA_RECURSED:
+ 	case RA_LOCKED | RA_NOTRECURSED:
+ 	case RA_RLOCKED:
+ #ifdef WITNESS
+ 		witness_assert(&rw->lock_object, what, file, line);
+ #else
+ 		/*
+ 		 * If some other thread has a write lock or we have one
+ 		 * and are asserting a read lock, fail.  Also, if no one
+ 		 * has a lock at all, fail.
+ 		 */
+ 		if (rw->rw_lock == RW_UNLOCKED ||
+ 		    (!(rw->rw_lock & RW_LOCK_READ) && (what == RA_RLOCKED ||
+ 		    rw_wowner(rw) != curthread)))
+ 			panic("Lock %s not %slocked @ %s:%d\n",
+ 			    rw->lock_object.lo_name, (what == RA_RLOCKED) ?
+ 			    "read " : "", file, line);
+ 
+ 		if (!(rw->rw_lock & RW_LOCK_READ)) {
+ 			if (rw_recursed(rw)) {
+ 				if (what & RA_NOTRECURSED)
+ 					panic("Lock %s recursed @ %s:%d\n",
+ 					    rw->lock_object.lo_name, file,
+ 					    line);
+ 			} else if (what & RA_RECURSED)
+ 				panic("Lock %s not recursed @ %s:%d\n",
+ 				    rw->lock_object.lo_name, file, line);
+ 		}
+ #endif
+ 		break;
+ 	case RA_WLOCKED:
+ 	case RA_WLOCKED | RA_RECURSED:
+ 	case RA_WLOCKED | RA_NOTRECURSED:
+ 		if (rw_wowner(rw) != curthread)
+ 			panic("Lock %s not exclusively locked @ %s:%d\n",
+ 			    rw->lock_object.lo_name, file, line);
+ 		if (rw_recursed(rw)) {
+ 			if (what & RA_NOTRECURSED)
+ 				panic("Lock %s recursed @ %s:%d\n",
+ 				    rw->lock_object.lo_name, file, line);
+ 		} else if (what & RA_RECURSED)
+ 			panic("Lock %s not recursed @ %s:%d\n",
+ 			    rw->lock_object.lo_name, file, line);
+ 		break;
+ 	case RA_UNLOCKED:
+ #ifdef WITNESS
+ 		witness_assert(&rw->lock_object, what, file, line);
+ #else
+ 		/*
+ 		 * If we hold a write lock fail.  We can't reliably check
+ 		 * to see if we hold a read lock or not.
+ 		 */
+ 		if (rw_wowner(rw) == curthread)
+ 			panic("Lock %s exclusively locked @ %s:%d\n",
+ 			    rw->lock_object.lo_name, file, line);
+ #endif
+ 		break;
+ 	default:
+ 		panic("Unknown rw lock assertion: %d @ %s:%d", what, file,
+ 		    line);
+ 	}
+ }
+ #endif /* INVARIANT_SUPPORT */
+ 
+ #ifdef DDB
+ void
+ db_show_rwlock(struct lock_object *lock)
+ {
+ 	struct rwlock *rw;
+ 	struct thread *td;
+ 
+ 	rw = (struct rwlock *)lock;
+ 
+ 	db_printf(" state: ");
+ 	if (rw->rw_lock == RW_UNLOCKED)
+ 		db_printf("UNLOCKED\n");
+ 	else if (rw->rw_lock == RW_DESTROYED) {
+ 		db_printf("DESTROYED\n");
+ 		return;
+ 	} else if (rw->rw_lock & RW_LOCK_READ)
+ 		db_printf("RLOCK: %ju locks\n",
+ 		    (uintmax_t)(RW_READERS(rw->rw_lock)));
+ 	else {
+ 		td = rw_wowner(rw);
+ 		db_printf("WLOCK: %p (tid %d, pid %d, \"%s\")\n", td,
+ 		    td->td_tid, td->td_proc->p_pid, td->td_proc->p_comm);
+ 		if (rw_recursed(rw))
+ 			db_printf(" recursed: %u\n", rw->rw_recurse);
+ 	}
+ 	db_printf(" waiters: ");
+ 	switch (rw->rw_lock & (RW_LOCK_READ_WAITERS | RW_LOCK_WRITE_WAITERS)) {
+ 	case RW_LOCK_READ_WAITERS:
+ 		db_printf("readers\n");
+ 		break;
+ 	case RW_LOCK_WRITE_WAITERS:
+ 		db_printf("writers\n");
+ 		break;
+ 	case RW_LOCK_READ_WAITERS | RW_LOCK_WRITE_WAITERS:
+ 		db_printf("readers and writers\n");
+ 		break;
+ 	default:
+ 		db_printf("none\n");
+ 		break;
+ 	}
+ }
+ 
+ #endif
Index: kern/kern_sx.c
===================================================================
RCS file: /cvs/ncvs/src/sys/kern/kern_sx.c,v
retrieving revision 1.25.2.4
diff -c -r1.25.2.4 kern_sx.c
*** kern/kern_sx.c	17 Aug 2006 19:53:06 -0000	1.25.2.4
--- kern/kern_sx.c	31 Aug 2007 01:48:11 -0000
***************
*** 1,12 ****
  /*-
!  * Copyright (C) 2001 Jason Evans <jasone@freebsd.org>.  All rights reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   * 1. Redistributions of source code must retain the above copyright
   *    notice(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
--- 1,14 ----
  /*-
!  * Copyright (c) 2007 Attilio Rao <attilio@freebsd.org>
!  * Copyright (c) 2001 Jason Evans <jasone@freebsd.org>
!  * All rights reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   * 1. Redistributions of source code must retain the above copyright
   *    notice(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
***************
*** 26,64 ****
   */
  
  /*
!  * Shared/exclusive locks.  This implementation assures deterministic lock
!  * granting behavior, so that slocks and xlocks are interleaved.
   *
   * Priority propagation will not generally raise the priority of lock holders,
   * so should not be relied upon in combination with sx locks.
   */
  
! #include <sys/cdefs.h>
! __FBSDID("$FreeBSD: src/sys/kern/kern_sx.c,v 1.25.2.4 2006/08/17 19:53:06 jhb Exp $");
! 
  #include "opt_ddb.h"
  
  #include <sys/param.h>
- #include <sys/systm.h>
  #include <sys/ktr.h>
- #include <sys/linker_set.h>
- #include <sys/condvar.h>
  #include <sys/lock.h>
  #include <sys/mutex.h>
  #include <sys/proc.h>
  #include <sys/sx.h>
  
  #ifdef DDB
  #include <ddb/ddb.h>
  
  static void	db_show_sx(struct lock_object *lock);
  #endif
  
  struct lock_class lock_class_sx = {
! 	"sx",
! 	LC_SLEEPLOCK | LC_SLEEPABLE | LC_RECURSABLE | LC_UPGRADABLE,
  #ifdef DDB
! 	db_show_sx
  #endif
  };
  
--- 28,117 ----
   */
  
  /*
!  * Shared/exclusive locks.  This implementation attempts to ensure
!  * deterministic lock granting behavior, so that slocks and xlocks are
!  * interleaved.
   *
   * Priority propagation will not generally raise the priority of lock holders,
   * so should not be relied upon in combination with sx locks.
   */
  
! #include "opt_adaptive_sx.h"
  #include "opt_ddb.h"
  
+ #include <sys/cdefs.h>
+ __FBSDID("$FreeBSD: src/sys/kern/kern_sx.c,v 1.54 2007/07/06 13:20:44 attilio Exp $");
+ 
  #include <sys/param.h>
  #include <sys/ktr.h>
  #include <sys/lock.h>
  #include <sys/mutex.h>
  #include <sys/proc.h>
+ #include <sys/sleepqueue.h>
  #include <sys/sx.h>
+ #include <sys/systm.h>
+ 
+ #ifdef ADAPTIVE_SX
+ #include <machine/cpu.h>
+ #endif
  
  #ifdef DDB
  #include <ddb/ddb.h>
+ #endif
+ 
+ #if !defined(SMP) && defined(ADAPTIVE_SX)
+ #error "You must have SMP to enable the ADAPTIVE_SX option"
+ #endif
+ 
+ CTASSERT(((SX_ADAPTIVESPIN | SX_RECURSE) & LO_CLASSFLAGS) ==
+     (SX_ADAPTIVESPIN | SX_RECURSE));
+ 
+ /* Handy macros for sleep queues. */
+ #define	SQ_EXCLUSIVE_QUEUE	0
+ #define	SQ_SHARED_QUEUE		1
  
+ /*
+  * Variations on DROP_GIANT()/PICKUP_GIANT() for use in this file.  We
+  * drop Giant anytime we have to sleep or if we adaptively spin.
+  */
+ #define	GIANT_DECLARE							\
+ 	int _giantcnt = 0;						\
+ 	WITNESS_SAVE_DECL(Giant)					\
+ 
+ #define	GIANT_SAVE() do {						\
+ 	if (mtx_owned(&Giant)) {					\
+ 		WITNESS_SAVE(&Giant.mtx_object, Giant);		\
+ 		while (mtx_owned(&Giant)) {				\
+ 			_giantcnt++;					\
+ 			mtx_unlock(&Giant);				\
+ 		}							\
+ 	}								\
+ } while (0)
+ 
+ #define GIANT_RESTORE() do {						\
+ 	if (_giantcnt > 0) {						\
+ 		mtx_assert(&Giant, MA_NOTOWNED);			\
+ 		while (_giantcnt--)					\
+ 			mtx_lock(&Giant);				\
+ 		WITNESS_RESTORE(&Giant.mtx_object, Giant);		\
+ 	}								\
+ } while (0)
+ 
+ /*
+  * Returns true if an exclusive lock is recursed.  It assumes
+  * curthread currently has an exclusive lock.
+  */
+ #define	sx_recursed(sx)		((sx)->sx_recurse != 0)
+ 
+ #ifdef DDB
  static void	db_show_sx(struct lock_object *lock);
  #endif
  
  struct lock_class lock_class_sx = {
! 	.lc_name = "sx",
! 	.lc_flags = LC_SLEEPLOCK | LC_SLEEPABLE | LC_RECURSABLE | LC_UPGRADABLE,
  #ifdef DDB
! 	.lc_ddb_show = db_show_sx,
  #endif
  };
  
***************
*** 75,317 ****
  }
  
  void
! sx_init(struct sx *sx, const char *description)
  {
  
! 	sx->sx_lock = mtx_pool_find(mtxpool_lockbuilder, sx);
! 	sx->sx_cnt = 0;
! 	cv_init(&sx->sx_shrd_cv, description);
! 	sx->sx_shrd_wcnt = 0;
! 	cv_init(&sx->sx_excl_cv, description);
! 	sx->sx_excl_wcnt = 0;
! 	sx->sx_xholder = NULL;
! 	lock_init(&sx->sx_object, &lock_class_sx, description, NULL,
! 	    LO_WITNESS | LO_RECURSABLE | LO_SLEEPABLE | LO_UPGRADABLE);
  }
  
  void
  sx_destroy(struct sx *sx)
  {
  
! 	KASSERT((sx->sx_cnt == 0 && sx->sx_shrd_wcnt == 0 && sx->sx_excl_wcnt ==
! 	    0), ("%s (%s): holders or waiters\n", __func__,
! 	    sx->sx_object.lo_name));
! 
! 	sx->sx_lock = NULL;
! 	cv_destroy(&sx->sx_shrd_cv);
! 	cv_destroy(&sx->sx_excl_cv);
! 
! 	lock_destroy(&sx->sx_object);
  }
  
! void
! _sx_slock(struct sx *sx, const char *file, int line)
  {
  
! 	mtx_lock(sx->sx_lock);
! 	KASSERT(sx->sx_xholder != curthread,
! 	    ("%s (%s): slock while xlock is held @ %s:%d\n", __func__,
! 	    sx->sx_object.lo_name, file, line));
! 	WITNESS_CHECKORDER(&sx->sx_object, LOP_NEWORDER, file, line);
! 
! 	/*
! 	 * Loop in case we lose the race for lock acquisition.
! 	 */
! 	while (sx->sx_cnt < 0) {
! 		sx->sx_shrd_wcnt++;
! 		cv_wait(&sx->sx_shrd_cv, sx->sx_lock);
! 		sx->sx_shrd_wcnt--;
  	}
  
! 	/* Acquire a shared lock. */
! 	sx->sx_cnt++;
! 
! 	LOCK_LOG_LOCK("SLOCK", &sx->sx_object, 0, 0, file, line);
! 	WITNESS_LOCK(&sx->sx_object, 0, file, line);
! 	curthread->td_locks++;
! 
! 	mtx_unlock(sx->sx_lock);
  }
  
  int
  _sx_try_slock(struct sx *sx, const char *file, int line)
  {
  
! 	mtx_lock(sx->sx_lock);
! 	if (sx->sx_cnt >= 0) {
! 		sx->sx_cnt++;
! 		LOCK_LOG_TRY("SLOCK", &sx->sx_object, 0, 1, file, line);
! 		WITNESS_LOCK(&sx->sx_object, LOP_TRYLOCK, file, line);
  		curthread->td_locks++;
- 		mtx_unlock(sx->sx_lock);
  		return (1);
- 	} else {
- 		LOCK_LOG_TRY("SLOCK", &sx->sx_object, 0, 0, file, line);
- 		mtx_unlock(sx->sx_lock);
- 		return (0);
  	}
  }
  
! void
! _sx_xlock(struct sx *sx, const char *file, int line)
  {
  
! 	mtx_lock(sx->sx_lock);
! 
! 	/*
! 	 * With sx locks, we're absolutely not permitted to recurse on
! 	 * xlocks, as it is fatal (deadlock). Normally, recursion is handled
! 	 * by WITNESS, but as it is not semantically correct to hold the
! 	 * xlock while in here, we consider it API abuse and put it under
! 	 * INVARIANTS.
! 	 */
! 	KASSERT(sx->sx_xholder != curthread,
! 	    ("%s (%s): xlock already held @ %s:%d", __func__,
! 	    sx->sx_object.lo_name, file, line));
! 	WITNESS_CHECKORDER(&sx->sx_object, LOP_NEWORDER | LOP_EXCLUSIVE, file,
  	    line);
! 
! 	/* Loop in case we lose the race for lock acquisition. */
! 	while (sx->sx_cnt != 0) {
! 		sx->sx_excl_wcnt++;
! 		cv_wait(&sx->sx_excl_cv, sx->sx_lock);
! 		sx->sx_excl_wcnt--;
  	}
  
! 	MPASS(sx->sx_cnt == 0);
! 
! 	/* Acquire an exclusive lock. */
! 	sx->sx_cnt--;
! 	sx->sx_xholder = curthread;
! 
! 	LOCK_LOG_LOCK("XLOCK", &sx->sx_object, 0, 0, file, line);
! 	WITNESS_LOCK(&sx->sx_object, LOP_EXCLUSIVE, file, line);
! 	curthread->td_locks++;
! 
! 	mtx_unlock(sx->sx_lock);
  }
  
  int
  _sx_try_xlock(struct sx *sx, const char *file, int line)
  {
  
! 	mtx_lock(sx->sx_lock);
! 	if (sx->sx_cnt == 0) {
! 		sx->sx_cnt--;
! 		sx->sx_xholder = curthread;
! 		LOCK_LOG_TRY("XLOCK", &sx->sx_object, 0, 1, file, line);
! 		WITNESS_LOCK(&sx->sx_object, LOP_EXCLUSIVE | LOP_TRYLOCK, file,
! 		    line);
  		curthread->td_locks++;
- 		mtx_unlock(sx->sx_lock);
- 		return (1);
- 	} else {
- 		LOCK_LOG_TRY("XLOCK", &sx->sx_object, 0, 0, file, line);
- 		mtx_unlock(sx->sx_lock);
- 		return (0);
  	}
  }
  
  void
  _sx_sunlock(struct sx *sx, const char *file, int line)
  {
  
! 	_sx_assert(sx, SX_SLOCKED, file, line);
! 	mtx_lock(sx->sx_lock);
  
  	curthread->td_locks--;
! 	WITNESS_UNLOCK(&sx->sx_object, 0, file, line);
  
! 	/* Release. */
! 	sx->sx_cnt--;
  
  	/*
! 	 * If we just released the last shared lock, wake any waiters up, giving
! 	 * exclusive lockers precedence.  In order to make sure that exclusive
! 	 * lockers won't be blocked forever, don't wake shared lock waiters if
! 	 * there are exclusive lock waiters.
  	 */
! 	if (sx->sx_excl_wcnt > 0) {
! 		if (sx->sx_cnt == 0)
! 			cv_signal(&sx->sx_excl_cv);
! 	} else if (sx->sx_shrd_wcnt > 0)
! 		cv_broadcast(&sx->sx_shrd_cv);
! 
! 	LOCK_LOG_LOCK("SUNLOCK", &sx->sx_object, 0, 0, file, line);
! 
! 	mtx_unlock(sx->sx_lock);
  }
  
  void
! _sx_xunlock(struct sx *sx, const char *file, int line)
  {
  
! 	_sx_assert(sx, SX_XLOCKED, file, line);
! 	mtx_lock(sx->sx_lock);
! 	MPASS(sx->sx_cnt == -1);
  
! 	curthread->td_locks--;
! 	WITNESS_UNLOCK(&sx->sx_object, LOP_EXCLUSIVE, file, line);
  
! 	/* Release. */
! 	sx->sx_cnt++;
! 	sx->sx_xholder = NULL;
  
  	/*
! 	 * Wake up waiters if there are any.  Give precedence to slock waiters.
  	 */
! 	if (sx->sx_shrd_wcnt > 0)
! 		cv_broadcast(&sx->sx_shrd_cv);
! 	else if (sx->sx_excl_wcnt > 0)
! 		cv_signal(&sx->sx_excl_cv);
  
! 	LOCK_LOG_LOCK("XUNLOCK", &sx->sx_object, 0, 0, file, line);
  
! 	mtx_unlock(sx->sx_lock);
  }
  
  int
! _sx_try_upgrade(struct sx *sx, const char *file, int line)
  {
  
! 	_sx_assert(sx, SX_SLOCKED, file, line);
! 	mtx_lock(sx->sx_lock);
  
! 	if (sx->sx_cnt == 1) {
! 		sx->sx_cnt = -1;
! 		sx->sx_xholder = curthread;
  
! 		LOCK_LOG_TRY("XUPGRADE", &sx->sx_object, 0, 1, file, line);
! 		WITNESS_UPGRADE(&sx->sx_object, LOP_EXCLUSIVE | LOP_TRYLOCK,
! 		    file, line);
  
! 		mtx_unlock(sx->sx_lock);
! 		return (1);
! 	} else {
! 		LOCK_LOG_TRY("XUPGRADE", &sx->sx_object, 0, 0, file, line);
! 		mtx_unlock(sx->sx_lock);
! 		return (0);
  	}
  }
  
  void
! _sx_downgrade(struct sx *sx, const char *file, int line)
  {
  
! 	_sx_assert(sx, SX_XLOCKED, file, line);
! 	mtx_lock(sx->sx_lock);
! 	MPASS(sx->sx_cnt == -1);
  
! 	WITNESS_DOWNGRADE(&sx->sx_object, 0, file, line);
  
! 	sx->sx_cnt = 1;
! 	sx->sx_xholder = NULL;
!         if (sx->sx_shrd_wcnt > 0)
!                 cv_broadcast(&sx->sx_shrd_cv);
  
! 	LOCK_LOG_LOCK("XDOWNGRADE", &sx->sx_object, 0, 0, file, line);
  
! 	mtx_unlock(sx->sx_lock);
  }
  
  #ifdef INVARIANT_SUPPORT
--- 128,851 ----
  }
  
  void
! sx_init_flags(struct sx *sx, const char *description, int opts)
  {
+ 	struct lock_object *lock;
+ 	int flags;
  
! 	MPASS((opts & ~(SX_QUIET | SX_RECURSE | SX_NOWITNESS | SX_DUPOK |
! 	    SX_NOPROFILE | SX_ADAPTIVESPIN)) == 0);
! 
! 	bzero(sx, sizeof(*sx));
! 
! 	flags = LO_RECURSABLE | LO_SLEEPABLE | LO_UPGRADABLE;
! 	if (opts & SX_DUPOK)
! 		flags |= LO_DUPOK;
! 	if (!(opts & SX_NOWITNESS))
! 		flags |= LO_WITNESS;
! 	if (opts & SX_QUIET)
! 		flags |= LO_QUIET;
! 
! 	flags |= opts & (SX_ADAPTIVESPIN | SX_RECURSE);
! 	sx->sx_lock = SX_LOCK_UNLOCKED;
! 	sx->sx_recurse = 0;
! 	lock = &sx->lock_object;
! 	lock->lo_class = &lock_class_sx;
! 	lock->lo_flags = flags;
! 	lock->lo_name = lock->lo_type = description;
! 	LOCK_LOG_INIT(lock, opts);
! 	WITNESS_INIT(lock);
  }
  
  void
  sx_destroy(struct sx *sx)
  {
+ 	LOCK_LOG_DESTROY(&sx->lock_object, 0);
  
! 	KASSERT(sx->sx_lock == SX_LOCK_UNLOCKED, ("sx lock still held"));
! 	KASSERT(sx->sx_recurse == 0, ("sx lock still recursed"));
! 	sx->sx_lock = SX_LOCK_DESTROYED;
! 	WITNESS_DESTROY(&sx->lock_object);
  }
  
! int
! _sx_slock(struct sx *sx, int opts, const char *file, int line)
  {
+ 	int error = 0;
  
! 	MPASS(curthread != NULL);
! 	KASSERT(sx->sx_lock != SX_LOCK_DESTROYED,
! 	    ("sx_slock() of destroyed sx @ %s:%d", file, line));
! 	WITNESS_CHECKORDER(&sx->lock_object, LOP_NEWORDER, file, line);
! 	error = __sx_slock(sx, opts, file, line);
! 	if (!error) {
! 		LOCK_LOG_LOCK("SLOCK", &sx->lock_object, 0, 0, file, line);
! 		WITNESS_LOCK(&sx->lock_object, 0, file, line);
! 		curthread->td_locks++;
  	}
  
! 	return (error);
  }
  
  int
  _sx_try_slock(struct sx *sx, const char *file, int line)
  {
+ 	uintptr_t x;
  
! 	x = sx->sx_lock;
! 	KASSERT(x != SX_LOCK_DESTROYED,
! 	    ("sx_try_slock() of destroyed sx @ %s:%d", file, line));
! 	if ((x & SX_LOCK_SHARED) && atomic_cmpset_acq_ptr(&sx->sx_lock, x,
! 	    x + SX_ONE_SHARER)) {
! 		LOCK_LOG_TRY("SLOCK", &sx->lock_object, 0, 1, file, line);
! 		WITNESS_LOCK(&sx->lock_object, LOP_TRYLOCK, file, line);
  		curthread->td_locks++;
  		return (1);
  	}
+ 
+ 	LOCK_LOG_TRY("SLOCK", &sx->lock_object, 0, 0, file, line);
+ 	return (0);
  }
  
! int
! _sx_xlock(struct sx *sx, int opts, const char *file, int line)
  {
+ 	int error = 0;
  
! 	MPASS(curthread != NULL);
! 	KASSERT(sx->sx_lock != SX_LOCK_DESTROYED,
! 	    ("sx_xlock() of destroyed sx @ %s:%d", file, line));
! 	WITNESS_CHECKORDER(&sx->lock_object, LOP_NEWORDER | LOP_EXCLUSIVE, file,
  	    line);
! 	error = __sx_xlock(sx, curthread, opts, file, line);
! 	if (!error) {
! 		LOCK_LOG_LOCK("XLOCK", &sx->lock_object, 0, sx->sx_recurse,
! 		    file, line);
! 		WITNESS_LOCK(&sx->lock_object, LOP_EXCLUSIVE, file, line);
! 		curthread->td_locks++;
  	}
  
! 	return (error);
  }
  
  int
  _sx_try_xlock(struct sx *sx, const char *file, int line)
  {
+ 	int rval;
  
! 	MPASS(curthread != NULL);
! 	KASSERT(sx->sx_lock != SX_LOCK_DESTROYED,
! 	    ("sx_try_xlock() of destroyed sx @ %s:%d", file, line));
! 
! 	if (sx_xlocked(sx) && (sx->lock_object.lo_flags & SX_RECURSE) != 0) {
! 		sx->sx_recurse++;
! 		atomic_set_ptr(&sx->sx_lock, SX_LOCK_RECURSED);
! 		rval = 1;
! 	} else
! 		rval = atomic_cmpset_acq_ptr(&sx->sx_lock, SX_LOCK_UNLOCKED,
! 		    (uintptr_t)curthread);
! 	LOCK_LOG_TRY("XLOCK", &sx->lock_object, 0, rval, file, line);
! 	if (rval) {
! 		WITNESS_LOCK(&sx->lock_object, LOP_EXCLUSIVE | LOP_TRYLOCK,
! 		    file, line);
  		curthread->td_locks++;
  	}
+ 
+ 	return (rval);
  }
  
  void
  _sx_sunlock(struct sx *sx, const char *file, int line)
  {
  
! 	MPASS(curthread != NULL);
! 	KASSERT(sx->sx_lock != SX_LOCK_DESTROYED,
! 	    ("sx_sunlock() of destroyed sx @ %s:%d", file, line));
! 	_sx_assert(sx, SA_SLOCKED, file, line);
! 	curthread->td_locks--;
! 	WITNESS_UNLOCK(&sx->lock_object, 0, file, line);
! 	LOCK_LOG_LOCK("SUNLOCK", &sx->lock_object, 0, 0, file, line);
! #ifdef LOCK_PROFILING_SHARED
! 	if (SX_SHARERS(sx->sx_lock) == 1)
! 		lock_profile_release_lock(&sx->lock_object);
! #endif
! 	__sx_sunlock(sx, file, line);
! }
! 
! void
! _sx_xunlock(struct sx *sx, const char *file, int line)
! {
  
+ 	MPASS(curthread != NULL);
+ 	KASSERT(sx->sx_lock != SX_LOCK_DESTROYED,
+ 	    ("sx_xunlock() of destroyed sx @ %s:%d", file, line));
+ 	_sx_assert(sx, SA_XLOCKED, file, line);
  	curthread->td_locks--;
! 	WITNESS_UNLOCK(&sx->lock_object, LOP_EXCLUSIVE, file, line);
! 	LOCK_LOG_LOCK("XUNLOCK", &sx->lock_object, 0, sx->sx_recurse, file,
! 	    line);
! 	if (!sx_recursed(sx))
! 		lock_profile_release_lock(&sx->lock_object);
! 	__sx_xunlock(sx, curthread, file, line);
! }
  
! /*
!  * Try to do a non-blocking upgrade from a shared lock to an exclusive lock.
!  * This will only succeed if this thread holds a single shared lock.
!  * Return 1 if if the upgrade succeed, 0 otherwise.
!  */
! int
! _sx_try_upgrade(struct sx *sx, const char *file, int line)
! {
! 	uintptr_t x;
! 	int success;
! 
! 	KASSERT(sx->sx_lock != SX_LOCK_DESTROYED,
! 	    ("sx_try_upgrade() of destroyed sx @ %s:%d", file, line));
! 	_sx_assert(sx, SA_SLOCKED, file, line);
  
  	/*
! 	 * Try to switch from one shared lock to an exclusive lock.  We need
! 	 * to maintain the SX_LOCK_EXCLUSIVE_WAITERS flag if set so that
! 	 * we will wake up the exclusive waiters when we drop the lock.
  	 */
! 	x = sx->sx_lock & SX_LOCK_EXCLUSIVE_WAITERS;
! 	success = atomic_cmpset_ptr(&sx->sx_lock, SX_SHARERS_LOCK(1) | x,
! 	    (uintptr_t)curthread | x);
! 	LOCK_LOG_TRY("XUPGRADE", &sx->lock_object, 0, success, file, line);
! 	if (success)
! 		WITNESS_UPGRADE(&sx->lock_object, LOP_EXCLUSIVE | LOP_TRYLOCK,
! 		    file, line);
! 	return (success);
  }
  
+ /*
+  * Downgrade an unrecursed exclusive lock into a single shared lock.
+  */
  void
! _sx_downgrade(struct sx *sx, const char *file, int line)
  {
+ 	uintptr_t x;
  
! 	KASSERT(sx->sx_lock != SX_LOCK_DESTROYED,
! 	    ("sx_downgrade() of destroyed sx @ %s:%d", file, line));
! 	_sx_assert(sx, SA_XLOCKED | SA_NOTRECURSED, file, line);
! #ifndef INVARIANTS
! 	if (sx_recursed(sx))
! 		panic("downgrade of a recursed lock");
! #endif
  
! 	WITNESS_DOWNGRADE(&sx->lock_object, 0, file, line);
  
! 	/*
! 	 * Try to switch from an exclusive lock with no shared waiters
! 	 * to one sharer with no shared waiters.  If there are
! 	 * exclusive waiters, we don't need to lock the sleep queue so
! 	 * long as we preserve the flag.  We do one quick try and if
! 	 * that fails we grab the sleepq lock to keep the flags from
! 	 * changing and do it the slow way.
! 	 *
! 	 * We have to lock the sleep queue if there are shared waiters
! 	 * so we can wake them up.
! 	 */
! 	x = sx->sx_lock;
! 	if (!(x & SX_LOCK_SHARED_WAITERS) &&
! 	    atomic_cmpset_rel_ptr(&sx->sx_lock, x, SX_SHARERS_LOCK(1) |
! 	    (x & SX_LOCK_EXCLUSIVE_WAITERS))) {
! 		LOCK_LOG_LOCK("XDOWNGRADE", &sx->lock_object, 0, 0, file, line);
! 		return;
! 	}
  
  	/*
! 	 * Lock the sleep queue so we can read the waiters bits
! 	 * without any races and wakeup any shared waiters.
  	 */
! 	sleepq_lock(&sx->lock_object);
  
! 	/*
! 	 * Preserve SX_LOCK_EXCLUSIVE_WAITERS while downgraded to a single
! 	 * shared lock.  If there are any shared waiters, wake them up.
! 	 */
! 	x = sx->sx_lock;
! 	atomic_store_rel_ptr(&sx->sx_lock, SX_SHARERS_LOCK(1) |
! 	    (x & SX_LOCK_EXCLUSIVE_WAITERS));
! 	if (x & SX_LOCK_SHARED_WAITERS)
! 		sleepq_broadcast_queue(&sx->lock_object, SLEEPQ_SX, -1,
! 		    SQ_SHARED_QUEUE);
! 	else
! 		sleepq_release(&sx->lock_object);
  
! 	LOCK_LOG_LOCK("XDOWNGRADE", &sx->lock_object, 0, 0, file, line);
  }
  
+ /*
+  * This function represents the so-called 'hard case' for sx_xlock
+  * operation.  All 'easy case' failures are redirected to this.  Note
+  * that ideally this would be a static function, but it needs to be
+  * accessible from at least sx.h.
+  */
  int
! _sx_xlock_hard(struct sx *sx, uintptr_t tid, int opts, const char *file,
!     int line)
  {
+ 	GIANT_DECLARE;
+ #ifdef ADAPTIVE_SX
+ 	volatile struct thread *owner;
+ #endif
+ 	/* uint64_t waittime = 0; */
+ 	uintptr_t x;
+ 	int /* contested = 0, */error = 0;
+ 
+ 	/* If we already hold an exclusive lock, then recurse. */
+ 	if (sx_xlocked(sx)) {
+ 		KASSERT((sx->lock_object.lo_flags & SX_RECURSE) != 0,
+ 	    ("_sx_xlock_hard: recursed on non-recursive sx %s @ %s:%d\n",
+ 		    sx->lock_object.lo_name, file, line));
+ 		sx->sx_recurse++;
+ 		atomic_set_ptr(&sx->sx_lock, SX_LOCK_RECURSED);
+ 		if (LOCK_LOG_TEST(&sx->lock_object, 0))
+ 			CTR2(KTR_LOCK, "%s: %p recursing", __func__, sx);
+ 		return (0);
+ 	}
  
! 	if (LOCK_LOG_TEST(&sx->lock_object, 0))
! 		CTR5(KTR_LOCK, "%s: %s contested (lock=%p) at %s:%d", __func__,
! 		    sx->lock_object.lo_name, (void *)sx->sx_lock, file, line);
  
! 	while (!atomic_cmpset_acq_ptr(&sx->sx_lock, SX_LOCK_UNLOCKED, tid)) {
! #ifdef ADAPTIVE_SX
! 		/*
! 		 * If the lock is write locked and the owner is
! 		 * running on another CPU, spin until the owner stops
! 		 * running or the state of the lock changes.
! 		 */
! 		x = sx->sx_lock;
! 		if (!(x & SX_LOCK_SHARED) &&
! 		    (sx->lock_object.lo_flags & SX_ADAPTIVESPIN)) {
! 			x = SX_OWNER(x);
! 			owner = (struct thread *)x;
! 			if (TD_IS_RUNNING(owner)) {
! 				if (LOCK_LOG_TEST(&sx->lock_object, 0))
! 					CTR3(KTR_LOCK,
! 					    "%s: spinning on %p held by %p",
! 					    __func__, sx, owner);
! 				GIANT_SAVE();
! 				lock_profile_obtain_lock_failed(
! 				    &sx->lock_object, &contested, &waittime);
! 				while (SX_OWNER(sx->sx_lock) == x &&
! 				    TD_IS_RUNNING(owner))
! 					cpu_spinwait();
! 				continue;
! 			}
! 		}
! #endif
  
! 		sleepq_lock(&sx->lock_object);
! 		x = sx->sx_lock;
  
! 		/*
! 		 * If the lock was released while spinning on the
! 		 * sleep queue chain lock, try again.
! 		 */
! 		if (x == SX_LOCK_UNLOCKED) {
! 			sleepq_release(&sx->lock_object);
! 			continue;
! 		}
! 
! #ifdef ADAPTIVE_SX
! 		/*
! 		 * The current lock owner might have started executing
! 		 * on another CPU (or the lock could have changed
! 		 * owners) while we were waiting on the sleep queue
! 		 * chain lock.  If so, drop the sleep queue lock and try
! 		 * again.
! 		 */
! 		if (!(x & SX_LOCK_SHARED) &&
! 		    (sx->lock_object.lo_flags & SX_ADAPTIVESPIN)) {
! 			owner = (struct thread *)SX_OWNER(x);
! 			if (TD_IS_RUNNING(owner)) {
! 				sleepq_release(&sx->lock_object);
! 				continue;
! 			}
! 		}
! #endif
! 
! 		/*
! 		 * If an exclusive lock was released with both shared
! 		 * and exclusive waiters and a shared waiter hasn't
! 		 * woken up and acquired the lock yet, sx_lock will be
! 		 * set to SX_LOCK_UNLOCKED | SX_LOCK_EXCLUSIVE_WAITERS.
! 		 * If we see that value, try to acquire it once.  Note
! 		 * that we have to preserve SX_LOCK_EXCLUSIVE_WAITERS
! 		 * as there are other exclusive waiters still.  If we
! 		 * fail, restart the loop.
! 		 */
! 		if (x == (SX_LOCK_UNLOCKED | SX_LOCK_EXCLUSIVE_WAITERS)) {
! 			if (atomic_cmpset_acq_ptr(&sx->sx_lock,
! 			    SX_LOCK_UNLOCKED | SX_LOCK_EXCLUSIVE_WAITERS,
! 			    tid | SX_LOCK_EXCLUSIVE_WAITERS)) {
! 				sleepq_release(&sx->lock_object);
! 				CTR2(KTR_LOCK, "%s: %p claimed by new writer",
! 				    __func__, sx);
! 				break;
! 			}
! 			sleepq_release(&sx->lock_object);
! 			continue;
! 		}
! 
! 		/*
! 		 * Try to set the SX_LOCK_EXCLUSIVE_WAITERS.  If we fail,
! 		 * than loop back and retry.
! 		 */
! 		if (!(x & SX_LOCK_EXCLUSIVE_WAITERS)) {
! 			if (!atomic_cmpset_ptr(&sx->sx_lock, x,
! 			    x | SX_LOCK_EXCLUSIVE_WAITERS)) {
! 				sleepq_release(&sx->lock_object);
! 				continue;
! 			}
! 			if (LOCK_LOG_TEST(&sx->lock_object, 0))
! 				CTR2(KTR_LOCK, "%s: %p set excl waiters flag",
! 				    __func__, sx);
! 		}
! 
! 		/*
! 		 * Since we have been unable to acquire the exclusive
! 		 * lock and the exclusive waiters flag is set, we have
! 		 * to sleep.
! 		 */
! #if 0
! 		if (LOCK_LOG_TEST(&sx->lock_object, 0))
! 			CTR2(KTR_LOCK, "%s: %p blocking on sleep queue",
! 			    __func__, sx);
! #endif
! 
! 		GIANT_SAVE();
! 		lock_profile_obtain_lock_failed(&sx->lock_object, &contested,
! 		    &waittime);
! 		sleepq_add_queue(&sx->lock_object, NULL, sx->lock_object.lo_name,
! 		    SLEEPQ_SX | ((opts & SX_INTERRUPTIBLE) ?
! 		    SLEEPQ_INTERRUPTIBLE : 0), SQ_EXCLUSIVE_QUEUE);
! 		if (!(opts & SX_INTERRUPTIBLE))
! 			sleepq_wait(&sx->lock_object);
! 		else
! 			error = sleepq_wait_sig(&sx->lock_object);
! 
! 		if (error) {
! 			if (LOCK_LOG_TEST(&sx->lock_object, 0))
! 				CTR2(KTR_LOCK,
! 			"%s: interruptible sleep by %p suspended by signal",
! 				    __func__, sx);
! 			break;
! 		}
! 		if (LOCK_LOG_TEST(&sx->lock_object, 0))
! 			CTR2(KTR_LOCK, "%s: %p resuming from sleep queue",
! 			    __func__, sx);
  	}
+ 
+ 	GIANT_RESTORE();
+ 	if (!error)
+ 		lock_profile_obtain_lock_success(&sx->lock_object, contested,
+ 		    waittime, file, line);
+ 	return (error);
  }
  
+ /*
+  * This function represents the so-called 'hard case' for sx_xunlock
+  * operation.  All 'easy case' failures are redirected to this.  Note
+  * that ideally this would be a static function, but it needs to be
+  * accessible from at least sx.h.
+  */
  void
! _sx_xunlock_hard(struct sx *sx, uintptr_t tid, const char *file, int line)
! {
! 	uintptr_t x;
! 	int queue;
! 
! 	MPASS(!(sx->sx_lock & SX_LOCK_SHARED));
! 
! 	/* If the lock is recursed, then unrecurse one level. */
! 	if (sx_xlocked(sx) && sx_recursed(sx)) {
! 		if ((--sx->sx_recurse) == 0)
! 			atomic_clear_ptr(&sx->sx_lock, SX_LOCK_RECURSED);
! 		if (LOCK_LOG_TEST(&sx->lock_object, 0))
! 			CTR2(KTR_LOCK, "%s: %p unrecursing", __func__, sx);
! 		return;
! 	}
! 	MPASS(sx->sx_lock & (SX_LOCK_SHARED_WAITERS |
! 	    SX_LOCK_EXCLUSIVE_WAITERS));
! 	if (LOCK_LOG_TEST(&sx->lock_object, 0))
! 		CTR2(KTR_LOCK, "%s: %p contested", __func__, sx);
! 
! 	sleepq_lock(&sx->lock_object);
! 	x = SX_LOCK_UNLOCKED;
! 
! 	/*
! 	 * The wake up algorithm here is quite simple and probably not
! 	 * ideal.  It gives precedence to shared waiters if they are
! 	 * present.  For this condition, we have to preserve the
! 	 * state of the exclusive waiters flag.
! 	 */
! 	if (sx->sx_lock & SX_LOCK_SHARED_WAITERS) {
! 		queue = SQ_SHARED_QUEUE;
! 		x |= (sx->sx_lock & SX_LOCK_EXCLUSIVE_WAITERS);
! 	} else
! 		queue = SQ_EXCLUSIVE_QUEUE;
! 
! 	/* Wake up all the waiters for the specific queue. */
! 	if (LOCK_LOG_TEST(&sx->lock_object, 0))
! 		CTR3(KTR_LOCK, "%s: %p waking up all threads on %s queue",
! 		    __func__, sx, queue == SQ_SHARED_QUEUE ? "shared" :
! 		    "exclusive");
! 	atomic_store_rel_ptr(&sx->sx_lock, x);
! 	sleepq_broadcast_queue(&sx->lock_object, SLEEPQ_SX, -1, queue);
! }
! 
! /*
!  * This function represents the so-called 'hard case' for sx_slock
!  * operation.  All 'easy case' failures are redirected to this.  Note
!  * that ideally this would be a static function, but it needs to be
!  * accessible from at least sx.h.
!  */
! int
! _sx_slock_hard(struct sx *sx, int opts, const char *file, int line)
! {
! 	GIANT_DECLARE;
! #ifdef ADAPTIVE_SX
! 	volatile struct thread *owner;
! #endif
! #ifdef LOCK_PROFILING_SHARED
! 	uint64_t waittime = 0;
! 	int contested = 0;
! #endif
! 	uintptr_t x;
! 	int error = 0;
! 
! 	/*
! 	 * As with rwlocks, we don't make any attempt to try to block
! 	 * shared locks once there is an exclusive waiter.
! 	 */
! 	for (;;) {
! 		x = sx->sx_lock;
! 
! 		/*
! 		 * If no other thread has an exclusive lock then try to bump up
! 		 * the count of sharers.  Since we have to preserve the state
! 		 * of SX_LOCK_EXCLUSIVE_WAITERS, if we fail to acquire the
! 		 * shared lock loop back and retry.
! 		 */
! 		if (x & SX_LOCK_SHARED) {
! 			MPASS(!(x & SX_LOCK_SHARED_WAITERS));
! 			if (atomic_cmpset_acq_ptr(&sx->sx_lock, x,
! 			    x + SX_ONE_SHARER)) {
! #ifdef LOCK_PROFILING_SHARED
! 				if (SX_SHARERS(x) == 0)
! 					lock_profile_obtain_lock_success(
! 					    &sx->lock_object, contested,
! 					    waittime, file, line);
! #endif
! 				if (LOCK_LOG_TEST(&sx->lock_object, 0))
! 					CTR4(KTR_LOCK,
! 					    "%s: %p succeed %p -> %p", __func__,
! 					    sx, (void *)x,
! 					    (void *)(x + SX_ONE_SHARER));
! 				break;
! 			}
! 			continue;
! 		}
! 
! #ifdef ADAPTIVE_SX
! 		/*
! 		 * If the owner is running on another CPU, spin until
! 		 * the owner stops running or the state of the lock
! 		 * changes.
! 		 */
! 		else if (sx->lock_object.lo_flags & SX_ADAPTIVESPIN) {
! 			x = SX_OWNER(x);
! 			owner = (struct thread *)x;
! 			if (TD_IS_RUNNING(owner)) {
! 				if (LOCK_LOG_TEST(&sx->lock_object, 0))
! 					CTR3(KTR_LOCK,
! 					    "%s: spinning on %p held by %p",
! 					    __func__, sx, owner);
! 				GIANT_SAVE();
! #ifdef LOCK_PROFILING_SHARED
! 				lock_profile_obtain_lock_failed(
! 				    &sx->lock_object, &contested, &waittime);
! #endif
! 				while (SX_OWNER(sx->sx_lock) == x &&
! 				    TD_IS_RUNNING(owner))
! 					cpu_spinwait();
! 				continue;
! 			}
! 		}
! #endif
! 
! 		/*
! 		 * Some other thread already has an exclusive lock, so
! 		 * start the process of blocking.
! 		 */
! 		sleepq_lock(&sx->lock_object);
! 		x = sx->sx_lock;
! 
! 		/*
! 		 * The lock could have been released while we spun.
! 		 * In this case loop back and retry.
! 		 */
! 		if (x & SX_LOCK_SHARED) {
! 			sleepq_release(&sx->lock_object);
! 			continue;
! 		}
! 
! #ifdef ADAPTIVE_SX
! 		/*
! 		 * If the owner is running on another CPU, spin until
! 		 * the owner stops running or the state of the lock
! 		 * changes.
! 		 */
! 		if (!(x & SX_LOCK_SHARED) &&
! 		    (sx->lock_object.lo_flags & SX_ADAPTIVESPIN)) {
! 			owner = (struct thread *)SX_OWNER(x);
! 			if (TD_IS_RUNNING(owner)) {
! 				sleepq_release(&sx->lock_object);
! 				continue;
! 			}
! 		}
! #endif
! 
! 		/*
! 		 * Try to set the SX_LOCK_SHARED_WAITERS flag.  If we
! 		 * fail to set it drop the sleep queue lock and loop
! 		 * back.
! 		 */
! 		if (!(x & SX_LOCK_SHARED_WAITERS)) {
! 			if (!atomic_cmpset_ptr(&sx->sx_lock, x,
! 			    x | SX_LOCK_SHARED_WAITERS)) {
! 				sleepq_release(&sx->lock_object);
! 				continue;
! 			}
! 			if (LOCK_LOG_TEST(&sx->lock_object, 0))
! 				CTR2(KTR_LOCK, "%s: %p set shared waiters flag",
! 				    __func__, sx);
! 		}
! 
! 		/*
! 		 * Since we have been unable to acquire the shared lock,
! 		 * we have to sleep.
! 		 */
! 		if (LOCK_LOG_TEST(&sx->lock_object, 0))
! 			CTR2(KTR_LOCK, "%s: %p blocking on sleep queue",
! 			    __func__, sx);
! 
! 		GIANT_SAVE();
! #ifdef LOCK_PROFILING_SHARED
! 		lock_profile_obtain_lock_failed(&sx->lock_object, &contested,
! 		    &waittime);
! #endif
! 		sleepq_add_queue(&sx->lock_object, NULL, sx->lock_object.lo_name,
! 		    SLEEPQ_SX | ((opts & SX_INTERRUPTIBLE) ?
! 		    SLEEPQ_INTERRUPTIBLE : 0), SQ_SHARED_QUEUE);
! 		if (!(opts & SX_INTERRUPTIBLE))
! 			sleepq_wait(&sx->lock_object);
! 		else
! 			error = sleepq_wait_sig(&sx->lock_object);
! 
! 		if (error) {
! 			if (LOCK_LOG_TEST(&sx->lock_object, 0))
! 				CTR2(KTR_LOCK,
! 			"%s: interruptible sleep by %p suspended by signal",
! 				    __func__, sx);
! 			break;
! 		}
! 		if (LOCK_LOG_TEST(&sx->lock_object, 0))
! 			CTR2(KTR_LOCK, "%s: %p resuming from sleep queue",
! 			    __func__, sx);
! 	}
! 
! 	GIANT_RESTORE();
! 	return (error);
! }
! 
! /*
!  * This function represents the so-called 'hard case' for sx_sunlock
!  * operation.  All 'easy case' failures are redirected to this.  Note
!  * that ideally this would be a static function, but it needs to be
!  * accessible from at least sx.h.
!  */
! void
! _sx_sunlock_hard(struct sx *sx, const char *file, int line)
  {
+ 	uintptr_t x;
+ 
+ 	for (;;) {
+ 		x = sx->sx_lock;
+ 
+ 		/*
+ 		 * We should never have sharers while at least one thread
+ 		 * holds a shared lock.
+ 		 */
+ 		KASSERT(!(x & SX_LOCK_SHARED_WAITERS),
+ 		    ("%s: waiting sharers", __func__));
  
! 		/*
! 		 * See if there is more than one shared lock held.  If
! 		 * so, just drop one and return.
! 		 */
! 		if (SX_SHARERS(x) > 1) {
! 			if (atomic_cmpset_ptr(&sx->sx_lock, x,
! 			    x - SX_ONE_SHARER)) {
! 				if (LOCK_LOG_TEST(&sx->lock_object, 0))
! 					CTR4(KTR_LOCK,
! 					    "%s: %p succeeded %p -> %p",
! 					    __func__, sx, (void *)x,
! 					    (void *)(x - SX_ONE_SHARER));
! 				break;
! 			}
! 			continue;
! 		}
  
! 		/*
! 		 * If there aren't any waiters for an exclusive lock,
! 		 * then try to drop it quickly.
! 		 */
! 		if (!(x & SX_LOCK_EXCLUSIVE_WAITERS)) {
! 			MPASS(x == SX_SHARERS_LOCK(1));
! 			if (atomic_cmpset_ptr(&sx->sx_lock, SX_SHARERS_LOCK(1),
! 			    SX_LOCK_UNLOCKED)) {
! 				if (LOCK_LOG_TEST(&sx->lock_object, 0))
! 					CTR2(KTR_LOCK, "%s: %p last succeeded",
! 					    __func__, sx);
! 				break;
! 			}
! 			continue;
! 		}
  
! 		/*
! 		 * At this point, there should just be one sharer with
! 		 * exclusive waiters.
! 		 */
! 		MPASS(x == (SX_SHARERS_LOCK(1) | SX_LOCK_EXCLUSIVE_WAITERS));
  
! 		sleepq_lock(&sx->lock_object);
  
! 		/*
! 		 * Wake up semantic here is quite simple:
! 		 * Just wake up all the exclusive waiters.
! 		 * Note that the state of the lock could have changed,
! 		 * so if it fails loop back and retry.
! 		 */
! 		if (!atomic_cmpset_ptr(&sx->sx_lock,
! 		    SX_SHARERS_LOCK(1) | SX_LOCK_EXCLUSIVE_WAITERS,
! 		    SX_LOCK_UNLOCKED)) {
! 			sleepq_release(&sx->lock_object);
! 			continue;
! 		}
! 		if (LOCK_LOG_TEST(&sx->lock_object, 0))
! 			CTR2(KTR_LOCK, "%s: %p waking up all thread on"
! 			    "exclusive queue", __func__, sx);
! 		sleepq_broadcast_queue(&sx->lock_object, SLEEPQ_SX, -1,
! 		    SQ_EXCLUSIVE_QUEUE);
! 		break;
! 	}
  }
  
  #ifdef INVARIANT_SUPPORT
***************
*** 327,370 ****
  void
  _sx_assert(struct sx *sx, int what, const char *file, int line)
  {
  
  	if (panicstr != NULL)
  		return;
  	switch (what) {
! 	case SX_LOCKED:
! 	case SX_SLOCKED:
  #ifdef WITNESS
! 		witness_assert(&sx->sx_object, what, file, line);
  #else
! 		mtx_lock(sx->sx_lock);
! 		if (sx->sx_cnt <= 0 &&
! 		    (what == SX_SLOCKED || sx->sx_xholder != curthread))
  			panic("Lock %s not %slocked @ %s:%d\n",
! 			    sx->sx_object.lo_name, (what == SX_SLOCKED) ?
! 			    "share " : "", file, line);
! 		mtx_unlock(sx->sx_lock);
  #endif
  		break;
! 	case SX_XLOCKED:
! 		mtx_lock(sx->sx_lock);
! 		if (sx->sx_xholder != curthread)
  			panic("Lock %s not exclusively locked @ %s:%d\n",
! 			    sx->sx_object.lo_name, file, line);
! 		mtx_unlock(sx->sx_lock);
  		break;
! 	case SX_UNLOCKED:
  #ifdef WITNESS
! 		witness_assert(&sx->sx_object, what, file, line);
  #else
  		/*
! 		 * We are able to check only exclusive lock here,
! 		 * we cannot assert that *this* thread owns slock.
  		 */
! 		mtx_lock(sx->sx_lock);
! 		if (sx->sx_xholder == curthread)
  			panic("Lock %s exclusively locked @ %s:%d\n",
! 			    sx->sx_object.lo_name, file, line);
! 		mtx_unlock(sx->sx_lock);
  #endif
  		break;
  	default:
--- 861,936 ----
  void
  _sx_assert(struct sx *sx, int what, const char *file, int line)
  {
+ #ifndef WITNESS
+ 	int slocked = 0;
+ #endif
  
  	if (panicstr != NULL)
  		return;
  	switch (what) {
! 	case SA_SLOCKED:
! 	case SA_SLOCKED | SA_NOTRECURSED:
! 	case SA_SLOCKED | SA_RECURSED:
! #ifndef WITNESS
! 		slocked = 1;
! 		/* FALLTHROUGH */
! #endif
! 	case SA_LOCKED:
! 	case SA_LOCKED | SA_NOTRECURSED:
! 	case SA_LOCKED | SA_RECURSED:
  #ifdef WITNESS
! 		witness_assert(&sx->lock_object, what, file, line);
  #else
! 		/*
! 		 * If some other thread has an exclusive lock or we
! 		 * have one and are asserting a shared lock, fail.
! 		 * Also, if no one has a lock at all, fail.
! 		 */
! 		if (sx->sx_lock == SX_LOCK_UNLOCKED ||
! 		    (!(sx->sx_lock & SX_LOCK_SHARED) && (slocked ||
! 		    sx_xholder(sx) != curthread)))
  			panic("Lock %s not %slocked @ %s:%d\n",
! 			    sx->lock_object.lo_name, slocked ? "share " : "",
! 			    file, line);
! 
! 		if (!(sx->sx_lock & SX_LOCK_SHARED)) {
! 			if (sx_recursed(sx)) {
! 				if (what & SA_NOTRECURSED)
! 					panic("Lock %s recursed @ %s:%d\n",
! 					    sx->lock_object.lo_name, file,
! 					    line);
! 			} else if (what & SA_RECURSED)
! 				panic("Lock %s not recursed @ %s:%d\n",
! 				    sx->lock_object.lo_name, file, line);
! 		}
  #endif
  		break;
! 	case SA_XLOCKED:
! 	case SA_XLOCKED | SA_NOTRECURSED:
! 	case SA_XLOCKED | SA_RECURSED:
! 		if (sx_xholder(sx) != curthread)
  			panic("Lock %s not exclusively locked @ %s:%d\n",
! 			    sx->lock_object.lo_name, file, line);
! 		if (sx_recursed(sx)) {
! 			if (what & SA_NOTRECURSED)
! 				panic("Lock %s recursed @ %s:%d\n",
! 				    sx->lock_object.lo_name, file, line);
! 		} else if (what & SA_RECURSED)
! 			panic("Lock %s not recursed @ %s:%d\n",
! 			    sx->lock_object.lo_name, file, line);
  		break;
! 	case SA_UNLOCKED:
  #ifdef WITNESS
! 		witness_assert(&sx->lock_object, what, file, line);
  #else
  		/*
! 		 * If we hold an exclusve lock fail.  We can't
! 		 * reliably check to see if we hold a shared lock or
! 		 * not.
  		 */
! 		if (sx_xholder(sx) == curthread)
  			panic("Lock %s exclusively locked @ %s:%d\n",
! 			    sx->lock_object.lo_name, file, line);
  #endif
  		break;
  	default:
***************
*** 375,381 ****
  #endif	/* INVARIANT_SUPPORT */
  
  #ifdef DDB
! void
  db_show_sx(struct lock_object *lock)
  {
  	struct thread *td;
--- 941,947 ----
  #endif	/* INVARIANT_SUPPORT */
  
  #ifdef DDB
! static void
  db_show_sx(struct lock_object *lock)
  {
  	struct thread *td;
***************
*** 384,399 ****
  	sx = (struct sx *)lock;
  
  	db_printf(" state: ");
! 	if (sx->sx_cnt < 0) {
! 		td = sx->sx_xholder;
  		db_printf("XLOCK: %p (tid %d, pid %d, \"%s\")\n", td,
  		    td->td_tid, td->td_proc->p_pid, td->td_proc->p_comm);
! 	} else if (sx->sx_cnt > 0)
! 		db_printf("SLOCK: %d locks\n", sx->sx_cnt);
! 	else
! 		db_printf("UNLOCKED\n");
! 	db_printf(" waiters: %d shared, %d exclusive\n", sx->sx_shrd_wcnt,
! 	    sx->sx_excl_wcnt);
  }
  
  /*
--- 950,985 ----
  	sx = (struct sx *)lock;
  
  	db_printf(" state: ");
! 	if (sx->sx_lock == SX_LOCK_UNLOCKED)
! 		db_printf("UNLOCKED\n");
! 	else if (sx->sx_lock == SX_LOCK_DESTROYED) {
! 		db_printf("DESTROYED\n");
! 		return;
! 	} else if (sx->sx_lock & SX_LOCK_SHARED)
! 		db_printf("SLOCK: %ju\n", (uintmax_t)SX_SHARERS(sx->sx_lock));
! 	else {
! 		td = sx_xholder(sx);
  		db_printf("XLOCK: %p (tid %d, pid %d, \"%s\")\n", td,
  		    td->td_tid, td->td_proc->p_pid, td->td_proc->p_comm);
! 		if (sx_recursed(sx))
! 			db_printf(" recursed: %d\n", sx->sx_recurse);
! 	}
! 
! 	db_printf(" waiters: ");
! 	switch(sx->sx_lock &
! 	    (SX_LOCK_SHARED_WAITERS | SX_LOCK_EXCLUSIVE_WAITERS)) {
! 	case SX_LOCK_SHARED_WAITERS:
! 		db_printf("shared\n");
! 		break;
! 	case SX_LOCK_EXCLUSIVE_WAITERS:
! 		db_printf("exclusive\n");
! 		break;
! 	case SX_LOCK_SHARED_WAITERS | SX_LOCK_EXCLUSIVE_WAITERS:
! 		db_printf("exclusive and shared\n");
! 		break;
! 	default:
! 		db_printf("none\n");
! 	}
  }
  
  /*
***************
*** 405,451 ****
  sx_chain(struct thread *td, struct thread **ownerp)
  {
  	struct sx *sx;
- 	struct cv *cv;
  
  	/*
! 	 * First, see if it looks like td is blocked on a condition
! 	 * variable.
  	 */
! 	cv = td->td_wchan;
! 	if (cv->cv_description != td->td_wmesg)
  		return (0);
  
- 	/*
- 	 * Ok, see if it looks like td is blocked on the exclusive
- 	 * condition variable.
- 	 */
- 	sx = (struct sx *)((char *)cv - offsetof(struct sx, sx_excl_cv));
- 	if (LOCK_CLASS(&sx->sx_object) == &lock_class_sx &&
- 	    sx->sx_excl_wcnt > 0)
- 		goto ok;
- 
- 	/*
- 	 * Second, see if it looks like td is blocked on the shared
- 	 * condition variable.
- 	 */
- 	sx = (struct sx *)((char *)cv - offsetof(struct sx, sx_shrd_cv));
- 	if (LOCK_CLASS(&sx->sx_object) == &lock_class_sx &&
- 	    sx->sx_shrd_wcnt > 0)
- 		goto ok;
- 
- 	/* Doesn't seem to be an sx lock. */
- 	return (0);
- 
- ok:
  	/* We think we have an sx lock, so output some details. */
  	db_printf("blocked on sx \"%s\" ", td->td_wmesg);
! 	if (sx->sx_cnt >= 0) {
! 		db_printf("SLOCK (count %d)\n", sx->sx_cnt);
! 		*ownerp = NULL;
! 	} else {
  		db_printf("XLOCK\n");
- 		*ownerp = sx->sx_xholder;
- 	}
  	return (1);
  }
  #endif
--- 991,1016 ----
  sx_chain(struct thread *td, struct thread **ownerp)
  {
  	struct sx *sx;
  
  	/*
! 	 * Check to see if this thread is blocked on an sx lock.
! 	 * First, we check the lock class.  If that is ok, then we
! 	 * compare the lock name against the wait message.
  	 */
! #define LOCK_CLASS(lo)	(lo)->lo_class
! 	sx = td->td_wchan;
! 	if (LOCK_CLASS(&sx->lock_object) != &lock_class_sx ||
! 	    sx->lock_object.lo_name != td->td_wmesg)
  		return (0);
  
  	/* We think we have an sx lock, so output some details. */
  	db_printf("blocked on sx \"%s\" ", td->td_wmesg);
! 	*ownerp = sx_xholder(sx);
! 	if (sx->sx_lock & SX_LOCK_SHARED)
! 		db_printf("SLOCK (count %ju)\n",
! 		    (uintmax_t)SX_SHARERS(sx->sx_lock));
! 	else
  		db_printf("XLOCK\n");
  	return (1);
  }
  #endif
Index: kern/kern_thread.c
===================================================================
RCS file: /cvs/ncvs/src/sys/kern/kern_thread.c,v
retrieving revision 1.216.2.6
diff -c -r1.216.2.6 kern_thread.c
*** kern/kern_thread.c	2 Sep 2006 17:29:57 -0000	1.216.2.6
--- kern/kern_thread.c	2 Sep 2007 21:56:36 -0000
***************
*** 305,311 ****
  
  	thread_zone = uma_zcreate("THREAD", sched_sizeof_thread(),
  	    thread_ctor, thread_dtor, thread_init, thread_fini,
! 	    UMA_ALIGN_CACHE, 0);
  	ksegrp_zone = uma_zcreate("KSEGRP", sched_sizeof_ksegrp(),
  	    ksegrp_ctor, NULL, NULL, NULL,
  	    UMA_ALIGN_CACHE, 0);
--- 305,311 ----
  
  	thread_zone = uma_zcreate("THREAD", sched_sizeof_thread(),
  	    thread_ctor, thread_dtor, thread_init, thread_fini,
! 	    THREAD_ALIGN, 0);
  	ksegrp_zone = uma_zcreate("KSEGRP", sched_sizeof_ksegrp(),
  	    ksegrp_ctor, NULL, NULL, NULL,
  	    UMA_ALIGN_CACHE, 0);
Index: kern/subr_sleepqueue.c
===================================================================
RCS file: /cvs/ncvs/src/sys/kern/subr_sleepqueue.c,v
retrieving revision 1.18.2.4
diff -c -r1.18.2.4 subr_sleepqueue.c
*** kern/subr_sleepqueue.c	17 Aug 2006 19:53:06 -0000	1.18.2.4
--- kern/subr_sleepqueue.c	4 Sep 2007 01:28:11 -0000
***************
*** 82,87 ****
--- 82,93 ----
  #include <ddb/ddb.h>
  #endif
  
+ #include <vm/uma.h>
+ 
+ #ifdef DDB
+ #include <ddb/ddb.h>
+ #endif
+ 
  /*
   * Constants for the hash table of sleep queue chains.  These constants are
   * the same ones that 4BSD (and possibly earlier versions of BSD) used.
***************
*** 94,100 ****
  #define	SC_SHIFT	8
  #define	SC_HASH(wc)	(((uintptr_t)(wc) >> SC_SHIFT) & SC_MASK)
  #define	SC_LOOKUP(wc)	&sleepq_chains[SC_HASH(wc)]
! 
  /*
   * There two different lists of sleep queues.  Both lists are connected
   * via the sq_hash entries.  The first list is the sleep queue chain list
--- 100,106 ----
  #define	SC_SHIFT	8
  #define	SC_HASH(wc)	(((uintptr_t)(wc) >> SC_SHIFT) & SC_MASK)
  #define	SC_LOOKUP(wc)	&sleepq_chains[SC_HASH(wc)]
! #define NR_SLEEPQS      2
  /*
   * There two different lists of sleep queues.  Both lists are connected
   * via the sq_hash entries.  The first list is the sleep queue chain list
***************
*** 114,126 ****
   *  c - sleep queue chain lock
   */
  struct sleepqueue {
! 	TAILQ_HEAD(, thread) sq_blocked;	/* (c) Blocked threads. */
  	LIST_ENTRY(sleepqueue) sq_hash;		/* (c) Chain and free list. */
  	LIST_HEAD(, sleepqueue) sq_free;	/* (c) Free queues. */
  	void	*sq_wchan;			/* (c) Wait channel. */
  #ifdef INVARIANTS
  	int	sq_type;			/* (c) Queue type. */
! 	struct mtx *sq_lock;			/* (c) Associated lock. */
  #endif
  };
  
--- 120,132 ----
   *  c - sleep queue chain lock
   */
  struct sleepqueue {
! 	TAILQ_HEAD(, thread) sq_blocked[NR_SLEEPQS];	/* (c) Blocked threads. */
  	LIST_ENTRY(sleepqueue) sq_hash;		/* (c) Chain and free list. */
  	LIST_HEAD(, sleepqueue) sq_free;	/* (c) Free queues. */
  	void	*sq_wchan;			/* (c) Wait channel. */
  #ifdef INVARIANTS
  	int	sq_type;			/* (c) Queue type. */
! 	struct mtx *sq_lock;		/* (c) Associated lock. */
  #endif
  };
  
***************
*** 142,157 ****
      0, "maxmimum depth achieved of a single chain");
  #endif
  static struct sleepqueue_chain sleepq_chains[SC_TABLESIZE];
! 
! static MALLOC_DEFINE(M_SLEEPQUEUE, "sleep queues", "sleep queues");
  
  /*
   * Prototypes for non-exported routines.
   */
  static int	sleepq_check_timeout(void);
  static void	sleepq_switch(void *wchan);
  static void	sleepq_timeout(void *arg);
- static void	sleepq_resume_thread(struct sleepqueue *sq, struct thread *td, int pri);
  
  /*
   * Early initialization of sleep queues that is called from the sleepinit()
--- 148,169 ----
      0, "maxmimum depth achieved of a single chain");
  #endif
  static struct sleepqueue_chain sleepq_chains[SC_TABLESIZE];
! static uma_zone_t sleepq_zone;
  
  /*
   * Prototypes for non-exported routines.
   */
+ static int	sleepq_catch_signals(void *wchan);
+ static int	sleepq_check_signals(void);
  static int	sleepq_check_timeout(void);
+ #ifdef INVARIANTS
+ static void	sleepq_dtor(void *mem, int size, void *arg);
+ #endif
+ static int	sleepq_init(void *mem, int size, int flags);
+ static void	sleepq_resume_thread(struct sleepqueue *sq, struct thread *td,
+ 		    int pri);
  static void	sleepq_switch(void *wchan);
  static void	sleepq_timeout(void *arg);
  
  /*
   * Early initialization of sleep queues that is called from the sleepinit()
***************
*** 182,202 ****
  		    NULL);
  #endif
  	}
  	thread0.td_sleepqueue = sleepq_alloc();
  }
  
  /*
!  * Malloc and initialize a new sleep queue for a new thread.
   */
  struct sleepqueue *
  sleepq_alloc(void)
  {
- 	struct sleepqueue *sq;
  
! 	sq = malloc(sizeof(struct sleepqueue), M_SLEEPQUEUE, M_WAITOK | M_ZERO);
! 	TAILQ_INIT(&sq->sq_blocked);
! 	LIST_INIT(&sq->sq_free);
! 	return (sq);
  }
  
  /*
--- 194,217 ----
  		    NULL);
  #endif
  	}
+ 	sleepq_zone = uma_zcreate("SLEEPQUEUE", sizeof(struct sleepqueue),
+ #ifdef INVARIANTS
+ 	    NULL, sleepq_dtor, sleepq_init, NULL, UMA_ALIGN_CACHE, 0);
+ #else
+ 	    NULL, NULL, sleepq_init, NULL, UMA_ALIGN_CACHE, 0);
+ #endif
+ 	
  	thread0.td_sleepqueue = sleepq_alloc();
  }
  
  /*
!  * Get a sleep queue for a new thread.
   */
  struct sleepqueue *
  sleepq_alloc(void)
  {
  
! 	return (uma_zalloc(sleepq_zone, M_WAITOK));
  }
  
  /*
***************
*** 206,214 ****
  sleepq_free(struct sleepqueue *sq)
  {
  
! 	MPASS(sq != NULL);
! 	MPASS(TAILQ_EMPTY(&sq->sq_blocked));
! 	free(sq, M_SLEEPQUEUE);
  }
  
  /*
--- 221,227 ----
  sleepq_free(struct sleepqueue *sq)
  {
  
! 	uma_zfree(sleepq_zone, sq);
  }
  
  /*
***************
*** 262,268 ****
   * woken up.
   */
  void
! sleepq_add(void *wchan, struct mtx *lock, const char *wmesg, int flags)
  {
  	struct sleepqueue_chain *sc;
  	struct sleepqueue *sq;
--- 275,282 ----
   * woken up.
   */
  void
! sleepq_add_queue(void *wchan, struct mtx *lock, const char *wmesg, int flags,
!     int queue)
  {
  	struct sleepqueue_chain *sc;
  	struct sleepqueue *sq;
***************
*** 273,282 ****
  	mtx_assert(&sc->sc_lock, MA_OWNED);
  	MPASS(td->td_sleepqueue != NULL);
  	MPASS(wchan != NULL);
  
  	/* If this thread is not allowed to sleep, die a horrible death. */
  	KASSERT(!(td->td_pflags & TDP_NOSLEEPING),
! 	    ("trying to sleep while sleeping is prohibited"));
  
  	/* Look up the sleep queue associated with the wait channel 'wchan'. */
  	sq = sleepq_lookup(wchan);
--- 287,297 ----
  	mtx_assert(&sc->sc_lock, MA_OWNED);
  	MPASS(td->td_sleepqueue != NULL);
  	MPASS(wchan != NULL);
+ 	MPASS((queue >= 0) && (queue < NR_SLEEPQS));
  
  	/* If this thread is not allowed to sleep, die a horrible death. */
  	KASSERT(!(td->td_pflags & TDP_NOSLEEPING),
! 	    ("Trying sleep, but thread marked as sleeping prohibited"));
  
  	/* Look up the sleep queue associated with the wait channel 'wchan'. */
  	sq = sleepq_lookup(wchan);
***************
*** 287,292 ****
--- 302,320 ----
  	 * into the sleep queue already in use by this wait channel.
  	 */
  	if (sq == NULL) {
+ #ifdef INVARIANTS
+ 		int i;
+ 
+ 		sq = td->td_sleepqueue;
+ 		for (i = 0; i < NR_SLEEPQS; i++)
+ 			KASSERT(TAILQ_EMPTY(&sq->sq_blocked[i]),
+ 				("thread's sleep queue %d is not empty", i));
+ 		KASSERT(LIST_EMPTY(&sq->sq_free),
+ 		    ("thread's sleep queue has a non-empty free list"));
+ 		KASSERT(sq->sq_wchan == NULL, ("stale sq_wchan pointer"));
+ 		sq->sq_lock = lock;
+ 		sq->sq_type = flags & SLEEPQ_TYPE;
+ #endif
  #ifdef SLEEPQUEUE_PROFILING
  		sc->sc_depth++;
  		if (sc->sc_depth > sc->sc_max_depth) {
***************
*** 297,321 ****
  #endif
  		sq = td->td_sleepqueue;
  		LIST_INSERT_HEAD(&sc->sc_queues, sq, sq_hash);
- 		KASSERT(TAILQ_EMPTY(&sq->sq_blocked),
- 		    ("thread's sleep queue has a non-empty queue"));
- 		KASSERT(LIST_EMPTY(&sq->sq_free),
- 		    ("thread's sleep queue has a non-empty free list"));
- 		KASSERT(sq->sq_wchan == NULL, ("stale sq_wchan pointer"));
  		sq->sq_wchan = wchan;
- #ifdef INVARIANTS
- 		sq->sq_lock = lock;
- 		sq->sq_type = flags & SLEEPQ_TYPE;
- #endif
  	} else {
  		MPASS(wchan == sq->sq_wchan);
  		MPASS(lock == sq->sq_lock);
  		MPASS((flags & SLEEPQ_TYPE) == sq->sq_type);
  		LIST_INSERT_HEAD(&sq->sq_free, td->td_sleepqueue, sq_hash);
  	}
! 	TAILQ_INSERT_TAIL(&sq->sq_blocked, td, td_slpq);
  	td->td_sleepqueue = NULL;
  	mtx_lock_spin(&sched_lock);
  	td->td_wchan = wchan;
  	td->td_wmesg = wmesg;
  	if (flags & SLEEPQ_INTERRUPTIBLE) {
--- 325,341 ----
  #endif
  		sq = td->td_sleepqueue;
  		LIST_INSERT_HEAD(&sc->sc_queues, sq, sq_hash);
  		sq->sq_wchan = wchan;
  	} else {
  		MPASS(wchan == sq->sq_wchan);
  		MPASS(lock == sq->sq_lock);
  		MPASS((flags & SLEEPQ_TYPE) == sq->sq_type);
  		LIST_INSERT_HEAD(&sq->sq_free, td->td_sleepqueue, sq_hash);
  	}
! 	TAILQ_INSERT_TAIL(&sq->sq_blocked[queue], td, td_slpq);
  	td->td_sleepqueue = NULL;
  	mtx_lock_spin(&sched_lock);
+ 	td->td_sqqueue = queue;
  	td->td_wchan = wchan;
  	td->td_wmesg = wmesg;
  	if (flags & SLEEPQ_INTERRUPTIBLE) {
***************
*** 606,617 ****
  	MPASS(td != NULL);
  	MPASS(sq->sq_wchan != NULL);
  	MPASS(td->td_wchan == sq->sq_wchan);
  	sc = SC_LOOKUP(sq->sq_wchan);
  	mtx_assert(&sc->sc_lock, MA_OWNED);
  	mtx_assert(&sched_lock, MA_OWNED);
  
  	/* Remove the thread from the queue. */
! 	TAILQ_REMOVE(&sq->sq_blocked, td, td_slpq);
  
  	/*
  	 * Get a sleep queue for this thread.  If this is the last waiter,
--- 626,638 ----
  	MPASS(td != NULL);
  	MPASS(sq->sq_wchan != NULL);
  	MPASS(td->td_wchan == sq->sq_wchan);
+ 	MPASS(td->td_sqqueue < NR_SLEEPQS && td->td_sqqueue >= 0);
  	sc = SC_LOOKUP(sq->sq_wchan);
  	mtx_assert(&sc->sc_lock, MA_OWNED);
  	mtx_assert(&sched_lock, MA_OWNED);
  
  	/* Remove the thread from the queue. */
! 	TAILQ_REMOVE(&sq->sq_blocked[td->td_sqqueue], td, td_slpq);
  
  	/*
  	 * Get a sleep queue for this thread.  If this is the last waiter,
***************
*** 652,668 ****
  	setrunnable(td);
  }
  
  /*
   * Find the highest priority thread sleeping on a wait channel and resume it.
   */
  void
! sleepq_signal(void *wchan, int flags, int pri)
  {
  	struct sleepqueue *sq;
  	struct thread *td, *besttd;
  
  	CTR2(KTR_PROC, "sleepq_signal(%p, %d)", wchan, flags);
  	KASSERT(wchan != NULL, ("%s: invalid NULL wait channel", __func__));
  	sq = sleepq_lookup(wchan);
  	if (sq == NULL) {
  		sleepq_release(wchan);
--- 673,723 ----
  	setrunnable(td);
  }
  
+ #ifdef INVARIANTS
+ /*
+  * UMA zone item deallocator.
+  */
+ static void
+ sleepq_dtor(void *mem, int size, void *arg)
+ {
+ 	struct sleepqueue *sq;
+ 	int i;
+ 
+ 	sq = mem;
+ 	for (i = 0; i < NR_SLEEPQS; i++)
+ 		MPASS(TAILQ_EMPTY(&sq->sq_blocked[i]));
+ }
+ #endif
+ 
+ /*
+  * UMA zone item initializer.
+  */
+ static int
+ sleepq_init(void *mem, int size, int flags)
+ {
+ 	struct sleepqueue *sq;
+ 	int i;
+ 
+ 	bzero(mem, size);
+ 	sq = mem;
+ 	for (i = 0; i < NR_SLEEPQS; i++)
+ 		TAILQ_INIT(&sq->sq_blocked[i]);
+ 	LIST_INIT(&sq->sq_free);
+ 	return (0);
+ }
+ 
  /*
   * Find the highest priority thread sleeping on a wait channel and resume it.
   */
  void
! sleepq_signal_queue(void *wchan, int flags, int pri, int queue)
  {
  	struct sleepqueue *sq;
  	struct thread *td, *besttd;
  
  	CTR2(KTR_PROC, "sleepq_signal(%p, %d)", wchan, flags);
  	KASSERT(wchan != NULL, ("%s: invalid NULL wait channel", __func__));
+ 	MPASS((queue >= 0) && (queue < NR_SLEEPQS));
  	sq = sleepq_lookup(wchan);
  	if (sq == NULL) {
  		sleepq_release(wchan);
***************
*** 678,684 ****
  	 * the tail of sleep queues.
  	 */
  	besttd = NULL;
! 	TAILQ_FOREACH(td, &sq->sq_blocked, td_slpq) {
  		if (besttd == NULL || td->td_priority < besttd->td_priority)
  			besttd = td;
  	}
--- 733,739 ----
  	 * the tail of sleep queues.
  	 */
  	besttd = NULL;
! 	TAILQ_FOREACH(td, &sq->sq_blocked[queue], td_slpq) {
  		if (besttd == NULL || td->td_priority < besttd->td_priority)
  			besttd = td;
  	}
***************
*** 693,704 ****
   * Resume all threads sleeping on a specified wait channel.
   */
  void
! sleepq_broadcast(void *wchan, int flags, int pri)
  {
  	struct sleepqueue *sq;
  
  	CTR2(KTR_PROC, "sleepq_broadcast(%p, %d)", wchan, flags);
  	KASSERT(wchan != NULL, ("%s: invalid NULL wait channel", __func__));
  	sq = sleepq_lookup(wchan);
  	if (sq == NULL) {
  		sleepq_release(wchan);
--- 748,760 ----
   * Resume all threads sleeping on a specified wait channel.
   */
  void
! sleepq_broadcast_queue(void *wchan, int flags, int pri, int queue)
  {
  	struct sleepqueue *sq;
  
  	CTR2(KTR_PROC, "sleepq_broadcast(%p, %d)", wchan, flags);
  	KASSERT(wchan != NULL, ("%s: invalid NULL wait channel", __func__));
+ 	MPASS((queue >= 0) && (queue < NR_SLEEPQS));
  	sq = sleepq_lookup(wchan);
  	if (sq == NULL) {
  		sleepq_release(wchan);
***************
*** 709,716 ****
  
  	/* Resume all blocked threads on the sleep queue. */
  	mtx_lock_spin(&sched_lock);
! 	while (!TAILQ_EMPTY(&sq->sq_blocked))
! 		sleepq_resume_thread(sq, TAILQ_FIRST(&sq->sq_blocked), pri);
  	mtx_unlock_spin(&sched_lock);
  	sleepq_release(wchan);
  }
--- 765,773 ----
  
  	/* Resume all blocked threads on the sleep queue. */
  	mtx_lock_spin(&sched_lock);
! 	while (!TAILQ_EMPTY(&sq->sq_blocked[queue]))
! 		sleepq_resume_thread(sq, TAILQ_FIRST(&sq->sq_blocked[queue]),
! 		    pri);
  	mtx_unlock_spin(&sched_lock);
  	sleepq_release(wchan);
  }
***************
*** 853,913 ****
  	mtx_lock_spin(&sched_lock);
  }
  
- #ifdef DDB
- DB_SHOW_COMMAND(sleepq, db_show_sleepqueue)
- {
- 	struct sleepqueue_chain *sc;
- 	struct sleepqueue *sq;
- #ifdef INVARIANTS
- 	struct lock_object *lock;
- #endif
- 	struct thread *td;
- 	void *wchan;
- 	int i;
- 
- 	if (!have_addr)
- 		return;
- 
- 	/*
- 	 * First, see if there is an active sleep queue for the wait channel
- 	 * indicated by the address.
- 	 */
- 	wchan = (void *)addr;
- 	sc = SC_LOOKUP(wchan);
- 	LIST_FOREACH(sq, &sc->sc_queues, sq_hash)
- 		if (sq->sq_wchan == wchan)
- 			goto found;
- 
- 	/*
- 	 * Second, see if there is an active sleep queue at the address
- 	 * indicated.
- 	 */
- 	for (i = 0; i < SC_TABLESIZE; i++)
- 		LIST_FOREACH(sq, &sleepq_chains[i].sc_queues, sq_hash) {
- 			if (sq == (struct sleepqueue *)addr)
- 				goto found;
- 		}
- 
- 	db_printf("Unable to locate a sleep queue via %p\n", (void *)addr);
- 	return;
- found:
- 	db_printf("Wait channel: %p\n", sq->sq_wchan);
- #ifdef INVARIANTS
- 	db_printf("Queue type: %d\n", sq->sq_type);
- 	if (sq->sq_lock) {
- 		lock = &sq->sq_lock->mtx_object;
- 		db_printf("Associated Interlock: %p - (%s) %s\n", lock,
- 		    LOCK_CLASS(lock)->lc_name, lock->lo_name);
- 	}
- #endif
- 	db_printf("Blocked threads:\n");
- 	if (TAILQ_EMPTY(&sq->sq_blocked))
- 		db_printf("\tempty\n");
- 	else
- 		TAILQ_FOREACH(td, &sq->sq_blocked, td_slpq) {
- 			db_printf("\t%p (tid %d, pid %d, \"%s\")\n", td,
- 			    td->td_tid, td->td_proc->p_pid,
- 			    td->td_proc->p_comm);
- 		}	
- }
- #endif
--- 910,912 ----
Index: kern/subr_turnstile.c
===================================================================
RCS file: /cvs/ncvs/src/sys/kern/subr_turnstile.c,v
retrieving revision 1.152.2.5
diff -c -r1.152.2.5 subr_turnstile.c
*** kern/subr_turnstile.c	23 Jan 2007 22:16:33 -0000	1.152.2.5
--- kern/subr_turnstile.c	31 Aug 2007 02:15:23 -0000
***************
*** 114,120 ****
   *  q - td_contested lock
   */
  struct turnstile {
! 	TAILQ_HEAD(, thread) ts_blocked;	/* (c + q) Blocked threads. */
  	TAILQ_HEAD(, thread) ts_pending;	/* (c) Pending threads. */
  	LIST_ENTRY(turnstile) ts_hash;		/* (c) Chain and free list. */
  	LIST_ENTRY(turnstile) ts_link;		/* (q) Contested locks. */
--- 114,121 ----
   *  q - td_contested lock
   */
  struct turnstile {
! 	/* struct mtx ts_lock;	*/		/* Spin lock for self. */
! 	TAILQ_HEAD(, thread) ts_blocked[2];	/* (c + q) Blocked threads. */
  	TAILQ_HEAD(, thread) ts_pending;	/* (c) Pending threads. */
  	LIST_ENTRY(turnstile) ts_hash;		/* (c) Chain and free list. */
  	LIST_ENTRY(turnstile) ts_link;		/* (q) Contested locks. */
***************
*** 143,148 ****
--- 144,155 ----
  static struct mtx td_contested_lock;
  static struct turnstile_chain turnstile_chains[TC_TABLESIZE];
  
+ /* XXX: stats, remove me */
+ static u_int turnstile_nullowners;
+ SYSCTL_UINT(_debug, OID_AUTO, turnstile_nullowners, CTLFLAG_RD,
+     &turnstile_nullowners, 0, "called with null owner on a shared queue");
+ 
+ 
  static MALLOC_DEFINE(M_TURNSTILE, "turnstiles", "turnstiles");
  
  /*
***************
*** 267,272 ****
--- 274,280 ----
  {
  	struct turnstile_chain *tc;
  	struct thread *td1, *td2;
+ 	int queue;
  
  	mtx_assert(&sched_lock, MA_OWNED);
  	MPASS(TD_ON_LOCK(td));
***************
*** 300,315 ****
  		 * Remove thread from blocked chain and determine where
  		 * it should be moved to.
  		 */
  		mtx_lock_spin(&td_contested_lock);
! 		TAILQ_REMOVE(&ts->ts_blocked, td, td_lockq);
! 		TAILQ_FOREACH(td1, &ts->ts_blocked, td_lockq) {
  			MPASS(td1->td_proc->p_magic == P_MAGIC);
  			if (td1->td_priority > td->td_priority)
  				break;
  		}
  
  		if (td1 == NULL)
! 			TAILQ_INSERT_TAIL(&ts->ts_blocked, td, td_lockq);
  		else
  			TAILQ_INSERT_BEFORE(td1, td, td_lockq);
  		mtx_unlock_spin(&td_contested_lock);
--- 308,325 ----
  		 * Remove thread from blocked chain and determine where
  		 * it should be moved to.
  		 */
+ 		queue = td->td_tsqueue;
+ 		MPASS(queue == TS_EXCLUSIVE_QUEUE || queue == TS_SHARED_QUEUE);
  		mtx_lock_spin(&td_contested_lock);
! 		TAILQ_REMOVE(&ts->ts_blocked[queue], td, td_lockq);
! 		TAILQ_FOREACH(td1, &ts->ts_blocked[queue], td_lockq) {
  			MPASS(td1->td_proc->p_magic == P_MAGIC);
  			if (td1->td_priority > td->td_priority)
  				break;
  		}
  
  		if (td1 == NULL)
! 			TAILQ_INSERT_TAIL(&ts->ts_blocked[queue], td, td_lockq);
  		else
  			TAILQ_INSERT_BEFORE(td1, td, td_lockq);
  		mtx_unlock_spin(&td_contested_lock);
***************
*** 412,418 ****
  	 * Note that we currently don't try to revoke lent priorities
  	 * when our priority goes up.
  	 */
! 	if (td == TAILQ_FIRST(&ts->ts_blocked) && td->td_priority < oldpri) {
  		mtx_unlock_spin(&tc->tc_lock);
  		critical_enter();
  		propagate_priority(td);
--- 422,431 ----
  	 * Note that we currently don't try to revoke lent priorities
  	 * when our priority goes up.
  	 */
! 	MPASS(td->td_tsqueue == TS_EXCLUSIVE_QUEUE ||
! 	    td->td_tsqueue == TS_SHARED_QUEUE);
! 	if (td == TAILQ_FIRST(&ts->ts_blocked[td->td_tsqueue]) &&
! 	    td->td_priority < oldpri) {
  		mtx_unlock_spin(&tc->tc_lock);
  		critical_enter();
  		propagate_priority(td);
***************
*** 429,436 ****
  {
  
  	mtx_assert(&td_contested_lock, MA_OWNED);
- 	MPASS(owner->td_proc->p_magic == P_MAGIC);
  	MPASS(ts->ts_owner == NULL);
  	ts->ts_owner = owner;
  	LIST_INSERT_HEAD(&owner->td_contested, ts, ts_link);
  }
--- 442,452 ----
  {
  
  	mtx_assert(&td_contested_lock, MA_OWNED);
  	MPASS(ts->ts_owner == NULL);
+ 	if (owner == NULL)
+ 		return;
+ 
+ 	MPASS(owner->td_proc->p_magic == P_MAGIC);
  	ts->ts_owner = owner;
  	LIST_INSERT_HEAD(&owner->td_contested, ts, ts_link);
  }
***************
*** 444,450 ****
  	struct turnstile *ts;
  
  	ts = malloc(sizeof(struct turnstile), M_TURNSTILE, M_WAITOK | M_ZERO);
! 	TAILQ_INIT(&ts->ts_blocked);
  	TAILQ_INIT(&ts->ts_pending);
  	LIST_INIT(&ts->ts_free);
  	return (ts);
--- 460,467 ----
  	struct turnstile *ts;
  
  	ts = malloc(sizeof(struct turnstile), M_TURNSTILE, M_WAITOK | M_ZERO);
! 	TAILQ_INIT(&ts->ts_blocked[TS_EXCLUSIVE_QUEUE]);
! 	TAILQ_INIT(&ts->ts_blocked[TS_SHARED_QUEUE]);
  	TAILQ_INIT(&ts->ts_pending);
  	LIST_INIT(&ts->ts_free);
  	return (ts);
***************
*** 458,464 ****
  {
  
  	MPASS(ts != NULL);
! 	MPASS(TAILQ_EMPTY(&ts->ts_blocked));
  	MPASS(TAILQ_EMPTY(&ts->ts_pending));
  	free(ts, M_TURNSTILE);
  }
--- 475,482 ----
  {
  
  	MPASS(ts != NULL);
! 	MPASS(TAILQ_EMPTY(&ts->ts_blocked[TS_EXCLUSIVE_QUEUE]));
! 	MPASS(TAILQ_EMPTY(&ts->ts_blocked[TS_SHARED_QUEUE]));
  	MPASS(TAILQ_EMPTY(&ts->ts_pending));
  	free(ts, M_TURNSTILE);
  }
***************
*** 507,512 ****
--- 525,546 ----
  }
  
  /*
+  * Return a pointer to the thread waiting on this turnstile with the
+  * most important priority or NULL if the turnstile has no waiters.
+  */
+ static struct thread *
+ turnstile_first_waiter(struct turnstile *ts)
+ {
+ 	struct thread *std, *xtd;
+ 
+ 	std = TAILQ_FIRST(&ts->ts_blocked[TS_SHARED_QUEUE]);
+ 	xtd = TAILQ_FIRST(&ts->ts_blocked[TS_EXCLUSIVE_QUEUE]);
+ 	if (xtd == NULL || (std != NULL && std->td_priority < xtd->td_priority))
+ 		return (std);
+ 	return (xtd);
+ }
+ 
+ /*
   * Take ownership of a turnstile and adjust the priority of the new
   * owner appropriately.
   */
***************
*** 527,533 ****
  	turnstile_setowner(ts, owner);
  	mtx_unlock_spin(&td_contested_lock);
  
! 	td = TAILQ_FIRST(&ts->ts_blocked);
  	MPASS(td != NULL);
  	MPASS(td->td_proc->p_magic == P_MAGIC);
  	mtx_unlock_spin(&tc->tc_lock);
--- 561,567 ----
  	turnstile_setowner(ts, owner);
  	mtx_unlock_spin(&td_contested_lock);
  
! 	td = turnstile_first_waiter(ts);
  	MPASS(td != NULL);
  	MPASS(td->td_proc->p_magic == P_MAGIC);
  	mtx_unlock_spin(&tc->tc_lock);
***************
*** 548,554 ****
   * turnstile chain locked and will return with it unlocked.
   */
  void
! turnstile_wait(struct lock_object *lock, struct thread *owner)
  {
  	struct turnstile_chain *tc;
  	struct turnstile *ts;
--- 582,588 ----
   * turnstile chain locked and will return with it unlocked.
   */
  void
! turnstile_wait_queue(struct lock_object *lock, struct thread *owner, int queue)
  {
  	struct turnstile_chain *tc;
  	struct turnstile *ts;
***************
*** 558,565 ****
  	tc = TC_LOOKUP(lock);
  	mtx_assert(&tc->tc_lock, MA_OWNED);
  	MPASS(td->td_turnstile != NULL);
! 	MPASS(owner != NULL);
! 	MPASS(owner->td_proc->p_magic == P_MAGIC);
  
  	/* Look up the turnstile associated with the lock 'lock'. */
  	ts = turnstile_lookup(lock);
--- 592,604 ----
  	tc = TC_LOOKUP(lock);
  	mtx_assert(&tc->tc_lock, MA_OWNED);
  	MPASS(td->td_turnstile != NULL);
! 	if (owner)
! 		MPASS(owner->td_proc->p_magic == P_MAGIC);
! 	/* XXX: stats, remove me */
! 	if (!owner && queue == TS_SHARED_QUEUE) {
! 		turnstile_nullowners++;
! 	}
! 	MPASS(queue == TS_SHARED_QUEUE || queue == TS_EXCLUSIVE_QUEUE);
  
  	/* Look up the turnstile associated with the lock 'lock'. */
  	ts = turnstile_lookup(lock);
***************
*** 582,606 ****
  		LIST_INSERT_HEAD(&tc->tc_turnstiles, ts, ts_hash);
  		KASSERT(TAILQ_EMPTY(&ts->ts_pending),
  		    ("thread's turnstile has pending threads"));
! 		KASSERT(TAILQ_EMPTY(&ts->ts_blocked),
! 		    ("thread's turnstile has a non-empty queue"));
  		KASSERT(LIST_EMPTY(&ts->ts_free),
  		    ("thread's turnstile has a non-empty free list"));
  		KASSERT(ts->ts_lockobj == NULL, ("stale ts_lockobj pointer"));
  		ts->ts_lockobj = lock;
  		mtx_lock_spin(&td_contested_lock);
! 		TAILQ_INSERT_TAIL(&ts->ts_blocked, td, td_lockq);
  		turnstile_setowner(ts, owner);
  		mtx_unlock_spin(&td_contested_lock);
  	} else {
! 		TAILQ_FOREACH(td1, &ts->ts_blocked, td_lockq)
  			if (td1->td_priority > td->td_priority)
  				break;
  		mtx_lock_spin(&td_contested_lock);
  		if (td1 != NULL)
  			TAILQ_INSERT_BEFORE(td1, td, td_lockq);
  		else
! 			TAILQ_INSERT_TAIL(&ts->ts_blocked, td, td_lockq);
  		mtx_unlock_spin(&td_contested_lock);
  		MPASS(td->td_turnstile != NULL);
  		LIST_INSERT_HEAD(&ts->ts_free, td->td_turnstile, ts_hash);
--- 621,647 ----
  		LIST_INSERT_HEAD(&tc->tc_turnstiles, ts, ts_hash);
  		KASSERT(TAILQ_EMPTY(&ts->ts_pending),
  		    ("thread's turnstile has pending threads"));
! 		KASSERT(TAILQ_EMPTY(&ts->ts_blocked[TS_EXCLUSIVE_QUEUE]),
! 		    ("thread's turnstile has exclusive waiters"));
! 		KASSERT(TAILQ_EMPTY(&ts->ts_blocked[TS_SHARED_QUEUE]),
! 		    ("thread's turnstile has shared waiters"));
  		KASSERT(LIST_EMPTY(&ts->ts_free),
  		    ("thread's turnstile has a non-empty free list"));
  		KASSERT(ts->ts_lockobj == NULL, ("stale ts_lockobj pointer"));
  		ts->ts_lockobj = lock;
  		mtx_lock_spin(&td_contested_lock);
! 		TAILQ_INSERT_TAIL(&ts->ts_blocked[queue], td, td_lockq);
  		turnstile_setowner(ts, owner);
  		mtx_unlock_spin(&td_contested_lock);
  	} else {
! 		TAILQ_FOREACH(td1, &ts->ts_blocked[queue], td_lockq)
  			if (td1->td_priority > td->td_priority)
  				break;
  		mtx_lock_spin(&td_contested_lock);
  		if (td1 != NULL)
  			TAILQ_INSERT_BEFORE(td1, td, td_lockq);
  		else
! 			TAILQ_INSERT_TAIL(&ts->ts_blocked[queue], td, td_lockq);
  		mtx_unlock_spin(&td_contested_lock);
  		MPASS(td->td_turnstile != NULL);
  		LIST_INSERT_HEAD(&ts->ts_free, td->td_turnstile, ts_hash);
***************
*** 664,670 ****
   * pending list.  This must be called with the turnstile chain locked.
   */
  int
! turnstile_signal(struct turnstile *ts)
  {
  	struct turnstile_chain *tc;
  	struct thread *td;
--- 705,711 ----
   * pending list.  This must be called with the turnstile chain locked.
   */
  int
! turnstile_signal_queue(struct turnstile *ts, int queue)
  {
  	struct turnstile_chain *tc;
  	struct thread *td;
***************
*** 675,689 ****
  	MPASS(ts->ts_owner == curthread);
  	tc = TC_LOOKUP(ts->ts_lockobj);
  	mtx_assert(&tc->tc_lock, MA_OWNED);
  
  	/*
  	 * Pick the highest priority thread blocked on this lock and
  	 * move it to the pending list.
  	 */
! 	td = TAILQ_FIRST(&ts->ts_blocked);
  	MPASS(td->td_proc->p_magic == P_MAGIC);
  	mtx_lock_spin(&td_contested_lock);
! 	TAILQ_REMOVE(&ts->ts_blocked, td, td_lockq);
  	mtx_unlock_spin(&td_contested_lock);
  	TAILQ_INSERT_TAIL(&ts->ts_pending, td, td_lockq);
  
--- 716,733 ----
  	MPASS(ts->ts_owner == curthread);
  	tc = TC_LOOKUP(ts->ts_lockobj);
  	mtx_assert(&tc->tc_lock, MA_OWNED);
+ 	MPASS(ts->ts_owner == curthread ||
+ 	    (queue == TS_EXCLUSIVE_QUEUE && ts->ts_owner == NULL));
+ 	MPASS(queue == TS_SHARED_QUEUE || queue == TS_EXCLUSIVE_QUEUE);
  
  	/*
  	 * Pick the highest priority thread blocked on this lock and
  	 * move it to the pending list.
  	 */
! 	td = TAILQ_FIRST(&ts->ts_blocked[queue]);
  	MPASS(td->td_proc->p_magic == P_MAGIC);
  	mtx_lock_spin(&td_contested_lock);
! 	TAILQ_REMOVE(&ts->ts_blocked[queue], td, td_lockq);
  	mtx_unlock_spin(&td_contested_lock);
  	TAILQ_INSERT_TAIL(&ts->ts_pending, td, td_lockq);
  
***************
*** 692,698 ****
  	 * give it to the about-to-be-woken thread.  Otherwise take a
  	 * turnstile from the free list and give it to the thread.
  	 */
! 	empty = TAILQ_EMPTY(&ts->ts_blocked);
  	if (empty) {
  		MPASS(LIST_EMPTY(&ts->ts_free));
  #ifdef TURNSTILE_PROFILING
--- 736,743 ----
  	 * give it to the about-to-be-woken thread.  Otherwise take a
  	 * turnstile from the free list and give it to the thread.
  	 */
! 	empty = TAILQ_EMPTY(&ts->ts_blocked[TS_EXCLUSIVE_QUEUE]) &&
! 	    TAILQ_EMPTY(&ts->ts_blocked[TS_SHARED_QUEUE]);
  	if (empty) {
  		MPASS(LIST_EMPTY(&ts->ts_free));
  #ifdef TURNSTILE_PROFILING
***************
*** 712,718 ****
   * the turnstile chain locked.
   */
  void
! turnstile_broadcast(struct turnstile *ts)
  {
  	struct turnstile_chain *tc;
  	struct turnstile *ts1;
--- 757,763 ----
   * the turnstile chain locked.
   */
  void
! turnstile_broadcast_queue(struct turnstile *ts, int queue)
  {
  	struct turnstile_chain *tc;
  	struct turnstile *ts1;
***************
*** 720,734 ****
  
  	MPASS(ts != NULL);
  	MPASS(curthread->td_proc->p_magic == P_MAGIC);
! 	MPASS(ts->ts_owner == curthread);
  	tc = TC_LOOKUP(ts->ts_lockobj);
  	mtx_assert(&tc->tc_lock, MA_OWNED);
  
  	/*
  	 * Transfer the blocked list to the pending list.
  	 */
  	mtx_lock_spin(&td_contested_lock);
! 	TAILQ_CONCAT(&ts->ts_pending, &ts->ts_blocked, td_lockq);
  	mtx_unlock_spin(&td_contested_lock);
  
  	/*
--- 765,781 ----
  
  	MPASS(ts != NULL);
  	MPASS(curthread->td_proc->p_magic == P_MAGIC);
! 	MPASS(ts->ts_owner == curthread ||
! 		    (queue == TS_EXCLUSIVE_QUEUE && ts->ts_owner == NULL));
  	tc = TC_LOOKUP(ts->ts_lockobj);
  	mtx_assert(&tc->tc_lock, MA_OWNED);
+ 	MPASS(queue == TS_SHARED_QUEUE || queue == TS_EXCLUSIVE_QUEUE);
  
  	/*
  	 * Transfer the blocked list to the pending list.
  	 */
  	mtx_lock_spin(&td_contested_lock);
! 	TAILQ_CONCAT(&ts->ts_pending, &ts->ts_blocked[queue], td_lockq);
  	mtx_unlock_spin(&td_contested_lock);
  
  	/*
***************
*** 756,770 ****
   * chain locked.
   */
  void
! turnstile_unpend(struct turnstile *ts)
  {
  	TAILQ_HEAD( ,thread) pending_threads;
  	struct turnstile_chain *tc;
  	struct thread *td;
  	u_char cp, pri;
  
  	MPASS(ts != NULL);
! 	MPASS(ts->ts_owner == curthread);
  	tc = TC_LOOKUP(ts->ts_lockobj);
  	mtx_assert(&tc->tc_lock, MA_OWNED);
  	MPASS(!TAILQ_EMPTY(&ts->ts_pending));
--- 803,819 ----
   * chain locked.
   */
  void
! turnstile_unpend_queue(struct turnstile *ts, int owner_type)
  {
  	TAILQ_HEAD( ,thread) pending_threads;
  	struct turnstile_chain *tc;
+ 	struct turnstile *nts;
  	struct thread *td;
  	u_char cp, pri;
  
  	MPASS(ts != NULL);
! 	MPASS(ts->ts_owner == curthread ||
! 	    (owner_type == TS_SHARED_LOCK && ts->ts_owner == NULL));
  	tc = TC_LOOKUP(ts->ts_lockobj);
  	mtx_assert(&tc->tc_lock, MA_OWNED);
  	MPASS(!TAILQ_EMPTY(&ts->ts_pending));
***************
*** 776,782 ****
  	TAILQ_INIT(&pending_threads);
  	TAILQ_CONCAT(&pending_threads, &ts->ts_pending, td_lockq);
  #ifdef INVARIANTS
! 	if (TAILQ_EMPTY(&ts->ts_blocked))
  		ts->ts_lockobj = NULL;
  #endif
  
--- 825,832 ----
  	TAILQ_INIT(&pending_threads);
  	TAILQ_CONCAT(&pending_threads, &ts->ts_pending, td_lockq);
  #ifdef INVARIANTS
! 	if (TAILQ_EMPTY(&ts->ts_blocked[TS_EXCLUSIVE_QUEUE]) &&
! 	    TAILQ_EMPTY(&ts->ts_blocked[TS_SHARED_QUEUE]))
  		ts->ts_lockobj = NULL;
  #endif
  
***************
*** 802,809 ****
  	pri = PRI_MAX;
  	mtx_lock_spin(&sched_lock);
  	mtx_lock_spin(&td_contested_lock);
! 	LIST_FOREACH(ts, &td->td_contested, ts_link) {
! 		cp = TAILQ_FIRST(&ts->ts_blocked)->td_priority;
  		if (cp < pri)
  			pri = cp;
  	}
--- 852,859 ----
  	pri = PRI_MAX;
  	mtx_lock_spin(&sched_lock);
  	mtx_lock_spin(&td_contested_lock);
! 	LIST_FOREACH(nts, &td->td_contested, ts_link) {
! 		cp = turnstile_first_waiter(nts)->td_priority;
  		if (cp < pri)
  			pri = cp;
  	}
***************
*** 837,855 ****
  }
  
  /*
   * Return the first thread in a turnstile.
   */
  struct thread *
! turnstile_head(struct turnstile *ts)
  {
  #ifdef INVARIANTS
  	struct turnstile_chain *tc;
  
  	MPASS(ts != NULL);
  	tc = TC_LOOKUP(ts->ts_lockobj);
  	mtx_assert(&tc->tc_lock, MA_OWNED);
  #endif
! 	return (TAILQ_FIRST(&ts->ts_blocked));
  }
  
  #ifdef DDB
--- 887,955 ----
  }
  
  /*
+  * Give up ownership of a turnstile.  This must be called with the
+  * turnstile chain locked.
+  */
+ void
+ turnstile_disown(struct turnstile *ts)
+ {
+ 	struct turnstile_chain *tc;
+ 	struct thread *td;
+ 	u_char cp, pri;
+ 
+ 	MPASS(ts != NULL);
+ 	MPASS(ts->ts_owner == curthread);
+ 	tc = TC_LOOKUP(ts->ts_lockobj);
+ 	mtx_assert(&tc->tc_lock, MA_OWNED);
+ 	MPASS(TAILQ_EMPTY(&ts->ts_pending));
+ 	MPASS(!TAILQ_EMPTY(&ts->ts_blocked[TS_EXCLUSIVE_QUEUE]) ||
+ 	    !TAILQ_EMPTY(&ts->ts_blocked[TS_SHARED_QUEUE]));
+ 
+ 	/*
+ 	 * Remove the turnstile from this thread's list of contested locks
+ 	 * since this thread doesn't own it anymore.  New threads will
+ 	 * not be blocking on the turnstile until it is claimed by a new
+ 	 * owner.
+ 	 */
+ 	mtx_lock_spin(&td_contested_lock);
+ 	ts->ts_owner = NULL;
+ 	LIST_REMOVE(ts, ts_link);
+ 	mtx_unlock_spin(&td_contested_lock);
+ 
+ 	/*
+ 	 * Adjust the priority of curthread based on other contested
+ 	 * locks it owns.  Don't lower the priority below the base
+ 	 * priority however.
+ 	 */
+ 	td = curthread;
+ 	pri = PRI_MAX;
+ 	mtx_lock_spin(&sched_lock);
+ 	mtx_lock_spin(&td_contested_lock);
+ 	LIST_FOREACH(ts, &td->td_contested, ts_link) {
+ 		cp = turnstile_first_waiter(ts)->td_priority;
+ 		if (cp < pri)
+ 			pri = cp;
+ 	}
+ 	mtx_unlock_spin(&td_contested_lock);
+ 	sched_unlend_prio(td, pri);
+ 	mtx_unlock_spin(&sched_lock);
+ }
+ 
+ /*
   * Return the first thread in a turnstile.
   */
  struct thread *
! turnstile_head_queue(struct turnstile *ts, int queue)
  {
  #ifdef INVARIANTS
  	struct turnstile_chain *tc;
  
  	MPASS(ts != NULL);
  	tc = TC_LOOKUP(ts->ts_lockobj);
+ 	MPASS(queue == TS_SHARED_QUEUE || queue == TS_EXCLUSIVE_QUEUE);
  	mtx_assert(&tc->tc_lock, MA_OWNED);
  #endif
! 	return (TAILQ_FIRST(&ts->ts_blocked[queue]));
  }
  
  #ifdef DDB
***************
*** 1146,1152 ****
   * Returns true if a turnstile is empty.
   */
  int
! turnstile_empty(struct turnstile *ts)
  {
  #ifdef INVARIANTS
  	struct turnstile_chain *tc;
--- 1246,1252 ----
   * Returns true if a turnstile is empty.
   */
  int
! turnstile_empty_queue(struct turnstile *ts, int queue)
  {
  #ifdef INVARIANTS
  	struct turnstile_chain *tc;
***************
*** 1154,1159 ****
  	MPASS(ts != NULL);
  	tc = TC_LOOKUP(ts->ts_lockobj);
  	mtx_assert(&tc->tc_lock, MA_OWNED);
  #endif
! 	return (TAILQ_EMPTY(&ts->ts_blocked));
  }
--- 1254,1260 ----
  	MPASS(ts != NULL);
  	tc = TC_LOOKUP(ts->ts_lockobj);
  	mtx_assert(&tc->tc_lock, MA_OWNED);
+ 	MPASS(queue == TS_SHARED_QUEUE || queue == TS_EXCLUSIVE_QUEUE);
  #endif
! 	return (TAILQ_EMPTY(&ts->ts_blocked[queue]));
  }
Index: netinet6/in6_src.c
===================================================================
RCS file: /cvs/ncvs/src/sys/netinet6/in6_src.c,v
retrieving revision 1.30.2.4
diff -c -r1.30.2.4 in6_src.c
*** netinet6/in6_src.c	25 Dec 2005 14:03:37 -0000	1.30.2.4
--- netinet6/in6_src.c	31 Aug 2007 01:23:38 -0000
***************
*** 76,81 ****
--- 76,82 ----
  #include <sys/errno.h>
  #include <sys/time.h>
  #include <sys/kernel.h>
+ #include <sys/lock.h>
  #include <sys/sx.h>
  
  #include <net/if.h>
Index: sys/_rwlock.h
===================================================================
RCS file: sys/_rwlock.h
diff -N sys/_rwlock.h
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- sys/_rwlock.h	31 Aug 2007 00:39:59 -0000
***************
*** 0 ****
--- 1,44 ----
+ /*-
+  * Copyright (c) 2006 John Baldwin <jhb@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 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/sys/sys/_rwlock.h,v 1.4 2007/06/26 21:31:56 attilio Exp $
+  */
+ 
+ #ifndef _SYS__RWLOCK_H_
+ #define	_SYS__RWLOCK_H_
+ 
+ /*
+  * Reader/writer lock.
+  */
+ struct rwlock {
+ 	struct lock_object	lock_object;
+ 	volatile uintptr_t	rw_lock;
+ 	volatile unsigned	rw_recurse;
+ };
+ 
+ #endif /* !_SYS__RWLOCK_H_ */
Index: sys/_sx.h
===================================================================
RCS file: sys/_sx.h
diff -N sys/_sx.h
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- sys/_sx.h	4 Sep 2007 01:20:03 -0000
***************
*** 0 ****
--- 1,59 ----
+ /*-
+  * Copyright (c) 2007 Attilio Rao <attilio@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/sys/sys/_sx.h,v 1.1 2007/03/31 23:23:42 jhb Exp $
+  */
+ 
+ #ifndef	_SYS__SX_H_
+ #define	_SYS__SX_H_
+ 
+ #include <sys/condvar.h>
+ 
+ /*
+  * Shared/exclusive lock main structure definition.
+  *
+  * Note, to preserve compatibility we have extra fields from
+  * the previous implementation left over.
+  */
+ struct sx {
+ 	struct lock_object	lock_object;
+ 	/* was: struct mtx *sx_lock; */
+ 	volatile uintptr_t	sx_lock;
+ 	/* was: int sx_cnt; */
+ 	volatile unsigned	sx_recurse;
+ 	/*
+ 	 * The following fields are unused but kept to preserve
+ 	 * sizeof(struct sx) for 6.x compat.
+ 	 */
+ 	struct cv       sx_shrd_cv;	/* unused */
+ 	int             sx_shrd_wcnt;	/* unused */
+ 	struct cv       sx_excl_cv;	/* unused */
+ 	int             sx_excl_wcnt;	/* unused */
+ 	struct thread   *sx_xholder;	/* unused */
+ };
+ 
+ #endif	/* !_SYS__SX_H_ */
Index: sys/lock_profile.h
===================================================================
RCS file: sys/lock_profile.h
diff -N sys/lock_profile.h
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- sys/lock_profile.h	31 Aug 2007 03:21:42 -0000
***************
*** 0 ****
--- 1,45 ----
+ /*-
+  * Copyright (c) 2007 Juniper Networks
+  * Author: Alfred Perlstein
+  * All rights reserved.
+  *
+  * Redistribution and use in source and binary forms, 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$
+  */
+ 
+ #ifndef	_LOCK_PROFILE_H_
+ #define	_LOCK_PROFILE_H_
+ 
+ /* temp stubs for lock profiling, not supported in 6.x (yet) */
+ 
+ #define lock_profile_obtain_lock_success(lock_object, a0, a1, file, line) \
+     do { ; } while (0)
+ #define lock_profile_release_lock(lock_object) \
+     do { ; } while (0)
+ #define lock_profile_obtain_lock_failed(lock_object, contested, waittime) \
+     do { ; } while (0)
+ 
+ #endif
+ 
Index: sys/proc.h
===================================================================
RCS file: /cvs/ncvs/src/sys/sys/proc.h,v
retrieving revision 1.432.2.10
diff -c -r1.432.2.10 proc.h
*** sys/proc.h	11 Jun 2007 11:27:04 -0000	1.432.2.10
--- sys/proc.h	2 Sep 2007 21:56:16 -0000
***************
*** 237,243 ****
--- 237,252 ----
   * When waiting to be run, threads are hung off the KSEGRP in priority order.
   * With N runnable and queued KSEs in the KSEGRP, the first N threads
   * are linked to them. Other threads are not yet assigned.
+  *
+  * We must force at least 16 byte alignment for "struct thread"
+  * because the rwlocks and sxlocks expect to use the bottom bits
+  * of the pointer for bookkeeping information.
+  *
+  * This causes problems for the thread0 data structure because it
+  * may not be properly aligned otherwise.
   */
+ #define THREAD_ALIGN	16
+ 
  struct thread {
  	struct proc	*td_proc;	/* (*) Associated process. */
  	struct ksegrp	*td_ksegrp;	/* (*) Associated KSEG. */
***************
*** 261,272 ****
--- 270,283 ----
  	int		td_inhibitors;	/* (j) Why can not run. */
  	int		td_pflags;	/* (k) Private thread (TDP_*) flags. */
  	int		td_dupfd;	/* (k) Ret value from fdopen. XXX */
+ 	int		td_sqqueue;	/* (t) Sleepqueue queue blocked on. */
  	void		*td_wchan;	/* (j) Sleep address. */
  	const char	*td_wmesg;	/* (j) Reason for sleep. */
  	u_char		td_lastcpu;	/* (j) Last cpu we were on. */
  	u_char		td_oncpu;	/* (j) Which cpu we are on. */
  	volatile u_char td_owepreempt;  /* (k*) Preempt on last critical_exit */
  	short		td_locks;	/* (k) Count of non-spin locks. */
+ 	u_char		td_tsqueue;	/* (t) Turnstile queue blocked on. */
  	struct turnstile *td_blocked;	/* (j) Lock process is blocked on. */
  	void		*td_ithd;	/* (n) Unused, kept to preserve ABI. */
  	const char	*td_lockname;	/* (j) Name of lock blocked on. */
***************
*** 324,330 ****
  	struct mdthread td_md;		/* (k) Any machine-dependent fields. */
  	struct td_sched	*td_sched;	/* (*) Scheduler-specific data. */
  	struct kaudit_record	*td_ar;	/* (k) Active audit record, if any. */
! };
  
  /*
   * Flags kept in td_flags:
--- 335,342 ----
  	struct mdthread td_md;		/* (k) Any machine-dependent fields. */
  	struct td_sched	*td_sched;	/* (*) Scheduler-specific data. */
  	struct kaudit_record	*td_ar;	/* (k) Active audit record, if any. */
! } __attribute__ ((aligned (THREAD_ALIGN)));
! 
  
  /*
   * Flags kept in td_flags:
Index: sys/rwlock.h
===================================================================
RCS file: sys/rwlock.h
diff -N sys/rwlock.h
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- sys/rwlock.h	31 Aug 2007 03:26:18 -0000
***************
*** 0 ****
--- 1,223 ----
+ /*-
+  * Copyright (c) 2006 John Baldwin <jhb@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 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/sys/sys/rwlock.h,v 1.13 2007/06/26 21:31:56 attilio Exp $
+  */
+ 
+ #ifndef _SYS_RWLOCK_H_
+ #define _SYS_RWLOCK_H_
+ 
+ #include <sys/_lock.h>
+ #include <sys/_rwlock.h>
+ #include <sys/lock_profile.h>
+ 
+ #ifdef _KERNEL
+ #include <sys/pcpu.h>
+ #include <machine/atomic.h>
+ #endif
+ 
+ /*
+  * The rw_lock field consists of several fields.  The low bit indicates
+  * if the lock is locked with a read (shared) or write (exclusive) lock.
+  * A value of 0 indicates a write lock, and a value of 1 indicates a read
+  * lock.  Bit 1 is a boolean indicating if there are any threads waiting
+  * for a read lock.  Bit 2 is a boolean indicating if there are any threads
+  * waiting for a write lock.  The rest of the variable's definition is
+  * dependent on the value of the first bit.  For a write lock, it is a
+  * pointer to the thread holding the lock, similar to the mtx_lock field of
+  * mutexes.  For read locks, it is a count of read locks that are held.
+  *
+  * When the lock is not locked by any thread, it is encoded as a read lock
+  * with zero waiters.
+  *
+  * A note about memory barriers.  Write locks need to use the same memory
+  * barriers as mutexes: _acq when acquiring a write lock and _rel when
+  * releasing a write lock.  Read locks also need to use an _acq barrier when
+  * acquiring a read lock.  However, since read locks do not update any
+  * locked data (modulo bugs of course), no memory barrier is needed when
+  * releasing a read lock.
+  */
+ 
+ #define	RW_LOCK_READ		0x01
+ #define	RW_LOCK_READ_WAITERS	0x02
+ #define	RW_LOCK_WRITE_WAITERS	0x04
+ #define	RW_LOCK_RECURSED	0x08
+ #define	RW_LOCK_FLAGMASK						\
+ 	(RW_LOCK_READ | RW_LOCK_READ_WAITERS | RW_LOCK_WRITE_WAITERS |	\
+ 	RW_LOCK_RECURSED)
+ 
+ #define	RW_OWNER(x)		((x) & ~RW_LOCK_FLAGMASK)
+ #define	RW_READERS_SHIFT	4
+ #define	RW_READERS(x)		(RW_OWNER((x)) >> RW_READERS_SHIFT)
+ #define	RW_READERS_LOCK(x)	((x) << RW_READERS_SHIFT | RW_LOCK_READ)
+ #define	RW_ONE_READER		(1 << RW_READERS_SHIFT)
+ 
+ #define	RW_UNLOCKED		RW_READERS_LOCK(0)
+ #define	RW_DESTROYED		(RW_LOCK_READ_WAITERS | RW_LOCK_WRITE_WAITERS)
+ 
+ #ifdef _KERNEL
+ 
+ /* Very simple operations on rw_lock. */
+ 
+ /* Try to obtain a write lock once. */
+ #define	_rw_write_lock(rw, tid)						\
+ 	atomic_cmpset_acq_ptr(&(rw)->rw_lock, RW_UNLOCKED, (tid))
+ 
+ /* Release a write lock quickly if there are no waiters. */
+ #define	_rw_write_unlock(rw, tid)					\
+ 	atomic_cmpset_rel_ptr(&(rw)->rw_lock, (tid), RW_UNLOCKED)
+ 
+ /*
+  * Full lock operations that are suitable to be inlined in non-debug
+  * kernels.  If the lock cannot be acquired or released trivially then
+  * the work is deferred to another function.
+  */
+ 
+ /* Acquire a write lock. */
+ #define	__rw_wlock(rw, tid, file, line) do {	\
+ 	uintptr_t _tid = (uintptr_t)(tid);				\
+ 	/* int contested = 0; XXX: notsup */                                             \
+         /*uint64_t waitstart = 0; XXX: notsup */                                         \
+ 						                        \
+ 	if (!_rw_write_lock((rw), _tid)) {				\
+ 		lock_profile_obtain_lock_failed(&(rw)->lock_object,	\
+ 		    &contested, &waitstart);				\
+ 		_rw_wlock_hard((rw), _tid, (file), (line));		\
+ 	}                                                               \
+ 	lock_profile_obtain_lock_success(&(rw)->lock_object, contested,	\
+ 	    waitstart, (file), (line));					\
+ } while (0)
+ 
+ /* Release a write lock. */
+ #define	__rw_wunlock(rw, tid, file, line) do {				\
+ 	uintptr_t _tid = (uintptr_t)(tid);				\
+ 									\
+ 	if (!_rw_write_unlock((rw), _tid))				\
+ 		_rw_wunlock_hard((rw), _tid, (file), (line));		\
+ } while (0)
+ 
+ /*
+  * Function prototypes.  Routines that start with _ are not part of the
+  * external API and should not be called directly.  Wrapper macros should
+  * be used instead.
+  */
+ 
+ #define	rw_init(rw, name)	rw_init_flags((rw), (name), 0)
+ void	rw_init_flags(struct rwlock *rw, const char *name, int opts);
+ void	rw_destroy(struct rwlock *rw);
+ void	rw_sysinit(void *arg);
+ int	rw_wowned(struct rwlock *rw);
+ void	_rw_wlock(struct rwlock *rw, const char *file, int line);
+ void	_rw_wunlock(struct rwlock *rw, const char *file, int line);
+ void	_rw_rlock(struct rwlock *rw, const char *file, int line);
+ void	_rw_runlock(struct rwlock *rw, const char *file, int line);
+ void	_rw_wlock_hard(struct rwlock *rw, uintptr_t tid, const char *file,
+ 	    int line);
+ void	_rw_wunlock_hard(struct rwlock *rw, uintptr_t tid, const char *file,
+ 	    int line);
+ int	_rw_try_upgrade(struct rwlock *rw, const char *file, int line);
+ void	_rw_downgrade(struct rwlock *rw, const char *file, int line);
+ #if defined(INVARIANTS) || defined(INVARIANT_SUPPORT)
+ void	_rw_assert(struct rwlock *rw, int what, const char *file, int line);
+ #endif
+ 
+ /*
+  * Public interface for lock operations.
+  *
+  * XXX: Missing try locks.
+  */
+ 
+ #ifndef LOCK_DEBUG
+ #error LOCK_DEBUG not defined, include <sys/lock.h> before <sys/rwlock.h>
+ #endif
+ #if LOCK_DEBUG > 0 || defined(RWLOCK_NOINLINE)
+ #define	rw_wlock(rw)		_rw_wlock((rw), LOCK_FILE, LOCK_LINE)
+ #define	rw_wunlock(rw)		_rw_wunlock((rw), LOCK_FILE, LOCK_LINE)
+ #else
+ #define	rw_wlock(rw)							\
+ 	__rw_wlock((rw), curthread, LOCK_FILE, LOCK_LINE)
+ #define	rw_wunlock(rw)							\
+ 	__rw_wunlock((rw), curthread, LOCK_FILE, LOCK_LINE)
+ #endif
+ #define	rw_rlock(rw)		_rw_rlock((rw), LOCK_FILE, LOCK_LINE)
+ #define	rw_runlock(rw)		_rw_runlock((rw), LOCK_FILE, LOCK_LINE)
+ #define	rw_try_upgrade(rw)	_rw_try_upgrade((rw), LOCK_FILE, LOCK_LINE)
+ #define	rw_downgrade(rw)	_rw_downgrade((rw), LOCK_FILE, LOCK_LINE)
+ #define	rw_sleep(chan, rw, pri, wmesg, timo)				\
+ 	_sleep((chan), &(rw)->lock_object, (pri), (wmesg), (timo))
+ 
+ #define	rw_initialized(rw)	lock_initalized(&(rw)->lock_object)
+ 
+ struct rw_args {
+ 	struct rwlock	*ra_rw;
+ 	const char 	*ra_desc;
+ };
+ 
+ #define	RW_SYSINIT(name, rw, desc)					\
+ 	static struct rw_args name##_args = {				\
+ 		(rw),							\
+ 		(desc),							\
+ 	};								\
+ 	SYSINIT(name##_rw_sysinit, SI_SUB_LOCK, SI_ORDER_MIDDLE,	\
+ 	    rw_sysinit, &name##_args);					\
+ 	SYSUNINIT(name##_rw_sysuninit, SI_SUB_LOCK, SI_ORDER_MIDDLE,	\
+ 	    rw_destroy, (rw))
+ 
+ /*
+  * Options passed to rw_init_flags().
+  */
+ #define	RW_DUPOK	0x01
+ #define	RW_NOPROFILE	0x02
+ #define	RW_NOWITNESS	0x04
+ #define	RW_QUIET	0x08
+ #define	RW_RECURSE	0x10
+ 
+ /*
+  * The INVARIANTS-enabled rw_assert() functionality.
+  *
+  * The constants need to be defined for INVARIANT_SUPPORT infrastructure
+  * support as _rw_assert() itself uses them and the latter implies that
+  * _rw_assert() must build.
+  */
+ #if defined(INVARIANTS) || defined(INVARIANT_SUPPORT)
+ #define	RA_LOCKED		LA_LOCKED
+ #define	RA_RLOCKED		LA_SLOCKED
+ #define	RA_WLOCKED		LA_XLOCKED
+ #define	RA_UNLOCKED		LA_UNLOCKED
+ #define	RA_RECURSED		LA_RECURSED
+ #define	RA_NOTRECURSED		LA_NOTRECURSED
+ #endif
+ 
+ #ifdef INVARIANTS
+ #define	rw_assert(rw, what)	_rw_assert((rw), (what), LOCK_FILE, LOCK_LINE)
+ #else
+ #define	rw_assert(rw, what)
+ #endif
+ 
+ #endif /* _KERNEL */
+ #endif /* !_SYS_RWLOCK_H_ */
Index: sys/sleepqueue.h
===================================================================
RCS file: /cvs/ncvs/src/sys/sys/sleepqueue.h,v
retrieving revision 1.6.2.1
diff -c -r1.6.2.1 sleepqueue.h
*** sys/sleepqueue.h	27 Feb 2006 00:19:39 -0000	1.6.2.1
--- sys/sleepqueue.h	31 Aug 2007 01:47:52 -0000
***************
*** 26,40 ****
   * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   *
!  * $FreeBSD: src/sys/sys/sleepqueue.h,v 1.6.2.1 2006/02/27 00:19:39 davidxu Exp $
   */
  
  #ifndef _SYS_SLEEPQUEUE_H_
  #define _SYS_SLEEPQUEUE_H_
  
  /*
!  * Sleep queue interface.  Sleep/wakeup and condition variables use a sleep
!  * queue for the queue of threads blocked on a sleep channel.
   *
   * A thread calls sleepq_lock() to lock the sleep queue chain associated
   * with a given wait channel.  A thread can then call call sleepq_add() to
--- 26,41 ----
   * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   *
!  * $FreeBSD: src/sys/sys/sleepqueue.h,v 1.12 2007/03/31 23:23:42 jhb Exp $
   */
  
  #ifndef _SYS_SLEEPQUEUE_H_
  #define _SYS_SLEEPQUEUE_H_
  
  /*
!  * Sleep queue interface.  Sleep/wakeup, condition variables, and sx
!  * locks use a sleep queue for the queue of threads blocked on a sleep
!  * channel.
   *
   * A thread calls sleepq_lock() to lock the sleep queue chain associated
   * with a given wait channel.  A thread can then call call sleepq_add() to
***************
*** 84,107 ****
  #define	SLEEPQ_TYPE		0x0ff		/* Mask of sleep queue types. */
  #define	SLEEPQ_MSLEEP		0x00		/* Used by msleep/wakeup. */
  #define	SLEEPQ_CONDVAR		0x01		/* Used for a cv. */
  #define	SLEEPQ_INTERRUPTIBLE	0x100		/* Sleep is interruptible. */
  
  void	init_sleepqueues(void);
  void	sleepq_abort(struct thread *td, int intrval);
! void	sleepq_add(void *, struct mtx *, const char *, int);
  struct sleepqueue *sleepq_alloc(void);
! void	sleepq_broadcast(void *, int, int);
  void	sleepq_free(struct sleepqueue *);
  void	sleepq_lock(void *);
  struct sleepqueue *sleepq_lookup(void *);
  void	sleepq_release(void *);
  void	sleepq_remove(struct thread *, void *);
! void	sleepq_signal(void *, int, int);
  void	sleepq_set_timeout(void *wchan, int timo);
  int	sleepq_timedwait(void *wchan);
  int	sleepq_timedwait_sig(void *wchan);
  void	sleepq_wait(void *);
  int	sleepq_wait_sig(void *wchan);
  
  #endif	/* _KERNEL */
  #endif	/* !_SYS_SLEEPQUEUE_H_ */
--- 85,117 ----
  #define	SLEEPQ_TYPE		0x0ff		/* Mask of sleep queue types. */
  #define	SLEEPQ_MSLEEP		0x00		/* Used by msleep/wakeup. */
  #define	SLEEPQ_CONDVAR		0x01		/* Used for a cv. */
+ #define	SLEEPQ_SX		0x03		/* Used by an sx lock. */
  #define	SLEEPQ_INTERRUPTIBLE	0x100		/* Sleep is interruptible. */
  
  void	init_sleepqueues(void);
  void	sleepq_abort(struct thread *td, int intrval);
! void	sleepq_add_queue(void *, struct mtx *, const char *, int, int);
  struct sleepqueue *sleepq_alloc(void);
! void	sleepq_broadcast_queue(void *, int, int, int);
  void	sleepq_free(struct sleepqueue *);
  void	sleepq_lock(void *);
  struct sleepqueue *sleepq_lookup(void *);
  void	sleepq_release(void *);
  void	sleepq_remove(struct thread *, void *);
! void	sleepq_signal_queue(void *, int, int, int);
  void	sleepq_set_timeout(void *wchan, int timo);
  int	sleepq_timedwait(void *wchan);
  int	sleepq_timedwait_sig(void *wchan);
  void	sleepq_wait(void *);
  int	sleepq_wait_sig(void *wchan);
  
+ /* Preserve source compat with 6.x */
+ #define sleepq_add(wchan, lock, wmesg, flags)		    \
+     sleepq_add_queue(wchan, lock, wmesg, flags, 0)
+ #define sleepq_broadcast(wchan, flags, pri)		     \
+     sleepq_broadcast_queue(wchan, flags, pri, 0)
+ #define sleepq_signal(wchan, flags, pri)		    \
+     sleepq_signal_queue(wchan, flags, pri, 0)
+ 
  #endif	/* _KERNEL */
  #endif	/* !_SYS_SLEEPQUEUE_H_ */
Index: sys/sx.h
===================================================================
RCS file: /cvs/ncvs/src/sys/sys/sx.h,v
retrieving revision 1.21.2.5
diff -c -r1.21.2.5 sx.h
*** sys/sx.h	27 Aug 2007 13:45:35 -0000	1.21.2.5
--- sys/sx.h	31 Aug 2007 01:02:47 -0000
***************
*** 1,5 ****
  /*-
!  * Copyright (C) 2001 Jason Evans <jasone@freebsd.org>.  All rights reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
--- 1,7 ----
  /*-
!  * Copyright (c) 2007 Attilio Rao <attilio@freebsd.org>
!  * Copyright (c) 2001 Jason Evans <jasone@freebsd.org>
!  * All rights reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
***************
*** 24,62 ****
   * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
   * DAMAGE.
   *
!  * $FreeBSD: src/sys/sys/sx.h,v 1.21.2.5 2007/08/27 13:45:35 jhb Exp $
   */
  
  #ifndef	_SYS_SX_H_
  #define	_SYS_SX_H_
  
- #include <sys/queue.h>
  #include <sys/_lock.h>
! #include <sys/condvar.h>	/* XXX */
  
! struct sx {
! 	struct lock_object sx_object;	/* Common lock properties. */
! 	struct mtx	*sx_lock;	/* General protection lock. */
! 	int		sx_cnt;		/* -1: xlock, > 0: slock count. */
! 	struct cv	sx_shrd_cv;	/* slock waiters. */
! 	int		sx_shrd_wcnt;	/* Number of slock waiters. */
! 	struct cv	sx_excl_cv;	/* xlock waiters. */
! 	int		sx_excl_wcnt;	/* Number of xlock waiters. */
! 	struct thread	*sx_xholder;	/* Thread presently holding xlock. */
! };
  
  #ifdef _KERNEL
  void	sx_sysinit(void *arg);
! void	sx_init(struct sx *sx, const char *description);
  void	sx_destroy(struct sx *sx);
! void	_sx_slock(struct sx *sx, const char *file, int line);
! void	_sx_xlock(struct sx *sx, const char *file, int line);
  int	_sx_try_slock(struct sx *sx, const char *file, int line);
  int	_sx_try_xlock(struct sx *sx, const char *file, int line);
  void	_sx_sunlock(struct sx *sx, const char *file, int line);
  void	_sx_xunlock(struct sx *sx, const char *file, int line);
  int	_sx_try_upgrade(struct sx *sx, const char *file, int line);
  void	_sx_downgrade(struct sx *sx, const char *file, int line);
  #if defined(INVARIANTS) || defined(INVARIANT_SUPPORT)
  void	_sx_assert(struct sx *sx, int what, const char *file, int line);
  #endif
--- 26,118 ----
   * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
   * DAMAGE.
   *
!  * $FreeBSD: src/sys/sys/sx.h,v 1.37 2007/07/06 13:20:44 attilio Exp $
   */
  
  #ifndef	_SYS_SX_H_
  #define	_SYS_SX_H_
  
  #include <sys/_lock.h>
! #include <sys/_sx.h>
! #include <sys/lock_profile.h>
  
! #ifdef	_KERNEL
! #include <machine/atomic.h>
! #endif
! 
! /*
!  * In general, the sx locks and rwlocks use very similar algorithms.
!  * The main difference in the implementations is how threads are
!  * blocked when a lock is unavailable.  For this, sx locks use sleep
!  * queues which do not support priority propagation, and rwlocks use
!  * turnstiles which do.
!  *
!  * The sx_lock field consists of several fields.  The low bit
!  * indicates if the lock is locked with a shared or exclusive lock.  A
!  * value of 0 indicates an exclusive lock, and a value of 1 indicates
!  * a shared lock.  Bit 1 is a boolean indicating if there are any
!  * threads waiting for a shared lock.  Bit 2 is a boolean indicating
!  * if there are any threads waiting for an exclusive lock.  Bit 3 is a
!  * boolean indicating if an exclusive lock is recursively held.  The
!  * rest of the variable's definition is dependent on the value of the
!  * first bit.  For an exclusive lock, it is a pointer to the thread
!  * holding the lock, similar to the mtx_lock field of mutexes.  For
!  * shared locks, it is a count of read locks that are held.
!  *
!  * When the lock is not locked by any thread, it is encoded as a
!  * shared lock with zero waiters.
!  *
!  * A note about memory barriers.  Exclusive locks need to use the same
!  * memory barriers as mutexes: _acq when acquiring an exclusive lock
!  * and _rel when releasing an exclusive lock.  On the other side,
!  * shared lock needs to use an _acq barrier when acquiring the lock
!  * but, since they don't update any locked data, no memory barrier is
!  * needed when releasing a shared lock.
!  */
! 
! #define	SX_LOCK_SHARED			0x01
! #define	SX_LOCK_SHARED_WAITERS		0x02
! #define	SX_LOCK_EXCLUSIVE_WAITERS	0x04
! #define	SX_LOCK_RECURSED		0x08
! #define	SX_LOCK_FLAGMASK						\
! 	(SX_LOCK_SHARED | SX_LOCK_SHARED_WAITERS |			\
! 	SX_LOCK_EXCLUSIVE_WAITERS | SX_LOCK_RECURSED)
! 
! #define	SX_OWNER(x)			((x) & ~SX_LOCK_FLAGMASK)
! #define	SX_SHARERS_SHIFT		4
! #define	SX_SHARERS(x)			(SX_OWNER(x) >> SX_SHARERS_SHIFT)
! #define	SX_SHARERS_LOCK(x)						\
! 	((x) << SX_SHARERS_SHIFT | SX_LOCK_SHARED)
! #define	SX_ONE_SHARER			(1 << SX_SHARERS_SHIFT)
! 
! #define	SX_LOCK_UNLOCKED		SX_SHARERS_LOCK(0)
! #define	SX_LOCK_DESTROYED						\
! 	(SX_LOCK_SHARED_WAITERS | SX_LOCK_EXCLUSIVE_WAITERS)
  
  #ifdef _KERNEL
+ 
+ /*
+  * Function prototipes.  Routines that start with an underscore are not part
+  * of the public interface and are wrappered with a macro.
+  */
  void	sx_sysinit(void *arg);
! #define	sx_init(sx, desc)	sx_init_flags((sx), (desc), 0)
! void	sx_init_flags(struct sx *sx, const char *description, int opts);
  void	sx_destroy(struct sx *sx);
! int	_sx_slock(struct sx *sx, int opts, const char *file, int line);
! int	_sx_xlock(struct sx *sx, int opts, const char *file, int line);
  int	_sx_try_slock(struct sx *sx, const char *file, int line);
  int	_sx_try_xlock(struct sx *sx, const char *file, int line);
  void	_sx_sunlock(struct sx *sx, const char *file, int line);
  void	_sx_xunlock(struct sx *sx, const char *file, int line);
  int	_sx_try_upgrade(struct sx *sx, const char *file, int line);
  void	_sx_downgrade(struct sx *sx, const char *file, int line);
+ int	_sx_xlock_hard(struct sx *sx, uintptr_t tid, int opts,
+ 	    const char *file, int line);
+ int	_sx_slock_hard(struct sx *sx, int opts, const char *file, int line);
+ void	_sx_xunlock_hard(struct sx *sx, uintptr_t tid, const char *file, int
+ 	    line);
+ void	_sx_sunlock_hard(struct sx *sx, const char *file, int line);
  #if defined(INVARIANTS) || defined(INVARIANT_SUPPORT)
  void	_sx_assert(struct sx *sx, int what, const char *file, int line);
  #endif
***************
*** 79,93 ****
  	SYSUNINIT(name##_sx_sysuninit, SI_SUB_LOCK, SI_ORDER_MIDDLE,	\
  	    sx_destroy, (sxa))
  
! #define	sx_xlocked(sx)		((sx)->sx_cnt < 0 && (sx)->sx_xholder == curthread)
! #define	sx_slock(sx)		_sx_slock((sx), LOCK_FILE, LOCK_LINE)
! #define	sx_xlock(sx)		_sx_xlock((sx), LOCK_FILE, LOCK_LINE)
  #define	sx_try_slock(sx)	_sx_try_slock((sx), LOCK_FILE, LOCK_LINE)
  #define	sx_try_xlock(sx)	_sx_try_xlock((sx), LOCK_FILE, LOCK_LINE)
- #define	sx_sunlock(sx)		_sx_sunlock((sx), LOCK_FILE, LOCK_LINE)
- #define	sx_xunlock(sx)		_sx_xunlock((sx), LOCK_FILE, LOCK_LINE)
  #define	sx_try_upgrade(sx)	_sx_try_upgrade((sx), LOCK_FILE, LOCK_LINE)
  #define	sx_downgrade(sx)	_sx_downgrade((sx), LOCK_FILE, LOCK_LINE)
  #define	sx_unlock(sx) do {						\
  	if (sx_xlocked(sx))						\
  		sx_xunlock(sx);						\
--- 135,253 ----
  	SYSUNINIT(name##_sx_sysuninit, SI_SUB_LOCK, SI_ORDER_MIDDLE,	\
  	    sx_destroy, (sxa))
  
! /*
!  * Full lock operations that are suitable to be inlined in non-debug kernels.
!  * If the lock can't be acquired or released trivially then the work is
!  * deferred to 'tougher' functions.
!  */
! 
! /* Acquire an exclusive lock. */
! static __inline int
! __sx_xlock(struct sx *sx, struct thread *td, int opts, const char *file,
!     int line)
! {
! 	uintptr_t tid = (uintptr_t)td;
! 	int error = 0;
! 
! 	if (!atomic_cmpset_acq_ptr(&sx->sx_lock, SX_LOCK_UNLOCKED, tid))
! 		error = _sx_xlock_hard(sx, tid, opts, file, line);
! 	else
! 		lock_profile_obtain_lock_success(&sx->lock_object, 0, 0, file,
! 		    line);
! 
! 	return (error);
! }
! 
! /* Release an exclusive lock. */
! static __inline void
! __sx_xunlock(struct sx *sx, struct thread *td, const char *file, int line)
! {
! 	uintptr_t tid = (uintptr_t)td;
! 
! 	if (!atomic_cmpset_rel_ptr(&sx->sx_lock, tid, SX_LOCK_UNLOCKED))
! 		_sx_xunlock_hard(sx, tid, file, line);
! }
! 
! /* Acquire a shared lock. */
! static __inline int
! __sx_slock(struct sx *sx, int opts, const char *file, int line)
! {
! 	uintptr_t x = sx->sx_lock;
! 	int error = 0;
! 
! 	if (!(x & SX_LOCK_SHARED) ||
! 	    !atomic_cmpset_acq_ptr(&sx->sx_lock, x, x + SX_ONE_SHARER))
! 		error = _sx_slock_hard(sx, opts, file, line);
! #ifdef LOCK_PROFILING_SHARED
! 	else if (SX_SHARERS(x) == 0)
! 		lock_profile_obtain_lock_success(&sx->lock_object, 0, 0, file,
! 		    line);
! #endif
! 
! 	return (error);
! }
! 
! /*
!  * Release a shared lock.  We can just drop a single shared lock so
!  * long as we aren't trying to drop the last shared lock when other
!  * threads are waiting for an exclusive lock.  This takes advantage of
!  * the fact that an unlocked lock is encoded as a shared lock with a
!  * count of 0.
!  */
! static __inline void
! __sx_sunlock(struct sx *sx, const char *file, int line)
! {
! 	uintptr_t x = sx->sx_lock;
! 
! 	if (x == (SX_SHARERS_LOCK(1) | SX_LOCK_EXCLUSIVE_WAITERS) ||
! 	    !atomic_cmpset_ptr(&sx->sx_lock, x, x - SX_ONE_SHARER))
! 		_sx_sunlock_hard(sx, file, line);
! }
! 
! /*
!  * Public interface for lock operations.
!  */
! #ifndef LOCK_DEBUG
! #error	"LOCK_DEBUG not defined, include <sys/lock.h> before <sys/sx.h>"
! #endif
! #if	(LOCK_DEBUG > 0) || defined(SX_NOINLINE)
! #define	sx_xlock(sx)		(void)_sx_xlock((sx), 0, LOCK_FILE, LOCK_LINE)
! #define	sx_xlock_sig(sx)						\
! 	_sx_xlock((sx), SX_INTERRUPTIBLE, LOCK_FILE, LOCK_LINE)
! #define	sx_xunlock(sx)		_sx_xunlock((sx), LOCK_FILE, LOCK_LINE)
! #define	sx_slock(sx)		(void)_sx_slock((sx), 0, LOCK_FILE, LOCK_LINE)
! #define	sx_slock_sig(sx)						\
! 	_sx_slock((sx), SX_INTERRUPTIBLE, LOCK_FILE, LOCK_LINE)
! #define	sx_sunlock(sx)		_sx_sunlock((sx), LOCK_FILE, LOCK_LINE)
! #else
! #define	sx_xlock(sx)							\
! 	(void)__sx_xlock((sx), curthread, 0, LOCK_FILE, LOCK_LINE)
! #define	sx_xlock_sig(sx)						\
! 	__sx_xlock((sx), curthread, SX_INTERRUPTIBLE, LOCK_FILE, LOCK_LINE)
! #define	sx_xunlock(sx)							\
! 	__sx_xunlock((sx), curthread, LOCK_FILE, LOCK_LINE)
! #define	sx_slock(sx)		(void)__sx_slock((sx), 0, LOCK_FILE, LOCK_LINE)
! #define	sx_slock_sig(sx)						\
! 	__sx_slock((sx), SX_INTERRUPTIBLE, LOCK_FILE, LOCK_LINE)
! #define	sx_sunlock(sx)		__sx_sunlock((sx), LOCK_FILE, LOCK_LINE)
! #endif	/* LOCK_DEBUG > 0 || SX_NOINLINE */
  #define	sx_try_slock(sx)	_sx_try_slock((sx), LOCK_FILE, LOCK_LINE)
  #define	sx_try_xlock(sx)	_sx_try_xlock((sx), LOCK_FILE, LOCK_LINE)
  #define	sx_try_upgrade(sx)	_sx_try_upgrade((sx), LOCK_FILE, LOCK_LINE)
  #define	sx_downgrade(sx)	_sx_downgrade((sx), LOCK_FILE, LOCK_LINE)
+ 
+ /*
+  * Return a pointer to the owning thread if the lock is exclusively
+  * locked.
+  */
+ #define	sx_xholder(sx)							\
+ 	((sx)->sx_lock & SX_LOCK_SHARED ? NULL :			\
+ 	(struct thread *)SX_OWNER((sx)->sx_lock))
+ 
+ #define	sx_xlocked(sx)							\
+ 	(((sx)->sx_lock & ~(SX_LOCK_FLAGMASK & ~SX_LOCK_SHARED)) ==	\
+ 	    (uintptr_t)curthread)
+ 
  #define	sx_unlock(sx) do {						\
  	if (sx_xlocked(sx))						\
  		sx_xunlock(sx);						\
***************
*** 95,111 ****
--- 255,293 ----
  		sx_sunlock(sx);						\
  } while (0)
  
+ #define	sx_sleep(chan, sx, pri, wmesg, timo)				\
+ 	_sleep((chan), &(sx)->lock_object, (pri), (wmesg), (timo))
+ 
+ /*
+  * Options passed to sx_init_flags().
+  */
+ #define	SX_DUPOK		0x01
+ #define	SX_NOPROFILE		0x02
+ #define	SX_NOWITNESS		0x04
+ #define	SX_QUIET		0x08
+ #define	SX_ADAPTIVESPIN		0x10
+ #define	SX_RECURSE		0x20
+ 
+ /*
+  * Options passed to sx_*lock_hard().
+  */
+ #define	SX_INTERRUPTIBLE	0x40
+ 
  #if defined(INVARIANTS) || defined(INVARIANT_SUPPORT)
  #define	SA_LOCKED		LA_LOCKED
  #define	SA_SLOCKED		LA_SLOCKED
  #define	SA_XLOCKED		LA_XLOCKED
  #define	SA_UNLOCKED		LA_UNLOCKED
+ #define	SA_RECURSED		LA_RECURSED
+ #define	SA_NOTRECURSED		LA_NOTRECURSED
  
  /* Backwards compatability. */
  #define	SX_LOCKED		LA_LOCKED
  #define	SX_SLOCKED		LA_SLOCKED
  #define	SX_XLOCKED		LA_XLOCKED
  #define	SX_UNLOCKED		LA_UNLOCKED
+ #define	SX_RECURSED		LA_RECURSED
+ #define	SX_NOTRECURSED		LA_NOTRECURSED
  #endif
  
  #ifdef INVARIANTS
Index: sys/turnstile.h
===================================================================
RCS file: /cvs/ncvs/src/sys/sys/turnstile.h,v
retrieving revision 1.7
diff -c -r1.7 turnstile.h
*** sys/turnstile.h	7 Jan 2005 02:29:24 -0000	1.7
--- sys/turnstile.h	31 Aug 2007 00:39:59 -0000
***************
*** 73,92 ****
  
  #ifdef _KERNEL
  
  void	init_turnstiles(void);
  void	turnstile_adjust(struct thread *, u_char);
  struct turnstile *turnstile_alloc(void);
! void	turnstile_broadcast(struct turnstile *);
  void	turnstile_claim(struct lock_object *);
! int	turnstile_empty(struct turnstile *);
  void	turnstile_free(struct turnstile *);
! struct thread *turnstile_head(struct turnstile *);
  void	turnstile_lock(struct lock_object *);
  struct turnstile *turnstile_lookup(struct lock_object *);
  void	turnstile_release(struct lock_object *);
! int	turnstile_signal(struct turnstile *);
! void	turnstile_unpend(struct turnstile *);
! void	turnstile_wait(struct lock_object *, struct thread *);
  
  #endif	/* _KERNEL */
  #endif	/* _SYS_TURNSTILE_H_ */
--- 73,115 ----
  
  #ifdef _KERNEL
  
+ /* Which queue to block on or which queue to wakeup one or more threads from. */
+ #define       TS_EXCLUSIVE_QUEUE      0
+ #define       TS_SHARED_QUEUE         1
+ 
+ /* The type of lock currently held. */
+ #define       TS_EXCLUSIVE_LOCK       TS_EXCLUSIVE_QUEUE
+ #define       TS_SHARED_LOCK          TS_SHARED_QUEUE
+ 
  void	init_turnstiles(void);
  void	turnstile_adjust(struct thread *, u_char);
  struct turnstile *turnstile_alloc(void);
! #define turnstile_wakeup(turnstile) turnstile_broadcast(turnstile)
! #define	turnstile_broadcast(turnstile) \
!     turnstile_broadcast_queue(turnstile, TS_EXCLUSIVE_QUEUE)
! void	turnstile_broadcast_queue(struct turnstile *, int);
  void	turnstile_claim(struct lock_object *);
! void	turnstile_disown(struct turnstile *);
! #define	turnstile_empty(turnstile)  \
!     turnstile_empty_queue(turnstile, TS_EXCLUSIVE_QUEUE);
! int	turnstile_empty_queue(struct turnstile *, int);
  void	turnstile_free(struct turnstile *);
! #define	turnstile_head(turnstile)   \
!     turnstile_head_queue(turnstile, TS_EXCLUSIVE_QUEUE)
! struct thread *turnstile_head_queue(struct turnstile *, int);
  void	turnstile_lock(struct lock_object *);
  struct turnstile *turnstile_lookup(struct lock_object *);
  void	turnstile_release(struct lock_object *);
! #define turnstile_signal(turnstile) \
!     turnstile_signal_queue(turnstile, TS_EXCLUSIVE_QUEUE)
! int	turnstile_signal_queue(struct turnstile *, int);
! struct turnstile *turnstile_trywait(struct lock_object *);
! #define	turnstile_unpend(turnstile) \
!     turnstile_unpend_queue(turnstile, TS_EXCLUSIVE_QUEUE);
! void	turnstile_unpend_queue(struct turnstile *, int);
! #define turnstile_wait(lock_object, thread) \
!     turnstile_wait_queue(lock_object, thread, TS_EXCLUSIVE_QUEUE) 
! void	turnstile_wait_queue(struct lock_object *, struct thread *, int);
  
  #endif	/* _KERNEL */
  #endif	/* _SYS_TURNSTILE_H_ */
Index: vm/vm_map.c
===================================================================
RCS file: /cvs/ncvs/src/sys/vm/vm_map.c,v
retrieving revision 1.366.2.4
diff -c -r1.366.2.4 vm_map.c
*** vm/vm_map.c	30 Aug 2007 02:32:04 -0000	1.366.2.4
--- vm/vm_map.c	31 Aug 2007 03:12:00 -0000
***************
*** 429,435 ****
  	if (map->system_map)
  		_mtx_lock_flags(&map->system_mtx, 0, file, line);
  	else
! 		_sx_xlock(&map->lock, file, line);
  	map->timestamp++;
  }
  
--- 429,435 ----
  	if (map->system_map)
  		_mtx_lock_flags(&map->system_mtx, 0, file, line);
  	else
! 		(void) _sx_xlock(&map->lock, 0, file, line);
  	map->timestamp++;
  }
  
***************
*** 450,456 ****
  	if (map->system_map)
  		_mtx_lock_flags(&map->system_mtx, 0, file, line);
  	else
! 		_sx_xlock(&map->lock, file, line);
  }
  
  void
--- 450,456 ----
  	if (map->system_map)
  		_mtx_lock_flags(&map->system_mtx, 0, file, line);
  	else
! 		(void) _sx_xlock(&map->lock, 0, file, line);
  }
  
  void

--SnV5plBeK2Ge1I9g--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20070904023152.GZ87451>