summaryrefslogtreecommitdiff
path: root/sys/kern/kern_sx.c
diff options
context:
space:
mode:
authorMateusz Guzik <mjg@FreeBSD.org>2017-11-25 20:13:50 +0000
committerMateusz Guzik <mjg@FreeBSD.org>2017-11-25 20:13:50 +0000
commitcec174732271804b6ccf31c92e610d41ba2179b8 (patch)
treed2cf4d16a235f77696331419412835fb52144501 /sys/kern/kern_sx.c
parent93118b62f9b7a180f15b054b5bf0889f2ef854b0 (diff)
downloadsrc-test2-cec174732271804b6ccf31c92e610d41ba2179b8.tar.gz
src-test2-cec174732271804b6ccf31c92e610d41ba2179b8.zip
Notes
Diffstat (limited to 'sys/kern/kern_sx.c')
-rw-r--r--sys/kern/kern_sx.c39
1 files changed, 20 insertions, 19 deletions
diff --git a/sys/kern/kern_sx.c b/sys/kern/kern_sx.c
index 44d0bd796d83..13af3897db2b 100644
--- a/sys/kern/kern_sx.c
+++ b/sys/kern/kern_sx.c
@@ -1168,45 +1168,46 @@ static void __noinline
_sx_sunlock_hard(struct sx *sx, uintptr_t x LOCK_FILE_LINE_ARG_DEF)
{
int wakeup_swapper;
+ uintptr_t setx;
if (SCHEDULER_STOPPED())
return;
- for (;;) {
- if (_sx_sunlock_try(sx, &x))
- break;
-
- /*
- * At this point, there should just be one sharer with
- * exclusive waiters.
- */
- MPASS(x == (SX_SHARERS_LOCK(1) | SX_LOCK_EXCLUSIVE_WAITERS));
+ if (_sx_sunlock_try(sx, &x))
+ goto out_lockstat;
- sleepq_lock(&sx->lock_object);
+ /*
+ * 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);
+ x = SX_READ_VALUE(sx);
+ for (;;) {
+ MPASS(x & SX_LOCK_EXCLUSIVE_WAITERS);
+ MPASS(!(x & SX_LOCK_SHARED_WAITERS));
/*
* 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_rel_ptr(&sx->sx_lock,
- SX_SHARERS_LOCK(1) | SX_LOCK_EXCLUSIVE_WAITERS,
- SX_LOCK_UNLOCKED)) {
- sleepq_release(&sx->lock_object);
- x = SX_READ_VALUE(sx);
+ setx = x - SX_ONE_SHARER;
+ setx &= ~SX_LOCK_EXCLUSIVE_WAITERS;
+ if (!atomic_fcmpset_rel_ptr(&sx->sx_lock, &x, setx))
continue;
- }
if (LOCK_LOG_TEST(&sx->lock_object, 0))
CTR2(KTR_LOCK, "%s: %p waking up all thread on"
"exclusive queue", __func__, sx);
wakeup_swapper = sleepq_broadcast(&sx->lock_object, SLEEPQ_SX,
0, SQ_EXCLUSIVE_QUEUE);
- sleepq_release(&sx->lock_object);
- if (wakeup_swapper)
- kick_proc0();
break;
}
+ sleepq_release(&sx->lock_object);
+ if (wakeup_swapper)
+ kick_proc0();
+out_lockstat:
LOCKSTAT_PROFILE_RELEASE_RWLOCK(sx__release, sx, LOCKSTAT_READER);
}