# 分区 RTOS:INTEGRITY / ARINC 653 / VxWorks 653 / PikeOS 这类系统的调度**不止一层**: ``` 分区级调度(major frame / partition window / budget) ↓ 分区内调度(进程/任务优先级,本分区自己的调度器) ``` 于是最常见的误判是: ``` Task A priority = 250,Task B = 100 B 在跑,A 完全没运行 → 不是"调度器坏了",也不是 starvation → A 可能处在当前没有执行窗口/预算的分区里 ``` **"高优先级线程没运行"在这里首先是分区级的解释,然后才是任务级的解释。** ## 一、两层调度与 major frame - **分区级**:固定、循环、离线定义的调度。分区在一个循环区间内被周期性释放一段时间 - 这个区间叫 **major time frame(MAF)**,由若干 **partition window** 组成;每个窗口由**时长、偏移、周期性**定义 - **激活顺序在配置表里静态定义,运行期不可更改**;设计良好时 **MAF 时长 ≈ 各分区周期的最小公倍数** - 分区调度表列出相对 MAF 起点的抢占点;调度就是"当前时钟落在某分区的窗口内(偏移 → 偏移+时长)" - **分区内**:由分区自己的调度器管理其进程(ARINC 653 语境下通常是固定优先级抢占式) **分析要求**:时间线必须**先在分区级对齐**,再谈线程级。 ## 二、分区模式:进程"不跑"常常是还没进 NORMAL ARINC 653 的分区有四态:**IDLE / COLD_START / WARM_START / NORMAL** | 模式 | 含义 | |---|---| | **COLD_START** | 初始化进行中;**抢占被锁定**;应用在跑初始化代码;初始环境可能需要**从非易失存储器把代码拷到 RAM** | | **WARM_START** | 也是初始化且抢占锁定,但初始环境与冷启动**可以不同**(例如不需要从 NVM 拷代码) | | **NORMAL** | 初始化完成,**分区的进程调度器活跃**,已创建的就绪进程可以运行 | | **IDLE** | 没有进程在执行,但分配给该分区的窗口仍保留 | - 迁移关系:IDLE → COLD/WARM_START;COLD_START → NORMAL;NORMAL → COLD/WARM_START(重启);→ IDLE(关机/设为 IDLE) - 服务:`SET_PARTITION_MODE` 与 `GET_PARTITION_STATUS`(返回标识、周期、时长、锁层级、**运行模式**、启动条件) - **初始化模式(COLD/WARM_START)下只有主进程可调度**;错误处理程序在初始化阶段创建,并可调用 `SET_PARTITION_MODE` 重启分区 **所以**: ``` CREATE_PROCESS() / START() 都做了,但进程一直不跑 → 先查是否执行了 SET_PARTITION_MODE(NORMAL) → 而不是立即判调度器损坏 ``` ## 三、采样端口与队列端口:语义不同,不能混 | | 采样端口(sampling) | 队列端口(queuing) | |---|---|---| | 缓冲 | **单条消息** | 可配置的消息条数 | | 覆盖 | **新消息覆盖旧消息**,应用总是读到**最新**的 | **不覆盖**,按 **FIFO** 传送 | | 丢消息 | **可能丢/被覆盖** | 不丢;队列满时发送失败/阻塞 | | 刷新周期 | **只对采样模式的接收有意义**(判断是否有新消息到达) | 不适用 | - channel 把一个源端口连到一个或多个目的端口;分区之间由内核强制内存保护,其他分区无法访问本分区的端口 **所以**: ``` 连续写了 A B C,最后只读到 C → 对采样端口可能完全正常 → 对队列端口则不正常 ``` ## 四、INTEGRITY:空间 + 时间 + 资源三域分区 - 微内核架构,支持**多个受保护的虚拟地址空间**,每个可含**多个应用任务**;用硬件 MMU 建立隔离 - **完整的分区包含空间、时间与资源三个域**;失败不会跨分区传播 - **固定预算**:可为每个进程分配**固定的 CPU 时间与内存预算**;保证时间窗也意味着**运行中的任务不会超出其窗口** - 其他机制:实时调度器支持多优先级与**完整的 CPU 百分比分配控制**;内核服务时间有界;**内核空间不做动态内存分配**;内置 **ARINC 653 Part 1 分区调度器**(带保证的执行时间窗);**内存配额系统**防止一个地址空间耗尽另一个的内存;**内核内存不用于消息、信号量等由进程请求创建的对象** - **静态配置**:架构师预先写好静态配置文件,定义分区、任务集、内存对象、链接、连接通道、时钟与分区调度机制;**启动表定义归属**;**连接静态分配且不可绕过**;MMU 设置可静态验证 - 多核:不同分区时间窗内可绑定到不同核;**共享资源争用可使 WCET 增加 8–13 倍**(这也是相关适航指导强调的) **RE 主线**: ``` CPU 明明还有空闲,应用却拿不到更多执行时间 → 可能是预算隔离(设计如此),不是调度效率 bug ``` ## 五、PikeOS:还有第三层 PikeOS 是第二代分离微内核(同时是 hypervisor):**静态循环调度分区**(时间隔离)+ 内存区(空间隔离);每个分区有自己的调度结构,**支持 256 个优先级**;**系统分区与当前活动分区同时被调度**以提供系统服务。 POSIX guest 的层次: ``` PikeOS 分区/资源调度器 ↓ PikeOS system thread(每核一个可供该 POSIX 内核使用) ↓ POSIX guest 内核自己的调度器 ↓ POSIX 用户线程 ``` - POSIX 内核**自己的调度器把它的用户线程映射到一个 PikeOS system thread**;许多 POSIX 驱动还会自建 I/O 线程 - POSIX guest 实现的是 PSE52 子集,加上实时与 PikeOS 专有扩展(**包含 ARINC 653 采样/队列端口**) - **APEX guest**:完整实现 ARINC 653 P1-5 与部分 P2-4(分区管理、健康监控、采样/队列端口、进程管理、分区内通信与同步、logbook、文件系统、内存块、服务访问点端口) - **APEX 服务经一张链接在固定地址的 API table 进入**:开发时应用与库及链接脚本给出的 API 服务表地址链接 - 初始化完成后 APEX 内核把控制交给用户提供的 `MAIN()`,**起始于 COLD_START**(抢占锁定、创建静态资源),之后分区转入 **NORMAL**(进程调度器活跃、完整 APEX API 可用) **两条推论**: ``` guest 内线程是最高优先级,但延迟突然到 10 ms → 不能只看 pthread 调度器:查当前分区是否有执行窗口、 对应 system thread 是否可运行、CPU affinity/分区调度是什么 看到大量 ldr x16, [固定基址+偏移]; blr x16 → 先查是否是 APEX 服务表,而不是控制流混淆 ``` ## 六、Deos:两级调度 + slack + SafeMC - 时间/空间/资源分区的安全关键 RTOS(DAL A 认证):分区允许把**不同设计保证等级**的软件混跑在同一处理器上,并提供故障隔离与应用重启 - **两级调度模型**(SafeMC 明确描述): ``` Level 1:时间被划分为在各核之间【对齐】的执行窗口 Level 2:每个核/window 指派具体 scheduler ├─ ARINC 653 ├─ Deos RMA(速率单调) └─ POSIX 应用被指派给一个或多个 scheduler;每个 scheduler 可跨多个 process/partition 调度多个 task ``` - **同一颗核在不同时间段可以跑不同调度规律**(window 1 用 ARINC 653、window 2 用 POSIX、window 3 用 RMA 是这套架构能表达的)——**trace 里调度规律切换不能自动判调度器状态损坏** - **Slack Scheduling(滑动时间窗)**:窗口可以**压缩、扩张、滑动**——分区提前完成可压缩窗口,需要更多时间且有空闲可扩张,也可以让他人提前或延后开始。**所以"budget 给了 10 ms、任务只用了 6 ms,另一个任务拿到剩余 CPU"不是时间分区逃逸**,而是 slack 回收;**CPU 接近 100% 也可以仍在预算内** - **Cache partitioning**:**软件实现、可配置**,把缓存隔离做到应用/分区级(不只是核级),**免去分区切换时的 cache flush**(那会影响 WCET),并与**内存池(memory pooling)**互补(控制应用落在物理内存的哪里) - 开发工具本身也可能**利用 slack time** 做通信/profiling/monitoring 以少干扰关键负载——trace 里"应用执行 → 一小段工具流量 → 应用执行"先确认是不是这个 - 多核用 **BMP(SMP 的扩展)+ 安全调度 + 缓存分区 + 内存池** 限制共享资源干扰。**任务 READY、CPU 也有,但执行被多核策略约束**,不一定是普通调度决策——要恢复 core assignment / window / cache partition / memory pool / 跨核干扰策略 - 也可以承载其他环境:例如某 para-virtualized RTOS 实现运行在它的安全分区里,对外提供 POSIX 接口——**看到 `pthread_*` 不代表脱离了 Deos 分区控制** - 两个不同安全分区**能看到共享内存**也不等于隔离被破坏:应查是否配置为共享、权限、谁可写、生命周期 - 若观测到 major frame 起点**缓慢漂移**:Deos 提供外部时钟同步类能力(本次核验未直接命中上游资料,**作为候选解释之一并在具体型号文档上确认**),不要直接判 timer drift 或 trace 时钟坏了 **排错顺序(重要)**: ``` Task 没运行 → 属于哪个 process/partition? → 在哪个 core? → 当前 window 是否 active? → window 内是什么 scheduler? → 本地优先级/状态? → budget? → SafeMC 限制? → 才看 deadlock/bug ``` **对这类系统,配置与分区调度表优先于反汇编猜内部调度器**——公开文档未必开放全部内核细节。 ## 同族系统 - XtratuM(配置驱动的分离 hypervisor):同样是"静态配置 + major frame + 时间槽",另有固定优先级计划与多计划切换,见 [[re-hypervisor/xtratum]] - LynxSecure(静态分离内核):见 [[re-hypervisor/lynxsecure]] - Quest-V(多内核 sandbox + 每 sandbox 一个 monitor):见 [[re-hypervisor/questv]] - Jailhouse / Bao(静态分区 hypervisor):见 [[re-hypervisor/jailhouse]]、[[re-hypervisor/bao]] ## 决策树 ``` 拿到分区 RTOS 目标 ├─ 先分层:分区级调度 vs 分区内调度 │ ├─ 对齐 major frame / partition window(时长、偏移、周期) │ └─ 再谈进程/任务优先级 ├─ 高优先级线程不运行 │ ├─ 查它所属分区当前是否有执行窗口 │ ├─ 查分区模式(是否还在 COLD/WARM_START,未进 NORMAL) │ └─ 查资源/时间预算是否已耗尽(故意的隔离) ├─ 通信异常 │ ├─ 采样端口:覆盖语义,"只读到最新"属正常 │ └─ 队列端口:FIFO、不覆盖,满则失败/阻塞 ├─ 看到固定地址函数表 │ └─ 先考虑 APEX 服务表一类的 ABI,不要直接判混淆 └─ 多核 / 性能归因 └─ 把共享资源争用与预算隔离算进去(WCET 可能显著放大) ``` ## 工具与验证 - 调度:分区调度表 / 时间窗配置、MAF 与窗口参数、分区模式状态 - 资源:分区/进程的 CPU 时间与内存配额、静态配置文件与启动表 - 通信:端口类型(采样/队列)与各自参数 - 验证:能同时说清「分区级时间窗 + 分区内调度结果 + 预算/模式状态」,三者缺一不能解释"为什么没跑" ## 该平台的坑(汇总) - **用统一的优先级队列解释调度**:至少两层(PikeOS 场景是三层) - **把"高优先级线程不跑"当 starvation 或调度器 bug**:先看分区窗口与预算 - **忽略分区模式**:COLD/WARM_START 下只有主进程可调度,进程当然"不跑" - **把采样端口当队列端口**:覆盖语义下"只读到最新"是正常的 - **把队列端口当采样端口**:消息不会互相覆盖,丢失就一定是问题 - **把资源/时间预算隔离当性能缺陷**:固定预算是隔离机制的一部分 - **只逆 guest 内容**:PikeOS 一类系统里 guest 调度器不是最终调度器 - **把固定地址的 APEX 服务表当控制流混淆** - **多核分析忽略共享资源争用**:WCET 可能成倍放大