diff options
author | Mateusz Guzik <mjg@FreeBSD.org> | 2017-11-17 02:26:15 +0000 |
---|---|---|
committer | Mateusz Guzik <mjg@FreeBSD.org> | 2017-11-17 02:26:15 +0000 |
commit | 8fef6b2c67812c4e8ea667870ff1d8db3f5964d7 (patch) | |
tree | 6b187e98e0623029e71711beaafeaee63ed275bc /sys/kern/kern_rwlock.c | |
parent | 8448e020813ca77e5b4ff60411eac6ddcb955e6b (diff) | |
download | src-8fef6b2c67812c4e8ea667870ff1d8db3f5964d7.tar.gz src-8fef6b2c67812c4e8ea667870ff1d8db3f5964d7.zip |
rwlock: unlock before traversing threads to wake up
While here perform a minor cleanup of the unlock path.
Notes
Notes:
svn path=/head/; revision=325921
Diffstat (limited to 'sys/kern/kern_rwlock.c')
-rw-r--r-- | sys/kern/kern_rwlock.c | 20 |
1 files changed, 11 insertions, 9 deletions
diff --git a/sys/kern/kern_rwlock.c b/sys/kern/kern_rwlock.c index 78b5f428073a..6cd6e3da4cc7 100644 --- a/sys/kern/kern_rwlock.c +++ b/sys/kern/kern_rwlock.c @@ -1081,7 +1081,7 @@ __rw_wunlock_hard(volatile uintptr_t *c, uintptr_t tid, const char *file, { struct rwlock *rw; struct turnstile *ts; - uintptr_t v; + uintptr_t v, setv; int queue; if (SCHEDULER_STOPPED()) @@ -1108,8 +1108,6 @@ __rw_wunlock_hard(volatile uintptr_t *c, uintptr_t tid, const char *file, CTR2(KTR_LOCK, "%s: %p contested", __func__, rw); turnstile_chain_lock(&rw->lock_object); - ts = turnstile_lookup(&rw->lock_object); - MPASS(ts != NULL); /* * Use the same algo as sx locks for now. Prefer waking up shared @@ -1127,19 +1125,23 @@ __rw_wunlock_hard(volatile uintptr_t *c, uintptr_t tid, const char *file, * there that could be worked around either by waking both queues * of waiters or doing some complicated lock handoff gymnastics. */ - v = RW_UNLOCKED; - if (rw->rw_lock & RW_LOCK_WRITE_WAITERS) { + setv = RW_UNLOCKED; + v = RW_READ_VALUE(rw); + queue = TS_SHARED_QUEUE; + if (v & RW_LOCK_WRITE_WAITERS) { queue = TS_EXCLUSIVE_QUEUE; - v |= (rw->rw_lock & RW_LOCK_READ_WAITERS); - } else - queue = TS_SHARED_QUEUE; + setv |= (v & RW_LOCK_READ_WAITERS); + } + atomic_store_rel_ptr(&rw->rw_lock, setv); /* 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"); + + ts = turnstile_lookup(&rw->lock_object); + MPASS(ts != NULL); turnstile_broadcast(ts, queue); - atomic_store_rel_ptr(&rw->rw_lock, v); turnstile_unpend(ts, TS_EXCLUSIVE_LOCK); turnstile_chain_unlock(&rw->lock_object); } |