Thread local storage
« | 18 Sep 2022 | »Einer der Gründe, warum ich auf meinem Weg zu C++ außerhalb von Betriebssystemen stolpere, liegt am “thread local storage”.
Denn wo werden Exception-Daten abgelegt?
Offenbar genau dort!
Und was mir fehlt ist ein funktionierender Nachbau von __tls_get_addr
.
Egal wie “free-standing” man sein Projekt kompiliert, ein Linux-GCC mischt zwangsläufig Linux-Standards in den Code. Und das betrifft vor allem C++ Exceptions und das dazugehörige Runtime-Type-Information (RTTI) System.
Wenn nämlich in einem Thread eine Exception fliegt, muss der Callstack rückabgewickelt werden, bis zum letzten installierten Exception Handler und auf dem Weg dorthin müssen alle herumliegenden Objekte freigegeben werden.
Das erfordert den Zugriff auf zwei OS-nahe Ressourcen:
- Die ELF-Sections mit Cleanup-Codes, die an das Speicherlayout angepasst sind
- Der Thread-local-storage, in dem die gültigen Exception Handler verlinkt sind.
Beide Ressourcen erfordern eine tiefe Kenntnis und “Konformität” zu den
Strukturen, wie Linux und die jeweilige C-Lib damit umgehen.
Und das ist unter Windows leider auch nicht anders.
Noch krasser wird die Geschichte, weil die neueren C-Standards ab C11 mit der
_Thread_local
Speicherklasse einem jeden Datentypen ermöglichen, zum Thread
gehören zu können und im Hintergrund nötige Anpassungen machen.
Offiziell erreicht man den Thread-local-storage über entsprechende APIs, wie pthread_key_create() und pthread_get/setspecific() oder TlsAlloc und TlsSetValue unter Windows.
Doch wie sich zeigt umgehen die internen Funktionen des GCC die POSIX API und
wollen mit APIs wie __tls_get_addr()
arbeiten und nutzen dann ihr
Geheimwissen und adressieren die Unterfelder dann direkt.
Ich habe nun länger nach Infos zu all diesen Details gesucht und
interessante Dinge über den TCB (thread control block) und den
DTV (dynamic thread vector) gelesen
… aber geholfen hat mir das leider nicht.
Fazit: Keinen Thread-local-storage nutzen!
Was ich mit C++ Exception machen soll, weiß ich noch nicht,
aber ich habe zumindest gelernt, dass der leichtsinnige
Einsatz von _Thread_local
kontraproduktiv sein kann.
Für mein UEFI Thema führt offenbar wirklich kein Weg daran vorbei, den
GCC und seine Kernbibliotheken neu zu bauen, denn dort hat man ein
paar Möglichkeiten, die Arbeitsweise zu beeinflussen.
Es gibt schließlich auch Mikrocontroller-Zielplattformen, die all
den Schnickschnack auch nicht unterstützen.