(x | y) – y warum kann es nicht einfach x oder gar `x | sein 0`

Lesezeit: 5 Minuten

Benutzeravatar von RaGa__M
RaGa__M

Ich habe einen Kernel-Code gelesen und an einer Stelle habe ich einen Ausdruck darin gesehen if Aussage wie

if (value == (SPINLOCK_SHARED | 1) - 1) {
         ............
}

wo SPINLOCK_SHARED = 0x80000000 ist eine vordefinierte Konstante.

Ich frage mich, wozu wir brauchen (SPINLOCK_SHARED | 1) - 1 – für Typkonvertierungszwecke? das Ergebnis des Ausdrucks wäre 80000000 – dasselbe wie 0x80000000, nicht wahr? aber warum ist ORing 1 und Subtracting 1 wichtig?

Habe das Gefühl, dass mir etwas fehlt..

  • #define SPINLOCK_SHARED 0x80000000

    – RaGa__M

    19. Dezember 2019 um 12:35 Uhr

  • Ich vermute, es gibt keinen Grund. Möglicherweise eine Copy-Paste-Sache. Könnten Sie hinzufügen, wo genau Sie das gefunden haben (welche Version von welchem ​​​​Kernel, welche Datei usw.).

    – Sander DeDycker

    19. Dezember 2019 um 12:39 Uhr

  • Hier, github.com/DragonFlyBSD/DragonFlyBSD/blob/master/sys/kern/…

    – RaGa__M

    19. Dezember 2019 um 12:42 Uhr

  • Dieselbe Quellcodedatei enthält auch if (atomic_cmpset_int(&spin->counta, SPINLOCK_SHARED|0, 1)).

    – Eric Postpischil

    19. Dezember 2019 um 12:58 Uhr


  • Dann denke ich, müssen wir den Autor fragen, warum es geändert wurde.

    – komischer Mann

    19. Dezember 2019 um 13:01 Uhr

Der Code befindet sich in _spin_lock_contesteddie von 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, dann count (der vorherige Wert) sein sollte 0, ist es aber nicht. Dies count value wird als Parameter an übergeben _spin_lock_contested als die value Parameter. Dies value wird dann mit überprüft if aus dem OP:

/*
 * 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;
}

Das im Hinterkopf behalten value ist der vorherige Wert von spin->countaund letzteres wurde bereits um 1 erhöht, erwarten wir spin->counta gleich value + 1 (sofern sich zwischenzeitlich nichts geändert hat).

Also prüfen ob spin->counta == SPINLOCK_SHARED | 1 (Voraussetzung für die atomic_cmpset_int) entspricht der Überprüfung von if value + 1 == SPINLOCK_SHARED | 1die umgeschrieben werden kann als value == (SPINLOCK_SHARED | 1) - 1 (auch wenn sich zwischenzeitlich nichts geändert hat).

Während value == (SPINLOCK_SHARED | 1) - 1 könnte umgeschrieben werden als value == SPINLOCK_SHAREDwird unverändert gelassen, um die Absicht des Vergleichs zu verdeutlichen (d. h. den inkrementierten vorherigen Wert mit dem Testwert zu vergleichen).

Oder iow. Die Antwort scheint zu sein: für Klarheit und Codekonsistenz.

  • Danke für deine Antwort, alles außer (SPINLOCK_SHARED | 1) - 1 Teil ist verständlich und value == SPINLOCK_SHARED ist auch mein Gedanke, weil wir prüfen, ob der vorherige Wert das Shared-Flag gesetzt hat. Wenn ja, schalten Sie die Sperre auf exklusiv………

    – RaGa__M

    19. Dezember 2019 um 13:19 Uhr

  • @RaGa__M : die Absicht der if prüfen ist zu prüfen, ob value + 1 (was der gleiche Wert sein sollte wie spin->counta wenn sich zwischenzeitlich nichts geändert hat) gleich SPINLOCK_SHARED | 1. Wenn du das schreibst if prüfen als value == SPINLOCK_SHARED, diese Absicht ist nicht klar, und es wäre viel schwieriger herauszufinden, was die Überprüfung bedeutet. Beides behalten SPINLOCK_SHARED | 1 und - 1 ausdrücklich in der if Überprüfung ist beabsichtigt.

    – Sander DeDycker

    19. Dezember 2019 um 13:26 Uhr

  • Aber es sorgt tatsächlich für Verwirrung.

    – RaGa__M

    20. Dezember 2019 um 5:30 Uhr

  • Warum nicht if (value + 1 == (SPINLOCK_SHARED | 1) )?

    – Paul H

    20. Dezember 2019 um 20:09 Uhr

  • Nun …. es könnte einfach sein value & SPINLOCK_SHARED was besser lesbar ist.

    – RaGa__M

    21. Dezember 2019 um 7:09 Uhr


Ich denke, das Ziel ist wahrscheinlich, das niedrigstwertige Bit zu ignorieren:

  • Wenn SPINLOCK_SHARED binär ausgedrückt xxx0 ist -> Ergebnis ist xxx0
  • Wenn SPINLOCK_SHARED = xxx1 -> Ergebnis ist auch xxx0

wäre vielleicht klarer gewesen, einen Bitmaskenausdruck zu verwenden?

  • Das ist, was der Code tut, aber die Frage ist warum Würden Sie das für eine definierte Konstante tun, bei der das niederwertigste Bit nicht gesetzt ist?

    – Sander DeDycker

    19. Dezember 2019 um 12:37 Uhr

  • @SanderDeDycker Weil Linux-Kernel?

    – Ludin

    19. Dezember 2019 um 12:39 Uhr

  • @Lundin Der Linux-Kernel ist nicht von verständlichen Codierungspraktiken ausgenommen. Ganz im Gegenteil.

    – Qix – MONICA WURDE MISSHANDELT

    19. Dezember 2019 um 12:40 Uhr

  • @ Qix Ich bin absolut anderer Meinung. Lesen Sie das Dokument zum Programmierstil des Linux-Kernels. Es ist ein Qualitätsdokument zum “Garagenhacken”, das völlig frei von Begründungen ist.

    – Ludin

    19. Dezember 2019 um 12:41 Uhr


  • @ Qix Wenn du das sagst. Ich war ein großer Linux-Fan, bis ich einen Blick auf den Code geworfen und das Kernel-Coding-Style-Dokument gelesen habe. Heute halte ich 10 Meter Sicherheitsabstand zu Linux-Rechnern ein.

    – Ludin

    19. Dezember 2019 um 12:53 Uhr

Der Effekt von

(SPINLOCK_SHARED | 1) - 1

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 niederwertige Bit eine bestimmte Verwendung oder Bedeutung, die in diesem Code nicht offensichtlich ist, und ich denke, wir müssen davon ausgehen, dass die Entwickler einen guten Grund dafür hatten. Eine interessante Frage wäre – ist das gleiche Muster (| 1) -1) in der gesamten Codebasis verwendet, die Sie sich ansehen?

Es ist eine verschleierte Art, eine Bitmaske zu schreiben. Lesbare Version: value == (SPINLOCK_SHARED & ~1u).

Es wurde nur aus Gründen der Klarheit so gemacht, das ist alles. Das liegt daran, dass atomic_fetchadd_int() (in zB sys/spinlock2.h) den Wert VOR der 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 den Prozeduren Konstanten in diesen Argumenten übergeben werden. Aus diesem Grund hat lockmgr() inline in sys/lock.h eine case-Anweisung …. weil diese gesamte case-Anweisung optimiert wird und in einen direkten Aufruf der entsprechenden Funktion übergeht.

Außerdem stellt bei all diesen Verriegelungsfunktionen der Overhead der atomaren Operationen alle anderen Berechnungen um zwei oder drei Größenordnungen in den Schatten.

-Matt

  • Diese Antwort stammt vom Autor.

    – RaGa__M

    2. September 2020 um 11:01 Uhr

Meistens wird dies getan, um mehrere zusätzliche Fälle zu behandeln. In diesem Fall sagen wir das zum Beispiel SPINLOCK_SHARED kann nicht 1 sein:

int SPINLOCK_SHARED = 0x01

int res = (SPINLOCK_SHARED | 1) - 1 // 0

  • Diese Antwort stammt vom Autor.

    – RaGa__M

    2. September 2020 um 11:01 Uhr

1407760cookie-check(x | y) – y warum kann es nicht einfach x oder gar `x | sein 0`

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy