- Was ist der Unterschied zwischen Kernel-Stack und Benutzer-Stack?
Kurz gesagt, nichts - abgesehen von der Verwendung einer anderen Speicherstelle (und damit eines anderen Werts für das Stapelzeigerregister) und normalerweise unterschiedlichen Speicherzugriffsschutzen. D.h. Bei der Ausführung im Benutzermodus ist der Kernel-Speicher (ein Teil davon ist der Kernel-Stack) nicht zugänglich, selbst wenn er zugeordnet ist. Umgekehrt, ohne ausdrücklich vom Kernel-Code angefordert zu werden (unter Linux durch Funktionen wie copy_from_user()
), ist der Benutzerspeicher (einschließlich des Benutzerstapels) normalerweise nicht direkt zugänglich.
- Warum wird [ ein separater ] Kernel-Stack verwendet ?
Trennung von Privilegien und Sicherheit. Zum einen können User-Space-Programme ihren Stapel (Zeiger) beliebig gestalten, und es gibt normalerweise keine architektonische Anforderung, überhaupt einen gültigen zu haben. Der Kernel kann daher nicht vertrauen der Stapelzeiger des Benutzerraums weder gültig noch verwendbar ist und daher einen Satz unter seiner eigenen Kontrolle erfordern wird. Verschiedene CPU-Architekturen implementieren dies auf unterschiedliche Weise; x86-CPUs schalten Stapelzeiger automatisch um, wenn Privilegmoduswechsel auftreten, und die Werte, die für verschiedene Privilegebenen verwendet werden sollen, sind konfigurierbar – durch privilegierten Code (d. h. nur der Kernel).
- Wenn eine lokale Variable in einer ISR deklariert wird, wo wird sie gespeichert?
Auf dem Kernel-Stack. Der Kernel (also Linux-Kernel) tut das nicht Haken Sie ISRs direkt an die Interrupt-Gates der x86-Architektur sondern delegiert stattdessen die Unterbrechungszuteilung an einen gemeinsamen Kernel-Unterbrechungseintritts-/-austrittsmechanismus, der den Zustand des Registers vor der Unterbrechung speichert, bevor er den/die registrierten Handler aufruft. Die CPU selbst kann beim Versenden eines Interrupts einen Privilegien- und/oder Stack-Switch ausführen, und dieser wird vom Kernel verwendet/eingerichtet, so dass sich der gemeinsame Interrupt-Eintrittscode bereits darauf verlassen kann, dass ein Kernel-Stack vorhanden ist.
Das heißt, Interrupts, die während der Ausführung von Kernel-Code auftreten, verwenden einfach (weiterhin) den Kernel-Stack, der zu diesem Zeitpunkt vorhanden ist. Dies kann, wenn Interrupt-Handler tief verschachtelte Aufrufpfade haben, zu Stapelüberläufen führen (wenn ein tiefer Kernel-Aufrufpfad unterbrochen wird und der Handler einen weiteren tiefen Pfad verursacht; unter Linux wird Dateisystem / Software-RAID-Code durch Netzwerkcode mit aktivem iptables unterbrochen Es ist bekannt, dass dies in ungetunten älteren Kerneln ausgelöst wird ... die Lösung besteht darin, die Kernel-Stack-Größen für solche Arbeitslasten zu erhöhen).
- Hat jeder Prozess seinen eigenen Kernel-Stack?
Nicht nur jeder Prozess - jeder Thread hat seinen eigenen Kernel-Stack (und tatsächlich auch seinen eigenen Benutzer-Stack). Denken Sie daran, dass der einzige Unterschied zwischen Prozessen und Threads (zu Linux) darin besteht, dass mehrere Threads einen Adressraum gemeinsam nutzen können (und einen Prozess bilden).
- Wie koordiniert der Prozess zwischen diesen beiden Stapeln?
Überhaupt nicht – das muss nicht sein. Das Scheduling (wie / wann verschiedene Threads ausgeführt werden, wie ihr Zustand gespeichert und wiederhergestellt wird) ist die Aufgabe des Betriebssystems und Prozesse müssen sich nicht darum kümmern. Wenn Threads erstellt werden (und jeder Prozess muss mindestens einen Thread haben), erstellt der Kernel Kernel-Stacks für sie, während User-Space-Stacks entweder explizit erstellt/bereitgestellt werden, je nachdem, welcher Mechanismus zum Erstellen eines Threads verwendet wird (Funktionen wie makecontext()
oder pthread_create()
dem Aufrufer erlauben, einen Speicherbereich anzugeben, der für den Stack des "untergeordneten" Threads verwendet werden soll) oder vererbt (durch Speicherklonen bei Zugriff, normalerweise als "Copy on Write" / COW bezeichnet, wenn ein neuer Prozess erstellt wird).
Das heißt, der Prozess kann Scheduling seiner Threads beeinflussen und/oder den Kontext beeinflussen (Zustand, darunter ist der Stapelzeiger des Threads). Dafür gibt es mehrere Möglichkeiten:UNIX-Signale, setcontext()
, pthread_yield()
/ pthread_cancel()
, ... - aber das schweift etwas von der ursprünglichen Frage ab.
Meine Antwort wird von anderen SO-Fragen mit meinen Sachen gesammelt.
What's the difference between kernel stack and user stack?
Als Kernel-Programmierer wissen Sie, dass der Kernel vor fehlerhaften Benutzerprogrammen geschützt werden sollte. Angenommen, Sie behalten denselben Stack für Kernel und Benutzerbereich bei, dann stürzt ein einfacher Segfault in der Benutzeranwendung den Kernel ab und muss neu gestartet werden.
Es gibt einen "Kernel Stack" pro CPU wie ISR Stack und einen "Kernel Stack" pro Prozess. Es gibt einen "Benutzer-Stack" für jeden Prozess, obwohl jeder Thread seinen eigenen Stack hat, der sowohl Benutzer- als auch Kernel-Threads enthält.
http://linux.derkeiler.com/Mailing-Lists/Kernel/2004-10/3194.html
Why kernel stack is used?
Wenn wir uns also im Kernel-Modus befinden, ist ein Stack-Mechanismus erforderlich, um mit Funktionsaufrufen umzugehen, lokale Variablen ähnlich dem Benutzerbereich.
http://www.kernel.org/doc/Documentation/x86/kernel-stacks
If a local variable is declared in an ISR, where it will be stored?
Es wird im ISR-Stack (IRQSTACKSIZE) gespeichert. Die ISR läuft nur dann auf einem separaten Interrupt-Stack, wenn die Hardware dies unterstützt. Andernfalls werden die ISR-Stapelrahmen auf den Stapel des unterbrochenen Threads geschoben.
Der Benutzerraum weiß nicht und kümmert sich ehrlich gesagt auch nicht darum, ob der Interrupt im Kernel-Stack des aktuellen Prozesses oder in einem separaten ISR-Stack bedient wird. Da Interrupts pro CPU kommen, muss der ISR-Stack pro CPU sein.
Does each process has its own kernel stack ?
Ja. Jeder Prozess hat seinen eigenen Kernel-Stack.
Then how the process coordinates between both these stacks?
Die Antwort von @FrankH sieht für mich großartig aus.