Wenn man ne richtige Datenstruktur schützt muss man immer zusätzlich einen Lock oder eine Semaphore vorsehen.
Der Meinung bin ich ja auch, nur als ich mich über den cmpxchg Befehl informieren wollte, wurde mir mal so ein Bsp. an den Kopf geknallt, das es doch besser ist diesen zu verwenden, wenn man nur eine Variable schützen möchte, als die Variable mit einem Lock zu schützen. Das leuchtet mir ja auch ein, aber warum sollte ich nur ne Variable ändern wollen die geschützt werden muss??
Da bin ich mir nicht mehr sicher. Zuerst war ich von den ganzen PUSHs und POPs irritiert und dann von ":[output] "=q"(spinlock->flags)" (deshalb dachte ich das bei "testl $1,(%%eax)\n\t" irgendwas in Abhängigkeit von den Flags aus dem Struct gemacht wird). Nach jetzt noch mal einigen Minuten Konzentration bin ich (fast) geneigt Dir recht zu geben.
Falls du dich besser fühlst, ich hasse die AT&T Syntax auch, aber GAS/GCC will du nunmal haben (ja ich weiß da gibts so´n switch der zur Intelsyntax wechselt).
Also die ganzen Push´s und Pop´s sind für die Flags, wenn du im Kernel nen Spinlock nutzt und die Ints ausschaltest und dann bei der Freigabe wieder anmachst, kann es sein das du das gar nicht "durftest", das sie bereits aus waren bevor du versucht hast den Lock zu bekommen.
Also als erstes speichere ich die Flags "pushfl", dann deaktiviere ich die Ints und dann gehe ich in eine Schleife wo ich gucke ob der Lock frei ist, ist das nicht der Fall aktiviere ich die ints wieder (obwohl das so nicht stimmt, ich setzte sie auf den Wert der vorher drin stand, deswegen auch "popfl; pushfl") und mache ne "pause"
Ist der Lock frei, wird versucht über "lock bts ..." den Lock zu bekommen, hat das nicht geklappt, geht der ganze Spaß wieder von vorne los.
":[output] "=q"(spinlock->flags)" heißt dass das Register "[output]" (anstelle von %0 oder %1, weil ich es lesbarer finde) eins von allen 6 (deswegen auch "q") sein kann.
In EAX steht die Adresse des Locks und mit "testl $1,(%%eax)" teste ich ob der Lock frei ist oder nicht.
Ganz unabhängig davon finde ich so eine vorgelagerte Schleife irgendwie sinnlos, klar wird beim warten möglicherweise etwas weniger Traffic auf dem CPU-Netzwerk erzeugt aber deshalb gibt doch der momentane Besitzer den Lock nicht schneller frei, oder irre ich da auch schon wieder?
Ist erstmal richig, aber ... Das mit dem Lock kommt noch und durch die "pause" wird die CPU entlastet, verbraucht weniger Strom (bin mir net sicher ob das so stimmt), legt wirklich ne kleine Pause ein und belastet damit nicht den Speicherbus und falls du auf ner CPU mit Hyperthreading läufst, kann so der andere logische Kern die Einheiten besser nutzen (stell dir es wie ein ganz kurzes "hlt" vor).
Gerade bei einer Semaphore musst Du wissen wie viele schon drin sind und da reicht ein einfacher add nicht, auch nicht mit lock-Präfix.
Da hast du natürlich recht, ich weiß auch nicht woran ich da dachte. Das einzige was mir spontan einfällt ist, wenn du das mit dem counter einer Semaphore machst (also das gelockete add) dann könntest du etwas sowas machen:
lock sub [eax],1
jae .locked
;versuche den spinlock für den Code zu bekommen
;füge den aktuellen thread der Queue hinzu und warte bis du aufgeweckt wirst
.locked:
;du darfst weiter machen
Ich bin mir jetzt aber nicht sicher ob das auch wirklich funktionieren würde. Was ich damit meine ist, das du nur versuchen musst den Spinlock der Semaphore zu bekommen, wenn du sowieso warten musst, ansonsten kannst du ja auch ganz einfach weiter machen. Beim Release dann das ganze umgekehrt, du machst nen gelocktes add und wenn es kleiner als 0 (also negativ) ist, versuchst du den Spinlock zu bekommen und weckst den nächsten Thread auf. So kann es im optimalen Fall passieren das du den Spinlock gar nicht bekommen musst. Wäre also nochmal nen Stück schneller/besser. Aber wie gesagt, ist jetzt ne spontane Idee (um mein Bsp. nicht als sinnlos dastehen zu lassen
) und müsste halt ausprobiert werden.
Was genau meinst Du mit diesem Satz? Für Deinen BTS-Befehl benutzt Du doch auch das LOCK-Präfix.
Der Punkt ist, das ich den Speicherbus nur locke, wenn ich vermute das der Lock frei ist. Du hingegen lockst den immer, bei jedem Zugriff. Soweit wie ich es verstanden habe, geht es darum, das alle anderen Zugriffe warten müssen bis du fertig bist und da man ja alles möglichst parallel macht bremst das halt tierisch die Performance. Weil ansonsten ja auch parallel aus dem Speicher gelesen werden kann, aber wenn du den Bus lockst ist das nicht mehr möglich. Ich hoffe ich war einigmaßen verständlich!
Ich meine die ganze Situation ist sowieso nur für SMP Systeme interessant, weil du auf nem 1 CPU System den Lock immer bekommst. Auf nem SMP System arbeiten alle CPUs gleichzeitig und greifen auch gleichzeitig auf den Speicher zu (und jetzt kommt der Buslock), es sei denn du lockst denn Bus, dann müssen alle auf dich warten.