Interrupts are signals that cause the computer's central processing unit to suspend what it is doing and transfer to a program called an interrupt handler. Special hardware mechanisms that are designed for maximum speed force the transfer. The interrupt handler determines the cause of the interrupt, takes the appropriate action, and then returns control to the original process that was suspended.
Interrupts are typically caused by events external to the central processor that require immediate attention, such as the following:
Completion of an I/O operation
Detection of a hardware failure
"Catastrophes" (power failures, for example)
In order to service interrupts more efficiently, most modern processors support multiple interrupt types, or levels. Each type usually has a reserved location in memory, called an interrupt vector, that specifies where the interrupt-handler program for that interrupt type is located. This design speeds processing of an interrupt because the computer can transfer control directly to the appropriate routine; it does not need a central routine that wastes precious machine cycles determining the cause of the interrupt. The concept of interrupt types also allows interrupts to be prioritized, so that if several interrupts occur simultaneously, the most important one can be processed first.
CPUs that support interrupts must also have the capability to block interrupts while they are executing critical sections of code. Sometimes the CPU can block interrupt levels selectively, but more frequently the effect is global. While an interrupt is being serviced, the CPU masks all other interrupts of the same or lower priority until the active handler has completed its execution; similarly, it can preempt the execution of a handler if a different interrupt with higher priority requires service. Some CPUs can even draw a distinction between selectively masking interrupts (they are recognized, but their processing is deferred) and simply disabling them (the interrupt is thrown away).
The creation of interrupt handlers has traditionally been considered one of the most arcane of programming tasks, suitable only for the elite cadre of system hackers. In reality, writing an interrupt handler is, in itself, straightforward. Although the exact procedure must, of course, be customized for the characteristics of the particular CPU and operating system, the guidelines on the following page are applicable to almost any computer system.
A program preparing to handle interrupts must do the following:
1.Disable interrupts, if they were previously enabled, to prevent them from occurring while interrupt vectors are being modified.
2.Initialize the vector for the interrupt of interest to point to the program's interrupt handler.
3.Ensure that, if interrupts were previously disabled, all other vectors point to some valid handler routine.
4.Enable interrupts again.
The interrupt handler itself must follow a simple but rigid sequence of steps:
1.Save the system context (registers, flags, and anything else that the handler will modify and that wasn't saved automatically by the CPU).
2.Block any interrupts that might cause interference if they were allowed to occur during this handler's processing. (This is often done automatically by the computer hardware.)
3.Enable any interrupts that should still be allowed to occur during this handler's processing.
4.Determine the cause of the interrupt.
5.Take the appropriate action for the interrupt: receive and store data from the serial port, set a flag to indicate the completion of a disk-sector transfer, and so forth.
6.Restore the system context.
7.Reenable any interrupt levels that were blocked during this handler's execution.
8.Resume execution of the interrupted process.
As in writing any other program, the key to success in writing an interrupt handler is to program defensively and cover all the bases. The main reason interrupt handlers have acquired such a mystical reputation is that they are so difficult to debug when they contain obscure errors. Because interrupts can occur asynchronously——that is, because they can be caused by external events without regard to the state of the currently executing process——bugs in interrupt handlers can cause the system as a whole to behave quite unpredictably.