DragonOS Workqueue 机制设计文档
1. 概述
工作队列(Workqueue)是 DragonOS 内核中的一种”下半部”(Bottom Half)机制,用于将任务推迟到进程上下文中执行。与 Softirq 和 Tasklet 不同,工作队列的处理函数运行在内核线程中,因此允许执行以下操作:
睡眠(阻塞等待资源)
获取互斥锁(Mutex)或信号量
执行 I/O 操作
分配内存(可能导致阻塞)
本机制的设计参考了 Linux 内核的工作队列实现,并针对 DragonOS 的 Rust 架构进行了适配。
2. 核心架构
2.1 核心组件
Workqueue 机制主要由以下三个组件构成:
Work(工作项):
定义了需要延迟执行的具体任务。
在 Rust 实现中,本质上是一个封装了闭包(Closure)或函数指针的结构体。
通过
Arc进行引用计数管理,支持跨线程共享。
WorkQueue(工作队列):
负责管理待处理的工作项(Pending Works)。
维护一个或多个关联的工作线程(Worker Thread)。
内部包含一个 FIFO 队列和一个
WaitQueue(用于线程同步)。
Worker Thread(工作线程):
一个专门的内核线程,循环从 WorkQueue 中取出任务并执行。
当队列为空时,线程进入睡眠状态(通过
WaitQueue挂起)。当有新任务入队时,线程被唤醒。
2.2 数据流图
graph TD
User[调用者 (Driver/Interrupt)] -->|schedule_work()| WQ[WorkQueue]
WQ -->|enqueue| Queue[待处理队列]
WQ -->|wakeup| Worker[Worker Thread]
subgraph Worker Thread Loop
Check{队列为空?} -->|Yes| Sleep[睡眠等待]
Check -->|No| Dequeue[取出 Work]
Dequeue --> Run[执行 Work.func()]
Run --> Check
end
Sleep -.->|被唤醒| Check
3. 详细设计
3.1 数据结构设计
Work
Work 结构体封装了具体的任务逻辑。使用 Box<dyn Fn() + Send + Sync> 来存储闭包,确保其可以在线程间安全传递和执行。
pub struct Work {
func: Box<dyn Fn() + Send + Sync>,
}
WorkQueue
WorkQueue 是核心管理结构。它包含:
queue: 一个受自旋锁(SpinLock)保护的双端队列,存储Arc<Work>。wait_queue: 用于工作线程的同步等待。worker: 指向关联内核线程 PCB 的引用。
pub struct WorkQueue {
queue: SpinLock<VecDeque<Arc<Work>>>,
wait_queue: Arc<WaitQueue>,
worker: SpinLock<Option<Arc<ProcessControlBlock>>>,
}
3.2 运行机制
初始化:
调用
WorkQueue::new(name)创建一个新的工作队列。该操作会自动启动一个名为
name的内核线程。
任务调度:
调用者使用
Work::new(closure)创建工作项。调用
wq.enqueue(work)将任务加入队列。enqueue操作会将任务推入队列尾部,并调用wait_queue.wakeup()唤醒工作线程。
任务执行:
工作线程运行
worker_loop函数。循环检查队列状态:
若队列非空:取出队首任务,调用
work.run()执行。若队列为空:在
wait_queue上调用wait_event_interruptible进入睡眠,等待被唤醒。
3.3 系统全局队列 (SYSTEM_WQ)
为了简化常见场景的使用,系统提供了一个全局默认工作队列 SYSTEM_WQ。
大多数简单的后台任务可以直接提交到该队列,无需创建专用的 WorkQueue。
通过
schedule_work(work)接口直接调度。
4. 接口说明
4.1 创建任务
let work = Work::new(|| {
log::info!("This is running in a workqueue!");
// 可以安全地睡眠或加锁
});
4.2 调度任务
// 调度到系统默认队列
schedule_work(work);
// 或者调度到自定义队列
let my_wq = WorkQueue::new("my_driver_wq");
my_wq.enqueue(work);
5. 与 Linux 的异同
相同点:
都是基于内核线程的延迟执行机制。
都支持睡眠和阻塞操作。
都提供了系统默认的全局队列。
不同点:
并发模型:DragonOS 当前实现采用”单线程单队列”模型(每个 WorkQueue 对应一个内核线程)。Linux 采用复杂的 Worker Pool 模型,支持动态扩缩容和并发管理(CM)。
Per-CPU:DragonOS 当前未实现 Per-CPU 的 WorkQueue,所有任务在同一个线程队列中处理。
API 风格:DragonOS 利用 Rust 的闭包特性,使得任务定义更加灵活简洁,不需要像 Linux 那样嵌入
work_struct到自定义结构体中(尽管也支持类似模式)。
6. 未来演进
并发管理:引入 Worker Pool 机制,允许多个 Worker 消费同一个队列,提高并发度。
Per-CPU 队列:实现 Per-CPU 的 WorkQueue,减少锁竞争,提高缓存局部性。
延迟工作(Delayed Work):集成定时器机制,支持
schedule_delayed_work,允许任务在指定延迟后执行。