Interrupt

aus Wikipedia, der freien Enzyklopädie
Wechseln zu: Navigation, Suche

In der Informatik versteht man unter einem Interrupt (engl. to interrupt, unterbrechen nach lat. interruptus, dem Partizip Perfekt Passiv von interrumpere, unterbrechen) eine vorübergehende Unterbrechung eines laufenden Programms,[1] um einen anderen, in der Regel kurzen, aber zeitkritischen, Vorgang abzuarbeiten.

Das auslösende Ereignis wird Unterbrechungsanforderung (engl. Interrupt Request, IRQ) genannt. Nach dieser Anforderung führt der Prozessor eine Unterbrechungsroutine aus (auch Unterbrechungsbehandlung genannt, engl. interrupt handler, interrupt service routine oder kurz ISR). Anschließend wird das unterbrochene Programm dort fortgeführt, wo es unterbrochen wurde.

Beispielsweise sendet die Tastatur eine Unterbrechungsanforderung, wenn eine Taste gedrückt wurde. Dazu wird ein Signal auf den Bus oder direkt an einen nur dafür vorgesehenen Prozessorpin (IRQ-Eingang) gelegt.[2] Die Unterbrechungsroutine kann daraufhin das jeweilige Zeichen von der Tastatursteuerung lesen und es an die jeweilige Anwendung weiterleiten.

Interrupts werden durch asynchrone externe Ereignisse ausgelöst.[3] Asynchron bedeutet in diesem Zusammenhang, dass das laufende Programm nicht immer an der gleichen Stelle unterbrochen wird.

Beispiele[Bearbeiten | Quelltext bearbeiten]

Weitere Beispiele, bei denen Geräte eine Unterbrechungsanforderung generieren:

  • Netzwerkkarte: wenn Daten empfangen wurden und im Puffer bereitliegen
  • Festplatte: wenn die vorher angeforderten Daten gelesen wurden und abholbereit sind (das Lesen von der Festplatte dauert relativ lange)
  • Grafikkarte: wenn das aktuelle Bild fertig gezeichnet wurde
  • Soundkarte: wenn wieder Sound-Daten zum Abspielen benötigt werden, bevor der Puffer leer wird.

Geschichte[Bearbeiten | Quelltext bearbeiten]

Ältere Computermodelle hatten keine Interrupts.[4] Rund 1958 gab es erste Modelle mit Interrupts, ein Beispiel war die Electrologica X1.[5]

Zweck[Bearbeiten | Quelltext bearbeiten]

Ein Interrupt dient dazu, auch während ein anderes Programm (z. B. eine Anwendung) abgearbeitet wird, auf eine Ein- oder Ausgabe (etwa von Tastatur, Festplatte, Netzwerk oder Zeitgeber) sofort reagieren zu können. Die Interface-Hardware muss nur einen Interrupt auslösen, 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 ohne Datentransfer (z. B. Timer).

Vorteile gegenüber dem Polling[Bearbeiten | Quelltext bearbeiten]

Neben Interrupts gibt es lediglich die Technik des programmierten (zyklischen) Abfragens (Polling), um den Status von Ein-/Ausgabegeräten, Prozessen oder anderem zu erfahren. Diese Methode ist zwar einfacher und benötigt keine zusätzliche Hardware, ist allerdings sehr viel ineffizienter als die Arbeit mit Interrupts, da sie die CPU sehr häufig in Anspruch nimmt. Zudem hängt die Reaktionsgeschwindigkeit beim Polling davon ab, wie viel Zeit zwischen den Abfragen vergeht, dies kann bei Situationen, die eine sofortige Reaktion verlangen, kritisch sein. 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 immer wieder 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 regelmäßig zu überwachen.

Anwendungsbeispiele[Bearbeiten | Quelltext bearbeiten]

Als Beispiel für eine Anwendung von Interrupts kann man sich einen Prozessor vorstellen, der, nachdem er einer Hardwarekomponente einen Auftrag gegeben hat, nicht aktiv auf deren Antwort wartet (Polling), sondern so lange andere Aufgaben erledigt, bis ihn jene Hardwarekomponente von sich aus durch einen Interrupt wieder auf sich aufmerksam macht. Ohne Interrupts wären beispielsweise präemptive (=verdrängen von laufenden Programmen) Multitasking-Betriebssysteme unmöglich, da Programme ohne sie nicht mehr unterbrochen, vom Betriebssystem umgeschaltet (Timesharing) und Ein-/Ausgabegeräte nicht mehr bedient werden könnten.

Funktionsweise[Bearbeiten | Quelltext bearbeiten]

Um ein Interrupt auslösen zu können, muss die an den Hauptprozessor (CPU) angeschlossene Hardware interruptfähig sein, d. h., bei Eintreffen eines bestimmten Ereignisses über die sogenannte Interrupt-Leitung ein Ausgangssignal (elektrische Spannung an einem Ausgangs-Pin) erzeugen. Die CPU besitzt im einfachsten Falle einen entsprechenden Eingangs-Pin. Erscheint an diesem Pin eine elektrische Spannung, so startet innerhalb der CPU eine Sequenz von Befehlen, die die Unterbrechungsroutine einleiten – den Interruptzyklus. Gibt es mehrere Interruptquellen, wird oft ein Interrupt-Controller zwischen die Signaleingänge und den Prozessor geschaltet.

Latenz[Bearbeiten | Quelltext bearbeiten]

Die Zeit zwischen dem Anlegen des IRQ-Signals und dem Beginn der entsprechenden Verarbeitung nennt man Latenz. Für einen IRQ der höchsten vergebenen Priorität hängt die Latenz vor allem von der Hardware ab – mit Schattenregistern kann der Kontextwechsel in einem Taktzyklus gelingen –, für IRQs mit geringerer Priorität von der Ausführungsdauer der bevorzugten Interrupt-Routinen. Echtzeitbetriebssysteme sind so organisiert und konfigurierbar, dass damit Echtzeitanforderungen leichter und beweisbar erfüllt werden können.

Maskierung[Bearbeiten | Quelltext bearbeiten]

Unterbrechungsanforderungen können zeitweise von der CPU ignoriert werden, zum Beispiel wenn gerade ein anderer Interrupt behandelt wird. Dies kann für gewisse zeitkritische und synchronisierende Routinen z. B. in Gerätetreibern notwendig sein. Diese Maskierung gilt für alle Interrupts bis auf die nicht maskierbaren (NMI: Non Maskable Interrupt), die für spezielle Fälle vorgesehen sind (Stromausfall, Speicherfehler usw.), und für die so genannten Software-Interrupts, die durch einen Befehl in einem Programm ausgelöst werden (z. B. 'int IRQNUMMER' bei x86 – dieser Befehl wird beispielsweise von Linux genutzt, um von normalen Anwendungen über Systemaufrufe (syscalls) in den Kernel-Modus zu wechseln).

Ohne besondere Maßnahmen können 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.

Asynchronität[Bearbeiten | Quelltext bearbeiten]

Externe Interrupts (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) oder auf Geräte (z. B. Festplatten) 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.

Interrupt-Routinen als Programmierprinzip[Bearbeiten | Quelltext bearbeiten]

Insbesondere bei hardwarenahen ereignisgesteuerten Anwendungen, wie sie in eingebetteten Systemen üblich sind, ist eine mögliche Vorgehensweise, mehr oder weniger die gesamte Funktionalität des Systems in die Interrupt-Routinen bzw. in von diesen angestoßene Tasks zu verlegen. Der Prozessor kann dabei typischerweise in einen energiesparenden Ruhezustand (Idle State oder Leerlauf) versetzt werden, aus dem er bei Interruptanforderungen (also bei externen Ereignissen) erwacht. Das Hauptprogramm besteht 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. Ruhezustands – nichts passiert.

Ablauf[Bearbeiten | Quelltext bearbeiten]

Interrupt-Prozess: Unterbrechungsanforderung, Thread anhalten, Status speichern, Interrupt-Routine ausführen, Status wiederherstellen, unterborchenen Thread fortführen.
Vereinfachte Ablaufdarstellung
Animation zum Ablauf eines Interrupts

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 gespeichert. Nun muss bestimmt werden, welche Quelle der Unterbrechungsanforderung ausgelöst hat. 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 Unterbrechungsroutine (ISR) ausgelöst. Vor oder während der ISR muss noch die bearbeitete Unterbrechungsanforderung (IRQ) gelöscht werden, damit sie nicht erneut ausgelöst wird. Bei Intel(=PC)-kompatiblen Architekturen erfolgt dies durch Input/Output-Instruktionen innerhalb der Unterbrechungsroutine. 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 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. Im Anschluss folgt die Bearbeitung der anderen noch anstehenden IRQs.

Prinzipieller Ablauf beim Auftreten einer Unterbrechungsanfrage (Übergang von Hardware auf Software):

  1. 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.
  2. Hardware (Interruptlogik des Interrupt-Controllers) bestimmt den Interruptvektor des aktivierten IRQs mit der höchsten Priorität, der nicht maskiert ist.
  3. 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 viele geschachtelte Interruptsequenzen auftreten können und den Stack überlaufen lassen.
  4. 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 gespeichert. 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.
  5. Die Software der Interrupt-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 den Stack kopieren, da sonst die Daten der unterbrochenen Tasks nicht wiederhergestellt werden können. (Wenn dabei Fehler gemacht werden, führt das zu zufälligen Fehlerauswirkungen in fremden Programmen, die nur schwer verfolgt werden können!)
  6. Die eigentliche Interrupt-Service-Routine 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 ein entsprechender 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.
  7. Die Software der ISR stellt alle von ihr gesicherten Register wieder her (engl. to restore).
  8. 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.
  9. Die aufgerufene Task kann nun die weitere Bearbeitung der gepufferten Daten übernehmen.

Kategorisierung von Interrupts[Bearbeiten | Quelltext bearbeiten]

Es wird zwischen präzisen Interrupts und unpräzisen Interrupts unterschieden. Präzise Interrupts halten die Maschine in einem wohldefinierten Zustand, unpräzise nicht.[6]

Ein Softwareinterrupt ist ein Programmbefehl, 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 eingeleitet.[1]

Auch nach ihrem Auslöser werden Interrupts unterschieden:[7]

  • Die Ein-/Ausgabegeräte können ein Signal schicken, dass sie mit ihrer Aufgabe fertig sind oder einen Fehler hatten.
  • 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.

Prozessor-Interrupts werden auch als Exceptions bezeichnet und können in drei Typen eingeteilt werden:[8]

  • Aborts sind sehr wichtige Fehler, z. B. Hardwarefehler,
  • Fehler (Faults) treten vor Abschluss einer Anweisung auf,
  • Traps treten nach Abschluss einer Anweisung auf (Einsatz beim Debuggen).

Hardware-Beispiel x86-Architektur[Bearbeiten | Quelltext bearbeiten]

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.

Bei modernen Systemen (zum Beispiel PCI-Systemen) können sich in der Regel mehrere Geräte einen Interrupt teilen (Interrupt-Sharing genannt). Die Behandlungsroutine für einen solchen Interrupt muss dann alle Treiber, deren Geräte diesen Interrupt ausgelöst haben könnten, aufrufen (am IRQ kann dies nicht festgestellt werden). Dabei kann es zu Problemen kommen, wenn einzelne Treiber zu lange aktiv sind, und in der Zwischenzeit im Gerät, welches den Interrupt ursprünglich ausgelöst hat, beispielsweise der Puffer voll wird und überläuft. Im schlimmsten Fall führt dies zu einem Datenverlust.

Bei modernen Peripheriegeräten vergeben der Computer und das Betriebssystem selbst die IRQ-Nummern (PnP = Plug-and-Play-Geräte); während bei alten Steckkarten, beispielsweise bei ISA-Karten, die IRQs von Hand eingestellt werden müssen oder fest auf den Karten verdrahtet sind.

Unter Linux kann man die Interrupts mit folgendem Befehl abfragen: cat /proc/interrupts

Unter Windows (XP und neuer) kann man die Interrupts mit folgendem Befehl abfragen: msinfo32.exe → Hardwareressourcen → IRQs

IRQ-Geräte-Tabelle
(Diese Liste unterscheidet sich von System zu System)
IRQ Verwendung
0 System-Taktgeber
1 Tastatur
2 Kaskadiert zu IRQ 9 (für 8-15)
3 COM 2,4,6,8 (EIA-232/RS-232)
4 COM 1,3,5,7
5 LPT 2 (IEEE 1284) oder Soundkarte
6 Diskettenlaufwerk (Floppy)
7 LPT 1
8 Echtzeituhr (RTC)
9 Zu IRQ 2 umgeleitet (aber auch VGA und NIC, IRQ 16–23)
10 Frei ggf. PCI-Bus
11 Frei ggf. Adaptec-SCSI
12 PS/2 (Maus, andere Eingabegeräte)
13 Mathematischer Coprozessor (FPU)
14 Primärer IDE oder ATA
15 Sekundärer IDE oder ATA

Siehe auch[Bearbeiten | Quelltext bearbeiten]

Weblinks[Bearbeiten | Quelltext bearbeiten]

 Wiktionary: Interrupt – Bedeutungserklärungen, Wortherkunft, Synonyme, Übersetzungen
 Wiktionary: Unterbrechungsroutine – Bedeutungserklärungen, Wortherkunft, Synonyme, Übersetzungen
 Wikibooks: Erklärung von Unterbrechungen – im Kapitel „Prozessor“ des Wikibooks „Computerhardware“

Einzelnachweise[Bearbeiten | Quelltext bearbeiten]

  1. a b A. Metzlar: BIOS. Das Praxisbuch. Franzis, 2004, ISBN 978-3772367069, S. 379.
  2. A. Tanenbaum: Moderne Betriebssysteme. Pearson Studium, 2009, ISBN 978-3827373427, S. 406.
  3. W. Stallings: Operating Systems: Internals and Design Principles. Prentice Hall International, 2000, ISBN 978-0130319999, S. 136.
  4. W. Stallings: Operating Systems: Internals and Design Principles. Prentice Hall International, 2000, ISBN 978-0130319999, S. 62.
  5. E. W. Dijkstra: My recollection of operating system design, EWD 1303, 2000, S. 15
  6. A. Tanenbaum: Moderne Betriebssysteme. Pearson Studium, 2009, ISBN 978-3827373427, S. 109.
  7. W. Stallings: Operating Systems: Internals and Design Principles. Prentice Hall International, 2000, ISBN 978-0130319999, S. 17.
  8. A. Metzlar: BIOS. Das Praxisbuch. Franzis, 2004, ISBN 978-3772367069, S. 85.