FreeBSD/sys/kern/kern_sx.c
/*
 * This function represents the so-called 'hard case' for sx_xunlock
 * operation.  All 'easy case' failures are redirected to this.  Note
 * that ideally this would be a static function, but it needs to be
 * accessible from at least sx.h.
 */
This function represents the so-called 'hard case' for sx_xunlock
operation.  All 'easy case' failures are redirected to this.  Note
that ideally this would be a static function, but it needs to be
accessible from at least sx.h.
This function represents the so - called ' hard case ' for sx_xunlock operation . All ' easy case ' failures are redirected to this . Note that ideally this would be a static function but it needs to be accessible from at least sx . h .
void
_sx_xunlock_hard(struct sx *sx, uintptr_t tid, const char *file, int line)
{
	uintptr_t x;
	int queue, wakeup_swapper;
	if (SCHEDULER_STOPPED())
		return;
	MPASS(!(sx->sx_lock & SX_LOCK_SHARED));
	if (sx_xlocked(sx) && sx_recursed(sx)) {
		if ((--sx->sx_recurse) == 0)
			atomic_clear_ptr(&sx->sx_lock, SX_LOCK_RECURSED);
		if (LOCK_LOG_TEST(&sx->lock_object, 0))
			CTR2(KTR_LOCK, "%s: %p unrecursing", __func__, sx);
		return;
	}
	MPASS(sx->sx_lock & (SX_LOCK_SHARED_WAITERS |
	    SX_LOCK_EXCLUSIVE_WAITERS));
	if (LOCK_LOG_TEST(&sx->lock_object, 0))
		CTR2(KTR_LOCK, "%s: %p contested", __func__, sx);
	sleepq_lock(&sx->lock_object);
	x = SX_LOCK_UNLOCKED;
	if ((sx->sx_lock & SX_LOCK_SHARED_WAITERS) != 0 &&
	    sleepq_sleepcnt(&sx->lock_object, SQ_SHARED_QUEUE) != 0) {
		queue = SQ_SHARED_QUEUE;
		x |= (sx->sx_lock & SX_LOCK_EXCLUSIVE_WAITERS);
	} else
		queue = SQ_EXCLUSIVE_QUEUE;
	if (LOCK_LOG_TEST(&sx->lock_object, 0))
		CTR3(KTR_LOCK, "%s: %p waking up all threads on %s queue",
		    __func__, sx, queue == SQ_SHARED_QUEUE ? "shared" :
		    "exclusive");
	atomic_store_rel_ptr(&sx->sx_lock, x);
	wakeup_swapper = sleepq_broadcast(&sx->lock_object, SLEEPQ_SX, 0,
	    queue);
	sleepq_release(&sx->lock_object);
	if (wakeup_swapper)
		kick_proc0();
}
void _sx_xunlock_hard ( struct sx * sx , uintptr_t tid , const char * file , int line ) { uintptr_t x ; int queue , wakeup_swapper ; if ( SCHEDULER_STOPPED ( ) ) return ; MPASS ( ! ( sx -> sx_lock & SX_LOCK_SHARED ) ) ; if ( sx_xlocked ( sx ) && sx_recursed ( sx ) ) { if ( ( -- sx -> sx_recurse ) == 0 ) atomic_clear_ptr ( & sx -> sx_lock , SX_LOCK_RECURSED ) ; if ( LOCK_LOG_TEST ( & sx -> lock_object , 0 ) ) CTR2 ( KTR_LOCK , " " , __func__ , sx ) ; return ; } MPASS ( sx -> sx_lock & ( SX_LOCK_SHARED_WAITERS | SX_LOCK_EXCLUSIVE_WAITERS ) ) ; if ( LOCK_LOG_TEST ( & sx -> lock_object , 0 ) ) CTR2 ( KTR_LOCK , " " , __func__ , sx ) ; sleepq_lock ( & sx -> lock_object ) ; x = SX_LOCK_UNLOCKED ; if ( ( sx -> sx_lock & SX_LOCK_SHARED_WAITERS ) != 0 && sleepq_sleepcnt ( & sx -> lock_object , SQ_SHARED_QUEUE ) != 0 ) { queue = SQ_SHARED_QUEUE ; x |= ( sx -> sx_lock & SX_LOCK_EXCLUSIVE_WAITERS ) ; } else queue = SQ_EXCLUSIVE_QUEUE ; if ( LOCK_LOG_TEST ( & sx -> lock_object , 0 ) ) CTR3 ( KTR_LOCK , " " , __func__ , sx , queue == SQ_SHARED_QUEUE ? " " : " " ) ; atomic_store_rel_ptr ( & sx -> sx_lock , x ) ; wakeup_swapper = sleepq_broadcast ( & sx -> lock_object , SLEEPQ_SX , 0 , queue ) ; sleepq_release ( & sx -> lock_object ) ; if ( wakeup_swapper ) kick_proc0 ( ) ; }
This function represents the so-called 'hard case' for sx_xunlock
 operation.
This function represents the so - called ' hard case ' for sx_xunlock operation .
/* If the lock is recursed, then unrecurse one level. */ /*
	 * The wake up algorithm here is quite simple and probably not
	 * ideal.  It gives precedence to shared waiters if they are
	 * present.  For this condition, we have to preserve the
	 * state of the exclusive waiters flag.
	 * If interruptible sleeps left the shared queue empty avoid a
	 * starvation for the threads sleeping on the exclusive queue by giving
	 * them precedence and cleaning up the shared waiters bit anyway.
	 */ /* Wake up all the waiters for the specific queue. */