Hallo! Ich versuche gerade das Context Switching zwischen Tasks nachzuvollziehen. Bei ChibiOS (Cortex-M3) und in diversen Artikeln über CS wird der Stack-Pointer und die relevanten Register wiederhergestellt. Nun meine eigentliche Frage: Ein Thread startet nach einem anderen, d.h. dieser hat einen SP oberhalb des alten. Wenn nun umgeschalten wird, wird der SP des ersten Threads geladen. Soweit so gut, was passiert aber wenn innerhalb des ersten Threads funktionen aufgerufen werden, also Dinge in den Stack geschrieben werden. Wird dann nicht der Stack korrumpiert? Mag sein, dass ich etwas im ARM ARM, Procedure Call Standard oder der Technical Reference Manual überlesen habe. Das sind aber auch dicke Schinken und wenn man nicht genau weiß was man sucht ist man verloren. Gruß, Peter
Peter Pan schrieb: > Soweit so gut, was passiert aber wenn > innerhalb des ersten Threads funktionen aufgerufen werden, also Dinge in > den Stack geschrieben werden. Wird dann nicht der Stack korrumpiert? ganz bestimmt nicht. Ich kenne zwar ChibiOS nicht, aber üblich ist das jeder Thread seinen eigenen Stack hat. Dieser wird beim Takswechel mit umgeschaltet.
Die Stacks müssen natürlich ausreichend Abstand haben, sprich die Stackgröße muss ausreichend bemessen sein. Stack Overflows sind nie gut, ob der Overflow jetzt in einen anderen Stack reinläuft oder in den Heap oder globale Variablen ist egal, nur das Fehlerbild ändert sich.
Dazu gibt es zwei Techniken (drei, wenn man eine MMU hat, also nicht in diesem Fall): - Jeder Thread kriegt seinen eigenen Stack, und man lässt auf gut Glück genug Platz zwischen den Stacks, dass das dann schon passen wird (mit Erfahrungswerten, Daumen drücken und hoffen und so) - Man benutzt einen sogenannten segmentierten Stack. Das ist hierbei der übliche Stand der Technik. Der Compiler, nicht das OS, steuert das: Er kann für jede Funktion während des Compilierens feststellen, wie viel Stack die Funktion braucht (ausser man benutzt alloca oder variabel große Arrays, in dem Fall wird der Compiler das gesondert behandeln). Wenn er das weiß, kann er zu Beginn der Funktion bereits allen nötigen Stack-Speicher reservieren, so dass bei einem Thread-Wechsel gefahrlos eine anderer Thread Stack belegen kann. Jeder Thread hat also seinen Stack-Pointer, und ein zusätzlicher Pointer zeigt an, wo neuer Speicher belegt werden kann. Da das Verfahren in dieser Weise viel Verwaltungsaufwand bei jedem einzelnen Funktionsaufruf benötigt und zudem zu Speicherfragmentation (d.h. ungenutzte Speicherbereiche, die nicht neu belegt werden können, weil sie z.B. zu klein sind) führen kann, wird einem Thread üblicherweise Stack-Speicher in fester Blockgröße (z.B. 128 Byte) zugewiesen. Eine Funktion muss dann am Anfang nur prüfen, ob der aktuelle Block noch genug Platz hat. Das erledigen manche Compiler in nur 2 Maschinenbefehlen, ist also für den häufigsten Fall sehr schnell. Passt das, dann arbeitet die Funktion als ob es keinen segmentierten Stäck gäbe. Reicht der aktuelle Block nicht aus, oder benötigt eine Funktion mehr als einen ganzen Block, dann wird erst die langsame Speicherverwaltung durchgeführt. In der Mitte freigewordene Blöcke können dann auch problemlos wiederverwendet werden, so dass die Fragmentation wesentlich geringer ausfällt. Sie entsteht aber trotzdem, da ein Block am Ende üblicherweise immer ein paar ungenutzte Bytes hat, weil dort die nächste Funktion nicht mehr passte.
Stack Overflows hbe ich auch schon fabriziert... da auf den Fehler muss man erstmal drauf kommen ohne große Erfahrung :-). Vielen Dank an Euch, ich suche dann mal danach wo die Stacks zugewiesen werden. Es war nur etwas eigenartig, dass auf einem Core ohne MMU den SP quasi 'beliebig' ändert, ohne dass Probleme auftreten. Vielen Dank für die Raschen Antworten! Peter
Sam P. schrieb: > wenn man eine MMU hat Der Cortex-M3 hat eine MPU mit der die Stacks der Threads begrenzt werden können. Somit sollte es keinen Stack Overflow geben. Zudem hat der Cortex-M3 User und Privileged Mode, und das OS sollte im Privileged Mode laufen und notfalls über den Memory Fault Handler mehr Stack bereitstellen.
Lothar schrieb: > Der Cortex-M3 hat eine MPU mit der die Stacks der Threads begrenzt > werden können. Die MPU ist optional, nicht obligatorisch. Es gibt sie also nicht in allen Implementierungen mit Cortex-M3. > notfalls über den Memory Fault Handler mehr Stack > bereitstellen. Das ist mit einer MPU, die keine Adressen verändert sondern nur überprüft, kaum realistisch. Denn ob da grad Platz für eine Erweiterung wäre, das wäre entweder pures Glück, oder der betreffende Platz war dafür reserviert wurden - dann aber hätte man den auch genauso gut vorneweg zuweisen können. Man sollte auch im Auge behalten, dass die MPU der Cortex-M3 nur wenige kontrollierte Speicherbereiche ermöglicht und bei Grösse und Platzierung nur Zweierpotenzen zulässt. Das schränkt die Möglichkeiten von dynamischer Speicherverwaltung bei Systemen mit eher knapper RAM-Ausstattung weiter ein (das ist der Hauptmarkt von Systemen mit diesem Core). Um Stacks in den Grenzen des Gesamtverbrauchs kalkulierbar dynamisch gestalten zu können benötigt man eine MMU, keine MPU. Eine MPU eignet sich besser dafür, eine vorwiegend statische Speicherzuteilung gegen Amok laufenden Code abzusichern.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.