Paldium
Well-Known Member
Wenn ich Speicherbarrieren richtig verstanden habe, dann stellen sie sicher, dass der Compiler Code nur zwischen zwei Barrieren beliebig austauschen darf. Zwei Barrieren wären "volatile" Variablen und Funktionsaufrufe.
Mein Beispielcode wäre dieser hier:
So weit, so simpel. Ich nehme an, dass die if-Abfrage nicht umsortiert wird, weil eine Umsortierung die Bedeutung des Codes ändern würde. Der malloc-Aufruf ist eine Speicherbarriere, weil es ein externer Funktionsaufruf ist.
Nun zum LIST_INSERT_HEAD... Das ist nämlich ein Makro. Aufgelöst sieht der Aufruf so aus:
Der Compiler müsste LIST_INSERT_HEAD und c->fn = "hallo" austauschen dürfen. Oder übersehe ich eine Regel?
Der Code stammt aus einem Programm, das ohne Threads arbeitet. Hat aber einen Signalhandler, der auf eben diese Liste zugreift. Ich würde jetzt sagen, dass das Programm zwei Schwächen hat:
- Elemente können in der Liste auftauchen, die "fn" nicht gesetzt haben. Und zwar dann, wenn der Code umsortiert wurde und das Signal genau zwischen den zwei Aufrufen kommt.
- Pointer-Zuweisungen sind nicht garantiert atomar. Stimmt das auf irgendeinem System, das von *BSD unterstützt wird?
Ich hab den Code testweise mit GCC kompiliert und den Signalhandler alle paar Millisekunden aufrufen lassen. Offenbar hab ich keine Optimierungsstufe gefunden, die den Code umsortieren würde. Wenn ich es per Hand umsortiere, braucht es nur ein paar Sekunden, bis der Signalhandler auf so ein Element stößt. Deshalb weiß ich jetzt nicht, ob das Programm eben doch richtig ist (und ich falsch liege :P) oder ob es einfach nur Glück war.
Mein Beispielcode wäre dieser hier:
Code:
struct cleanable *c;
c = malloc(sizeof(*c));
if (c == NULL)
break;
c->fn = "hallo";
LIST_INSERT_HEAD(&head, c, files); /* head is global */
So weit, so simpel. Ich nehme an, dass die if-Abfrage nicht umsortiert wird, weil eine Umsortierung die Bedeutung des Codes ändern würde. Der malloc-Aufruf ist eine Speicherbarriere, weil es ein externer Funktionsaufruf ist.
Nun zum LIST_INSERT_HEAD... Das ist nämlich ein Makro. Aufgelöst sieht der Aufruf so aus:
Code:
do {
if (((c)->files.le_next = (&head)->lh_first) != ((void *)0))
(&head)->lh_first->files.le_prev = &(c)->files.le_next;
(&head)->lh_first = (c); (c)->files.le_prev = &(&head)->lh_first;
} while ( 0);
Der Compiler müsste LIST_INSERT_HEAD und c->fn = "hallo" austauschen dürfen. Oder übersehe ich eine Regel?
Der Code stammt aus einem Programm, das ohne Threads arbeitet. Hat aber einen Signalhandler, der auf eben diese Liste zugreift. Ich würde jetzt sagen, dass das Programm zwei Schwächen hat:
- Elemente können in der Liste auftauchen, die "fn" nicht gesetzt haben. Und zwar dann, wenn der Code umsortiert wurde und das Signal genau zwischen den zwei Aufrufen kommt.
- Pointer-Zuweisungen sind nicht garantiert atomar. Stimmt das auf irgendeinem System, das von *BSD unterstützt wird?
Ich hab den Code testweise mit GCC kompiliert und den Signalhandler alle paar Millisekunden aufrufen lassen. Offenbar hab ich keine Optimierungsstufe gefunden, die den Code umsortieren würde. Wenn ich es per Hand umsortiere, braucht es nur ein paar Sekunden, bis der Signalhandler auf so ein Element stößt. Deshalb weiß ich jetzt nicht, ob das Programm eben doch richtig ist (und ich falsch liege :P) oder ob es einfach nur Glück war.