Index: sys/kern/kern_lock.c =================================================================== --- sys/kern/kern_lock.c +++ sys/kern/kern_lock.c @@ -1003,10 +1003,34 @@ x = lk->lk_lock; MPASS((x & LK_EXCLUSIVE_SPINNERS) == 0); x &= LK_ALL_WAITERS; - if (atomic_cmpset_rel_ptr(&lk->lk_lock, tid | x, - LK_SHARERS_LOCK(1) | x)) - break; - cpu_spinwait(); + if ((x & LK_EXCLUSIVE_WAITERS) || + !(x & LK_SHARED_WAITERS)) { + if (atomic_cmpset_rel_ptr(&lk->lk_lock, tid | x, + LK_SHARERS_LOCK(1) | x)) + break; + cpu_spinwait(); + continue; + } + + sleepq_lock(&lk->lock_object); + x = lk->lk_lock; + x &= LK_ALL_WAITERS; + + if ((x & LK_EXCLUSIVE_WAITERS) || + !(x & LK_SHARED_WAITERS) || + !atomic_cmpset_rel_ptr(&lk->lk_lock, tid | x, + LK_SHARERS_LOCK(1) | (x & ~LK_SHARED_WAITERS))) { + sleepq_release(&lk->lock_object); + continue; + } + LOCK_LOG2(lk, + "%s: %p waking up threads on the shared queue", + __func__, lk); + lk->lk_exslpfail = 0; + wakeup_swapper |= sleepq_broadcast(&lk->lock_object, + SLEEPQ_LK, 0, SQ_SHARED_QUEUE); + sleepq_release(&lk->lock_object); + break; } break; case LK_RELEASE: