FreeBSD/sys/kern/kern_sx.c
/*
 * Downgrade an unrecursed exclusive lock into a single shared lock.
 */
Downgrade an unrecursed exclusive lock into a single shared lock.
Downgrade an unrecursed exclusive lock into a single shared lock .
void
sx_downgrade_(struct sx *sx, const char *file, int line)
{
	uintptr_t x;
	int wakeup_swapper;
	if (SCHEDULER_STOPPED())
		return;
	KASSERT(sx->sx_lock != SX_LOCK_DESTROYED,
	    ("sx_downgrade() of destroyed sx @ %s:%d", file, line));
	_sx_assert(sx, SA_XLOCKED | SA_NOTRECURSED, file, line);
#ifndef INVARIANTS
	if (sx_recursed(sx))
		panic("downgrade of a recursed lock");
#endif
	WITNESS_DOWNGRADE(&sx->lock_object, 0, file, line);
	x = sx->sx_lock;
	if (!(x & SX_LOCK_SHARED_WAITERS) &&
	    atomic_cmpset_rel_ptr(&sx->sx_lock, x, SX_SHARERS_LOCK(1) |
	    (x & SX_LOCK_EXCLUSIVE_WAITERS))) {
		LOCK_LOG_LOCK("XDOWNGRADE", &sx->lock_object, 0, 0, file, line);
		return;
	}
	sleepq_lock(&sx->lock_object);
	wakeup_swapper = 0;
	x = sx->sx_lock;
	atomic_store_rel_ptr(&sx->sx_lock, SX_SHARERS_LOCK(1) |
	    (x & SX_LOCK_EXCLUSIVE_WAITERS));
	if (x & SX_LOCK_SHARED_WAITERS)
		wakeup_swapper = sleepq_broadcast(&sx->lock_object, SLEEPQ_SX,
		    0, SQ_SHARED_QUEUE);
	sleepq_release(&sx->lock_object);
	LOCK_LOG_LOCK("XDOWNGRADE", &sx->lock_object, 0, 0, file, line);
	LOCKSTAT_RECORD0(sx__downgrade, sx);
	if (wakeup_swapper)
		kick_proc0();
}
void sx_downgrade_ ( struct sx * sx , const char * file , int line ) { uintptr_t x ; int wakeup_swapper ; if ( SCHEDULER_STOPPED ( ) ) return ; KASSERT ( sx -> sx_lock != SX_LOCK_DESTROYED , ( " " , file , line ) ) ; _sx_assert ( sx , SA_XLOCKED | SA_NOTRECURSED , file , line ) ; #ifndef INVARIANTS if ( sx_recursed ( sx ) ) panic ( " " ) ; #endif WITNESS_DOWNGRADE ( & sx -> lock_object , 0 , file , line ) ; x = sx -> sx_lock ; if ( ! ( x & SX_LOCK_SHARED_WAITERS ) && atomic_cmpset_rel_ptr ( & sx -> sx_lock , x , SX_SHARERS_LOCK ( 1 ) | ( x & SX_LOCK_EXCLUSIVE_WAITERS ) ) ) { LOCK_LOG_LOCK ( " " , & sx -> lock_object , 0 , 0 , file , line ) ; return ; } sleepq_lock ( & sx -> lock_object ) ; wakeup_swapper = 0 ; x = sx -> sx_lock ; atomic_store_rel_ptr ( & sx -> sx_lock , SX_SHARERS_LOCK ( 1 ) | ( x & SX_LOCK_EXCLUSIVE_WAITERS ) ) ; if ( x & SX_LOCK_SHARED_WAITERS ) wakeup_swapper = sleepq_broadcast ( & sx -> lock_object , SLEEPQ_SX , 0 , SQ_SHARED_QUEUE ) ; sleepq_release ( & sx -> lock_object ) ; LOCK_LOG_LOCK ( " " , & sx -> lock_object , 0 , 0 , file , line ) ; LOCKSTAT_RECORD0 ( sx__downgrade , sx ) ; if ( wakeup_swapper ) kick_proc0 ( ) ; }
Downgrade an unrecursed exclusive lock into a single shared lock.
Downgrade an unrecursed exclusive lock into a single shared lock .
/*
	 * Try to switch from an exclusive lock with no shared waiters
	 * to one sharer with no shared waiters.  If there are
	 * exclusive waiters, we don't need to lock the sleep queue so
	 * long as we preserve the flag.  We do one quick try and if
	 * that fails we grab the sleepq lock to keep the flags from
	 * changing and do it the slow way.
	 *
	 * We have to lock the sleep queue if there are shared waiters
	 * so we can wake them up.
	 */ /*
	 * Lock the sleep queue so we can read the waiters bits
	 * without any races and wakeup any shared waiters.
	 */ /*
	 * Preserve SX_LOCK_EXCLUSIVE_WAITERS while downgraded to a single
	 * shared lock.  If there are any shared waiters, wake them up.
	 */