Interrupt
aus Wikipedia, der freien Enzyklopädie
In der Informatik versteht man unter Interrupt (lat. interruptus, Unterbrechung) die kurzfristige Unterbrechung eines Programms durch eine von der CPU abzuarbeitende Befehlssequenz, die Interrupt Service Routine (=ISR, Unterbrechungsroutine). Anschließend wird die Ausführung des Programmes an der Unterbrechungsstelle fortgesetzt.
Sinn eines Interrupts ist es, schnell auf Ein-/Ausgabe-Signale (z. B. Tastatur, Maus, Festplatte, Netzwerk usw.) oder Zeitgeber (Timer) zu reagieren. Interrupts sind nötig, um auf zeitkritische Ereignisse reagieren zu können. Beispielsweise ist präemptives Multitasking ohne Interrupts nicht möglich, da Tasks sonst nicht mehr unterbrochen und umgeschaltet werden können.
Im Gegensatz dazu gibt es die Technik des zyklischen Abfragens (Polling), um ohne Interrupts den Status von Ein-/Ausgabegeräten, Prozessen, etc. zu erfahren. Diese Methode ist jedoch meist ineffizienter als das Arbeiten mit Interrupts.
Insbesondere bei hardwarenahen ereignisgesteuerten Anwendungen, wie sie z. B. in eingebetteten Systemen üblich sind, wird u. U. praktisch die gesamte Programmausführung des Systems in die Interrupt-Routinen (bzw. in von diesen angestoßene Tasks) verlegt. Der Prozessor wird in einen energiesparenden Schlafzustand (Idle State) gelegt, aus dem er bei Interruptanforderungen erwacht – das eigentliche ‚Hauptprogramm‘ besteht dann im Extremfall nur noch aus einem Initialisierungsteil, welcher nach dem Systemstart durchlaufen wird, gefolgt von einer Endlosschleife, in der (abgesehen vom Aktivieren des o. g. Schlafzustands) gar nichts passiert.
Ausgelöst werden Interrupts durch Elektronikkomponenten (Interrupt Controller) mittels eines so genannten Interrupt Requests (=IRQ, "Unterbrechungsanfrage"), einer Signalisierung an die CPU. Wenn eine Unterbrechungsanfrage von der CPU angenommen wird (nach Ende einer laufenden Instruktion, sofern der Interrupt nicht deaktiviert („maskiert“) ist), wird in einer festen Sequenz (Interruptzyklus) die auslösende Quelle der Unterbrechungsanfrage über den Datenbus identifiziert, dadurch der zugehörige Interruptvektor gefunden und der Sprung zu der Interrupt-Service-Routine (ISR) ausgelöst. Stehen bis zu diesem Zeitpunkt mehrere IRQs von mehreren Quellen an, so wird in einem Auswahlverfahren durch die Hardware (Interrupt Controller) der Vektor der wichtigsten Unterbrechungsanfrage bestimmt (meist durch Prioritätsverfahren; nicht nach Reihenfolge) und angenommen.
Durch Hardware ausgelöste Unterbrechungsanfragen (Hardwareinterrupts) sind normalerweise maskierbar, d. h. die Annahme kann durch eine spezielle Instruktion unterbunden (maskiert) werden. (Notwendig für gewisse zeitkritische und synchronisierende Routinen z. B. in Gerätetreibern.) Bei den meisten CPU-Architekturen sind für Sonderfälle (Stromausfall, Speicherfehler usw.) auch nicht-maskierbare Interrupts (=NMI) implementiert, die immer einen Sprung des Prozessors in die Interruptroutine auslösen. Ohne besondere Maßnahmen können diese NMIs auch ihre eigene Service-Routine (ISR) unterbrechen. Damit dies nicht bei normalen (maskierbaren) Interruptanfragen passiert, maskiert die Interruptlogik in der CPU bei der Interruptannahme noch vor dem Einsprung in die ISR die entsprechenden Interrupts automatisch. Nach Ausführung der ISR wird mit dem Rücksprung in das unterbrochene Programm immer der alte Zustand (durch Rückspeicherung des Statusregisters) wiederhergestellt.
Hardwareinterrupts sind gegenüber dem unterbrochenen Programm grundsätzlich asynchron, d. h. sie treten zu einem unbestimmten Zeitpunkt auf. Daher dürfen Interrupts ohne besondere synchronisierende Maßnahmen keinen direkten Einfluss auf Programme (oder Programmvariablen) ausüben. ISRs sind keine Tasks im Sinne des Betriebssystems.
Einige Prozessoren kennen auch spezielle Befehle, um so genannte Software-"Interrupts" aus einer laufenden Task heraus auszulösen, die außer den besonderen Ein- und Rücksprungbedingungen wie Unterprogrammaufrufe wirken und daher auch nicht asynchron sind. Das gleiche gilt für Traps, die von der CPU bei Fehlern (geschützte Zugriffe, verbotene Instruktionen (z. B. Division durch Null), Singlestep Debugging, Memory-Management-Ereignisse usw.) selbst ausgelöst werden und sinnvollerweise den gleichen Mechanismus benutzen.
[Bearbeiten] Ablauf eines Interrupts
Prinzipieller Ablauf beim Auftreten einer Unterbechungsanfrage (Übergang von Hardware auf Software):
- Hardware (Interruptlogik in der CPU) bestimmt den Interruptvektor des IRQs mit der höchsten Priorität.
- Hardware (CPU) sichert Befehlszähler und Statusregister auf dem Stack.
- Hardware (CPU) holt neuen Befehlszähler (bei einigen Herstellern auch neue Statusregisterdaten) vom Interruptvektor.
- Software der Service-Routine (ISR) sichert (engl.: to store) auch den Inhalt aller Register auf dem Stack, die sie selbst benutzen wird, da sonst die Daten der unterbrochenen Task überschrieben (zerstört) würden.
- ISR läuft (je nach Aufgabe werden z. B. Ein- und/oder Ausgabendaten gepuffert z. B. in einem Ringpuffer; hierbei gehen üblicherweise Zeitbezüge verloren, nicht aber Reihenfolgen).
- Bei Bedarf kann nach Aufruf einer speziellen Betriebssystemfunktion durch die ISR eine entsprechende Task durch den Scheduler des Betriebssystems gestartet (geweckt) werden. Da das eine Zeit dauert, kann evt. zwischenzeitlich der gleiche Interrupt erneut auftreten, was im Algorithmus der ISR zu berücksichtigen ist.
- Software der ISR stellt alle selbst gesicherten Register wieder her (engl. to restore).
- ISR beendet sich durch Rücksprung (Rückspeichern von Befehlszähler und Statusregister vom Stack, der dadurch wieder seinen alten Stand wie vor der Unterbrechung hat, so als wäre nichts gewesen).
- Die aufgerufene Task kann die weitere Bearbeitung der gepufferten Daten übernehmen.
[Bearbeiten] Hardware-Beispiel x86-Architektur
Bei x86-Prozessoren gibt es 256 Interrupts. Wird ein Interrupt aufgerufen, egal ob von der Software oder von der Hardware, so werden Statusregister, Codesegment und Instruction Pointer auf dem Stack gesichert und zu einer Funktion gesprungen, deren Adresse - auch Interruptvektor genannt - in der Interrupttabelle steht.
Im Real Mode befindet sich diese Tabelle in dem ersten Kilobyte des Hauptspeichers (0000h:0000h-0000h:0400h). Jede Interruptnummer benötigt 4 Bytes: 2 Bytes für das Codesegment und 2 für den Offset innerhalb des Segments.
Im Protected Mode der CPU wird die Position in der Interrupt-Deskriptor-Tabelle festgelegt. Hier benötigt sie jedoch mehr Speicher, da hier für jeden Interrupt ein Deskriptor gebraucht wird.