ax-task
路径:
os/arceos/modules/axtask类型:库 crate 分层:ArceOS 层 / ArceOS 内核模块 版本:0.3.0-preview.3文档依据:Cargo.toml、README.md、src/lib.rs、src/api.rs、src/task.rs、src/run_queue.rs、src/wait_queue.rs、src/timers.rs、src/future/*
ax-task 是 ArceOS 的任务管理核心模块。它既承担线程/任务对象的创建、阻塞、退出与回收,又通过 axsched 抽象把 FIFO、RR、CFS 等调度策略统一到同一个运行队列框架下,并进一步向 StarryOS 和 Axvisor 输出可复用的调度基础设施。
架构设计
1.1 总体设计
ax-task 的设计目标不是提供“单一线程库”,而是构造一个可裁剪的内核任务运行时:
- 通过
multitaskfeature 在“真正多任务调度器”和“单任务桩实现”之间切换。 - 通过
multitask、sched-rr、sched-cfs在同一套 API 下选择不同调度策略。 - 通过
irq、preempt、smp、tls、task-ext决定任务系统究竟具备多少内核能力。
因此,ax-task 是一个强 feature 驱动的状态机模块,而不是简单的 API 封装。
模块结构
src/lib.rs:顶层 feature 门控。决定编译run_queue、task、api、wait_queue、future、timers还是退回api_s单任务实现。src/task.rs:任务实体定义与状态机,包含TaskInner、TaskState、CurrentTask、栈对象、退出码、join 与可选 TLS/TaskExt 字段。src/run_queue.rs:每 CPU 运行队列、调度切换、GC 任务、SMP 下多队列初始化与迁移逻辑。src/api.rs:多任务模式下的公开 API,如spawn()、yield_now()、sleep()、exit()、set_priority()、set_current_affinity()等。src/api_s.rs:单任务模式下的桩实现,很多“阻塞”行为会退化为 busy-wait 或等待 IRQ。src/wait_queue.rs:基于event-listener的等待队列封装。src/timers.rs:IRQ 打开时的定时事件回调与每核计时事件检查。src/future/mod.rs:内核态block_on、waker、阻塞/唤醒桥接。src/future/time.rs:截止时间驱动的 sleep/timeout future 与每核TimerRuntime。src/future/poll.rs:I/O poll 异步适配,与axpoll协作。src/tests.rs:FIFO、浮点状态切换、WaitQueue、join等单元测试。
1.3 关键数据结构
TaskState:Running、Ready、Blocked、Exited,是任务生命周期分析的核心。TaskInner:任务内部主体,包含任务名、entry 闭包、上下文、栈、退出码、等待退出事件、CPU 亲和、可选 TLS、可选TaskExt等。CurrentTask:当前任务句柄,是 API 层访问当前任务状态、优先级、亲和性和扩展对象的主要入口。AxTaskRef/WeakAxTaskRef:调度器持有的任务引用类型。AxRunQueue:每 CPU 运行队列包装,内部持有具体Scheduler实例并负责上下文切换。WaitQueue:内核阻塞/唤醒的基础同步原语。TimerRuntime:基于截止时间和 waker 的软件定时运行时,仅在irq路径启用。AxTaskExt/TaskExt:供上层系统附加任务私有语义的扩展接口,是 StarryOS 线程对象与 Axvisor vCPU 任务集成的关键点。
1.4 调度器抽象与算法实现
ax-task 并不自己实现完整调度算法,而是通过 api.rs 中的类型别名把 TaskInner 适配到 axsched:
multitask:FifoScheduler+FifoTask,协作式调度。sched-rr:RRScheduler+RRTask,带时间片,依赖preempt。sched-cfs:CFScheduler+CFSTask,公平调度,同样依赖preempt。
这层设计的关键好处是:
TaskInner始终保持稳定。- 上层 API 如
spawn、yield_now、sleep无需感知底层采用 FIFO、RR 还是 CFS。 - StarryOS、Axvisor 可以在不重写任务核心对象的前提下复用调度机制。
1.5 任务生命周期主线
典型生命周期可概括为:
更具体的初始化主线如下:
init_scheduler()调用run_queue::init()。- 主 CPU 创建 idle 任务、当前 init 任务和 GC 任务。
spawn_task()/spawn()把新任务加入选中的运行队列。yield_current()、blocked_resched()、scheduler_timer_tick()驱动状态在Running/Ready/Blocked间转换。exit_current()把任务移入退出队列,由 GC 任务清理最终资源。
核心功能
功能概览
- 任务创建:
spawn_task()、spawn_raw()、spawn_with_name()、spawn()。 - 任务调度:
yield_now()、调度器 tick、优先级调整、CPU 亲和迁移。 - 阻塞与等待:
WaitQueue、block_on()、sleep/timeout。 - 退出与回收:
exit()、join()、GC 任务。 - 扩展语义:通过
TaskExt把上层系统数据挂到任务对象上。
2.2 关键 API
最常用的 API 入口在 src/api.rs:
current()/current_may_uninit()init_scheduler()/init_scheduler_secondary()spawn()/spawn_task()yield_now()sleep()/sleep_until()exit()set_priority()set_current_affinity()on_timer_tick()(irq打开时)
2.3 典型使用示例
use core::time::Duration;
let worker = ax-task::spawn(|| {
// do work
});
ax-task::yield_now();
ax-task::sleep(Duration::from_millis(10));
let _exit_code = worker.join();
若需要等待条件成立,通常走 WaitQueue:
let wq = ax-task::WaitQueue::new();
// 条件不满足时 wait,条件满足后 wake
依赖关系
常见 feature 组合:
multitask:启用完整任务管理。multitask/sched-rr/sched-cfs:选择调度器。preempt:允许基于 timer tick 的抢占。irq:启用 sleep/timeout 等基于中断的时间能力。smp:启用多核运行队列与任务迁移。tls:启用任务 TLS。task-ext:允许外部系统挂接扩展任务对象。
4.2 初始化与接入顺序
- 先确保上层运行时已完成
ax-hal初始化。 - 主 CPU 调
init_scheduler(),从 CPU 调init_scheduler_secondary()。 - 再通过
spawn()等 API 投递任务。 - 若启用
irq与preempt,需要保证 timer tick 能 够进入on_timer_tick()。
4.3 关键开发注意事项
- 修改
TaskInner时,要同时检查调度器包装类型、TaskExt、TLS、join 和 GC 回收路径是否仍一致。 - 修改
run_queue.rs时,要同时检查 FIFO/RR/CFS 三种调度器行为是否都成立。 - 修改
WaitQueue、future、timers时,要区分irq开启与关闭两条实现路径。 - 修改
smp相关逻辑时,要同时验证 CPU 亲和、迁移任务和每核队列初始化。
测试
单元测试
src/tests.rs 已经覆盖了几类关键路径:
- FIFO 调度顺序。
- 浮点状态切换。
WaitQueue行为。- 任务
join路径。
后续新增功能时,应优先补这几类单元测试:
- 状态转换与退出码传播。
- 多调度器策略的一致性。
task-ext、TLS、CPU 亲和与迁移路径。irq与非irq两种 sleep/timeout 语义。