ax-sync
路径:
os/arceos/modules/axsync类型:库 crate 分层:ArceOS 层 / ArceOS 内核模块 版本:0.3.0-preview.3文档依据:Cargo.toml、README.md、src/lib.rs、src/mutex.rs
ax-sync 是 ArceOS 提供统一同步原语的模块。它的设计很克制:不是实现一整套锁家族,而是把“阻塞互斥锁”和“自旋锁”统一收敛到一个稳定的 Mutex 名称上,并通过 feature 决定当前系统拿到的到底是哪一种语义。
架构设计
设计定位
ax-sync 的目标不是做一个庞大的同步库,而是解决两个现实问题:
- 对大多数上层模块来说,只需要一个统一的
Mutex名字,不想在代码里到处分辨当前是“多任务可阻塞锁”还是“无调度环境自旋锁”。 - 对需要显式控制抢占/中断语义的低层代码来说,仍然要能直接访问
ax-kspin提供的自旋锁家族。
因此,ax-sync 的职责边界是:
- 向上提供统一的
Mutex/MutexGuard/ 可选RawMutex。 - 向下复用
ax-kspin、lock_api、event-listener和ax-task,而不是重复造轮子。
模块结构
src/lib.rs:feature 分流入口。决定Mutex是ax_kspin::SpinNoIrq的别名,还是本 crate 自己的阻塞 mutex。src/mutex.rs:只在multitask开启时编译,定义RawMutex、Mutex<T>和MutexGuard。README.md:说明multitaskfeature 的语义与使用方式。
1.3 关键类型与锁语义
ax-sync::spin:直接再导出ax-kspincrate,供调用者显式使用自旋锁。Mutex/MutexGuard:- 未启用
multitask时:别名到SpinNoIrq与其 guard。 - 启用
multitask时:别名到lock_api::Mutex<RawMutex, T>。
- 未启用
RawMutex:multitask路径中的底层锁实现,内部维护:owner_id: AtomicU64:锁拥有者任务 ID,0表示未持有。event: Event:等待与唤醒队列。
1.4 阻塞 mutex 的主线
RawMutex::lock() 的实现路径很值得单独说明:
这条路径体现了三个层次:
- 先尝试快速 CAS 抢锁。
- 若失败,先做一小段指数退避式自旋与
yield_now()。 - 再进一步进入
event-listener+ax-task::future::block_on()的阻塞等待。
因此 ax-sync 的阻塞 mutex 不是纯 parking lock,也不是纯自旋锁,而是“短自旋 + 让出 + 阻塞”的混合策略。
1.5 解锁与非重入约束
unlock()通过swap(0, Release)清空owner_id,然后调用event.notify(1)唤醒等待者。lock()中显式断言当前任务不能重复获取自己已持有的锁,因此RawMutex是 非重入 mutex。GuardMarker = GuardSend,表明 guard 的发送语义遵循lock_api的该类约定。
1.6 multitask feature 的决定性作用
这是 ax-sync 最关键的 feature:
- 打开
multitask:- 编译
src/mutex.rs - 导出
RawMutex Mutex变为真正可阻塞的互斥锁- 同时要求
ax-task/multitask
- 编译
- 关闭
multitask:RawMutex不存在Mutex只是SpinNoIrq的别名
需要注意的是,源码注释里曾有“multitask 默认启用”的描述,但 Cargo.toml 实际以 default = [] 为准。也就是说,当前仓库中应以 manifest 为真,而不是以旧注释为真。
核心功能
功能概览
- 在多任务环境中提供阻塞式互斥锁。
- 在无多任务环境中把同名
Mutex退化为关中断自旋锁。 - 通过
ax-sync::spin暴露完整的ax-kspin自旋锁家族。
使用场景
Mutex<T>:上层模块最常用的统一互斥抽象。MutexGuard:保护临界区访问。RawMutex:在需要和lock_api深度集成时使用,但只在multitask下存在。ax-sync::spin::*:需要显式使 用自旋锁或中断屏蔽语义时使用。
使用方式
最典型的调用方式是把它当成统一互斥抽象:
use ax-sync::Mutex;
static COUNTER: Mutex<u64> = Mutex::new(0);
let mut guard = COUNTER.lock();
*guard += 1;
同一段代码在 multitask 打开与关闭时可以保持相同接口,但底层语义会分别落到阻塞 mutex 或 SpinNoIrq。