模型概述
区分任务状态、等待原因和调度资格
HRTOS 的等待机制并不是单独增加一种任务类型, 而是在任务记录中保存等待上下文,并通过任务状态与调度标志的配合, 表示任务暂时不能参与正常调度的情况。
任务状态 · state
表示任务当前所处的状态。所提供的等待实现明确将普通等待任务设置为
WAIT,唤醒后设置为 READY。
等待原因 · wait_type
记录等待类型。普通任务进入等待时写入传入的
type,唤醒清理时恢复为 WAIT_NONE。
调度资格 · OS_PROCESS_OK
等待时清除任务对应标志的最低位,唤醒时重新设置该位。
它与 state 是不同的管理信息。
等待结果 · wait_flag
保存唤醒时传入的结果标志。任务恢复执行后, 等待调用可通过该字段返回结果。
任务状态
等待机制实际使用的状态转换
在当前提供的 wait.c 与 wake_task.c 中,
可以直接确认普通任务等待过程使用了 WAIT 和
READY 两个状态。完整状态集合及其数值定义,
应以 HRTOS 4.0 的实际头文件为准。
| 状态标识 | 等待机制中的行为 |
|---|---|
WAIT |
普通任务进入等待时写入 OS_TASK[tid].state。 |
READY |
有效唤醒完成时,目标任务被设置为 READY。 |
DEAD |
wake_task() 检测到该状态时,不继续执行后续唤醒处理。 |
RUNNING、SUSPEND
及状态数值没有出现在这两份等待函数的定义中。
在核对实际状态宏之前,不应将它们的数值和完整转换规则写成已由这两份源码证实的事实。
等待上下文模型
一次普通任务等待需要记录的信息
源码通过 OS_TASK[tid] 访问任务记录,
并使用以下字段维护普通任务的等待上下文。
这里沿用真实代码中的字段名称,不额外假定结构体类型名称。
OS_TASK[tid].wait_type = type;
OS_TASK[tid].wait_obj = obj;
OS_TASK[tid].wait_tick = tick;
OS_TASK[tid].wait_flag = 0;
| 字段 | 含义 |
|---|---|
wait_type |
等待类型;WAIT_NONE 表示当前没有登记中的普通任务等待上下文。 |
wait_obj |
等待对象编号;唤醒清理后设为 OS_INVALID_ID。 |
wait_tick |
等待时间参数,以系统 Tick 为单位;唤醒清理时设为 0。 |
wait_flag |
等待结果字段;进入等待时初始化为 0,唤醒时写入传入的 flag。 |
这组字段让等待原因和等待结果与任务记录关联起来。 不同等待类型可以共享这套上下文,但各类型的资源检查、超时判断和唤醒触发条件, 仍需结合对应的资源管理代码分析。
状态转换
从进入等待到重新获得调度资格
上图是普通任务等待的概念路径。实际代码中,
os_wait() 通过设置 OS_SCHED_REASON
和 TF0 请求后续调度处理;
wake_task() 同样更新调度请求并触发 T0 中断。
这些操作本身不代表函数直接完成了上下文切换。
资源等待关系
wait_mask 与 wait_cnt
普通任务等待非延时资源时,如果对象编号有效,
os_wait() 会将任务 ID 对应的位写入资源等待位图,
并递增等待计数。
if(type != WAIT_DELAY && obj != OS_INVALID_ID)
{
OS_RES[obj].wait_mask |= ((u16)1 << tid);
OS_RES[obj].wait_cnt++;
}
if(obj != OS_INVALID_ID)
{
OS_RES[obj].wait_mask &= ~((u16)1 << tid);
if(OS_RES[obj].wait_cnt)
{
OS_RES[obj].wait_cnt--;
}
}
wait_mask使用位操作记录对应任务的等待关系。wait_cnt在等待登记时递增,在唤醒清理时于非零条件下递减。WAIT_DELAY不通过普通资源登记代码加入等待位图。- 资源位图只记录等待关系;具体资源何时可用,以及哪个任务应被唤醒,需要结合资源操作代码判断。
唤醒后的状态恢复
wake_task() 如何结束普通任务等待
对通过普通任务等待上下文管理的任务,
wake_task() 会写入唤醒结果、清理等待字段,
并恢复任务的 READY 状态与调度资格。
OS_TASK[tid].wait_flag = flag;
OS_TASK[tid].wait_type = WAIT_NONE;
OS_TASK[tid].wait_obj = OS_INVALID_ID;
OS_TASK[tid].wait_tick = 0;
OS_TASK[tid].state = READY;
OS_PROCESS_OK[tid] |= 1;
OS_SCHED_REASON = 1;
任务状态恢复和调度资格恢复是两个不同的操作。
设置 READY 表明任务已离开等待状态;
恢复 OS_PROCESS_OK[tid] 的最低位,
则使该任务重新具备相应的调度资格。
wake_task() 在清理资源等待关系后,
会检查 OS_PROCESS_OK[tid] == 0 和
state == DEAD。若命中这些条件,就直接返回,
不执行后续的结果写入与 READY 恢复。
高速任务的特殊路径
延时处理不等同于普通任务阻塞
当等待类型为 WAIT_DELAY 时,
os_wait() 会先检查当前任务编号。
对两个高速任务,源码使用独立的 OS_WAIT_DI2[]
计数器保存延时参数,而不是建立普通任务的等待上下文。
OS_WAIT_DI2[0] = tick; /* 高速任务 A */
OS_WAIT_DI2[1] = tick; /* 高速任务 B */
该分支还会更新相应的高速任务标志、设置调度请求并触发 T0 中断,
随后直接返回 WAIT_TIMEOUT。
因此,不能将这一分支描述成普通任务从 WAIT 状态被唤醒后返回结果的完整流程。
设计要点
等待模型的结构性特点
状态与等待原因分离
state 记录任务状态,wait_type
记录等待原因。多个等待类型可以共享 WAIT 状态,
不必仅因等待原因不同就增加独立的任务状态。
等待信息保存在任务记录中
普通任务等待字段通过 OS_TASK[tid] 访问,
使等待上下文与对应任务直接关联。
资源等待使用位图登记
wait_mask 和 wait_cnt
用于维护资源对象与等待任务之间的关系,具体唤醒策略由相关调用路径决定。
唤醒与实际运行分离
wake_task() 恢复任务的 READY 状态并请求调度;
任务重新获得 CPU 的时机由后续调度过程决定。
高速任务使用独立延时处理
高速任务的延时分支使用专用计数器,与普通任务等待上下文分开。 描述和审计时,应将两条路径明确区分。