Zephyr 内核对象、同步与内存管理
1. 内核对象的共同模式
多数内核对象包含:
- 当前状态或资源计数;
- wait queue;
- spinlock/全局调度锁保护;
- iterable/object core 元数据;
- userspace 权限元数据。
API 的典型结构:
1 | 立即路径:资源可用 → 更新状态 → 返回 |
2. Semaphore
实现:kernel/sem.c。
1 | K_SEM_DEFINE(sem, initial, limit); |
- count 大于 0 时
take直接减一; - count 为 0 时线程进入 wait queue;
give优先直接唤醒等待者,否则递增 count;- ISR 可
give,take仅能使用不阻塞语义。
适合事件计数和有界资源,不携带数据。
3. Mutex
实现:kernel/mutex.c。
1 | K_MUTEX_DEFINE(lock); |
特性:
- 记录 owner;
- 支持递归 lock count;
- priority inheritance 缓解优先级反转;
- 只能在线程上下文使用;
- owner 才能 unlock。
继承提高 owner 的有效优先级;释放嵌套 mutex 时需要重新计算其可恢复优先级。
4. Condition variable
实现:kernel/condvar.c。
condition variable 与 mutex 配合:
1 | lock mutex |
wait 原子释放 mutex 并阻塞;被唤醒后重新获得 mutex。必须循环检查 predicate,不能假定一次 signal 就代表条件仍成立。
5. Events
实现:kernel/events.c。
k_event 保存 bitset:
- post/set/clear bits;
- 等待 any/all;
- 可选择 reset;
- 一次表达多个逻辑事件。
适合控制状态组合;大量数据仍应通过 queue/msgq 传输。
6. Queue、FIFO 与 LIFO
实现:kernel/queue.c。
k_queue:通用 intrusive queue;k_fifo:尾插头取;k_lifo:头插头取。
入队元素需提供保留 link 字段,或使用 alloc append 让内核分配 wrapper。ISR 可进行非阻塞 put/get,具体限制以 API 为准。
7. Message queue
实现:kernel/msg_q.c。
1 | K_MSGQ_DEFINE(q, msg_size, max_msgs, align); |
消息按值复制到固定环形 buffer:
- 内存上界确定;
- producer 与 consumer 解耦;
- 消息大小固定;
- put/get 均可阻塞。
适合小型控制消息;大 payload 可传 buffer pointer,但必须管理生命周期。
8. Mailbox 与 Pipe
kernel/mailbox.c:同步/异步 mailbox message,支持直接或缓冲传递;kernel/pipes.c:字节流 buffer,可读写部分数据并阻塞。
若只需要固定消息,优先 msgq;连续字节流才考虑 pipe/ring buffer。
9. Poll
实现:kernel/poll.c。
k_poll() 一次等待多个对象:
- semaphore available;
- queue data available;
- signal raised;
- ignore。
对象状态变化时通知 poller。复杂事件循环可借助 poll,但应控制 event 数量和并发 registration 生命周期。
10. Workqueue
实现:
kernel/work.ckernel/system_work_q.c
对象:
k_work:普通 work;k_work_delayable:带 timeout;k_work_poll:poll 触发;k_work_q:自定义 worker thread。
流程:
1 | k_work_submit() |
system workqueue 是共享线程。handler 阻塞过久会延迟所有共用者。长期 I/O、flash erase 或不可信 callback 应使用独立 workqueue。
取消 delayable work 时要区分:
- 尚未到期;
- 已排队;
- 正在执行;
- handler 内重新提交。
需要严格同步可使用 k_work_cancel_sync() / flush API。
11. Timer
实现:kernel/timer.c,底层依赖 timeout。
1 | K_TIMER_DEFINE(timer, expiry_fn, stop_fn); |
expiry callback 通常在系统 clock interrupt 或相关内核上下文执行,不能做阻塞操作。复杂处理应提交 work。
k_timer_status_sync() 可在线程中等待到期次数。
12. Heap
kernel/kheap.c 把系统 heap 封装为内核 API:
1 | k_malloc / k_calloc / k_realloc / k_free |
底层 heap 实现在 lib/heap/,支持按 bucket/size class 管理空闲块。动态分配具有碎片和时延不确定性:
- 初始化期分配、运行期固定持有较安全;
- 高频实时路径优先 slab/固定池;
- 检查
CONFIG_HEAP_MEM_POOL_SIZE; - userspace thread 可绑定 resource pool。
13. Memory slab
实现:kernel/mem_slab.c。
1 | K_MEM_SLAB_DEFINE(slab, block_size, num_blocks, align); |
特点:
- 固定大小 block;
- 无外部碎片;
- 分配/释放时间更稳定;
- 可阻塞等待空闲块。
适合 network packet metadata、消息节点、固定协议对象。
14. Stack 与线程内存
线程 stack 使用 K_THREAD_STACK_DEFINE() 等宏,而非普通 byte array,原因包括:
- MPU/MMU guard;
- userspace privilege stack;
- architecture alignment;
- stack metadata;
- sanitizer。
常用诊断:
CONFIG_STACK_SENTINEL;CONFIG_STACK_CANARIES;CONFIG_THREAD_STACK_INFO;CONFIG_INIT_STACKS;- thread analyzer;
k_thread_stack_space_get()。
stack overflow 可能破坏邻近对象,不能只按平均使用量估算。
15. Userspace
主要文件:
kernel/userspace.ckernel/userspace_handler.ckernel/mem_domain.cinclude/zephyr/syscall.hscripts/build/gen_syscalls.py
启用 CONFIG_USERSPACE 后:
- user thread 以非特权模式运行;
- kernel object 有权限位图/哈希表;
- syscall 进入 verifier;
- verifier 检查 object type、权限、buffer address;
- 实际实现为
z_impl_*; - MPU/MMU memory domain 限制访问范围。
典型 API 生成模式:
1 | public syscall declaration |
userspace 提升隔离但增加代码、RAM、syscall 和 context-switch 成本。
16. Memory domain
k_mem_domain 把 memory partitions 分配给 user threads:
- code/data partition;
- application shared memory;
- thread 加入/移出 domain;
- architecture MPU/MMU 更新。
分区数量受硬件 MPU region 数量约束。动态切换前应确认 alignment 和 region 合并规则。
17. Object core 与 Runtime stats
kernel/obj_core.c 提供统一对象注册/查询基础,可用于:
- thread/device/kernel object 枚举;
- runtime statistics;
- shell/debug 工具;
- tracing。
CONFIG_OBJ_CORE 及 stats 选项会增加 metadata 和运行期开销。
18. Fatal error
kernel/fatal.c 处理:
- CPU exception;
- stack check failure;
- kernel oops/panic;
- essential thread abort;
- unhandled fault。
路径通常为:
1 | arch fault |
应用可覆盖 fatal handler,但生产系统必须避免在状态已损坏时盲目继续。常见策略是记录最小 crash 信息、触发 watchdog/reset,并由 boot/update 策略处理重复崩溃。
19. 对象选择建议
- 计数/唤醒:semaphore;
- 保护共享结构:mutex;
- 等待 predicate:condvar;
- 多 bit 状态:event;
- 固定小消息:msgq;
- 指针对象:fifo/queue;
- 延后 ISR 工作:workqueue;
- 固定块内存:slab;
- 可变大小低频内存:heap;
- 等待多个来源:poll。
选择错误会导致不必要复制、动态分配、优先级反转或 system workqueue 阻塞。
正在加载留言…