--- //depot/vendor/freebsd/src/sys/conf/options	2007/02/10 14:03:10
+++ //depot/user/attilio/attilio_smpng/conf/options	2007/02/14 13:58:06
@@ -552,6 +552,7 @@
 REGRESSION		opt_global.h
 RESTARTABLE_PANICS	opt_global.h
 RWLOCK_NOINLINE		opt_global.h
+SXLOCK_NOINLINE		opt_global.h
 VFS_BIO_DEBUG		opt_global.h
 
 # These are VM related options
--- //depot/vendor/freebsd/src/sys/dev/acpica/acpi_ec.c	2005/12/06 14:55:33
+++ //depot/user/attilio/attilio_smpng/dev/acpica/acpi_ec.c	2006/11/04 01:33:58
@@ -142,6 +142,7 @@
 #include <sys/param.h>
 #include <sys/kernel.h>
 #include <sys/bus.h>
+#include <sys/lock.h>
 #include <sys/malloc.h>
 #include <sys/module.h>
 #include <sys/sx.h>
--- //depot/vendor/freebsd/src/sys/dev/led/led.c	2005/03/07 11:10:19
+++ //depot/user/attilio/attilio_smpng/dev/led/led.c	2006/11/04 01:33:58
@@ -15,6 +15,7 @@
 #include <sys/conf.h>
 #include <sys/kernel.h>
 #include <sys/systm.h>
+#include <sys/lock.h>
 #include <sys/malloc.h>
 #include <sys/ctype.h>
 #include <sys/sbuf.h>
--- //depot/vendor/freebsd/src/sys/dev/mxge/if_mxge.c	2007/02/15 17:26:52
+++ //depot/user/attilio/attilio_smpng/dev/mxge/if_mxge.c	2007/02/21 14:40:54
@@ -40,6 +40,7 @@
 #include <sys/firmware.h>
 #include <sys/endian.h>
 #include <sys/sockio.h>
+#include <sys/lock.h>
 #include <sys/mbuf.h>
 #include <sys/malloc.h>
 #include <sys/kdb.h>
--- //depot/vendor/freebsd/src/sys/dev/sound/pcm/sndstat.c	2006/11/26 12:27:44
+++ //depot/user/attilio/attilio_smpng/dev/sound/pcm/sndstat.c	2006/11/29 09:15:17
@@ -27,6 +27,7 @@
 #include <dev/sound/pcm/sound.h>
 #include <dev/sound/pcm/vchan.h>
 #ifdef	USING_MUTEX
+#include <sys/lock.h>
 #include <sys/sx.h>
 #endif
 
--- //depot/vendor/freebsd/src/sys/dev/usb/if_aue.c	2007/02/03 13:57:44
+++ //depot/user/attilio/attilio_smpng/dev/usb/if_aue.c	2007/02/06 01:28:29
@@ -71,6 +71,7 @@
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/sockio.h>
+#include <sys/lock.h>
 #include <sys/mbuf.h>
 #include <sys/malloc.h>
 #include <sys/kernel.h>
--- //depot/vendor/freebsd/src/sys/dev/usb/if_axe.c	2006/10/19 01:18:01
+++ //depot/user/attilio/attilio_smpng/dev/usb/if_axe.c	2006/11/04 01:33:58
@@ -70,6 +70,7 @@
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/sockio.h>
+#include <sys/lock.h>
 #include <sys/mbuf.h>
 #include <sys/malloc.h>
 #include <sys/kernel.h>
--- //depot/vendor/freebsd/src/sys/gnu/fs/xfs/FreeBSD/support/mrlock.c	2005/12/12 01:05:49
+++ //depot/user/attilio/attilio_smpng/gnu/fs/xfs/FreeBSD/support/mrlock.c	2006/10/18 21:45:37
@@ -1,6 +1,7 @@
 #include <sys/param.h>
 #include <support/mrlock.h>
 
+#if 0
 void
 _sx_xfs_destroy(struct sx *sx)
 {
@@ -46,4 +47,4 @@
 }
 
 
-
+#endif
--- //depot/vendor/freebsd/src/sys/i386/acpica/acpi_machdep.c	2006/08/11 19:25:48
+++ //depot/user/attilio/attilio_smpng/i386/acpica/acpi_machdep.c	2006/12/05 20:24:17
@@ -29,6 +29,7 @@
 
 #include <sys/param.h>
 #include <sys/bus.h>
+#include <sys/condvar.h>
 #include <sys/conf.h>
 #include <sys/fcntl.h>
 #include <sys/kernel.h>
--- //depot/vendor/freebsd/src/sys/kern/kern_sx.c	2006/11/13 05:46:59
+++ //depot/user/attilio/attilio_smpng/kern/kern_sx.c	2007/01/17 14:58:19
@@ -1,57 +1,37 @@
-/*-
- * 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
- *    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.
- */
-
-/*
- * 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 "opt_ddb.h"
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sys/kern/kern_sx.c,v 1.32 2006/11/13 05:41:46 kmacy 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/lock_profile.h>
 #include <sys/mutex.h>
 #include <sys/proc.h>
+#include <sys/sleepqueue.h>
 #include <sys/sx.h>
-#include <sys/lock_profile.h>
+#include <sys/systm.h>
 
 #ifdef DDB
 #include <ddb/ddb.h>
+#endif
+
+#ifndef INVARIANTS
+#define	_sx_assert(sx, what, file, line)
+#endif
+
+/* Handy macros for delivery sleep queues */
+#define	SQ_EXCLUSIVE_QUEUE	0
+#define	SQ_SHARED_QUEUE		1
+
+/*
+ * Currently, we keep track of the exclusive holder for debugging purposes.
+ */
+#define	sx_xholder(sx)							\
+	(sx->sx_lock & SX_SHARED_BIT ? NULL :				\
+	(struct thread *)SX_HOLDER(sx->sx_lock))
 
+#ifdef DDB
 static void	db_show_sx(struct lock_object *lock);
 #endif
 
@@ -63,10 +43,6 @@
 #endif
 };
 
-#ifndef INVARIANTS
-#define	_sx_assert(sx, what, file, line)
-#endif
-
 void
 sx_sysinit(void *arg)
 {
@@ -79,13 +55,8 @@
 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;
+	sx->sx_lock = SX_UNHELD;
+	sx->sx_desc = description;
 	lock_profile_object_init(&sx->sx_object, &lock_class_sx, description);
 	lock_init(&sx->sx_object, &lock_class_sx, description, NULL,
 	    LO_WITNESS | LO_RECURSABLE | LO_SLEEPABLE | LO_UPGRADABLE);
@@ -95,243 +66,479 @@
 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);
-	
+	KASSERT(sx->sx_lock == SX_UNHELD, ("sx lock still held"));
 	lock_profile_object_destroy(&sx->sx_object);
 	lock_destroy(&sx->sx_object);
 }
 
 void
-_sx_slock(struct sx *sx, const char *file, int line)
+_sx_xlock(struct sx *sx, const char *file, int line)
 {
-	uint64_t waittime = 0;
-	int contested;
+	uint64_t waitstart;
 
-	mtx_lock(sx->sx_lock);
-	KASSERT(sx->sx_xholder != curthread,
-	    ("%s (%s): slock while xlock is held @ %s:%d\n", __func__,
+	MPASS(curthread != NULL);
+	KASSERT(sx_xholder(sx) != curthread,
+	    ("%s (%s): xlock alredy held @ %s:%d", __func__,
 	    sx->sx_object.lo_name, file, line));
-	WITNESS_CHECKORDER(&sx->sx_object, LOP_NEWORDER, file, line);
+	witness_check_exclusive_sx(sx);
+	lock_profile_waitstart(&waitstart);
+	__sx_xlock(sx, curthread, file, line);
+	lock_profile_obtain_lock_success(&sx->sx_object, waitstart, file,
+	    line);
+	LOCK_LOG_LOCK("XLOCK", &sx->sx_object, 0, 0, file, line);
+	WITNESS_LOCK(&sx->sx_object, LOP_EXCLUSIVE, file, line);
+	curthread->td_locks++;
+}
 
-	/*
-	 * Loop in case we lose the race for lock acquisition.
-	 */
-        if (sx->sx_cnt < 0)
-		lock_profile_waitstart(&waittime);
-	while (sx->sx_cnt < 0) {
-		sx->sx_shrd_wcnt++;
-		lock_profile_obtain_lock_failed(&sx->sx_object, &contested);
-		cv_wait(&sx->sx_shrd_cv, sx->sx_lock);
-		sx->sx_shrd_wcnt--;
-	}
+void
+_sx_xunlock(struct sx *sx, const char *file, int line)
+{
 
-	/* Acquire a shared lock. */
-	sx->sx_cnt++;
+	MPASS(curthread != NULL);
+	_sx_assert(sx, SX_XLOCKED, file, line);
+	curthread->td_locks--;
+	WITNESS_UNLOCK(&sx->sx_object, LOP_EXCLUSIVE, file, line);
+	LOCK_LOG_LOCK("XUNLOCK", &sx->sx_object, 0, 0, file, line);
+	lock_profile_release_lock(&sx->sx_object);
+	__sx_xunlock(sx, curthread, file, line);
+}
 
-        if (sx->sx_cnt == 1)
-		lock_profile_obtain_lock_success(&sx->sx_object, waittime, file, line);
+void
+_sx_slock(struct sx *sx, const char *file, int line)
+{
+	uint64_t waitstart;
 
+	witness_check_shared_sx(sx);
+	lock_profile_waitstart(&waitstart);
+	__sx_slock(sx, file, line);
+	lock_profile_obtain_lock_success(&sx->sx_object, waitstart, file,
+	    line);
 	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);
+void
+_sx_sunlock(struct sx *sx, const char *file, int line)
+{
+
+	_sx_assert(sx, SX_SLOCKED, file, line);
+	curthread->td_locks--;
+	WITNESS_UNLOCK(&sx->sx_object, 0, file, line);
+	LOCK_LOG_LOCK("SUNLOCK", &sx->sx_object, 0, 0, file, line);
+	lock_profile_release_lock(&sx->sx_object);
+	__sx_sunlock(sx, file, line);
+}
+
+/*
+ * Try to do a non-blocking sx_xlock.  Return 1 if succeed, 0 otherwise.
+ */
+int
+_sx_try_xlock(struct sx *sx, const char *file, int line)
+{
+	uintptr_t tid;
+
+	MPASS(curthread != NULL);
+	KASSERT(sx_xholder(sx) != curthread,
+	    ("%s (%s): xlock alredy held @ %s:%d", __func__,
+	    sx->sx_object.lo_name, file, line));
+
+	tid = (uintptr_t)curthread;
+	if (atomic_cmpset_acq_ptr(&sx->sx_lock, SX_UNHELD, tid)) {
+		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++;
+		return (1);
+	}
+
+	LOCK_LOG_TRY("XLOCK", &sx->sx_object, 0, 0, file, line);
+	return (0);
 }
 
+/*
+ * Try to do a non-blocking sx_slock.  Return 1 if succeed, 0 otherwise.
+ */
 int
 _sx_try_slock(struct sx *sx, const char *file, int line)
 {
+	uintptr_t x;
 
-	mtx_lock(sx->sx_lock);
-	if (sx->sx_cnt >= 0) {
-		sx->sx_cnt++;
+	x = sx->sx_lock;
+	if ((x & SX_SHARED_BIT) && atomic_cmpset_acq_ptr(&sx->sx_lock, x,
+	    x + SX_ONE_SHARER)) {
 		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);
 	}
+
+	LOCK_LOG_TRY("SLOCK", &sx->sx_object, 0, 0, file, line);
+	return (0);
 }
 
-void
-_sx_xlock(struct sx *sx, const char *file, int 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)
 {
-	int contested;
-	uint64_t waittime = 0;
+	uintptr_t tid, x;
+
+	_sx_assert(sx, SX_SLOCKED, file, line);
 
-	mtx_lock(sx->sx_lock);
+	tid = (uintptr_t)curthread;
 
 	/*
-	 * 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.
+	 * Try to switch from one sharer to an exclusive lock without
+	 * lock the sleepqueue (assume that there aren't any exclusive waiter).
 	 */
-	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);
-
-        if (sx->sx_cnt)
-		lock_profile_waitstart(&waittime);
-	/* Loop in case we lose the race for lock acquisition. */
-	while (sx->sx_cnt != 0) {
-		sx->sx_excl_wcnt++;
-		lock_profile_obtain_lock_failed(&sx->sx_object, &contested);
-		cv_wait(&sx->sx_excl_cv, sx->sx_lock);
-		sx->sx_excl_wcnt--;
+	if (!(sx->sx_lock & SX_EXCLUSIVE_WAITERS_BIT) &&
+	    atomic_cmpset_acq_ptr(&sx->sx_lock, SX_SHARERS_LOCK(1), tid)) {
+		LOCK_LOG_TRY("XUPGRADE", &sx->sx_object, 0, 1, file, line);
+		WITNESS_UPGRADE(&sx->sx_object, LOP_EXCLUSIVE | LOP_TRYLOCK,
+		    file, line);
+		return (1);
 	}
 
-	MPASS(sx->sx_cnt == 0);
+	sleepq_lock(&sx->sx_object);
 
-	/* Acquire an exclusive lock. */
-	sx->sx_cnt--;
-	sx->sx_xholder = curthread;
+	/*
+	 * Since we might have SX_EXCLUSIVE_WAITERS_BIT set, mantain it (if
+	 * really present) in order to preserve a consistent state.  Than,
+	 * if upgrade succeeds return true, false otherwise.
+	 */
+	x = sx->sx_lock & SX_EXCLUSIVE_WAITERS_BIT;
+	if (atomic_cmpset_acq_ptr(&sx->sx_lock, SX_SHARERS_LOCK(1) | x,
+	    tid | x)) {
+		sleepq_release(&sx->sx_object);
+		LOCK_LOG_TRY("XUPGRADE", &sx->sx_object, 0, 1, file, line);
+		WITNESS_UPGRADE(&sx->sx_object, LOP_EXCLUSIVE | LOP_TRYLOCK,
+		    file, line);
+		return (1);
+	}
+	sleepq_release(&sx->sx_object);
 
-	lock_profile_obtain_lock_success(&sx->sx_object, waittime, file, line);
-	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);
+	LOCK_LOG_TRY("XUPGRADE", &sx->sx_object, 0, 0, file, line);
+	return (0);
 }
 
-int
-_sx_try_xlock(struct sx *sx, const char *file, int line)
+/*
+ * Downgrade an exclusive lock into a shared lock.
+ */
+void
+_sx_downgrade(struct sx *sx, const char *file, int line)
 {
+	uintptr_t tid, x;
+
+	_sx_assert(sx, SX_XLOCKED, file, line);
+	WITNESS_DOWNGRADE(&sx->sx_object, 0, file, line);
+
+	tid = (uintptr_t)curthread;
 
-	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);
+	/*
+	 * Try to switch from an exclusive lock to one sharer without lock the
+	 * sleepqueue (assume that there aren't any waiter).
+	 */
+	if (atomic_cmpset_rel_ptr(&sx->sx_lock, tid, SX_SHARERS_LOCK(1))) {
+		LOCK_LOG_LOCK("XDOWNGRADE", &sx->sx_object, 0, 0, file, line);
+		return;
 	}
+
+	sleepq_lock(&sx->sx_object);
+
+	/*
+	 * Since we could have SX_EXCLUSIVE_WAITERS_BIT set, mantain it (if
+	 * really present) in order to preserve a consistent state.  Than,
+	 * wake up eventual shared waiters here and downgrade the lock.
+	 */
+	x = sx->sx_lock;
+	atomic_store_rel_ptr(&sx->sx_lock, SX_SHARERS_LOCK(1) | (x &
+	    SX_EXCLUSIVE_WAITERS_BIT));
+	if (x & SX_SHARED_WAITERS_BIT)
+		sleepq_broadcast(&sx->sx_object, SLEEPQ_SX, -1,
+		    SQ_SHARED_QUEUE);
+	else
+		sleepq_release(&sx->sx_object);
+
+	LOCK_LOG_LOCK("XDOWNGRADE", &sx->sx_object, 0, 0, file, line);
 }
 
+/*
+ * This function rappresents the so-called 'hard case' for sx_xlock operation.
+ * All 'easy case' failures are redirected to this.  Note that ideally
+ * this might be a static function, but it needs to be accessible at least
+ * from sx.h.
+ */
 void
-_sx_sunlock(struct sx *sx, const char *file, int line)
+_sx_xlock_hard(struct sx *sx, uintptr_t tid, const char *file, int line)
 {
+	uintptr_t x;
+	int contested;
+
+	while (!atomic_cmpset_acq_ptr(&sx->sx_lock, SX_UNHELD, tid)) {
+		sleepq_lock(&sx->sx_object);
+		x = sx->sx_lock;
 
-	_sx_assert(sx, SX_SLOCKED, file, line);
-	mtx_lock(sx->sx_lock);
+		/*
+		 * If the lock was released while spinning on the sleepqueue
+		 * chain lock, try again.
+		 */
+		if (x == SX_UNHELD) {
+			sleepq_release(&sx->sx_object);
+			continue;
+		}
+
+		/*
+		 * Since we assume a share locked variable, only
+		 * SX_EXCLUSIVE_WAITERS_BIT could be set, so, if a pending
+		 * queue of exclusive sleepers is left on sx_xunlock, simply
+		 * reset the lock to held state.
+		 */
+		if (x == (SX_UNHELD | SX_EXCLUSIVE_WAITERS_BIT)) {
+			if (atomic_cmpset_acq_ptr(&sx->sx_lock, SX_UNHELD |
+			    SX_EXCLUSIVE_WAITERS_BIT, tid |
+			    SX_EXCLUSIVE_WAITERS_BIT)) {
+				sleepq_release(&sx->sx_object);
+				break;
+			}
+			sleepq_release(&sx->sx_object);
+			lock_profile_obtain_lock_failed(&sx->sx_object,
+			    &contested);
+			continue;
+		}
 
-	curthread->td_locks--;
-	WITNESS_UNLOCK(&sx->sx_object, 0, file, line);
+		/*
+		 * Try to set the SX_EXCLUSIVE_WAITERS_BIT.  If we fail,
+		 * than loop back and retry.
+		 */
+		if (!(x & SX_EXCLUSIVE_WAITERS_BIT) &&
+		    !atomic_cmpset_ptr(&sx->sx_lock, x, x |
+		    SX_EXCLUSIVE_WAITERS_BIT)) {
+			sleepq_release(&sx->sx_object);
+			lock_profile_obtain_lock_failed(&sx->sx_object,
+			    &contested);
+			continue;
+		}
 
-	/* Release. */
-	sx->sx_cnt--;
+		/*
+		 * Since we have been unable to acquire the exclusive lock,
+		 * we have to sleep.
+		 */
+		if (LOCK_LOG_TEST(&sx->sx_object, 0))
+			CTR2(KTR_LOCK, "%s: %p blocking on sleepqueue",
+			    __func__, sx);
 
-       if (sx->sx_cnt == 0)
-	       lock_profile_release_lock(&sx->sx_object);
-	/*
-	 * 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);
+		DROP_GIANT();
+		sleepq_add(&sx->sx_object, NULL, sx->sx_desc, SLEEPQ_SX,
+		    SQ_EXCLUSIVE_QUEUE);
+		sleepq_wait(&sx->sx_object);
+		PICKUP_GIANT();
 
-	LOCK_LOG_LOCK("SUNLOCK", &sx->sx_object, 0, 0, file, line);
+		if (LOCK_LOG_TEST(&sx->sx_object, 0))
+			CTR2(KTR_LOCK, "%s: %p resuming from sleepqueue",
+			    __func__, sx);
+	}
 
-	mtx_unlock(sx->sx_lock);
 }
 
+/*
+ * This function rappresents the so-called 'hard case' for sx_xunlock operation.
+ * All 'easy case' failures are redirected to this.  Note that ideally
+ * this might be a static function, but it needs to be accessible at least
+ * from sx.h.
+ */
 void
-_sx_xunlock(struct sx *sx, const char *file, int line)
+_sx_xunlock_hard(struct sx *sx, uintptr_t tid, const char *file, int line)
 {
+	uintptr_t x;
+	int queue;
 
-	_sx_assert(sx, SX_XLOCKED, file, line);
-	mtx_lock(sx->sx_lock);
-	MPASS(sx->sx_cnt == -1);
+	MPASS(sx->sx_lock & (SX_SHARED_WAITERS_BIT | SX_EXCLUSIVE_WAITERS_BIT));
+	MPASS(!(sx->sx_lock & SX_SHARED_BIT));
 
-	curthread->td_locks--;
-	WITNESS_UNLOCK(&sx->sx_object, LOP_EXCLUSIVE, file, line);
+	if (LOCK_LOG_TEST(&sx->sx_object, 0))
+		CTR2(KTR_LOCK, "%s: %p contested", __func__, sx);
 
-	/* Release. */
-	sx->sx_cnt++;
-	sx->sx_xholder = NULL;
+	sleepq_lock(&sx->sx_object);
+	x = SX_UNHELD;
 
-	lock_profile_release_lock(&sx->sx_object);
 	/*
-	 * Wake up waiters if there are any.  Give precedence to slock waiters.
+	 * The waking up algorithm here is quite simple and, probabilly, 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_shrd_wcnt > 0)
-		cv_broadcast(&sx->sx_shrd_cv);
-	else if (sx->sx_excl_wcnt > 0)
-		cv_signal(&sx->sx_excl_cv);
+	if (sx->sx_lock & SX_SHARED_WAITERS_BIT) {
+		queue = SQ_SHARED_QUEUE;
+		x |= (sx->sx_lock & SX_EXCLUSIVE_WAITERS_BIT);
+	} else
+		queue = SQ_EXCLUSIVE_QUEUE;
 
-	LOCK_LOG_LOCK("XUNLOCK", &sx->sx_object, 0, 0, file, line);
-
-	mtx_unlock(sx->sx_lock);
+	/*
+	 * Wake up all the waiters for the specific queue.
+	 */
+	if (LOCK_LOG_TEST(&sx->sx_object, 0))
+		CTR3(KTR_LOCK, "%s: %p waking up all thread on %s queue",
+		    __func__, sx, queue == SQ_SHARED_QUEUE ? "shared" :
+		    "exclusive");
+	atomic_store_rel_ptr(&sx->sx_lock, x);
+	sleepq_broadcast(&sx->sx_object, SLEEPQ_SX, -1, queue);
 }
 
-int
-_sx_try_upgrade(struct sx *sx, const char *file, int line)
+/*
+ * This function rappresents the so-called 'hard case' for sx_slock operation.
+ * All 'easy case' failures are redirected to this.  Note that ideally
+ * this might be a static function, but it needs to be accessible at least
+ * from sx.h.
+ */
+void
+_sx_slock_hard(struct sx *sx, const char *file, int line)
 {
+	uintptr_t x;
+	int contested;
+
+	for (;;) {
+		x = sx->sx_lock;
 
-	_sx_assert(sx, SX_SLOCKED, file, line);
-	mtx_lock(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_EXCLUSIVE_WAITERS_BIT, if we fail to acquire the
+		 * shared lock loop back and retry.
+		 */
+		if (x & SX_SHARED_BIT) {
+			MPASS(!(x & SX_SHARED_WAITERS_BIT));
+			if (atomic_cmpset_acq_ptr(&sx->sx_lock, x,
+			    x + SX_ONE_SHARER))
+				break;
+			lock_profile_obtain_lock_failed(&sx->sx_object,
+			    &contested);
+			continue;
+		}
+
+		/*
+		 * Some other thread alredy has an exclusive lock, so start
+		 * process of blocking.
+		 */
+		sleepq_lock(&sx->sx_object);
+		x = sx->sx_lock;
+
+		/*
+		 * The lock could be released while we spun.  In this case
+		 * loop back and retry.
+		 */
+		if (x & SX_SHARED_BIT) {
+			sleepq_release(&sx->sx_object);
+			continue;
+		}
+
+		/*
+		 * We have to mantain consistent the SX_SHARED_WAITERS_BIT
+		 * flag, so try to set it (if not alredy set).  If we fail to
+		 * set it drop the sleepqueue lock and loop back.
+		 */
+		if (!(x & SX_SHARED_WAITERS_BIT) &&
+		    !atomic_cmpset_ptr(&sx->sx_lock, x, x |
+		    SX_SHARED_WAITERS_BIT)) {
+			sleepq_release(&sx->sx_object);
+			continue;
+		}
 
-	if (sx->sx_cnt == 1) {
-		sx->sx_cnt = -1;
-		sx->sx_xholder = curthread;
+		/*
+		 * Since we have been unable to acquire the shared lock,
+		 * we have to sleep.
+		 */
+		if (LOCK_LOG_TEST(&sx->sx_object, 0))
+			CTR2(KTR_LOCK, "%s: %p blocking on sleepqueue",
+			    __func__, sx);
 
-		LOCK_LOG_TRY("XUPGRADE", &sx->sx_object, 0, 1, file, line);
-		WITNESS_UPGRADE(&sx->sx_object, LOP_EXCLUSIVE | LOP_TRYLOCK,
-		    file, line);
+		DROP_GIANT();
+		sleepq_add(&sx->sx_object, NULL, sx->sx_desc, SLEEPQ_SX,
+		    SQ_SHARED_QUEUE);
+		sleepq_wait(&sx->sx_object);
+		PICKUP_GIANT();
 
-		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);
+		if (LOCK_LOG_TEST(&sx->sx_object, 0))
+			CTR2(KTR_LOCK, "%s: %p resuming from sleepqueue",
+			    __func__, sx);
 	}
 }
 
+/*
+ * This function rappresents the so-called 'hard case' for sx_sunlock operation.
+ * All 'easy case' failures are redirected to this.  Note that ideally
+ * this might be a static function, but it needs to be accessible at least
+ * from sx.h.
+ */
 void
-_sx_downgrade(struct sx *sx, const char *file, int line)
+_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_SHARED_WAITERS_BIT),
+		    ("%s: waiting sharers", __func__));
+
+		/*
+		 * See if there is more than one read 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))
+				break;
+			continue;
+		}
 
-	_sx_assert(sx, SX_XLOCKED, file, line);
-	mtx_lock(sx->sx_lock);
-	MPASS(sx->sx_cnt == -1);
+		/*
+		 * If there aren't any waiters for an exclusive lock, then try
+		 * to drop it quickly.
+		 */
+		if (!(x & SX_EXCLUSIVE_WAITERS_BIT)) {
+			MPASS(x == SX_SHARERS_LOCK(1));
+			if (atomic_cmpset_ptr(&sx->sx_lock, SX_SHARERS_LOCK(1),
+			    SX_UNHELD))
+				break;
+			continue;
+		}
 
-	WITNESS_DOWNGRADE(&sx->sx_object, 0, file, line);
+		/*
+		 * At this point, there should just be one sharer with
+		 * exclusive waiters.
+		 */
+		MPASS(x == (SX_SHARERS_LOCK(1) | SX_EXCLUSIVE_WAITERS_BIT));
 
-	sx->sx_cnt = 1;
-	sx->sx_xholder = NULL;
-        if (sx->sx_shrd_wcnt > 0)
-                cv_broadcast(&sx->sx_shrd_cv);
+		sleepq_lock(&sx->sx_object);
 
-	LOCK_LOG_LOCK("XDOWNGRADE", &sx->sx_object, 0, 0, file, line);
+		/*
+		 * Wake up semantic here is mantained quite simple:
+		 * Just wake up all the exclusive waiters.
+		 * Note that the state of the lock could be changed, so if it
+		 * fails loop back and retry.
+		 */
+		if (!atomic_cmpset_ptr(&sx->sx_lock, SX_SHARERS_LOCK(1) |
+		    SX_EXCLUSIVE_WAITERS_BIT, SX_UNHELD)) {
+			sleepq_release(&sx->sx_object);
+			continue;
+		}
+		if (LOCK_LOG_TEST(&sx->sx_object, 0))
+			CTR2(KTR_LOCK, "%s: %p waking up all thread on"
+			    "exclusive queue", __func__, sx);
+		sleepq_broadcast(&sx->sx_object, SLEEPQ_SX, -1,
+		    SQ_EXCLUSIVE_QUEUE);
 
-	mtx_unlock(sx->sx_lock);
+		break;
+	}
 }
 
 #ifdef INVARIANT_SUPPORT
@@ -356,35 +563,35 @@
 #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))
+		/*
+		 * 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 (sx->sx_lock == SX_UNHELD || (!(sx->sx_lock &
+		    SX_SHARED_BIT) && (what == RA_RLOCKED || sx_xholder(sx) !=
+		    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)
+		if (sx_xholder(sx) != 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.
+		 * If we hold a write lock fail.  We can't reliably check
+		 * to see if we hold a read lock or not.
 		 */
-		mtx_lock(sx->sx_lock);
-		if (sx->sx_xholder == curthread)
+		if (sx_xholder(sx) == curthread)
 			panic("Lock %s exclusively locked @ %s:%d\n",
 			    sx->sx_object.lo_name, file, line);
-		mtx_unlock(sx->sx_lock);
 #endif
 		break;
 	default:
@@ -395,76 +602,64 @@
 #endif	/* INVARIANT_SUPPORT */
 
 #ifdef DDB
-void
+static void
 db_show_sx(struct lock_object *lock)
 {
-	struct thread *td;
-	struct sx *sx;
+        struct thread *td;
+        struct sx *sx;
+
+        sx = (struct sx *)lock;
 
-	sx = (struct sx *)lock;
+	db_printf(" mask: 0x%x\n", sx->sx_lock);
+                   
+        db_printf(" state: ");
+        if (sx->sx_lock == SX_UNHELD)
+                db_printf("UNLOCKED\n");
+        else if (sx->sx_lock & SX_SHARED_BIT)
+                db_printf("SLOCK: %u\n", 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);
+        }
 
-	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);
+	db_printf(" waiters: ");
+	switch(sx->sx_lock & (SX_SHARED_WAITERS_BIT |
+	    SX_EXCLUSIVE_WAITERS_BIT)) {
+		case SX_EXCLUSIVE_WAITERS_BIT:
+			db_printf("shared\n");
+		break;
+		case SX_SHARED_WAITERS_BIT:
+			db_printf("exclusive\n");
+		break;
+		case SX_SHARED_WAITERS_BIT | SX_EXCLUSIVE_WAITERS_BIT:
+			db_printf("exclusive and shared\n");
+		break;
+		default:
+			db_printf("none\n");
+	}
 }
 
-/*
- * Check to see if a thread that is blocked on a sleep queue is actually
- * blocked on an sx lock.  If so, output some details and return true.
- * If the lock has an exclusive owner, return that in *ownerp.
- */
 int
 sx_chain(struct thread *td, struct thread **ownerp)
 {
 	struct sx *sx;
-	struct cv *cv;
+
+	sx = td->td_wchan;
 
-	/*
-	 * First, see if it looks like td is blocked on a condition
-	 * variable.
-	 */
-	cv = td->td_wchan;
-	if (cv->cv_description != td->td_wmesg)
+	if (sx->sx_desc != 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);
+	db_printf("blocked on sx lock");
+	if (sx->sx_lock == SX_UNHELD) {
+		db_printf("UNHELD\n");
+		*ownerp = NULL;
+	} else if (sx->sx_lock & SX_SHARED_BIT) {
+		db_printf("SHARED (count %u)\n", SX_SHARERS(sx->sx_lock));
 		*ownerp = NULL;
 	} else {
-		db_printf("XLOCK\n");
-		*ownerp = sx->sx_xholder;
+		db_printf("EXCL (holder: 0x%x)\n", SX_HOLDER(sx->sx_lock));
+		*ownerp = (struct thread *)SX_HOLDER(sx->sx_lock);
 	}
 	return (1);
 }
--- //depot/vendor/freebsd/src/sys/kern/vfs_mount.c	2007/02/13 01:31:40
+++ //depot/user/attilio/attilio_smpng/kern/vfs_mount.c	2007/02/14 13:58:06
@@ -43,6 +43,7 @@
 #include <sys/jail.h>
 #include <sys/kernel.h>
 #include <sys/libkern.h>
+#include <sys/lock.h>
 #include <sys/malloc.h>
 #include <sys/mount.h>
 #include <sys/mutex.h>
--- //depot/vendor/freebsd/src/sys/kern/vfs_syscalls.c	2007/02/19 10:57:16
+++ //depot/user/attilio/attilio_smpng/kern/vfs_syscalls.c	2007/02/21 14:40:54
@@ -45,6 +45,7 @@
 #include <sys/bio.h>
 #include <sys/buf.h>
 #include <sys/sysent.h>
+#include <sys/lock.h>
 #include <sys/malloc.h>
 #include <sys/mount.h>
 #include <sys/mutex.h>
--- //depot/vendor/freebsd/src/sys/netinet6/in6_src.c	2006/12/12 12:23:39
+++ //depot/user/attilio/attilio_smpng/netinet6/in6_src.c	2006/12/16 21:33:24
@@ -66,6 +66,7 @@
 
 #include <sys/param.h>
 #include <sys/systm.h>
+#include <sys/lock.h>
 #include <sys/malloc.h>
 #include <sys/mbuf.h>
 #include <sys/priv.h>
--- //depot/vendor/freebsd/src/sys/security/mac_biba/mac_biba.c	2007/02/10 09:03:30
+++ //depot/user/attilio/attilio_smpng/security/mac_biba/mac_biba.c	2007/02/14 13:58:06
@@ -46,6 +46,7 @@
 #include <sys/extattr.h>
 #include <sys/kernel.h>
 #include <sys/ksem.h>
+#include <sys/lock.h>
 #include <sys/malloc.h>
 #include <sys/mman.h>
 #include <sys/mount.h>
--- //depot/vendor/freebsd/src/sys/security/mac_lomac/mac_lomac.c	2007/02/06 14:22:42
+++ //depot/user/attilio/attilio_smpng/security/mac_lomac/mac_lomac.c	2007/02/09 22:24:44
@@ -45,6 +45,7 @@
 #include <sys/conf.h>
 #include <sys/extattr.h>
 #include <sys/kernel.h>
+#include <sys/lock.h>
 #include <sys/malloc.h>
 #include <sys/mman.h>
 #include <sys/mount.h>
--- //depot/vendor/freebsd/src/sys/security/mac_mls/mac_mls.c	2007/02/06 14:22:42
+++ //depot/user/attilio/attilio_smpng/security/mac_mls/mac_mls.c	2007/02/09 22:24:44
@@ -46,6 +46,7 @@
 #include <sys/extattr.h>
 #include <sys/kernel.h>
 #include <sys/ksem.h>
+#include <sys/lock.h>
 #include <sys/mman.h>
 #include <sys/malloc.h>
 #include <sys/mount.h>
--- //depot/vendor/freebsd/src/sys/security/mac_none/mac_none.c	2007/02/06 11:02:49
+++ //depot/user/attilio/attilio_smpng/security/mac_none/mac_none.c	2007/02/09 22:24:44
@@ -48,6 +48,7 @@
 #include <sys/conf.h>
 #include <sys/extattr.h>
 #include <sys/kernel.h>
+#include <sys/lock.h>
 #include <sys/mount.h>
 #include <sys/proc.h>
 #include <sys/systm.h>
--- //depot/vendor/freebsd/src/sys/security/mac_partition/mac_partition.c	2007/02/06 17:25:55
+++ //depot/user/attilio/attilio_smpng/security/mac_partition/mac_partition.c	2007/02/09 22:24:44
@@ -43,6 +43,7 @@
 #include <sys/param.h>
 #include <sys/conf.h>
 #include <sys/kernel.h>
+#include <sys/lock.h>
 #include <sys/mount.h>
 #include <sys/priv.h>
 #include <sys/proc.h>
--- //depot/vendor/freebsd/src/sys/security/mac_stub/mac_stub.c	2007/02/06 11:02:49
+++ //depot/user/attilio/attilio_smpng/security/mac_stub/mac_stub.c	2007/02/09 22:24:44
@@ -52,6 +52,7 @@
 #include <sys/extattr.h>
 #include <sys/kernel.h>
 #include <sys/ksem.h>
+#include <sys/lock.h>
 #include <sys/mount.h>
 #include <sys/proc.h>
 #include <sys/systm.h>
--- //depot/vendor/freebsd/src/sys/security/mac_test/mac_test.c	2007/02/06 14:22:42
+++ //depot/user/attilio/attilio_smpng/security/mac_test/mac_test.c	2007/02/09 22:24:44
@@ -47,6 +47,7 @@
 #include <sys/extattr.h>
 #include <sys/kernel.h>
 #include <sys/ksem.h>
+#include <sys/lock.h>
 #include <sys/malloc.h>
 #include <sys/mount.h>
 #include <sys/proc.h>
--- //depot/vendor/freebsd/src/sys/sys/lock.h	2007/02/03 07:52:31
+++ //depot/user/attilio/attilio_smpng/sys/lock.h	2007/02/06 01:28:29
@@ -320,11 +320,11 @@
 	    LOCK_LINE)
 
 #define	witness_check_shared_sx(sx)					\
-	WITNESS_CHECKORDER(&(sx)->sx_object, 0, LOCK_FILE, LOCK_LINE)
+	WITNESS_CHECKORDER(&(sx)->sx_object, LOP_NEWORDER, LOCK_FILE, LOCK_LINE)
 	
 #define	witness_check_exclusive_sx(sx)					\
-	WITNESS_CHECKORDER(&(sx)->sx_object, LOP_EXCLUSIVE, LOCK_FILE,	\
-	    LOCK_LINE)
+	WITNESS_CHECKORDER(&(sx)->sx_object, LOP_NEWORDER |		\
+	    LOP_EXCLUSIVE, LOCK_FILE, LOCK_LINE)
 
 #endif	/* _KERNEL */
 #endif	/* _SYS_LOCK_H_ */
--- //depot/vendor/freebsd/src/sys/sys/sleepqueue.h	2006/12/16 06:56:39
+++ //depot/user/attilio/attilio_smpng/sys/sleepqueue.h	2006/12/16 21:33:24
@@ -33,8 +33,8 @@
 #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.
+ * 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,6 +84,7 @@
 #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		0x02		/* Used for a sx lock. */
 #define	SLEEPQ_INTERRUPTIBLE	0x100		/* Sleep is interruptible. */
 
 void	init_sleepqueues(void);
--- //depot/vendor/freebsd/src/sys/sys/sx.h	2006/08/29 20:39:49
+++ //depot/user/attilio/attilio_smpng/sys/sx.h	2007/01/08 02:16:26
@@ -1,51 +1,103 @@
-/*-
- * Copyright (C) 2001 Jason Evans <jasone@freebsd.org>.  All rights reserved.
+#ifndef	_SYS_SX_H_
+#define	_SYS_SX_H_
+
+#include <sys/_lock.h>
+#include <sys/_sx.h>
+
+#ifdef	_KERNEL
+#include <machine/atomic.h>
+#endif
+
+/*
+ * The sx_lock member can be considered as a double-side bitmap.
+ * This means that when a sx lock is held as shared lock (one side), lower bits
+ * are reserved for lock manage and the other are used as a count for
+ * sharers.
+ * Otherwise, when a sx lock is held as an exclusive lock (the other side),
+ * lower bits are reserved for lock manage and the other are used in order to
+ * track the (singular) holder.
  *
- * Redistribution and use in source and binary forms, 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.
+ * When the lock is not locked by any thread, it is encoded as a shared lock
+ * with zero waiters.
  *
- * 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.26 2006/08/29 20:36:33 jhb Exp $
+ * 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_SHARED_BIT			0x01
+#define	SX_SHARED_WAITERS_BIT		0x02
+#define	SX_EXCLUSIVE_WAITERS_BIT	0x04
+#define	SX_FLAGMASK							\
+	(SX_SHARED_BIT | SX_SHARED_WAITERS_BIT | SX_EXCLUSIVE_WAITERS_BIT)
+
+#define	SX_HOLDER(x)			((x) & ~SX_FLAGMASK)
+#define	SX_SHARERS_SHIFT		3
+#define	SX_SHARERS(x)			(SX_HOLDER(x) >> SX_SHARERS_SHIFT)
+#define	SX_SHARERS_LOCK(x)		((x) << SX_SHARERS_SHIFT |	\
+					SX_SHARED_BIT)
+#define	SX_ONE_SHARER			(1 << SX_SHARERS_SHIFT)
+#define	SX_UNHELD			SX_SHARERS_LOCK(0)
+
+#ifdef _KERNEL
+
+/*
+ * 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.
  */
 
-#ifndef	_SYS_SX_H_
-#define	_SYS_SX_H_
+/* Acquire an exclusive lock. */
+#define	__sx_xlock(sx, tid, file, line) do {				\
+		uintptr_t _tid = (uintptr_t)(tid);			\
+									\
+		if (!atomic_cmpset_acq_ptr(&(sx)->sx_lock, SX_UNHELD,	\
+		    _tid))						\
+			_sx_xlock_hard((sx), _tid, (file), (line));	\
+} while (0)
+
+/* Release an exclusive lock. */
+#define	__sx_xunlock(sx, tid, file, line) do {				\
+		uintptr_t _tid = (uintptr_t)(tid);			\
+									\
+		if (!atomic_cmpset_rel_ptr(&(sx)->sx_lock, _tid,	\
+		    SX_UNHELD))						\
+			_sx_xunlock_hard((sx), _tid, (file), (line));	\
+} while (0)
 
-#include <sys/queue.h>
-#include <sys/_lock.h>
-#include <sys/condvar.h>	/* XXX */
+/* Acquire a shared lock. */
+#define	__sx_slock(sx, file, line) do {					\
+		uintptr_t x = (sx)->sx_lock;				\
+									\
+		if (x & SX_SHARED_BIT) {				\
+			if (!atomic_cmpset_acq_ptr(&(sx)->sx_lock, x,	\
+			    x + SX_ONE_SHARER))				\
+				_sx_slock_hard((sx), (file), (line));	\
+		} else							\
+			_sx_slock_hard((sx), (file), (line));		\
+} while (0)
 
-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. */
-};
+/* Release a shared lock. */
+#define	__sx_sunlock(sx, file, line) do {				\
+		uintptr_t x = (sx)->sx_lock;				\
+									\
+		if (SX_SHARERS(x) > 1) {				\
+			if (!atomic_cmpset_ptr(&(sx)->sx_lock, x,	\
+			    x - SX_ONE_SHARER))				\
+				_sx_sunlock_hard((sx), (file), (line));	\
+		} else if (!(x & SX_EXCLUSIVE_WAITERS_BIT)) {		\
+			if(!atomic_cmpset_ptr(&(sx)->sx_lock,		\
+			    SX_SHARERS_LOCK(1), SX_UNHELD))		\
+				_sx_sunlock_hard((sx), (file), (line));	\
+		} else							\
+			_sx_sunlock_hard((sx), (file), (line));		\
+} while (0)
 
-#ifdef _KERNEL
+/*
+ * Function prototipes.  Routines that start with an underscore are not part
+ * of the public interface and might be wrappered with a macro.
+ */
 void	sx_sysinit(void *arg);
 void	sx_init(struct sx *sx, const char *description);
 void	sx_destroy(struct sx *sx);
@@ -57,6 +109,12 @@
 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);
+void	_sx_xlock_hard(struct sx *sx, uintptr_t tid, const char *file, int
+	    line);
+void	_sx_slock_hard(struct sx *sx, 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,15 +137,33 @@
 	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)
+/*
+ * 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(SXLOCK_NOINLINE)
+#define	sx_xlock(sx)		_sx_xlock((sx), LOCK_FILE, LOCK_LINE)
+#define	sx_xunlock(sx)		_sx_xunlock((sx), LOCK_FILE, LOCK_LINE)
 #define	sx_slock(sx)		_sx_slock((sx), LOCK_FILE, LOCK_LINE)
-#define	sx_xlock(sx)		_sx_xlock((sx), LOCK_FILE, LOCK_LINE)
+#define	sx_sunlock(sx)		_sx_sunlock((sx), LOCK_FILE, LOCK_LINE)
+#else
+#define	sx_xlock(sx)							\
+	__sx_xlock((sx), curthread, LOCK_FILE, LOCK_LINE)
+#define	sx_xunlock(sx)							\
+	__sx_xunlock((sx), curthread, LOCK_FILE, LOCK_LINE)
+#define	sx_slock(sx)		__sx_slock((sx), LOCK_FILE, LOCK_LINE)
+#define	sx_sunlock(sx)		__sx_sunlock((sx), LOCK_FILE, LOCK_LINE)
+#endif	/* LOCK_DEBUG > 0 || SXLOCK_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_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_xlocked(sx)							\
+	(SX_HOLDER((sx)->sx_lock) == (uintptr_t)curthread)
+
 #define	sx_unlock(sx) do {						\
 	if (sx_xlocked(sx))						\
 		sx_xunlock(sx);						\
