FreeBSD/sys/kern/kern_rwlock.c
/*
 * Downgrade a write lock into a single read lock.
 */
Downgrade a write lock into a single read lock.
Downgrade a write lock into a single read lock .
void
__rw_downgrade(volatile uintptr_t *c, const char *file, int line)
{
	struct rwlock *rw;
	struct turnstile *ts;
	uintptr_t tid, v;
	int rwait, wwait;
	if (SCHEDULER_STOPPED())
		return;
	rw = rwlock2rw(c);
	KASSERT(rw->rw_lock != RW_DESTROYED,
	    ("rw_downgrade() of destroyed rwlock @ %s:%d", file, line));
	__rw_assert(c, RA_WLOCKED | RA_NOTRECURSED, file, line);
#ifndef INVARIANTS
	if (rw_recursed(rw))
		panic("downgrade of a recursed lock");
#endif
	WITNESS_DOWNGRADE(&rw->lock_object, 0, file, line);
	tid = (uintptr_t)curthread;
	if (atomic_cmpset_rel_ptr(&rw->rw_lock, tid, RW_READERS_LOCK(1)))
		goto out;
	turnstile_chain_lock(&rw->lock_object);
	v = rw->rw_lock & RW_LOCK_WAITERS;
	rwait = v & RW_LOCK_READ_WAITERS;
	wwait = v & RW_LOCK_WRITE_WAITERS;
	MPASS(rwait | wwait);
	ts = turnstile_lookup(&rw->lock_object);
	MPASS(ts != NULL);
	if (!wwait)
		v &= ~RW_LOCK_READ_WAITERS;
	atomic_store_rel_ptr(&rw->rw_lock, RW_READERS_LOCK(1) | v);
	if (rwait && !wwait) {
		turnstile_broadcast(ts, TS_SHARED_QUEUE);
		turnstile_unpend(ts, TS_EXCLUSIVE_LOCK);
	} else
		turnstile_disown(ts);
	turnstile_chain_unlock(&rw->lock_object);
out:
	curthread->td_rw_rlocks++;
	LOCK_LOG_LOCK("WDOWNGRADE", &rw->lock_object, 0, 0, file, line);
	LOCKSTAT_RECORD0(rw__downgrade, rw);
}
void __rw_downgrade ( volatile uintptr_t * c , const char * file , int line ) { struct rwlock * rw ; struct turnstile * ts ; uintptr_t tid , v ; int rwait , wwait ; if ( SCHEDULER_STOPPED ( ) ) return ; rw = rwlock2rw ( c ) ; KASSERT ( rw -> rw_lock != RW_DESTROYED , ( " " , file , line ) ) ; __rw_assert ( c , RA_WLOCKED | RA_NOTRECURSED , file , line ) ; #ifndef INVARIANTS if ( rw_recursed ( rw ) ) panic ( " " ) ; #endif WITNESS_DOWNGRADE ( & rw -> lock_object , 0 , file , line ) ; tid = ( uintptr_t ) curthread ; if ( atomic_cmpset_rel_ptr ( & rw -> rw_lock , tid , RW_READERS_LOCK ( 1 ) ) ) goto out ; turnstile_chain_lock ( & rw -> lock_object ) ; v = rw -> rw_lock & RW_LOCK_WAITERS ; rwait = v & RW_LOCK_READ_WAITERS ; wwait = v & RW_LOCK_WRITE_WAITERS ; MPASS ( rwait | wwait ) ; ts = turnstile_lookup ( & rw -> lock_object ) ; MPASS ( ts != NULL ) ; if ( ! wwait ) v &= ~ RW_LOCK_READ_WAITERS ; atomic_store_rel_ptr ( & rw -> rw_lock , RW_READERS_LOCK ( 1 ) | v ) ; if ( rwait && ! wwait ) { turnstile_broadcast ( ts , TS_SHARED_QUEUE ) ; turnstile_unpend ( ts , TS_EXCLUSIVE_LOCK ) ; } else turnstile_disown ( ts ) ; turnstile_chain_unlock ( & rw -> lock_object ) ; out : curthread -> td_rw_rlocks ++ ; LOCK_LOG_LOCK ( " " , & rw -> lock_object , 0 , 0 , file , line ) ; LOCKSTAT_RECORD0 ( rw__downgrade , rw ) ; }
Downgrade a write lock into a single read lock.
Downgrade a write lock into a single read lock .
/*
	 * Convert from a writer to a single reader.  First we handle
	 * the easy case with no waiters.  If there are any waiters, we
	 * lock the turnstile and "disown" the lock.
	 */ /*
	 * Ok, we think we have waiters, so lock the turnstile so we can
	 * read the waiter flags without any races.
	 */ /*
	 * Downgrade from a write lock while preserving waiters flag
	 * and give up ownership of the turnstile.
	 */ /*
	 * Wake other readers if there are no writers pending.  Otherwise they
	 * won't be able to acquire the lock anyway.
	 */