Fundamentals 15 min read

Understanding Linux IRQ and SoftIRQ: From Hardware Interrupts to Deferred Handling

This article explains the fundamentals of Linux interrupt handling, covering hardware and software interrupts, the IRQ processing flow, maskable vs non‑maskable interrupts, and the three deferred execution mechanisms—softirq, tasklet, and workqueue—along with code examples and performance considerations.

Liangxu Linux
Liangxu Linux
Liangxu Linux
Understanding Linux IRQ and SoftIRQ: From Hardware Interrupts to Deferred Handling

What is an interrupt?

CPU time‑multiplexes many tasks, including hardware tasks like disk I/O and keyboard input, and software tasks such as network packet processing. When a hardware or software event needs immediate attention, it sends an interrupt request (IRQ) to pre‑empt the current task and be serviced.

Hard interrupts

Interrupt handling flow

When an interrupt occurs, the kernel must:

Pre‑empt the current task : pause the running process.

Execute the interrupt handler : locate and run the corresponding handler function.

Resume the pre‑empted task after the handler finishes.

Maskable and non‑maskable

On x86_64, maskable interrupts can be disabled and enabled with the cli and sti instructions:

static inline void native_irq_disable(void) { asm volatile("cli" ::: "memory"); }
static inline void native_irq_enable(void) { asm volatile("sti" ::: "memory"); }

Maskable interrupts can be temporarily blocked; most IRQs are of this type (e.g., network card hardware interrupts). Non‑maskable interrupts cannot be blocked and are treated as higher‑priority events.

Speed vs. complexity trade‑off

IRQ handlers must run very quickly to avoid event loss, yet they often need to perform complex logic such as packet reception, creating an inherent conflict.

Deferred interrupt handling

To resolve this, Linux splits interrupt processing into two parts:

Top half : the minimal work that must run in hard‑interrupt context.

Bottom half : the remaining work queued for later execution outside the hard‑interrupt context.

This deferred handling is now a generic term covering several mechanisms.

SoftIRQ

SoftIRQ subsystem

Each CPU runs a kernel thread ksoftirqd that processes pending softirqs. SoftIRQ handlers are registered with open_softirq(softirq_id, handler). For example, network TX/RX handlers are registered as:

// net/core/dev.c
open_softirq(NET_TX_SOFTIRQ, net_tx_action);
open_softirq(NET_RX_SOFTIRQ, net_rx_action);

The CPU usage of softirqs can be observed with top; the si column shows softirq overhead.

Main processing

The scheduler may invoke ksoftirqd, which calls __do_softirq() to:

Determine which softirqs need handling.

Execute their handlers.

Avoiding excessive CPU consumption

Softirqs can consume significant CPU time, reflected in the si metric. Linux mitigates this with a budget mechanism that limits the time spent in softirq processing:

unsigned long end = jiffies + MAX_SOFTIRQ_TIME;
...restart:
while ((softirq_bit = ffs(pending))) {
    h->action(h); // internal limit logic
    ...
}
pending = local_softirq_pending();
if (pending) {
    if (time_before(jiffies, end) && !need_resched() && --max_restart)
        goto restart;
}

Hard‑interrupt → SoftIRQ call stack

When an IRQ handler finishes, do_IRQ() eventually calls exiting_irq()irq_exit(), which checks for pending softirqs and wakes ksoftirqd if needed:

if (!in_interrupt() && local_softirq_pending())
    invoke_softirq();

SoftIRQ execution steps

Register the handler with open_softirq().

Mark the softirq as pending via raise_softirq(), which wakes ksoftirqd.

The scheduler runs ksoftirqd, which processes all pending softirqs by invoking their handlers.

For network packet reception, the IRQ handler only raises NET_RX_SOFTIRQ; the actual packet processing occurs in the softirq’s poll() method.

Three deferred execution mechanisms

Linux provides three ways to defer work:

softirq

tasklet

workqueue

Key differences:

softirq and tasklet run in softirq context.

workqueue runs in process context, allowing sleeping and non‑atomic operations.

softirq

Softirqs are statically defined at kernel compile time (e.g., NET_RX_SOFTIRQ). They are stored in an array softirq_vec indexed by enum values:

static struct softirq_action softirq_vec[NR_SOFTIRQS] __cacheline_aligned_in_smp;
void open_softirq(int nr, void (*action)(struct softirq_action *)) {
    softirq_vec[nr].action = action;
}

Linux 5.10 defines the following softirq types:

enum {
    HI_SOFTIRQ = 0,
    TIMER_SOFTIRQ,
    NET_TX_SOFTIRQ,
    NET_RX_SOFTIRQ,
    BLOCK_SOFTIRQ,
    IRQ_POLL_SOFTIRQ,
    TASKLET_SOFTIRQ,
    SCHED_SOFTIRQ,
    HRTIMER_SOFTIRQ,
    RCU_SOFTIRQ,
    NR_SOFTIRQS
};

tasklet

Tasklets are built on top of softirqs (specifically HI_SOFTIRQ and TASKLET_SOFTIRQ) and can be created at runtime. The kernel initializes per‑CPU tasklet vectors and registers the tasklet softirqs:

void __init softirq_init(void) {
    for_each_possible_cpu(cpu) {
        per_cpu(tasklet_vec, cpu).tail = &per_cpu(tasklet_vec, cpu).head;
        per_cpu(tasklet_hi_vec, cpu).tail = &per_cpu(tasklet_hi_vec, cpu).head;
    }
    open_softirq(TASKLET_SOFTIRQ, tasklet_action);
    open_softirq(HI_SOFTIRQ, tasklet_hi_action);
}

Tasklet structures contain a function pointer, data, and state, and are processed by tasklet_action() which iterates over the per‑CPU list.

workqueue

Workqueues provide an asynchronous execution context using kernel worker threads (e.g., kworker). Unlike tasklets, workqueues run in process context, allowing sleeping and non‑atomic operations. Work items are enqueued and processed by worker threads:

// Example of a workqueue worker thread list
$ systemd-cgls -k | grep kworker
├─ 5 [kworker/0:0H]
├─ 15 [kworker/1:0H]
...

The core structures are worker_pool and work_struct, where each work item holds a function pointer and data. Workers pull items from the queue and execute them sequentially.

References

Linux Inside (online book), “Interrupts and Interrupt Handling” – https://0xax.gitbooks.io/linux-insides/content/Interrupts/linux-interrupts-9.html

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.

InterruptssoftirqDeferred Execution
Liangxu Linux
Written by

Liangxu Linux

Liangxu, a self‑taught IT professional now working as a Linux development engineer at a Fortune 500 multinational, shares extensive Linux knowledge—fundamentals, applications, tools, plus Git, databases, Raspberry Pi, etc. (Reply “Linux” to receive essential resources.)

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.