Day83 - Deferred Work Architecture and Selection¶
Objective¶
Understand how Linux drivers choose between different deferred execution mechanisms.
The goal of this lab is not to learn new APIs, but to understand the design trade-offs between:
- Threaded IRQ
- Workqueue
- kthread_worker
- Dedicated kthread
and how they fit into real Linux driver architectures.
Background¶
Interrupt handlers execute in hard IRQ context.
Hard IRQ context has strict limitations:
- Cannot sleep
- Cannot block
- Cannot acquire sleeping locks
- Should finish as quickly as possible
Therefore, Linux drivers often move processing into a deferred execution context.
Typical architecture:
Lab1 - Execution Context Comparison¶
Goal¶
Compare where different deferred mechanisms execute.
Mechanisms tested:
- Threaded IRQ
- Workqueue
- kthread_worker
- Dedicated kthread
Test Code¶
Each execution context prints:
to identify the executing thread.
Example:
static void print_context(const char *name)
{
log_info("[%s] tid=%lu",
name,
(unsigned long)pthread_self());
}
Threaded IRQ¶
Top half:
static irqreturn_t irq_top_half(int irq, void *data)
{
print_context("TOP_HALF");
return IRQ_WAKE_THREAD;
}
Thread function:
static irqreturn_t irq_thread_fn(int irq, void *data)
{
print_context("THREADED_IRQ");
msleep(100);
log_info("[THREADED_IRQ] sleep OK");
return IRQ_HANDLED;
}
Workqueue¶
static void work_func(struct work_struct *work)
{
print_context("WORKQUEUE");
msleep(100);
log_info("[WORKQUEUE] sleep OK");
}
kthread_worker¶
static void kthread_work_func(struct kthread_work *work)
{
print_context("KTHREAD_WORKER");
msleep(100);
log_info("[KTHREAD_WORKER] sleep OK");
}
Dedicated kthread¶
Result¶
Example output:
[TOP_HALF] tid=134842914649920
[THREADED_IRQ] tid=134842912077504
[WORKQUEUE] tid=134842903684800
[KTHREAD_WORKER] tid=134842870113984
[KTHREAD] tid=134842861721280
Observation¶
Top half executes in IRQ context.
The following execute in thread context:
- Threaded IRQ
- Workqueue
- kthread_worker
- Dedicated kthread
All of them can sleep.
This demonstrates the primary purpose of deferred execution:
Lab2 - Driver Pattern Selection¶
Goal¶
Map common Linux driver designs to appropriate deferred execution mechanisms.
Button Driver¶
Scenario¶
GPIO button debounce.
Architecture:
Implementation:
Recommended mechanism:
Reason:
- Simple processing
- No state machine
- No dedicated thread required
Sensor Driver¶
Scenario¶
Data-ready interrupt from a sensor.
Architecture:
Implementation:
static irqreturn_t sensor_irq_thread_fn(
int irq,
void *data)
{
log_info("[SENSOR] read register");
msleep(100);
log_info("[SENSOR] update value");
return IRQ_HANDLED;
}
Recommended mechanism:
Reason:
- Strongly tied to a specific IRQ
- Requires sleepable bus access
- Processing is relatively simple
Touch Driver¶
Scenario¶
Touch packet processing.
Architecture:
Implementation:
static void touch_work_func(
struct kthread_work *work)
{
log_info("[TOUCH] read packet");
log_info("[TOUCH] parse packet");
log_info("[TOUCH] report event");
}
Recommended mechanism:
Reason:
- Ordered packet processing
- FIFO execution
- Dedicated worker thread
WiFi Driver¶
Scenario¶
Multiple event sources.
Events:
- RX
- TX
- Timeout
- Recovery
- Scan
Architecture:
Implementation:
static int wifi_thread(void *data)
{
while (!kthread_should_stop()) {
log_info("[WIFI] process RX");
log_info("[WIFI] process TX");
log_info("[WIFI] process timeout");
msleep(100);
}
return 0;
}
Recommended mechanism:
Reason:
- Multiple event sources
- Long-running background thread
- State-machine based design
Deferred Mechanism Selection Matrix¶
| Requirement | Recommended Mechanism |
|---|---|
| Very short work, no sleep | ISR |
| IRQ-bound sleepable work | Threaded IRQ |
| Simple deferred work | Workqueue |
| FIFO ordering required | kthread_worker |
| Multiple event sources | Dedicated kthread |
| State machine required | Dedicated kthread |
Key Takeaways¶
Deferred execution is fundamentally about execution context selection.
Different mechanisms represent different trade-offs:
| Mechanism | Sleep | Ordering | Dedicated Thread | FSM |
|---|---|---|---|---|
| ISR | No | N/A | No | No |
| Threaded IRQ | Yes | IRQ-local | Yes | No |
| Workqueue | Yes | Limited | No | No |
| kthread_worker | Yes | FIFO | Yes | No |
| Dedicated kthread | Yes | Custom | Yes | Yes |
Understanding these trade-offs is more important than memorizing APIs.