Знайдено код _spin_lock_contested
, який викликається, _spin_lock_quick
коли хтось інший намагається отримати замок:
count = atomic_fetchadd_int(&spin->counta, 1);
if (__predict_false(count != 0)) {
_spin_lock_contested(spin, ident, count);
}
Якщо немає змагань, то count
(попереднє значення) має бути 0
, але це не так. Це count
значення передається як параметр, _spin_lock_contested
як value
параметр. Потім value
це перевіряється за if
допомогою ОП:
/*
* 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;
}
Маючи на увазі, що value
попереднє значення spin->counta
, а останнє вже збільшено на 1, ми очікуємо, що воно spin->counta
буде рівним value + 1
(якщо щось не змінилося тим часом).
Отже, перевірка того, що spin->counta == SPINLOCK_SHARED | 1
(передумова atomic_cmpset_int
) відповідає перевірці, якщо value + 1 == SPINLOCK_SHARED | 1
, що можна переписати як value == (SPINLOCK_SHARED | 1) - 1
(знову ж таки, якщо нічого за цей час не змінилося).
Хоча це value == (SPINLOCK_SHARED | 1) - 1
може бути переписано як value == SPINLOCK_SHARED
, залишається таким, як є, для уточнення наміру порівняння (тобто порівняння нарощеного попереднього значення з тестовим значенням).
Або iow. начебто відповідь: для ясності та послідовності коду.