In this article, i am going to discuss about Interrupt handling mechanism of Linux kernel.
So the story starts from When an interrupts occurs, the processor looks if interrupts are masked. If they are, nothing happens until they are unmasked. When interrupts become unmasked, if there are any pending interrupts, the processor picks one. Then the processor executes the interrupt by branching to a particular address in memory. The code at that address is called the interrupt handler. When the processor branches there, it masks interrupts (so the interrupt handler has exclusive control) and saves the contents of some registers in stack. When the handler finishes executing, it executes a special return-from-interrupt instruction that restores the saved registers and unmasks interrupts.
The problem over here is :
The Corresponding interrupt is disabled during the execution of a interrupt handler, the interrupt handler expected to be finish fast But, what if you have to do a lot of data processing, memory allocation in a interrupt handler.
After kernel release of 2.6 this problem is resolved by designing and developing proper interrupt handling mechanism. Which splits he interrupt handling in to two parts.
- Top-Half: The top half is the real interrupt handler: It just tells the kernel to run the bottom half, and exits. The kernel guarantees that the top half is never re-entered: if another interrupt arrives, it is queued until the top half is finished. Because the top half disables interrupts, it has to be very fast.
- Bottom-Half: The bottom half is run after the interrupts are processed(Top half is executed).The interrupts are not disabled while the bottom half is run, so it can do slower actions.
NOTE: Its totally device driver developers choice to split interrupt processing or not. If the ISR is going to very short and can be managed then there is no need of bottom-half. Similarly, if the disabled interrupt for a long time is OK for use case, then healthy top half is also possible. So, it is a totally design decision.
Linux provides three mechanism to implement bottom half.
1. softIrq :
It is a vector of 10 different entries (in kernel 3.16) supporting variety of bottom half processing also called software interrupt. All entries are shown by the image below.
- Softirqs are statically allocated at compile-time. So there are fixed number of softirq and they run in priority order.
- Softirqs have strong CPU affinity, so they are reserved for most of time critical and important bottom half processing on the system.
- softirq is guaranteed to run on the CPU it was scheduled on in SMP systems.
- It Runs in interrupt context, so Interrupt context cannot perform certain actions that can result in the kernel putting the current context to sleep, such as downing a semaphore, copying to or from user-space memory or non-atomically allocating memory
- it can’t preempted and can’t scheduled
- Atomic execution
- it can run simultaneously on one or more processor, even two of the same type of softirq can run concurrently
Softirqs are most often raised from within interrupt handlers. First the interrupt handler(top half) performs the basic hardware-related work, raises the softirq, and then exits. After the kernel is done processing interrupts, it checks wither any of the softirqs have been raised or not. Code flow in Linux kernel for interrupt handling is explained below.
| do_IRQ() (top half which masks all interrupts and invoke softirq)
| irq_exit() (Release all masked interrupts)
| invoke_softirq() (Kernel checks for the any pending invoked irq)
| do_softirq() (Execution of softirq (bottom half) with )
Tasklets are build on top of softirq. The central idea of tasklet is to provide rich bottom half mechanisum. Only below points diffres from softirq.
- Tasklets have a weaker CPU affinity than softirqs
- Unlike softirqs, tasklets are dynamically allocated.
- A tasklet can run on only one CPU at a time.
- Runs in interrupt contex, Interrupt context cannot perform certain actions that can result in the kernel putting the current context to sleep, such as downing a semaphore, copying to or from user-space memory or non-atomically allocating memory
- Atomic execution
- Two different tasklets can run concurrently on different processors, but two of the same type of tasklet cannot run simultaneously on same processor.
- Tasklet is strictly serialized wrt itself, but not wrt another tasklets.
- Tasklet runs on same CPU from where is raised
Why softIRQ if tasklet is there ?
Workqueues are also like tasklets. They are useful to schedule a task that for future. There is some identical difference between two,
Runs in kenrel process context. Because work queues run in process context (kernel threads), they are capable of sleeping
- Non atomic execution.
- Workqueue runs on same CPU from where is raised
- Higher latency compared to tasklet.
NOTE: This article contains only conceptual details of Interrupt handling mechanism of Linux.