Workqueue and Deferred Execution¶
Overview¶
Linux drivers frequently need to perform work that cannot be executed directly inside interrupt handlers.
Examples include:
- I2C transactions
- SPI transfers
- Mutex operations
- Memory allocation with sleepable flags
- Long-running recovery procedures
To support these operations safely, Linux provides deferred execution mechanisms.
Why Deferred Execution Exists¶
Hard IRQ handlers execute in atomic context.
Restrictions:
- Cannot sleep
- Cannot schedule
- Cannot wait for events
- Cannot acquire mutexes
Therefore, interrupt handlers should perform only minimal processing:
More complex operations must be moved into a sleepable context.
Linux Execution Contexts¶
Hard IRQ Context¶
Examples:
Characteristics:
- Atomic context
- Cannot sleep
- Lowest interrupt latency
Suitable for:
- Interrupt acknowledgement
- Status collection
- Event notification
Threaded IRQ Context¶
Examples:
Characteristics:
- Sleepable
- Dedicated IRQ thread
- Interrupt-driven processing
Suitable for:
- Sensor event processing
- I2C/SPI register access
- Immediate post-interrupt handling
Workqueue Context¶
Examples:
Characteristics:
- Sleepable
- Executed by kworker threads
- Event-driven background processing
Suitable for:
- Retry operations
- Deferred processing
- Recovery procedures
- Delayed execution
Kernel Thread Context¶
Examples:
Characteristics:
- Sleepable
- Long-lived execution
- Driver-managed lifecycle
Suitable for:
- State machines
- Monitoring services
- Connection managers
- Reclaimers
Workqueue Architecture¶
Basic workflow:
The work handler executes in process context.
Allowed operations:
- mutex_lock()
- msleep()
- wait_event()
- i2c_transfer()
- spi_sync()
Global vs Private Workqueues¶
system_wq¶
Default global workqueue provided by Linux.
Used by:
Equivalent to:
Advantages:
- Simple
- No lifecycle management required
Disadvantages:
- Shared with other kernel subsystems
- Shared worker resources
Private Workqueue¶
Created by:
Advantages:
- Workload isolation
- Dedicated worker pool
- Independent lifecycle
Suitable when:
- Work execution may be lengthy
- Driver requires concurrency control
- Driver requires dedicated resources
Delayed Work¶
Delayed Work combines:
Execution flow:
Common applications:
- Debounce
- Retry logic
- Monitoring
- Timeout handling
Workqueue Lifecycle¶
Typical driver lifecycle:
Cleanup sequence:
disable_irq()
↓
cancel_work_sync()
↓
cancel_delayed_work_sync()
↓
destroy_workqueue()
↓
free resources
Purpose:
Workqueue vs Threaded IRQ¶
Threaded IRQ:
Workqueue:
Selection guideline:
Workqueue vs Kernel Thread¶
Workqueue:
Characteristics:
- Event-driven
- Finite execution
- Managed by kernel worker pools
Examples:
- Recovery work
- Retry work
- Debounce work
Kernel Thread:
Characteristics:
- Long-lived execution
- Continuous operation
- Explicit lifecycle management
Examples:
- State machines
- Monitoring services
- Protocol engines
- Reclaimers
Design Selection Guide¶
Need lowest interrupt latency?
→ Hard IRQ
Need interrupt-driven processing with sleep?
→ Threaded IRQ
Need deferred background work?
→ Workqueue
Need long-lived service or state machine?
→ Kernel Thread
Key Takeaways¶
- Deferred execution moves work into a sleepable context.
- Workqueues execute jobs using kernel-managed worker threads.
- Delayed Work combines timer functionality with workqueues.
- Private workqueues isolate driver workloads from system workqueues.
- Threaded IRQ is optimized for interrupt-driven processing.
- Kernel Threads are optimized for long-lived services and state machines.
- Choosing the correct execution context simplifies driver design and improves maintainability.