HRTOS · WAIT SUBSYSTEM

等待超时机制 Wait Timeout

从等待时间记录到任务恢复,理解 HRTOS 等待超时处理中的关键数据、 状态变化与结果传递。重点区分等待计时、超时判定和任务唤醒三个环节。

wait_tick WAIT 状态 wake_task() 8051 RTOS
01

机制概述

等待时间与任务恢复是两个相关但不同的过程

等待超时用于限制任务在某项等待操作中停留的时间。 当等待时间结束时,系统需要根据具体等待类型和超时处理逻辑, 结束等待并使任务具备再次参与调度的条件。

在 HRTOS 的普通任务等待路径中, os_wait() 负责记录等待上下文、设置等待状态并请求调度; wake_task() 则承担任务等待结束后的上下文清理与状态恢复。 实际超时由谁检测、何时调用唤醒函数,应结合对应的时间管理代码确认。

核心区别

计时结束不等于资源获取成功。 超时只说明本次等待达到时间限制;任务最终得到什么结果, 取决于超时处理路径传递的结果标志。

02

等待时间与上下文

理解 wait_tick 在等待流程中的作用

普通任务调用 os_wait(type, obj, tick) 时,等待参数会写入对应任务的等待上下文。 结合已提供的 wait.c, 其中涉及以下字段:

Wait Context Fields Source-based
OS_TASK[tid].wait_type
OS_TASK[tid].wait_obj
OS_TASK[tid].wait_tick
OS_TASK[tid].wait_flag
OS_TASK[tid].state
wait_type

等待类型

记录当前等待操作的类型,等待结束时可被清理。

wait_obj

等待对象

记录等待关联的对象标识;延时等待与资源等待的使用方式有所不同。

wait_tick

等待时间参数

保存传入的等待 tick 数值,具体递减与超时检测规则由时间处理路径决定。

wait_flag

等待结果标志

用于保存等待结束时的结果标志,并供任务恢复后读取。

实现边界

wait.c 能确认等待参数的保存行为,但单凭该文件不能证明 wait_tick 在每次 Tick 中断中如何递减,也不能确认所有等待类型共用完全相同的超时路径。

03

超时处理流程

从设置等待到重新进入调度范围

对于需要计时的普通任务等待,可以从逻辑上划分为三个阶段: 建立等待上下文、检测等待是否结束、处理等待结果并恢复任务。 以下展示的是机制关系,而非对未提供的 Tick 实现逐条复原。

调用 os_wait() 记录等待参数与任务状态
任务进入 WAIT 普通任务等待路径清除可运行标志位
时间管理与等待条件检查 具体检测时机由对应实现决定
等待条件满足
正常唤醒路径 由对应事件处理逻辑触发
写入相应结果 以实际调用传入的标志为准
等待时间到期
超时处理路径 由时间管理相关代码判定
传递超时结果 具体标志以实际定义为准
任务状态恢复与调度 是否可运行仍受任务有效性及调度条件约束
如何核对真实执行顺序

应将时间管理模块中的等待时间更新和超时判断代码, 与 wake_task() 的调用位置一起阅读。只有找到真实调用链后, 才能准确说明超时发生在哪个执行上下文、是否立即触发调度,以及具体结果如何传递。

04

等待结果与返回语义

区分函数返回值、结果标志与任务恢复

在已提供的 wait.c 中, wait_flag 会在普通等待建立时被初始化为 0, 而 wake_task(tid, flag) 会将传入的 flag 写入该字段。等待调用的返回语义因此需要结合任务切换和恢复过程理解。

WAIT_TIMEOUT

超时结果

已提供的代码确认,延时等待参数为 0 时, os_wait() 会返回 WAIT_TIMEOUT。 其他超时场景的结果传递需核对对应调用点。

wait_flag

保存的结果

wake_task() 会保存调用方传入的标志。成功、超时或其他结束原因的具体宏值, 应以项目中的宏定义和实际调用点为准。

不要混淆两个时刻

等待建立时的函数执行,与任务之后从等待中恢复并读取结果, 并不一定发生在同一个连续执行阶段。分析返回值时, 需要同时考虑上下文切换与任务恢复后的执行位置。

05

延时等待的特殊路径

普通任务与高速任务不能一概而论

wait.c 中的 WAIT_DELAY 具有单独的处理分支。对普通任务,内核会记录等待上下文、 设置 WAIT 状态、清除可运行标志,并请求后续调度。

高速任务使用专门的延时处理分支: 当任务 ID 对应 OS_PROCESS_MAX 或 OS_PROCESS_MAX + 1 时,代码分别更新高速任务标志和 OS_WAIT_DI2[] 中的等待值,并设置调度请求。

Implementation Distinction
普通任务延时
    └─ 任务等待上下文
       ├─ wait_type
       ├─ wait_obj
       ├─ wait_tick
       ├─ state
       └─ 可运行标志位

高速任务延时
    └─ 专用延时处理分支
       ├─ 高速任务状态标志
       └─ OS_WAIT_DI2[]

这意味着文档不能简单地把所有延时任务都描述成: “写入普通 TCB 的 wait_tick,然后由同一套流程唤醒”。 高速任务的具体计时、到期恢复和调度行为,还需要结合其专用处理代码核对。

06

任务恢复与唤醒接口

wake_task() 在等待结束时承担的职责

Interface Confirmed Signature
u8 os_wait(u8 type, u8 obj, u16 tick);

void wake_task(u8 tid, u8 flag);

从已提供的实现可以确认, wake_task() 会先读取任务的等待对象,并在对象有效时尝试清除对应资源等待位图中的任务位, 同时在计数大于零时递减等待计数。

01

检查并清理资源等待记录

当 wait_obj 不等于 OS_INVALID_ID 时,处理对应资源的等待位图和计数。

02

检查任务是否仍然有效

代码会检查任务可运行标志和 DEAD 状态; 满足相应提前返回条件时,不再继续执行后面的恢复操作。

03

写入结果并清理等待上下文

正常恢复路径会写入 wait_flag, 清除等待类型、对象和计时字段,并将任务状态设为 READY。

04

恢复可运行标志并请求调度

代码会设置相应可运行位,置位 OS_SCHED_REASON, 并设置 TF0 以推动后续调度处理。

调度不是简单的直接跳转

设置调度请求和触发相关定时器标志,并不等于在这一行代码中立即完成任务上下文切换。 实际切换时机由 HRTOS 的调度和中断处理路径决定。

07

源码核对要点

让超时文档与实际内核实现保持一致

如果要进一步描述超时的精确执行时序,建议围绕以下问题核对源码, 再补充对应实现细节。

A

谁更新等待时间?

确认 Tick 或其他时间处理路径是否递减 wait_tick,以及高速任务是否采用独立计时逻辑。

B

谁检测超时并调用唤醒函数?

定位超时比较、结果标志传递和 wake_task() 调用点,确认其真实执行顺序。

C

超时结果如何定义?

核对 WAIT_TIMEOUT 等宏的定义及所有相关调用点,避免混淆不同等待操作的结果语义。

D

如何避免重复恢复?

检查超时处理与资源唤醒之间的竞态、等待记录清理条件,以及重复调用唤醒函数时的计数一致性。

实现审查提示

当前提供的 wake_task() 在修改资源等待计数之前,并没有先验证对应等待位是否确实存在; 此外,提前返回分支与 EA 的恢复方式也值得结合调用上下文审查。 这些属于源码审查事项,不应在没有确认设计约束前直接等同于已发生的故障。

08

机制小结

把时间、结果和任务状态分开理解

HRTOS 的等待超时机制不能只用一个计数器概括。 等待上下文记录任务正在等待什么以及等待参数; 时间管理路径负责判断等待期限; 唤醒路径负责处理等待结束后的结果和任务状态; 调度器则决定何时实际恢复任务执行。

对于普通任务与高速任务,还需要分别理解其延时路径。 只有将这些环节与真实源码调用链对应起来, 才能准确说明超时的边界条件、返回语义和实时行为。