- Interrupt
-
In der Informatik versteht man unter Interrupt (engl. to interrupt, unterbrechen) die kurzfristige Unterbrechung der normalen Programmausführung[1], um eine andere, meist kurze, aber zeitkritische Verarbeitung durchzuführen.
Das auslösende Ereignis wird Unterbrechungsanforderung (Interrupt Request, IRQ) genannt. Danach wird die Unterbrechungsroutine (Interrupt Service Routine, ISR) ausgeführt. Anschließend wird die Ausführung des Programms an der Unterbrechungsstelle fortgesetzt.
Interrupts können beispielsweise von Ein-/Ausgabegeräten gesendet werden, sobald diese eine Aufgabe beendet haben. Dazu wird ein Signal auf den Bus oder direkt an einen dafür vorgesehenen Prozessorpin (IRG-Eingang) gelegt, das extra dafür zugeteilt wurde.[2]
Ältere Computermodelle hatten keine Interrupts.[3] In den 1960er Jahren gab es erste Modelle mit Interrupts, ein Beispiel war die Electrologica X1.
Interrupts werden durch asynchrone externe Ereignisse ausgelöst.[4] Asynchron bedeutet in diesem Zusammenhang, dass das laufende Programm nicht immer an der gleichen Stelle unterbrochen wird.
Inhaltsverzeichnis
Zweck
Sinn eines Interrupts ist es, auf Ein-/Ausgabe-Ereignisse (Signale) (z. B. von Tastatur, Maus, Festplatte, Netzwerk, Zeitgeber/Timer usw.) sofort reagieren zu können, während ein anderer Programmcode (z. B. von Anwendungsprogrammen) abgearbeitet wird. Von der Interface-Hardware wird nur ein Interrupt ausgelöst bzw. ist nur dann erforderlich, wenn die nächste Operation auf dem Interface (Hardware) nicht möglich ist, beispielsweise bei Puffer leer (Ausgabe), Puffer voll (Eingabe), bei Fehlermeldungen der Interface-Hardware oder einem Ereignis selbst ohne Datentransfer (z. B. Timer).
Neben Interrupts gibt es lediglich die Technik des programmierten (zyklischen) Abfragens (Polling), um den Status von Ein-/Ausgabegeräten, Prozessen, etc. zu erfahren. Diese Methode ist zwar einfacher und benötigt keine zusätzliche Hardware, ist jedoch auch wesentlich ineffizienter als das Arbeiten mit Interrupts, da dabei ständig CPU-Leistung belegt wird. Bei Multitasking-Betriebssystemen ist das Polling als alleinige Methode nicht möglich.
Die Standard-Analogie für Interrupts im Alltag ist eine Tür mit Klingel: Während man seine Aufgaben erledigt, kann man jederzeit durch die Klingel unterbrochen werden, wenn ein Gast eine „Abarbeitung“ wünscht, und sich ihm dann zuwenden. Beim Polling – also ohne Klingel – müsste ständig an die Tür gelaufen werden, um nachzuschauen, ob Besuch da ist oder nicht. Beim Erhitzen von Milch hingegen ist es wohl besser, nicht erst auf den „Interrupt“ des Überkochens zu warten, sondern den Prozess vielmehr regelmäßig zu überwachen.
Ein Beispiel für eine Anwendung von Interrupts lässt sich bei einem Prozessor darstellen, der, nachdem er einen Auftrag an eine Hardwarekomponente ausgegeben hat, nicht aktiv auf die Antwort warten muss (Polling), sondern in der Zwischenzeit andere Aufgaben erledigen kann, um später mittels Interrupt durch jene Hardwarekomponente wieder zu dieser Ein-/Ausgabeaktion zurückgeholt zu werden. Ohne Interrupts wären beispielsweise auch präemptive (=verdrängen von laufenden Programmen) Multitasking-Betriebssysteme nicht möglich, da Programme sonst nicht mehr unterbrochen, vom Betriebssystem umgeschaltet (Timesharing) und Ein-/Ausgabegeräte nicht mehr bedient werden können.
Ablauf
Ausgelöst werden externe Interrupts (Hardwareinterrupts) mittels eines so genannten Interrupt-Requests (=IRQ, „Unterbrechungsanforderung“), einer Signalisierung an den Interrupt-Signaleingang der CPU. Gibt es mehrere Interruptquellen, wird zu deren Verwaltung oft ein Interrupt-Controller zwischen diese Signaleingänge und den Prozessor geschaltet. Wenn eine Unterbrechungsanforderung von der CPU angenommen wird (nach dem Ende einer laufenden Instruktion und sofern der Interrupt nicht deaktiviert („maskiert“) ist), läuft eine feste Sequenz, der Interruptzyklus, ab. Im Interruptzyklus der CPU wird der alte (unterbrochene) Befehlszähler-Stand (bei Intel Codesegment und Instruction Pointer) und bei einigen Architekturen auch das Statusregister auf dem Stack gesichert. Nun muss die auslösende Quelle der Unterbrechungsanforderung bestimmt werden. Bei den meisten CPUs wird die Quelle innerhalb des Interruptzyklus über einen Wert auf dem Datenbus, der üblicherweise vom Interrupt-Controller gesetzt wird, identifiziert, dadurch der zugehörige Interruptvektor gefunden und der Sprung zu der passenden Interrupt-Service-Routine (ISR) ausgelöst. Vor oder während der ISR muss noch der bearbeitete IRQ gelöscht werden, damit er nicht erneut ausgelöst wird. Bei Intel(=PC)-kompatiblen Architekturen erfolgt dies durch I/O-Instruktionen innerhalb der ISR. (So können u. U. ohne besondere Maßnahmen in der Software wegen der (kurzen) Laufzeit bis zur Löschinstruktion auch 'echte' IRQs mit gelöscht werden.) Bei einigen CPU-Architekturen, insbesondere bei Mikrocontrollern, kann es auch mehrere Interrupteingänge geben, wobei hier der Interrupt-Controller schon integriert ist. Bei einfachen CPUs erfolgt nur der IRQ und der Interruptzyklus, wobei per Software überprüft werden muss, welche Quelle der Auslöser war und dementsprechend welche Routine abzuarbeiten ist.
Stehen bis zum Zeitpunkt des Interruptzyklus mehrere IRQs von mehreren Quellen an, so wird mittels eines Auswahlverfahrens durch die Hardware (Interrupt-Controller) der Vektor der wichtigsten Unterbrechungsanfrage bestimmt und abgearbeitet (meist durch Prioritätsverfahren, seltener durch Zufallsverfahren; jedoch nicht nach einer Reihenfolge). Im Anschluss folgt die Bearbeitung der anderen noch anstehenden IRQs.
Durch Hardware ausgelöste (externe) Interrupts sind durch eine spezielle Instruktion insgesamt maskierbar, d. h. die Annahme kann durch Software unterbunden (maskiert) bzw. wieder freigegeben werden. (Das kann für gewisse zeitkritische und synchronisierende Routinen z. B. in Gerätetreibern notwendig sein.) Bei den meisten CPU-Architekturen sind für Sonderfälle (Stromausfall, Speicherfehler usw.) auch nicht-maskierbare Interrupts (non maskable I. =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, was zu erheblichen Softwareproblemen führen kann. Damit dies nicht bei normalen (maskierbaren) Interruptanfragen passiert, maskiert die Interruptlogik in der CPU im normalen Interruptzyklus noch vor dem Einsprung in die ISR die Interrupts automatisch aus. Nach Ausführung der ISR wird mit dem Rücksprung in das unterbrochene Programm immer der alte Zustand (durch Rückspeicherung des Statusregisters) wiederhergestellt.
Externe Interrupts 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) oder auf Geräte (z. B. Harddisk) ausüben. ISRs sind keine Tasks im Sinne des Betriebssystems. Für ISRs ist weiter darauf hinzuweisen, dass nur mit besonderen Softwarekonzepten innerhalb der ISR die Interruptmaskierung aufgehoben (Interrupt enable) werden darf, da sowohl eine Interruptschachtelung durch fremde ISRs als auch eine Wiedereintrittsmöglichkeit (Reentrance) des gleichen Interrupts geschaffen wird.
Einige Prozessoren kennen 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, aber auch als Standard-Schnittstelle zu Betriebssystem-Aufrufen usw.) selbst ausgelöst werden und sinnvollerweise den gleichen Mechanismus benutzen.
Insbesondere bei hardwarenahen ereignisgesteuerten Anwendungen, wie sie z. B. in eingebetteten Systemen üblich sind, wird u. U. praktisch die 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 (also bei externen Ereignissen) 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.
Prinzipieller Ablauf beim Auftreten einer Unterbrechungsanfrage (Übergang von Hardware auf Software):
- Solange entweder der Interrupteingang der CPU oder der Einzelinterrupt auf dem Interrupt Controller maskiert ist, passiert nichts weiter. Interruptanforderungen werden auch nur nach Ablauf der gerade laufenden Instruktion akzeptiert. Normalerweise bleiben Interruptanforderungen bestehen, bis sie akzeptiert werden.
- Hardware (Interruptlogik des Interrupt-Controllers) bestimmt den Interruptvektor des aktivierten IRQs mit der höchsten Priorität, der nicht maskiert ist.
- Die CPU akzeptiert die Unterbrechungsanforderung und führt den Interruptzyklus durch, in dessen Verlauf (je nach CPU) der Interruptvektor vom Datenbus gelesen wird. Danach wird der Interrupteingang automatisch maskiert und somit gesperrt, damit nicht beliebig geschachtelte Interruptsequenzen auftreten können und dadurch einen Stackoverflow ermöglicht.
- Im Interruptzyklus der CPU wird der alte (unterbrochene) Befehlszähler-Stand (bei x86 Codesegment cs und Instruction Pointer eip) und bei einigen Architekturen auch das Statusregister auf dem Stack gesichert. Der neue Befehlszählerstand wird aus bestimmten Speicherstellen oder aus einer Interrupttabelle gelesen, deren Index aus dem Interruptvektor bestimmt wird. Die Vektoren selbst stellen im letzteren Fall jedoch nicht die indirekten Einsprungadressen dar.
- Die Software der Service-Routine (ISR) startet und muss zunächst die Inhalte aller Register, die sie selbst benutzen wird (ggf. auch das Statusregister, wenn es nicht automatisch gesichert wurde) auf dem Stack sichern, da sonst die Daten der unterbrochenen Tasks nicht restauriert werden können. (Wenn hier Fehler gemacht werden, führt das zu zufälligen Fehlerauswirkungen in fremden Programmen, die nur schwer verfolgt werden können!)
- Die eigentliche ISR läuft nun ab. 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 evtl. 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 evtl. zwischenzeitlich der gleiche Interrupt erneut auftreten, was im Algorithmus der ISR zu berücksichtigen ist, falls die Interrupts nicht ohnehin maskiert bleiben.
- Die Software der ISR stellt alle selbst gesicherten Register wieder her (engl. to restore).
- Die ISR beendet sich durch einen Rücksprung (RTI), der das Rückspeichern des alten Befehlszählers und ggf. des alten Statusregisters vom Stack bewirkt und der dadurch wieder seinen Stand wie vor der Unterbrechung hat (so als wäre nichts gewesen). Durch die Rückspeicherung des Statusregisters (das auch das Interrupt-Mask-Bit enthält) ist die Interruptlogik unmittelbar bereit, weitere IRQs zu akzeptieren.
- Die aufgerufene Task kann nun die weitere Bearbeitung der gepufferten Daten übernehmen.
Kategorisierung von Interrupts
Es wird zwischen präzisen Interrupts und unpräzisen Interrupts unterschieden. Präzise Interrupts halten die Maschine in einem wohldefiniertem Zustand, unpräzise nicht.[5]
Ein Softwareinterrupt ist nichts anderes als ein ins Programm eingebauter Software-Befehl, der so wirkt wie ein Hardware-Interrupt, man spricht von einem expliziten Interrupt-Auftrag. Ein Hardwareinterrupt wird dagegen von außen über einen IRQ-Kanal oder -Pin an den Prozessor geleitet.[1]
Ein weitere Art, Interrupts zu kategorisieren, unterscheidet nach dem Auslöser:[6]
- Das Programm kann durch arithmetischen Überlauf, dem Teilen durch Null, den Versuch, einen unerlaubtem Maschinencode auszuführen, oder eine Referenz auf ein Ziel außerhalb des erlaubten Bereichs einen Interrupt auslösen. Hierbei schlägt eine prozessorinterne Fehlererkennung an und aktiviert den Interrupt auf prozessorinternen, aber rein hardwaremäßigen Signalwegen.
- Der Timer erlaubt dem Betriebssystem, Aufgaben regelmäßig zu erledigen. Dazu werden laufende Programme unterbrochen. So ein Timer kann sowohl in den Prozessor eingebaut sein als auch als externer Baustein vorliegen, in beiden Fällen wirkt sein Ablaufen wie ein Ein-/Ausgabeereignis.
- Die Ein-/Ausgabegeräte können ein Signal schicken, dass sie mit ihrer Aufgabe fertig sind oder einen Fehler hatten.
Prozessor-Interrupts werden auch als Exceptions bezeichnet und können in drei Typen eingeteilt werden:[7]
- Fehler (Faults) treten vor Abschluss einer Anweisung auf;
- Traps treten nach Abschluss einer Anweisung auf (Einsatz beim Debuggen);
- Aborts sind sehr wichtige Fehler, z. B. Hardwarefehler.
Hardware-Beispiel x86-Architektur
Alle Intel-Prozessoren haben einen Interrupt-Signaleingang für maskierbare Interrupts. Um mehrere Interruptquellen anschließen zu können, gibt es einen eigenen Interrupt-Controller-Baustein (z. B. den Programmable Interrupt Controller (PIC)), der mehrere Interrupt-Eingänge besitzt und zu einem Signal zusammenführt. Außerdem ist er über interne Register konfigurierbar, sodass er je nach ausgelöstem Interrupt im CPU-Interruptzyklus verschiedene, vorgegebene Interruptvektoren auf den Bus legt, die die CPU dann einliest. Bei neueren Prozessoren sind all diese Funktionalitäten mit in den Kern des Hauptprozessors integriert.
Bei x86-Prozessoren sind 256 verschiedene Interruptvektoren möglich. Der Interruptvektor wird im Interruptzyklus des Prozessors als 8-Bit-Wert vom Datenbus gelesen.
Bei x86-Prozessoren sind die Vektoren selbst nicht die indirekten Einsprungadressen. Der Vektor wird vielmehr im REAL-Mode mit 4 multipliziert (binäres Verschieben), damit für jeden Vektor 32-Bit-Sprungadressen untergebracht werden können, zu denen dann gesprungen wird. Im Protected-Mode wird mit 8 multipliziert, weil ein Descriptoreintrag 8 Bytes lang ist. Im Real Mode befindet sich die Interrupttabelle in dem ersten Kilobyte des Hauptspeichers (0000h:0000h-0000h:03FFh). 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 der Tabelle durch die Interrupt-Deskriptor-Tabelle festgelegt. Hier werden für jeden Interrupt 8 Bytes für den Deskriptor-Eintrag der ISR benötigt.Siehe auch
Weblinks
Wiktionary: Interrupt – Bedeutungserklärungen, Wortherkunft, Synonyme, ÜbersetzungenEinzelnachweise
- ↑ a b A. Metzlar: BIOS. Das Praxisbuch. Franzis, 2004, ISBN 978-3772367069, S. 379.
- ↑ A. Tanenbaum: Moderne Betriebssysteme. Pearson Studium, 2009, ISBN 978-3827373427, S. 406.
- ↑ W. Stallings: Operating Systems: Internals and Design Principles. Prentice Hall International, 2000, ISBN 978-0130319999, S. 62.
- ↑ W. Stallings: Operating Systems: Internals and Design Principles. Prentice Hall International, 2000, ISBN 978-0130319999, S. 136.
- ↑ A. Tanenbaum: Moderne Betriebssysteme. Pearson Studium, 2009, ISBN 978-3827373427, S. 109.
- ↑ W. Stallings: Operating Systems: Internals and Design Principles. Prentice Hall International, 2000, ISBN 978-0130319999, S. 17.
- ↑ A. Metzlar: BIOS. Das Praxisbuch. Franzis, 2004, ISBN 978-3772367069, S. 85.
Wikimedia Foundation.