Warum Kernel-Code / Thread im Interrupt-Kontext ausführen kann nicht schlafen?

StackOverflow https://stackoverflow.com/questions/1053572

  •  20-08-2019
  •  | 
  •  

Frage

Ich lese folgende Artikel von Robert Love

http://www.linuxjournal.com/article/6916

das sagt

“... Lassen Sie sich die Tatsache diskutieren, dass die Arbeit Warteschlangen in Prozesskontext ausgeführt werden. Dies steht im Gegensatz zu den anderen unterer Hälfte Mechanismen, die alle laufen im Interrupt-Kontext.-Code im Interrupt-Kontext ausgeführt wird, um zu schlafen nicht in der Lage ist, oder Block , da Interrupt-Kontext neu zu planen keinen Rückhalt Prozess, mit dem hat. Daher kann, da Interrupt-Handler nicht mit einem Prozess verbunden ist, gibt es nichts für die Planer in dem Schlaf zu bringen und, was noch wichtiger ist, nichts für den Scheduler zu wecken. .. "

Ich bekomme es nicht. AFAIK, Scheduler im Kernel ist O (1), das durch die Bitmap-implementiert ist. Also, was hält die scehduler davon ab, Interrupt-Kontext zu schlafen und am nächsten planbaren Prozess zu nehmen und sie die Steuerung vorbei?

War es hilfreich?

Lösung

Ich denke, es ist eine Design-Idee.

Sicher, können Sie ein System entwerfen, die Sie in Interrupt schlafen können, aber außer in dem System schwer zu begreifen und kompliziert (viele viele Situation, die Sie berücksichtigen müssen) zu machen, dann ist das nichts helfen. Also von einer Entwurfsansicht, Interrupt-Handler deklarieren kann nicht schlafen ist sehr klar und einfach zu implementieren.


Von Robert Love (ein Kernel-Hacker): http://permalink.gmane.org/gmane.linux.kernel.kernelnewbies/1791

Sie können nicht in einem Interrupt-Handler schlafen, weil Unterbrechungen haben keine ein Trägerprozesskontext, und somit gibt es nichts zurück zur Umschuldung in. Mit anderen Worten, Interrupt-Handler nicht mit einer Aufgabe verbunden ist, so gibt es nichts zu „schlafen gelegt“ und (noch wichtiger) „nichts zu aufwacht“. Sie müssen atomar ausgeführt werden.

Dies ist nicht anders als bei anderen Betriebssystemen. In den meisten Betriebssystemen, Interrupts werden nicht eingefädelt. Untere Hälfte oft sind jedoch.

Der Grund für die Seitenfehlerbehandler schlafen kann, ist, dass es nur aufgerufen wird, von Code, der im Prozesskontext ausgeführt wird. Da der Kernel eigenen Speicher nicht durchgeblättert ist, nur User-Space-Speicherzugriffe können ergebnis Seitenfehler. Somit ist nur ein paar bestimmte Orte (wie zB Anrufe copy_ {an, von} _USER ()) kann einen Seitenfehler im Kernel verursachen. Jene Plätze müssen alle durch Code vorgenommen werden, die schlafen können (das heißt, Prozesskontext, keine Schlösser, et cetera).

Andere Tipps

  

Also, was die scehduler davon ab, Interrupt-Kontext hält neben planbaren Prozess zu schlafen und zu nehmen und sie die Kontrolle vorbei?

Das Problem ist, dass der Interrupt-Kontext kein Prozess ist, und kann daher nicht in den Schlaf gebracht werden.

Wenn ein Interrupt auftritt, speichert der Prozessor die Register auf den Stapel und springt an den Anfang der Interrupt-Service-Routine. Das bedeutet, dass, wenn der Interrupt-Handler ausgeführt wird, ist es im Rahmen des Prozesses ausgeführt wird, der ausgeführt wurde, als die Unterbrechung auftrat. Die Unterbrechung wird an diesem Prozess des Stapels ausgeführt wird, und wenn der Interrupt-Handler abgeschlossen ist, wird dieser Prozess fortgesetzt ausgeführt wird.

Wenn Sie versucht haben oder Block innerhalb eines Interrupt-Handler zu schlafen, würden Sie nicht nur die Interrupt-Handler stoppen aufzuwickeln, sondern auch den Prozess der sie unterbrochen. Dies könnte gefährlich sein, da die Interrupt-Handler nicht wissen, was der unterbrochene Prozess haben tat, oder auch wenn es sicher ist, für das Verfahren ausgesetzt werden.

Ein einfaches Szenario, in dem die Dinge schief gehen könnte ein Deadlock zwischen dem Interrupt-Handler und den Prozess unterbricht er sein würde.

  1. Process1 tritt Kernel-Modus.
  2. Process1 akquiriert locka .
  3. Interrupt auftritt.
  4. ISR beginnt mit der Ausführung Process1 's-Stack.
  5. ISR versucht zu erwerben locka .
  6. ISR ruft Schlaf warten locka freigegeben werden.

An diesem Punkt haben Sie eine Sackgasse. Process1 kann nicht fortgesetzt werden, bis die Ausführung der ISR mit seinem Stack erfolgt. Aber die ISR blockiert wartet Process1 lösen locka .

Da die Thread-Umschalt-Infrastruktur an diesem Punkt nicht verwendbar ist. Wenn ein Interrupt-Service, nur Sachen höherer Priorität ausführen können - Siehe Intel Software Developer Manual auf Interrupt, Aufgaben- und Prozessor Priorität . Wenn ja ein anderer Thread erlauben auszuführen (was Sie in Ihrer Frage implizieren, dass es einfach sein würde, zu tun), würden Sie nicht in der Lage sein, um es etwas tun zu lassen - wenn es einen Seitenfehler verursacht werden, müssten Sie Dienste nutzen im Kernel, die unbrauchbar sind, während die Interrupt bedient wird (siehe unten, warum).

Normalerweise Ihr einziges Ziel in einer Interrupt-Routine ist es, das Gerät zu erhalten stoppen zu unterbrechen und etwas zu einer niedrigeren Interrupt-Ebene Warteschlange (in Unix ist dies typischerweise eine Nicht-Interrupt-Ebene, aber für Windows, ist es Versand, apc oder passiv Ebene), das schwere Heben zu tun, wo Sie Zugriff auf weitere Funktionen der Kernels / os haben. Siehe -. einen Handler Implementierung

Es ist eine Eigenschaft, wie O / S arbeiten müssen, nicht etwas inhärent in Linux. Eine Interrupt-Routine kann an jedem Punkt auszuführen, so der Zustand von dem, was Sie unterbrochen ist inkonsistent. Wenn Sie den Thread-Scheduling-Code unterbrochen, sein Zustand ist nicht konsistent, so dass Sie nicht sicher sein können, können Sie „Schlaf“ und Threads wechseln. Auch wenn Sie von den Faden Schaltcode schützen unterbrochen wird, ist Threadwechsel ein sehr hohes Niveau Merkmal des O / S, und wenn Sie alles geschützt stützt sie sich auf ein Interrupt eher ein Vorschlag wird als der Imperativ der Name schon sagt.

  

Also, was die scehduler davon ab, Interrupt-Kontext hält neben planbaren Prozess zu schlafen und zu nehmen und sie die Kontrolle vorbei?

Scheduling geschieht auf Timer-Interrupts. Die Grundregel ist, dass nur eine Unterbrechung zu einem Zeitpunkt geöffnet sein kann, wenn Sie also in den „erhaltene Daten vom Gerät X“ unterbrechen, das Timer-Interrupt laufen schlafen gehen kann, es nicht planen aus.

Unterbricht auch oft und Überlappung passieren. Wenn Sie die „bekam Daten“ in den Schlaf unterbrechen setzen, und dann mehr Daten bekommen, was passiert? Es ist verwirrend (und zerbrechlich) genug, dass die allumfassende Regel: kein Schlaf in Interrupts. Sie werden es falsch machen.

Auch wenn Sie eine ISR setzen könnte schlafen, würden Sie es nicht tun wollen. Sie mögen Ihre ISR so schnell wie möglich, um das Risiko der fehlenden nachfolgende Unterbrechungen zu reduzieren.

ein Interrupt-Handler Verbieten zu blockieren ist eine Designwahl. Wenn einige Daten auf dem Gerät ist, fängt den Interrupt-Handler den aktuellen Prozess, bereitet die Übertragung der Daten und ermöglicht die Unterbrechung; bevor der Handler das aktuelle Interrupt ermöglicht, hat das Gerät zu hängen. Wir halten wollen, dass unsere E / A beschäftigt und unser System anspricht, dann hatten wir besser nicht die Interrupt-Handler blockieren.

Ich glaube nicht, daß die „instabilen Zustände“ sind ein wesentlicher Grund. Prozesse, egal sie in Benutzermodus oder Kernelmodus sind, sollten sich bewusst sein, dass sie durch Interrupts unterbrochen werden. Wenn einige Kernel-Modus-Datenstruktur sowohl Interrupthandler zugegriffen wird, und den aktuellen Prozess, und Race-Bedingung existiert, dann sollte der aktuelle Prozess lokalen Interrupts deaktivieren und darüber hinaus für Multi-Prozessor-Architekturen, spinlocks sollte während der kritischen Abschnitte zu verwendende .

Ich glaube nicht, dass auch wenn die Interrupt-Handler blockiert wurden, kann es nicht aufgeweckt werden. Wenn wir „Block“ sagen, im Grunde bedeutet es, dass der blockierte Prozess für ein Ereignis / Ressource wartet, so dass es verbindet sich in eine Warte-Warteschlange für dieses Ereignis / Ressource. Jedes Mal, wenn die Ressource freigegeben wird, ist der Freigabeprozess für Wach den Warteprozess (es).

Doch das wirklich Ärgerliche ist, dass der blockierte Prozess nichts während der Sperrzeit tun kann; es tat nichts falsch für diese Strafe, die unfair. Und niemand konnte sicher die Sperrzeit vorhersagen, so dass der unschuldige Prozess aus unklaren Grund zu warten hat und für unbegrenzte Zeit.

Von Natur aus ist die Frage, ob in Interrupt-Handler können Sie eine gültige „aktuelle“ erhalten (Adresse für den aktuellen Prozess task_structure), wenn ja, es ist möglich, den Inhalt dort entsprechend ändern sie in „Schlaf“ Zustand zu machen, die durch Scheduler kann später wieder, wenn der Staat irgendwie umziehen. Die Antwort kann hardwareabhängig.

Aber in ARM, es ist nicht möglich, da ‚aktuelle‘ ist irrelevant unter Interrupt-Modus zu verarbeiten. Sehen Sie den Code unten:

#linux/arch/arm/include/asm/thread_info.h 
94 static inline struct thread_info *current_thread_info(void)
95 {
96  register unsigned long sp asm ("sp");
97  return (struct thread_info *)(sp & ~(THREAD_SIZE - 1));
98 }

sp im User-Modus und SVC-Modus sind die „gleicher“ ( „gleich“ hier nicht bedeuten, sie sind gleich, stattdessen sp Punkt des Benutzermodus der User-Space-Stack, während SVC-Modus des sp r13_svc Punkt auf den Kernel-Stack, wo die task_structure des Benutzers Prozess wurde bei vorherigen Taskwechsel aktualisiert, wenn ein Systemaufruf auftritt, Kernraum der Prozess erneut eingeben, wenn die sp (sp_svc) noch nicht geändert, so werden diese 2 sp miteinander verbunden sind, in diesem Sinne, sie‘ re ‚gleiche‘), also unter SVC-Modus kann Kernel-Code die gültigen ‚aktuelle‘ erhalten. Aber unter anderen privilegierten Modi, sagen Interrupt-Modus, sp ist ‚anders‘, zeigen Sie auf spezielle Adresse in cpu_init () definiert. Die ‚aktuelle‘ unter diesem Modus berechnet wird den unterbrochenen Prozess irrelevant sein, Zugriff auf mich in unerwartetem Verhalten führen. Deshalb ist es immer gesagt, dass Systemaufruf schlafen kann aber unterbrechen Handler können nicht, Systemaufruf funktioniert auf Prozesskontext aber nicht unterbrechen.

High-Level-Interrupt-Handler maskieren die Operationen aller niedrigerer Priorität Interrupts, einschließlich derjenigen des Systems Timer-Interrupt. Folglich muss der Interrupt-Handler vermeiden sich in einer Tätigkeit, die, die es könnte dazu führen, zu schlafen. Falls der Handler schläft, dann kann das System hängen, weil der Zeitgeber maskiert und nicht fähig ist, Thread der Einplanung des Schlafes. Ist dies sinnvoll?

Wenn eine höherer Ebene Interrupt-Routine auf den Punkt, wo das nächste, was es hat tun müssen, nach einer Zeit geschehen, dann braucht es eine Anfrage in die Timer-Warteschlange zu stellen, bitten, dass ein andere Interrupt-Routine ausgeführt werden ( bei niedrigerer Prioritätsstufe) einige Zeit später.

Wenn diese Routine läuft unterbrechen, wäre es dann Prioritätsstufe auf das Niveau der ursprünglichen Interrupt-Routine erhöhen zurück, und die Ausführung fortzusetzen. Dies hat den gleichen Effekt wie ein Schlaf.

Der Linux-Kernel hat zwei Möglichkeiten Unterbrechungs-Stack zuzuordnen. Man ist auf dem Kernel Stack des unterbrochenen Prozesses, der andere ist ein spezieller Interrupt-Stapel pro CPU. Wenn der Interrupt-Kontext vollständig auf dem dedizierten Unterbrechungs-Stack pro CPU, dann in der Tat der Interrupt-Kontext gespeichert ist mit keinem Prozess verbunden ist. Die „aktuellen“ Makro wird einen ungültigen Zeiger auf laufenden Prozess herzustellen, da der „aktuelle“ Makro mit einiger Architektur mit dem Stapelzeiger berechnet werden. Der Stapelzeiger in dem Interrupt-Kontext auf den dedizierten Unterbrechungs-Stack zeigen kann, nicht der Kernel-Stack von einigem Prozess.

Es ist nur ein Design / Implementierung Entscheidungen in Linux OS. Der Vorteil dieser Konstruktion ist einfach, aber es kann für Echtzeit-Betriebssystem nicht gut sein.

Andere OSes haben andere Entwürfe / Implementierungen.

Zum Beispiel in Solaris könnten die Interrupts unterschiedliche Prioritäten haben, dass können die meisten Geräte Interrupts in Interrupt-Threads aufgerufen werden. Die Unterbrechungs-Threads ermöglicht Schlaf, weil jede der Unterbrechungs-Threads im Kontext des Gewindes separate Stapel hat. Das Interrupt-Threads Design ist gut für die Echtzeit-Threads, die höheren Prioritäten als Interrupts haben sollte.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top