svn commit: r330415 - head/sys/kern

Mateusz Guzik mjg at FreeBSD.org
Sun Mar 4 21:41:06 UTC 2018


Author: mjg
Date: Sun Mar  4 21:41:05 2018
New Revision: 330415
URL: https://svnweb.freebsd.org/changeset/base/330415

Log:
  sx: don't do an atomic op in upgrade if it cananot succeed
  
  The code already pays the cost of reading the lock to obtain the waiters
  flag. Checking whether there is more than one reader is not a problem and
  avoids dirtying the line.
  
  This also fixes a small corner case: if waiters were to show up between
  reading the flag and upgrading the lock, the operation would fail even
  though it should not. No correctness change here though.

Modified:
  head/sys/kern/kern_sx.c

Modified: head/sys/kern/kern_sx.c
==============================================================================
--- head/sys/kern/kern_sx.c	Sun Mar  4 21:38:30 2018	(r330414)
+++ head/sys/kern/kern_sx.c	Sun Mar  4 21:41:05 2018	(r330415)
@@ -413,6 +413,7 @@ int
 sx_try_upgrade_int(struct sx *sx LOCK_FILE_LINE_ARG_DEF)
 {
 	uintptr_t x;
+	uintptr_t waiters;
 	int success;
 
 	if (SCHEDULER_STOPPED())
@@ -427,9 +428,18 @@ sx_try_upgrade_int(struct sx *sx LOCK_FILE_LINE_ARG_DE
 	 * 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_acq_ptr(&sx->sx_lock, SX_SHARERS_LOCK(1) | x,
-	    (uintptr_t)curthread | x);
+	success = 0;
+	x = SX_READ_VALUE(sx);
+	for (;;) {
+		if (SX_SHARERS(x) > 1)
+			break;
+		waiters = (x & SX_LOCK_EXCLUSIVE_WAITERS);
+		if (atomic_fcmpset_acq_ptr(&sx->sx_lock, &x,
+		    (uintptr_t)curthread | waiters)) {
+			success = 1;
+			break;
+		}
+	}
 	LOCK_LOG_TRY("XUPGRADE", &sx->lock_object, 0, success, file, line);
 	if (success) {
 		WITNESS_UPGRADE(&sx->lock_object, LOP_EXCLUSIVE | LOP_TRYLOCK,


More information about the svn-src-head mailing list