Fundamentals 26 min read

How Linux Handles Hardware Interrupts: From Signal to Response

This article explains the complete Linux interrupt management process, covering the basics of hardware and software interrupts, the role of programmable interrupt controllers, the CPU's response workflow, top‑half and bottom‑half handling, registration techniques, performance optimizations, and debugging tools, all illustrated with concrete examples and code.

Linux Kernel Journey
Linux Kernel Journey
Linux Kernel Journey
How Linux Handles Hardware Interrupts: From Signal to Response

1. Interrupt Basics

An interrupt is an urgent signal from hardware or software that forces the CPU to pause the current task and handle the event, analogous to a phone ringing while reading a book. Linux distinguishes hardware interrupts (e.g., keyboard, disk, network) and software interrupts (system calls, timers). Compared with polling, which wastes CPU cycles by repeatedly checking device status, interrupts allow devices to notify the CPU only when needed, dramatically improving efficiency.

1.1 Types of Interrupts

Hardware interrupt: asynchronous signals from external devices such as keyboards, network cards, or SSDs. They have higher priority and can pre‑empt the current CPU task.

Software interrupt: triggered by the kernel or applications, used for system calls, scheduling, and timers.

1.2 Polling vs. Interrupts

Polling continuously checks device status, wasting CPU time when the device is idle. Interrupts are asynchronous; the device sends a signal only when an event occurs, allowing the CPU to remain idle otherwise.

1.3 Linux Interrupt Classification

Linux groups interrupts into hardware and software categories, each with distinct characteristics and use cases.

2. Full Interrupt Handling Flow

2.1 Hardware Trigger

When a device (e.g., a keyboard) generates an interrupt, the signal first reaches an interrupt controller (PIC, APIC, or GIC). The controller collects requests, performs priority arbitration, and forwards the highest‑priority request to the CPU.

2.2 CPU Response

The CPU saves the current context (registers, program counter) on the stack, checks the interrupt flag (IF), and looks up the interrupt vector table (IVT) using the interrupt number to obtain the handler address.

2.3 Interrupt Processing

Linux splits handling into a top half (hard interrupt) and a bottom half (soft interrupt or tasklet). The top half quickly acknowledges the device, clears the interrupt flag, and reads minimal data. The bottom half, executed in process context or by the ksoftirqd kernel thread, performs longer work such as packet parsing or disk I/O.

Example: a network card’s top half copies received data into a kernel buffer and triggers a soft interrupt; the bottom half then processes the packet through the network stack.

3. Core Components of Interrupt Management

3.1 Interrupt Vector Table

The vector table maps interrupt numbers to handler addresses. On x86 it resides in a fixed memory region and is accessed via the IDT (Interrupt Descriptor Table). When a keyboard interrupt occurs, the CPU uses the IDT entry to jump to the corresponding handler.

3.2 request_irq Registration

Device drivers register handlers with request_irq, providing the IRQ number, handler function, flags, and a name. This creates a mapping in the vector table.

3.3 Interrupt Controller

Early PCs used the 8259A PIC (up to 8 IRQs, cascaded for 16). Modern multi‑core systems use APIC, consisting of I/O APIC (collects device requests) and Local APIC (per‑core). APIC supports dynamic priority and load‑balancing across cores.

3.4 Interrupt Context

Interrupt handlers run in interrupt context, which lacks a process control block and cannot invoke blocking functions (e.g., wait_event) or trigger page faults. This restriction ensures minimal latency.

4. Registration and Performance Optimizations

4.1 Example: Button Driver

#include <linux/init.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>

static irqreturn_t button_interrupt(int irq, void *dev_id) {
    printk(KERN_INFO "Button interrupt received
");
    return IRQ_HANDLED;
}

static int __init button_driver_init(void) {
    int irq;
    struct device_node *np = of_find_node_by_path("/button");
    if (!np) return -ENODEV;
    irq = irq_of_parse_and_map(np, 0);
    if (!irq) { of_node_put(np); return -EINVAL; }
    if (request_irq(irq, button_interrupt, IRQF_TRIGGER_FALLING, "my_button", NULL)) {
        printk(KERN_ERR "Failed to request IRQ %d
", irq);
        of_node_put(np);
        return -EFAULT;
    }
    of_node_put(np);
    return 0;
}

static void __exit button_driver_exit(void) {
    free_irq(irq, NULL);
}

module_init(button_driver_init);
module_exit(button_driver_exit);
MODULE_LICENSE("GPL");

4.2 Optimization Strategies

Shorten top‑half time: keep the top half minimal (clear flags, read status) and defer heavy work to the bottom half.

Interrupt affinity: bind frequently occurring IRQs to specific CPUs (e.g., echo 8 > /proc/irq/16/smp_affinity) to reduce cache migration.

Shared interrupts: use IRQF_SHARED and provide a unique dev_id to differentiate devices sharing the same IRQ.

5. Common Issues and Debugging Tools

5.1 Interrupt Nesting

Older kernels allowed nesting via fast and slow interrupts (IRQF_DISABLED). Modern kernels disable nesting by default to simplify handling and avoid race conditions, though real‑time patches can re‑enable it.

5.2 Viewing Interrupt Statistics

Hard‑interrupt counts are in /proc/interrupts (e.g., CPU0 123 CPU1 0 IO‑APIC‑edge timer). Soft‑interrupt counts are in /proc/softirqs (e.g., NET_RX 54321 54325). These files help assess load distribution and identify hotspots.

5.3 Tools

sar -u

shows CPU usage, including %hi (hard‑interrupt) and %si (soft‑interrupt). sar -I ALL reports per‑interrupt statistics. tcpdump can capture network traffic that may correlate with interrupt activity.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

PerformancekernelLinuxdevice driverAPICInterrupts
Linux Kernel Journey
Written by

Linux Kernel Journey

Linux Kernel Journey

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.