In any operating system, interrupts are very important because these provide mechanism to handle asynchronous events from various sources like keyboard, network cards, timers etc.These devices do not need CPU at all the time but when they need it, they should be able to request it. Interrupt provide that mechanism. Else we need to rely on the polling by CPU.
Let’s understand what exactly interrupts are. Going by the literal meaning of word interrupt, we can say that anything which is external to currently executing task and alters the execution paths of the task is an interrupt. New task which is executed is Interrupt Service Routine (ISR). Once ISR finishes, control goes back to the next instructions of previously executing task.
|Typical handling of an interrupt|
Classification of interrupts
There are two source of interrupts :Hardware interrupts and software interrupts. As names suggest one is raised by hardware and other by the software.
Examples of hardware interrupts: Interrupts generated by the clocks external to CPU, network card interrupts etc. Software interrupts are divide by zero, illegal memory access, page faults etc.
Hardware interrupts are indicated on dedicated line to CPU and then CPU indicates the reception of such interrupt on Interrupt Acknowledgement line.
If a task or operating system wants to ignore a particular interrupt, it can mask it. Masking of an interrupt will make sure that ISR for that interrupt is not executed even if interrupt has occurred.
Non-Maskable Interrupts (NMI) are interrupts which by nature can not be masked by task or operating system. Usually non maskable interrupts are used to sense state of sub systems external to CPU, if CPU sees that there is no activity on a given line for a particular sub system, it can take action. It avoids deadlocks in overall system.
In Pentium architecture, there is a pin each for raising non maskable and maskable interrupts.
Identifying an interrupt handler
Every interrupt has an interrupt number associated with it. This number helps CPU to identify which ISR needs to be invoked when a particular interrupt occurs. operating systems sets up an Interrupt Descriptor Table (IDT) at boot time. So handler pointer is stored at IDT[intrrupt_number].
Since we have suspended normal execution of a task, it is important that we resume that task as soon as possible. So two things come up here : We need to return where we came from, so save the return address, and we need to exit ISR as soon as possible, hence no big processing here.
What else? What if other interrupt comes while are servicing an interrupt? We need to take call, what all interrupts can be serviced from this ISR, rest all are masked, so that they are ignored. Even if the same interrupt comes while in ISR, we may need to ignore it.
Since we are going to resume task we suspended, we need its register states. So save all registers states and restore it once ISR is executed.
Apart from these three basic actions, do the interrupt specific processing and return as soon as possible.
One more design issue which we need to take care is what if two interrupts occur at same time? We need to associate priority to each interrupt and based on the priority of interrupts, execution order is decided.
In next post we will discuss what are bottom halves, how interrupts is actually written in operating systems and various APIs available in Linux kernel.