Ich habe einen Kernel-Code gelesen und an einer Stelle habe ich einen Ausdruck in einer if
Anweisung wie gesehen
if (value == (SPINLOCK_SHARED | 1) - 1) {
............
}
wo SPINLOCK_SHARED = 0x80000000
ist eine vordefinierte Konstante.
Ich frage mich, warum wir brauchen (SPINLOCK_SHARED | 1) - 1
- für die Typkonvertierung? Das Ergebnis des Ausdrucks wäre 80000000 - genau wie 0x80000000, nicht wahr? Warum ist ORing 1 und Subtrahieren von 1 wichtig?
Ich habe das Gefühl, dass mir etwas fehlt.
c
bit-manipulation
RaGa__M
quelle
quelle
if (atomic_cmpset_int(&spin->counta, SPINLOCK_SHARED|0, 1))
.Antworten:
Es wurde nur aus Gründen der Klarheit so gemacht, das ist alles. Dies liegt daran, dass atomic_fetchadd_int () (z. B. sys / spinlock2.h) den Wert PRIOR für die Addition / Subtraktion zurückgibt und dieser Wert an _spin_lock_contested () übergeben wird.
Beachten Sie, dass der C-Compiler alle konstanten Ausdrücke vollständig vorberechnet. Tatsächlich kann der Compiler sogar Inline-Code basierend auf Bedingungen optimieren, die übergebene Prozedurargumente verwenden, wenn die Prozeduren Konstanten in diesen Argumenten übergeben werden. Aus diesem Grund hat die Inline lockmgr () in sys / lock.h eine case-Anweisung .... da diese gesamte case-Anweisung optimiert und in einen direkten Aufruf der entsprechenden Funktion umgewandelt wird.
Bei all diesen Verriegelungsfunktionen stellt der Overhead der Atomoperationen alle anderen Berechnungen um zwei oder drei Größenordnungen in den Schatten.
-Matt
quelle
Der Code befindet sich in
_spin_lock_contested
, der aufgerufen wird,_spin_lock_quick
wenn jemand anderes versucht, die Sperre zu erhalten:Wenn es keinen Wettbewerb gibt, sollte
count
(der vorherige Wert) sein0
, ist es aber nicht. Diesercount
Wert wird als Parameter an_spin_lock_contested
alsvalue
Parameter übergeben. Diesvalue
wird dann mit demif
vom OP überprüft :Wenn wir bedenken, dass dies
value
der vorherige Wert vonspin->counta
ist und dieser bereits um 1 erhöht wurde, erwarten wir, dassspin->counta
er gleich istvalue + 1
(es sei denn, etwas hat sich in der Zwischenzeit geändert).Die Überprüfung, ob
spin->counta == SPINLOCK_SHARED | 1
(die Voraussetzung deratomic_cmpset_int
) entspricht der Überprüfung, obvalue + 1 == SPINLOCK_SHARED | 1
, was umgeschrieben werden kannvalue == (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önntevalue == 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.
quelle
(SPINLOCK_SHARED | 1) - 1
Teil ist verständlich undvalue == SPINLOCK_SHARED
ist auch mein Gedanke, denn wir prüfen, ob für den vorherigen Wert das Shared-Flag gesetzt wurde. Wenn ja, verwandeln Sie die Sperre in exklusives .........if
Prüfung soll geprüft werden , obvalue + 1
(was der gleiche Wert sein sollte, alsspin->counta
hätte sich in der Zwischenzeit nichts geändert) gleich istSPINLOCK_SHARED | 1
. Wenn Sie denif
Scheck als schreibenvalue == SPINLOCK_SHARED
, ist diese Absicht nicht klar, und es wäre viel schwieriger herauszufinden, was der Scheck bedeutet. BeidesSPINLOCK_SHARED | 1
und- 1
explizit in derif
Kontrolle zu halten, ist beabsichtigt.if (value + 1 == (SPINLOCK_SHARED | 1) )
?value & SPINLOCK_SHARED
was besser lesbar ist.Ich denke, das Ziel ist wahrscheinlich, das niedrigstwertige Bit zu ignorieren:
wäre es vielleicht klarer gewesen, einen Bitmaskenausdruck zu verwenden?
quelle
Der Effekt von
soll sicherstellen, dass das niederwertige Bit des Ergebnisses vor dem Vergleich mit gelöscht wird
value
. Ich stimme zu, dass es ziemlich sinnlos erscheint, aber anscheinend hat das Bit niedriger Ordnung eine bestimmte Verwendung oder Bedeutung, die in diesem Code nicht ersichtlich ist, und ich denke, wir müssen davon ausgehen, dass die Entwickler einen guten Grund dafür hatten. Eine interessante Frage wäre: Wird dasselbe Muster (| 1) -1
) in der gesamten Codebasis verwendet, die Sie betrachten?quelle
Es ist eine verschleierte Art, eine Bitmaske zu schreiben. Lesbare Version :
value == (SPINLOCK_SHARED & ~1u)
.quelle
SPINLOCK_SHARED
es sich um eine bekannte Konstante handelt. Wenn sie nur testen, ob sieSPINLOCK_SHARED
in einer Maske vorhanden sind, warum nichtif (value & SPINLOCK_SHARED)
?value == (SPINLOCK_SHARED & ~1u)
ist nicht gleichwertig, da esvalue == (SPINLOCK_SHARED | 1) - 1
auch dann funktioniert, wenn der TypSPINLOCK_SHARED
breiter als istunsigned
.& ~1u
klarer ist. Ich dachte daran,& 0xFFFFFFFE
in meiner Antwort einen Vorschlag zu machen, stellte jedoch fest, dass dies auch nicht wirklich klar ist. Ihr Vorschlag hat jedoch den Vorteil der Kürze. :-)0x80000000
. OP hat angegeben, dass es mit definiert ist#define SPINLOCK_SHARED 0x80000000
, aber das könnte drin sein#if…#endif
und unter anderen Umständen wird eine andere Definition verwendet, oder der Autor dieses Codes könnte beabsichtigt haben, dass es funktioniert, selbst wenn die Definition bearbeitet oder der Code mit anderen Headern kompiliert wird, die definiere es anders. Unabhängig davon sind die beiden Codeteile für sich genommen nicht gleichwertig.Die meisten davon werden durchgeführt, um mehrere zusätzliche Fälle zu behandeln. In diesem Fall sagen wir zum Beispiel, dass
SPINLOCK_SHARED
dies nicht 1 sein kann:quelle
SPINLOCK_SHARED
es eine definierte Konstante und die getestete Variable istvalue
. In diesem Fall bleibt das Geheimnis.| 1) - 1
Teil beibehalten , als SPINLOCK_SHARED0x80000000
die Auswirkungen hielt| 1) - 1
.SPINLOCK_SHARED
in Zukunft verändert zu werden. Aber es ist überhaupt nicht klar. Ich würde an die Kernel-Entwickler schreiben und um eine Klarstellung bitten oder um eine Neuordnung des Ausdrucks, damit er sich selbst dokumentiert.