Verwirklichung von thread_local



  • Hallo zusammen,

    ich frage mich gerade, wie man thread_local intern umsetzt.
    Also ich stelle mir es im Moment so vor:
    An einer fest definierten Stelle innerhalb des Stack Segments (z.B. 0x0000012 - wahrscheinlich nähe Anfang oder Ende) liegt eine map.
    Als (eindeutiger) key würde sich eventuell der Instruction Pointer des Befehls davor (oder danach) anbieten.
    Als value hat man dann das entsprechende Objekt.

    Liege ich mit meiner Vorstellung wenigstens annähernd richtig oder komplett falsch?
    Ich gehe nicht davon aus, dass der Standard vorschreibt wie es zu verwirklichen ist, aber evtl. gibt es eine gängige Umsetzung.

    Gruß und guten Rutsch,
    XSpille



  • An einer fest definierten Stelle innerhalb des Stack Segments (z.B. 0x0000012 - wahrscheinlich nähe Anfang oder Ende) liegt eine map.

    Naja, dazu müsste man erstmal wissen wo der Stack anfängt. Weiss man aber nicht unbedingt, der Stack-Zeiger zeigt ja irgendwo mitten in den Stack rein. Man muss also das OS bemühen.
    Windows z.B. bietet dazu Funktionen an.
    Mit TlsAlloc holt man sich einen "key" (TLS index), und mit TlsSetValue/TlsGetValue kann man auf den Wert zugreifen (Wert = void-Zeiger).

    Der Compiler könnte dann hergehen und sich einen solchen TLS index holen, und den void* auf eine eigene Datenstruktur zeigen lassen.

    Da drin kann dann eine map sein oder ein Array oder was auch immer.

    Unter Windows gibt es allerdings noch eine andere Möglichkeit: man kann gleich das PE Format verwenden. Wie genau das abläuft weiss ich nicht. Ich schätze aber dass es effizienter sein wird als wenn der Compiler selbst was stricken muss.
    Bis Windows XP konnte man DLLs die dieses Feature nutzen nicht per LoadLibrary nachträglich laden, sondern nur "statisch". Soll mit Vista aber behoben sein.

    Und es würde mich nicht wundern, wenn andere Betriebssysteme ähnliche Features anbieten.

    Als (eindeutiger) key würde sich eventuell der Instruction Pointer des Befehls davor (oder danach) anbieten.

    Adressen von Befehlen halte ich für eher problematisch. Dazu müssten vermutlich der Code-Generator und Optimizer angepasst werden. Halte ich nicht für sinnvoll. Man könnte aber Dummy-Variablen erzeugen, von denen man nur die Adresse verwendet.
    Oder man lässt den Linker ne Liste von thread-local Variablen führen, und vergibt dann einfach ansteigende Nummern.



  • Danke hustbaer!

    Von den Windows-Funktionen habe ich gehört. Allerdings braucht man ja jetzt vermutlich keinen 'langsamen' string als Identifikation.

    hustbaer schrieb:

    Naja, dazu müsste man erstmal wissen wo der Stack anfängt. Weiss man aber nicht unbedingt, der Stack-Zeiger zeigt ja irgendwo mitten in den Stack rein.

    Ich dachte der aktuelle Stackeintrag wird über SS[SP] adressiert. Ist dann nicht immer SS[0x00000012] während des Programm-Ablaufs immer gleich?

    hustbaer schrieb:

    Oder man lässt den Linker ne Liste von thread-local Variablen führen, und vergibt dann einfach ansteigende Nummern.

    Das funktioniert aber doch nicht bei dynamisch geladenen Libraries, oder?
    Deswegen dachte ich, dass der Instruction Pointer eindeutig ist. (Auch bei dynamisch geladenen Libraries oder wird da das Stack Semgent verändert?)

    EDIT: Man kann natürlich zwischen statisch gelinken Programm-Teilen und dynamischen Libraries differenzieren, so dass es sicherlich bei statisch gelinktem Code performanter ist. 👍



  • Win32 verwendet nur wenige unterschiedliche Segment-Deskriptoren. Der Stack wird zwar über SS adressiert, nur dass SS mit dem gleichen Deskriptor geladen ist wie DS und CS. Was ziemlich praktisch ist, da man dann überall die gleichen Adressen verwenden kann.

    FS zeigt auf den Thread Information Block.

    http://en.wikipedia.org/wiki/Win32_Thread_Information_Block

    In dem gibt es mal die ersten 64 TLS Slots.
    Wenn der Platz da drinnen ausgeht, dann werden vermutlich über die "TLS links" Liste weitere Blöcke eingeklinkt.

    Wenn Windows es irgendwie hinbringt, dass auch die TLS Slots >= 64 an fixen Offsets liegen, dann müsste es sogar gehen dass man "direkt" über FS auf TLS Slots zugreift.

    Das funktioniert aber doch nicht bei dynamisch geladenen Libraries, oder?

    Das funktioniert genau dann bei DLLs, wenn jemand dafür sorgt dass es funktioniert 🙂
    D.h. wenn z.B. der PE-Loader irgendwas macht damit es geht, dann geht es halt.
    Oder wenn die Runtime beim Laden der DLL die Indexe mit nem entsprechenden Offset versieht. Wie auch immer, irgendwie bekommt man das schon hingebogen.


Anmelden zum Antworten