Work Queue Demo
Description
Demonstrates kernel work queues for deferred work execution in process context.
Features
- Immediate work - Executes ASAP
- Delayed work - Executes after delay
- Dedicated workqueue - Separate worker threads
- Process context - Can sleep, use mutexes
- Periodic execution - Self-rescheduling work
Build & Test
make
sudo insmod workqueue_demo.ko
# Watch work execute (in another terminal)
dmesg -w
# Wait ~10 seconds for all work to complete
sleep 10
# Unload (cancels pending work)
sudo rmmod workqueue_demo
dmesg | tail -20
Expected Output
=== Work Queue Demo ===
1. Scheduling immediate work...
Immediate work scheduled
2. Scheduling delayed work (2 seconds)...
Delayed work scheduled
3. Creating dedicated workqueue...
Dedicated workqueue created
Queued work item 0
Queued work item 1
Queued work item 2
=== Work items scheduled ===
# Shortly after:
Immediate work executed! Count: 1, PID: 1234
Immediate work done
Dedicated work [0]: Processing task_0, PID: 1235
Dedicated work [0]: Done
Dedicated work [1]: Processing task_1, PID: 1235
...
# After 2 seconds:
Delayed work executed! Count: 4, PID: 1236
Rescheduling delayed work (count: 4)
# After 4 seconds:
Delayed work executed! Count: 5, PID: 1236
Delayed work finished
Work Queue Types
1. System Workqueue
schedule_work(&work); // Shared system workqueue
- Pros: Simple, no setup needed
- Cons: Shared with all modules
- Use: Short, non-blocking work
2. Delayed Work
schedule_delayed_work(&dwork, delay);
- Pros: Built-in delay mechanism
- Cons: Less precise than timers
- Use: Periodic tasks, timeouts
3. Dedicated Workqueue
wq = create_singlethread_workqueue("name");
queue_work(wq, &work);
- Pros: Isolated, predictable
- Cons: More overhead
- Use: Long-running work, priority control
Work Queue vs Other Mechanisms
| Mechanism | Context | Can Sleep | Latency | Use Case |
|---|---|---|---|---|
| Interrupt | Hardirq | No | Lowest | Quick hardware ack |
| Tasklet | Softirq | No | Low | Fast deferred work |
| Work Queue | Process | Yes | Medium | Blocking operations |
| Kernel Thread | Process | Yes | Variable | Background tasks |
Learning Points
Process Context
Work functions run in process context, so they can:
- Sleep (
msleep,msleep_interruptible) - Use mutexes (
mutex_lock,mutex_unlock) - Allocate with
GFP_KERNEL - Access user space (carefully)
Cancellation
Always cancel work before cleanup:
cancel_work_sync(&work); // Wait for completion
cancel_delayed_work_sync(&dwork); // Cancel and wait
Container Pattern
Use container_of to get your data:
struct my_work {
struct work_struct work;
int data;
};
static void my_work_fn(struct work_struct *work)
{
struct my_work *mw = container_of(work, struct my_work, work);
// Use mw->data
}
Common Use Cases
- Network drivers: Process received packets
- Block drivers: I/O completion handling
- Character drivers: Deferred reads/writes
- Power management: Suspend/resume operations
- Cleanup tasks: Free resources asynchronously
Advanced Options
// Create with specific flags
create_workqueue("name"); // Multi-threaded
create_singlethread_workqueue("name"); // Single thread
alloc_workqueue("name", flags, max_active); // Custom
// Flags
WQ_UNBOUND // Not bound to specific CPU
WQ_HIGHPRI // High priority
WQ_CPU_INTENSIVE // Long-running work
Debugging
# See active workqueues
cat /proc/workqueues
# See worker threads
ps aux | grep kworker