Der Code befindet sich in _spin_lock_contested
, der aufgerufen wird, _spin_lock_quick
wenn jemand anderes versucht, die Sperre zu erhalten:
count = atomic_fetchadd_int(&spin->counta, 1);
if (__predict_false(count != 0)) {
_spin_lock_contested(spin, ident, count);
}
Wenn es keinen Wettbewerb gibt, sollte count
(der vorherige Wert) sein 0
, ist es aber nicht. Dieser count
Wert wird als Parameter an _spin_lock_contested
als value
Parameter übergeben. Dies value
wird dann mit dem if
vom OP überprüft :
/*
* WARNING! Caller has already incremented the lock. We must
* increment the count value (from the inline's fetch-add)
* to match.
*
* Handle the degenerate case where the spinlock is flagged SHARED
* with only our reference. We can convert it to EXCLUSIVE.
*/
if (value == (SPINLOCK_SHARED | 1) - 1) {
if (atomic_cmpset_int(&spin->counta, SPINLOCK_SHARED | 1, 1))
return;
}
Wenn wir bedenken, dass dies value
der vorherige Wert von spin->counta
ist und dieser bereits um 1 erhöht wurde, erwarten wir, dass spin->counta
er gleich ist value + 1
(es sei denn, etwas hat sich in der Zwischenzeit geändert).
Die Überprüfung, ob spin->counta == SPINLOCK_SHARED | 1
(die Voraussetzung der atomic_cmpset_int
) entspricht der Überprüfung, ob value + 1 == SPINLOCK_SHARED | 1
, was umgeschrieben werden kann value == (SPINLOCK_SHARED | 1) - 1
(erneut, wenn sich in der Zwischenzeit nichts geändert hat).
Während value == (SPINLOCK_SHARED | 1) - 1
es umgeschrieben werden könnte value == SPINLOCK_SHARED
, bleibt es unverändert , um die Absicht des Vergleichs zu verdeutlichen (dh den inkrementierten vorherigen Wert mit dem Testwert zu vergleichen).
Oder jetzt. Die Antwort scheint zu sein: aus Gründen der Klarheit und Codekonsistenz.