与第 1 版内核的改动

为了提升开发者的易用性,第 2 版内核有巨大的变量。这些变化的主要优点包括:

  • 消除了单独的 micorkernel 和 nanokernel 的编译类型
  • 消除了基于 microkernel 的应用程序的 MDEF
  • 简化、统一了内核的 API
  • 减轻了使用内核对象的限制
  • 减小了合并相似服务的内存占用
  • 通过减小上下文切换提升了性能

注解

为了使已存在的应用程序和其它 Zephyr 子系统能够更方便地移植到新的内核模型,新的内核将在今后的短时间内继续支持第 1 版遗留的 API 和 MDEF,经过这段时间后,这些 API 和 MDEF 将被移除。

由于第 2 版所做的改动太多了,本文并不能完整描述;建议读者查阅 Zephyr 内核原语的各个章节,以熟悉其在第 2 版中的实现方式。尽管如此,我们将重要的改动做了如下的总结。

应用程序设计

Zephyr 的 microkernel 和 nanokernel 被合并为了一个叫做“内核”的实体。相应地,现在只有一种方法去设计、编译 Zephyr 应用程序。

task 和 fiber 上下文类型被合并为了一个叫做“线程”的类型。优先级为负数的线程被叫做“协作式线程”,它的运行方式与 fiber 类似;优先级非负的线程被叫做“可抢占式线程”,它的运作方式与 task 类似。

现在的内核对象既可以被 task 类线程使用,又可以被 fiber 类线程使用(第 1 版内核不允许 fiber 使用 microkernel 的对象,且当 task 使用 nanokernel 对象时会导致不可预料的忙等待)。

现在的内核对象通常都允许多线程等待一个给定的对象(第 1 版的内核严格限制只能单一线程等待特定的对象)。

现在的内核对象 API 总是执行在线程的上下文(第 1 版内核需要 microkernel 对象 API 切换到microkernel 服务 fiber,然后再切换回调用的线程)。

MDEF 被完全删除了。相应地,所有的内核对象直接被定义在代码里面。

内核 API

大多数的内核 API 都被重命名或者/和修改了参数列表,以使其更直观、统一。现在,大多数内核 API 都以 k_K_ 作为前缀。

第 1 版内核的操作在 task、fiber 和 ISR 中需要使用不同的 API 进行调用,而现在在线程或者 ISR 中的 API 是统一的。

现在,许多内核 API 都通过返回 0 表示成功,非 0 表示错误代码,以只是错误的原因(第 1 版只支持两个错误代码)。

线程

task 类的线程现在可以锁定内核的调度器(而不是锁定中断)使自己临时不可被抢占。

现在可以给线程的入口点传递三个参数(第 1 版只允许给 fiber 传递两个参数,且不允许给 task 传递参数)。

现在可以延迟启动静态定义的线程(第 1 版只允许在运行时延迟 fiber 的产生)。

task 不再需要指定 task 正常结束或者异常终止时自动调用的“task 终止处理着”函数。

应用程序不再需要使用“任务组”来指定用于单个内核 API 调用的一系列相近的任务。

内核现在在启动时同时创建 main 线程和 idle 线程(第 1 版内核只创建一个线程)。

内核的 main 线程负责执行系统的初始化,然后调用 main() 函数。如果应用程序没有指定:cpp:func:main() 函数,main 线程将直接结束。

现在的系统初始化代码可以执行阻塞操作,在阻塞期间将会执行内核的 idle 线程。

定时

现在大多数内核 API 都能以毫秒(而不是系统时钟滴答)为单位指定超时间隔。这个改动让开发者可以更直观地使用 API。尽管如此,内核内部依然使用基于滴答的系统时钟来实现的超时功能。

nanokernel 定时器和 microkernel 定时器对象类型被合并为一个类型。

内存分配

microkernel 内存映射对象被重命名为“内存片”,更能折现出管理大小相等的内存块的思想。

现在可以指定内存片或者内存池所使用的内存块的对齐操作。

现在可以直接在代码里定义内存池。

现在可以使用类似 malloc() 的方式从堆数据池分配、释放内存。

同步

nanokernel 信号量和 microkernel 信号量对象类型被合并为了单一类型。新的类型可以直接作为二元信号量以及计数信号量。

应用程序不能再使用信号量组来达到一个线程同时等待多个信号量的目的。在内核提供 select()poll() 功能前,那些希望等待多个信号量的线程必须以非阻塞的方式单独测试每个信号量,或者使用其它的机制(例如事件对象)给某个有效信号量发送信号。

microkernel 事件对象类型被重命名为“警报”,且类似于 Unix 风格的信号。由于对信号量进行了改进,对于基本同步,警报的效率比信号量的效率低。自然而然,警报主要被保留用于需要使用回调函数的场景。

数据传递

为了避免与 nanokernel 的 FIFO 的对象类型冲突,microkernel 的 FIFO 对象类型已被重命名为“消息队列”。

现在可以指定消息队列(即以前的 microkernel FIFO)中所存储的数据线的对齐操作。

microkernel 的邮箱对象类型不再支持显式的消息优先级概念。现在的消息以发送消息的线程的优先级作为隐式顺序。

microkernel 的邮箱对象类型将支持使用消息缓冲发送同步消息(第 1 版内核仅支持使用消息块发送同步消息)。

现在可以指定 microkernel 管道对象的缓冲的对齐操作。