ax-handler-table 技术文档
路径:
components/handler_table类型:库 crate 分层:组件层 / 处理器表基础件 版本:0.3.2文档依据:Cargo.toml、README.md、src/lib.rs
ax-handler-table 是一个固定大小、无锁、仅存函数指针的处理器表。它用 AtomicUsize 数组保存 fn() 处理函数,支持按槽位注册、注销和调用。它是非常典型的叶子基础件:不是中断控制器、不是事件总线、也不是通用回调注册中心。
1. 架构设计分析
1.1 设计定位
这个 crate 解决的是“如何在极低开销下按编号存放一组处理函数”:
- 事件编号天然 是整数索引。
- 处理器要求是极简的
fn(),没有捕获环境、没有参数、没有返回值。 - 注册/注销/查询要尽量避免引入锁。
在当前仓库里,它最真实的使用场景是 ax_plat::irq 及各平台的 IRQ_HANDLER_TABLE。
1.2 核心类型
Handler = fn():处理函数类型,刻意限制为普通函数指针。HandlerTable<const N: usize>:内部持有[AtomicUsize; N]的表结构。
1.3 实现主线
它的实现非常直接:
几个关键点需要文档里明确:
- 注册只允许空槽位写入,已存在处理器时返回
false。 - 注销返回原来的函数指针,便于调用方做恢复或复用。
handle()只做一次 load 并立即调用,没有额外同步。
1.4 能力边界
- 它不支持捕获闭包,因为底层存的就是裸
fn()指针。 - 它不支持处理器链、优先级或共享状态。
- 它也不保证“注销后绝不会再跑一次处理器”:如果
handle()已经 load 到指针,再unregister(),那次调用仍可能继续发生。
2. 核心功能说明
2.1 主要功能
- 以 O(1) 索引方式注册或注销处理器。
- 以无锁 load 的方式调用对应槽位的函数。
- 为空槽位和越界索引返回显式失败结果。
2.2 关键 API 与真实使用位置
HandlerTable::new():各平台 IRQ 子系统用它声明静态处理器表。register_handler()/unregister_handler():被components/axplat_crates/ax-plat/src/irq.rs的平台实现间接消费。handle():由平台 IRQ 处理路径在拿到实际 IRQ 号后调用。
2.3 使用边界
ax-handler-table不负责从硬件拿 IRQ 号,也不负责 EOI/ACK。ax-handler-table不区分设备中断、IPI 或软中断类型;它只管“编号 -> 函数”的映射。ax-handler-table也不是通用事件系统,过于复杂的回调模型不适合塞进来。
3. 依赖关系图谱
3.1 关键直接依赖
这个 crate 本体没有本地 crate 依赖,保持了非常小的体量。
3.2 关键直接消费者
ax_plat::irq:把HandlerTable作为平台 IRQ 管理接口的一部分导出。- 各平台 IRQ 实现:如
ax-plat-x86-pc、ax-plat-riscv64-qemu-virt等,都直接声明静态IRQ_HANDLER_TABLE。
4. 开发指南
4.1 依赖配置
[dependencies]
ax-handler-table = { workspace = true }
4.2 修改时的关键约束
Handler当前是fn(),这不是偶然简化,而是设计边界;改成闭包会影响存储模型和无锁语义。AtomicUsize与函数指针互转是这个 crate 的基础假设,任何改动都要重新评估平台 ABI。- 若增加更多同步保证,要明确代价和语义变化,避免把它从“简表”做成“复杂注册中心”。
- 索引越界目前统一返回失败而非 panic,这个 API 风格不应随意变动。
4.3 开发建议
- 需要复杂回调上下文时,外层应自己维护状态再注册一个静态跳板函数。
- 需要多处理器链或共享对象时,应新建专门结构,而不是强行扩展
ax-handler-table。 - 平台层如果想做 IRQ 抽象,应把
ax-handler-table作为内部数据结构,而不是把所有控制逻辑下沉到这里。