Czytałem kod jądra i w jednym miejscu zobaczyłem wyrażenie w środku if
instrukcji, takie jak
if (value == (SPINLOCK_SHARED | 1) - 1) {
............
}
gdzie SPINLOCK_SHARED = 0x80000000
jest predefiniowaną stałą.
Zastanawiam się, dlaczego potrzebujemy (SPINLOCK_SHARED | 1) - 1
- do konwersji typu? wynikiem wyrażenia byłoby 80000000 - to samo co 0x80000000, prawda? jednak dlaczego ORing 1 i odejmowanie 1 ma znaczenie?
Mam wrażenie, że brakuje mi czegoś ...
c
bit-manipulation
RaGa__M
źródło
źródło
if (atomic_cmpset_int(&spin->counta, SPINLOCK_SHARED|0, 1))
.Odpowiedzi:
Zrobiono to w ten sposób dla jasności, to wszystko. Jest tak, ponieważ atomic_fetchadd_int () (np. Sys / spinlock2.h) zwraca wartość PRIOR do dodawania / odejmowania, a ta wartość jest przekazywana do _spin_lock_contested ()
Zauważ, że kompilator C całkowicie wstępnie oblicza wszystkie wyrażenia stałe. W rzeczywistości kompilator może nawet zoptymalizować wbudowany kod w oparciu o warunki warunkowe, które wykorzystują argumenty procedury przekazanej, gdy procedury są przekazywane w tych argumentach stałymi. To dlatego funkcja lockmgr () wbudowana w sys / lock.h ma instrukcję case .... ponieważ cała instrukcja case zostanie zoptymalizowana i przekształci się w bezpośrednie wywołanie odpowiedniej funkcji.
Ponadto we wszystkich tych funkcjach blokowania narzut operacji atomowej przewyższa wszystkie inne obliczenia o dwa lub trzy rzędy wielkości.
-Matt
źródło
Znaleziono kod
_spin_lock_contested
, który jest wywoływany,_spin_lock_quick
gdy ktoś inny próbuje uzyskać blokadę:Jeśli nie ma konkursu, to
count
(poprzednia wartość) powinna być0
, ale tak nie jest. Tacount
wartość jest przekazywana jako parametr_spin_lock_contested
jakovalue
parametr. Jestvalue
to następnie sprawdzane za pomocąif
z PO:Pamiętając o tym, że
value
jest to poprzednia wartośćspin->counta
, a ta ostatnia została już zwiększona o 1, spodziewamyspin->counta
się równościvalue + 1
(chyba że w międzyczasie coś się zmieniło).Zatem sprawdzenie, czy
spin->counta == SPINLOCK_SHARED | 1
(warunek wstępnyatomic_cmpset_int
) odpowiada sprawdzeniu, czyvalue + 1 == SPINLOCK_SHARED | 1
można to przepisać jakovalue == (SPINLOCK_SHARED | 1) - 1
(ponownie, jeśli w międzyczasie nic się nie zmieniło).Chociaż
value == (SPINLOCK_SHARED | 1) - 1
można go przepisać jakovalue == SPINLOCK_SHARED
, pozostawia się tak, jak jest, aby wyjaśnić cel porównania (tj. Porównać zwiększoną poprzednią wartość z wartością testową).Lub iow. odpowiedź wydaje się brzmieć: dla jasności i spójności kodu.
źródło
(SPINLOCK_SHARED | 1) - 1
części jest zrozumiałe ivalue == SPINLOCK_SHARED
jest to również moja myśl, ponieważ sprawdzamy, czy poprzednia wartość ma ustawioną flagę współdzieloną. Jeśli tak, zamień blokadę w wyłączność .........if
kontroli jest sprawdzenie, czyvalue + 1
(która powinna być taka sama, jakspin->counta
gdyby nic się nie zmieniło w międzyczasie) jest równaSPINLOCK_SHARED | 1
. Jeśli wypiszeszif
czek jakovalue == SPINLOCK_SHARED
, zamiar ten nie jest jasny i znacznie trudniej byłoby zrozumieć, co oznacza czek. Utrzymanie obuSPINLOCK_SHARED | 1
i- 1
wyraźnie wif
kontroli jest celowe.if (value + 1 == (SPINLOCK_SHARED | 1) )
?value & SPINLOCK_SHARED
bardziej czytelne.Myślę, że celem jest prawdopodobnie zignorowanie najmniej znaczącego fragmentu:
byłoby chyba bardziej przejrzyste użycie wyrażenia nieco maskującego?
źródło
Efekt
ma zapewnić, że bit wyniku niskiego rzędu zostanie wyczyszczony przed porównaniem z
value
. Zgadzam się, że wydaje się to raczej bezcelowe, ale najwyraźniej bit niskiego rzędu ma szczególne zastosowanie lub znaczenie, które nie jest widoczne w tym kodzie, i myślę, że musimy założyć, że deweloperzy mieli dobry powód, aby to zrobić. Ciekawym pytaniem byłoby - czy ten sam wzorzec (| 1) -1
) jest używany w całej bazie kodu, na którą patrzysz?źródło
To zaciemniony sposób pisania trochę maski. Czytelna wersja:
value == (SPINLOCK_SHARED & ~1u)
.źródło
SPINLOCK_SHARED
jest znaną stałą. Jeśli po prostu testująSPINLOCK_SHARED
obecność w masce, dlaczego nieif (value & SPINLOCK_SHARED)
?value == (SPINLOCK_SHARED & ~1u)
nie jest równoważne, ponieważvalue == (SPINLOCK_SHARED | 1) - 1
działa, nawet jeśli typSPINLOCK_SHARED
jest szerszy niżunsigned
.& ~1u
jest bardziej zrozumiałe. Pomyślałem o sugestii& 0xFFFFFFFE
w mojej odpowiedzi, ale zdałem sobie sprawę, że to też nie jest do końca jasne. Twoja sugestia ma jednak zaletę zwięzłości. :-)0x80000000
. OP stwierdził, że jest zdefiniowany#define SPINLOCK_SHARED 0x80000000
, ale może być w środku,#if…#endif
a inna definicja jest używana w innych okolicznościach, lub autor tego kodu mógł chcieć, aby działał, nawet jeśli definicja jest edytowana lub kod jest skompilowany z innymi nagłówkami, które zdefiniuj to inaczej. Niezależnie od tego dwa fragmenty kodu same w sobie nie są równoważne.Większość tego jest wykonywana w celu obsługi kilku dodatkowych przypadków. Na przykład w tym przypadku mówimy, że
SPINLOCK_SHARED
nie może być 1:źródło
SPINLOCK_SHARED
jest zdefiniowaną stałą, a testowaną zmienną jestvalue
. W tym przypadku tajemnica pozostaje.| 1) - 1
część, gdy SPINLOCK_SHARED trzyma0x80000000
wpływ, jaki miałby wpływ| 1) - 1
?SPINLOCK_SHARED
zmianą w przyszłości. Ale to wcale nie jest jasne. Chciałbym napisać do deweloperów jądra i poprosić o komentarz wyjaśniający lub o zmianę wyrażenia w celu samodokumentowania.