Я читал код ядра, и в одном месте я видел выражение внутри if
оператора, как
if (value == (SPINLOCK_SHARED | 1) - 1) {
............
}
где SPINLOCK_SHARED = 0x80000000
предопределенная константа.
Интересно, зачем нам (SPINLOCK_SHARED | 1) - 1
- для преобразования типов? результат выражения будет 80000000 - так же, как 0x80000000, не так ли? тем не менее, почему ORing 1 и вычитание 1 имеют значение?
Такое ощущение, что мне не хватает чего-то получить ..
c
bit-manipulation
RaGa__M
источник
источник
if (atomic_cmpset_int(&spin->counta, SPINLOCK_SHARED|0, 1))
.Ответы:
Это было просто сделано для ясности, вот и все. Это потому, что atomic_fetchadd_int () (например, в sys / spinlock2.h) возвращает значение PRIOR для сложения / вычитания, и это значение передается в _spin_lock_contested ()
Обратите внимание, что компилятор C полностью предварительно вычисляет все константные выражения. Фактически, компилятор может даже оптимизировать встроенный код на основе условных выражений, которые используют переданные аргументы процедур, когда процедурам передаются константы в этих аргументах. Вот почему встроенный в sys / lock.h файл lockmgr () имеет оператор case .... потому что весь оператор case будет оптимизирован и превращен в прямой вызов соответствующей функции.
Кроме того, во всех этих функциях блокировки накладные расходы на атомные операции затмевают все остальные вычисления на два или три порядка.
Матф
источник
Код находится в
_spin_lock_contested
, который вызывается,_spin_lock_quick
когда кто-то еще пытается получить блокировку:Если нет никакого конкурса, тогда
count
(предыдущее значение) должно быть0
, но это не так. Этоcount
значение передается как параметр в_spin_lock_contested
качествеvalue
параметра. Этоvalue
затем проверяется сif
из ОП:Имея в виду, что
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
, оно оставлено как есть, чтобы уточнить цель сравнения (т. Е. Сравнить увеличенное предыдущее значение с тестовым значением).Или да. Ответ, кажется, для ясности и последовательности кода.
источник
(SPINLOCK_SHARED | 1) - 1
части, понятно, иvalue == SPINLOCK_SHARED
это тоже моя мысль, потому что мы проверяем, имеет ли предыдущее значение флаг общего набора set.if да, превращаем блокировку в исключительную .........if
проверки состоит в том, чтобы проверить, равно лиvalue + 1
(что должно быть то же значение, какspin->counta
если бы ничего не изменилось за это время), равнымSPINLOCK_SHARED | 1
. Если вы напишитеif
чек какvalue == SPINLOCK_SHARED
, это намерение неясно, и было бы намного сложнее понять, что означает этот чек. Держать обаSPINLOCK_SHARED | 1
и- 1
явно вif
проверке является преднамеренным.if (value + 1 == (SPINLOCK_SHARED | 1) )
?value & SPINLOCK_SHARED
что более читабельно.Я думаю, что цель, вероятно, состоит в том, чтобы игнорировать младший значащий бит:
Возможно, было бы яснее использовать выражение битовой маски?
источник
Эффект
должен гарантировать, что младший бит результата очищается перед сравнением с
value
. Я согласен, что это кажется довольно бессмысленным, но очевидно, что младший бит имеет определенное использование или значение, которое не очевидно в этом коде, и я думаю, что мы должны предположить, что у разработчиков были веские причины для этого. Интересный вопрос: используется ли этот шаблон (| 1) -1
) в кодовой базе, которую вы просматриваете?источник
Это запутанный способ написания немного маски. Читаемая версия:
value == (SPINLOCK_SHARED & ~1u)
.источник
SPINLOCK_SHARED
известная константа. Если они просто проверяют наличиеSPINLOCK_SHARED
в маске, почему бы и нетif (value & SPINLOCK_SHARED)
?value == (SPINLOCK_SHARED & ~1u)
не эквивалентно, потому чтоvalue == (SPINLOCK_SHARED | 1) - 1
работает, даже если типSPINLOCK_SHARED
шире, чемunsigned
.& ~1u
это понятнее. Я думал предложить& 0xFFFFFFFE
в своем ответе, но понял, что это также не совсем понятно. Ваше предложение действительно имеет преимущество краткости, однако. :-)0x80000000
. OP заявил, что он определен с#define SPINLOCK_SHARED 0x80000000
, но это может быть внутри,#if…#endif
и другое определение используется в других обстоятельствах, или автор этого кода мог бы заставить его работать, даже если определение отредактировано или код скомпилирован с другими заголовками, которые определить это по-другому. Независимо от этого, две части кода не являются эквивалентными сами по себе.Скорее всего, это сделано для обработки нескольких дополнительных случаев. Например, в этом случае мы говорим, что
SPINLOCK_SHARED
не может быть 1:источник
SPINLOCK_SHARED
это определенная константа, а проверенная переменная - этоvalue
. В этом случае загадка остается.| 1) - 1
часть, когда SPINLOCK_SHARED удерживает,0x80000000
каково будет влияние| 1) - 1
?SPINLOCK_SHARED
изменений в будущем. Но это не совсем понятно. Я хотел бы написать разработчикам ядра и попросить дать поясняющий комментарий или переставить выражение, чтобы оно самодокументировалось.