机制概述
等待时间与任务恢复是两个相关但不同的过程
等待超时用于限制任务在某项等待操作中停留的时间。 当等待时间结束时,系统需要根据具体等待类型和超时处理逻辑, 结束等待并使任务具备再次参与调度的条件。
在 HRTOS 的普通任务等待路径中, os_wait() 负责记录等待上下文、设置等待状态并请求调度; wake_task() 则承担任务等待结束后的上下文清理与状态恢复。 实际超时由谁检测、何时调用唤醒函数,应结合对应的时间管理代码确认。
计时结束不等于资源获取成功。 超时只说明本次等待达到时间限制;任务最终得到什么结果, 取决于超时处理路径传递的结果标志。
等待时间与上下文
理解 wait_tick 在等待流程中的作用
普通任务调用 os_wait(type, obj, tick) 时,等待参数会写入对应任务的等待上下文。 结合已提供的 wait.c, 其中涉及以下字段:
OS_TASK[tid].wait_type OS_TASK[tid].wait_obj OS_TASK[tid].wait_tick OS_TASK[tid].wait_flag OS_TASK[tid].state
等待类型
记录当前等待操作的类型,等待结束时可被清理。
等待对象
记录等待关联的对象标识;延时等待与资源等待的使用方式有所不同。
等待时间参数
保存传入的等待 tick 数值,具体递减与超时检测规则由时间处理路径决定。
等待结果标志
用于保存等待结束时的结果标志,并供任务恢复后读取。
wait.c 能确认等待参数的保存行为,但单凭该文件不能证明 wait_tick 在每次 Tick 中断中如何递减,也不能确认所有等待类型共用完全相同的超时路径。
超时处理流程
从设置等待到重新进入调度范围
对于需要计时的普通任务等待,可以从逻辑上划分为三个阶段: 建立等待上下文、检测等待是否结束、处理等待结果并恢复任务。 以下展示的是机制关系,而非对未提供的 Tick 实现逐条复原。
应将时间管理模块中的等待时间更新和超时判断代码, 与 wake_task() 的调用位置一起阅读。只有找到真实调用链后, 才能准确说明超时发生在哪个执行上下文、是否立即触发调度,以及具体结果如何传递。
等待结果与返回语义
区分函数返回值、结果标志与任务恢复
在已提供的 wait.c 中, wait_flag 会在普通等待建立时被初始化为 0, 而 wake_task(tid, flag) 会将传入的 flag 写入该字段。等待调用的返回语义因此需要结合任务切换和恢复过程理解。
超时结果
已提供的代码确认,延时等待参数为 0 时, os_wait() 会返回 WAIT_TIMEOUT。 其他超时场景的结果传递需核对对应调用点。
保存的结果
wake_task() 会保存调用方传入的标志。成功、超时或其他结束原因的具体宏值, 应以项目中的宏定义和实际调用点为准。
等待建立时的函数执行,与任务之后从等待中恢复并读取结果, 并不一定发生在同一个连续执行阶段。分析返回值时, 需要同时考虑上下文切换与任务恢复后的执行位置。
延时等待的特殊路径
普通任务与高速任务不能一概而论
wait.c 中的 WAIT_DELAY 具有单独的处理分支。对普通任务,内核会记录等待上下文、 设置 WAIT 状态、清除可运行标志,并请求后续调度。
高速任务使用专门的延时处理分支: 当任务 ID 对应 OS_PROCESS_MAX 或 OS_PROCESS_MAX + 1 时,代码分别更新高速任务标志和 OS_WAIT_DI2[] 中的等待值,并设置调度请求。
普通任务延时
└─ 任务等待上下文
├─ wait_type
├─ wait_obj
├─ wait_tick
├─ state
└─ 可运行标志位
高速任务延时
└─ 专用延时处理分支
├─ 高速任务状态标志
└─ OS_WAIT_DI2[]
这意味着文档不能简单地把所有延时任务都描述成: “写入普通 TCB 的 wait_tick,然后由同一套流程唤醒”。 高速任务的具体计时、到期恢复和调度行为,还需要结合其专用处理代码核对。
任务恢复与唤醒接口
wake_task() 在等待结束时承担的职责
u8 os_wait(u8 type, u8 obj, u16 tick); void wake_task(u8 tid, u8 flag);
从已提供的实现可以确认, wake_task() 会先读取任务的等待对象,并在对象有效时尝试清除对应资源等待位图中的任务位, 同时在计数大于零时递减等待计数。
检查并清理资源等待记录
当 wait_obj 不等于 OS_INVALID_ID 时,处理对应资源的等待位图和计数。
检查任务是否仍然有效
代码会检查任务可运行标志和 DEAD 状态; 满足相应提前返回条件时,不再继续执行后面的恢复操作。
写入结果并清理等待上下文
正常恢复路径会写入 wait_flag, 清除等待类型、对象和计时字段,并将任务状态设为 READY。
恢复可运行标志并请求调度
代码会设置相应可运行位,置位 OS_SCHED_REASON, 并设置 TF0 以推动后续调度处理。
设置调度请求和触发相关定时器标志,并不等于在这一行代码中立即完成任务上下文切换。 实际切换时机由 HRTOS 的调度和中断处理路径决定。
源码核对要点
让超时文档与实际内核实现保持一致
如果要进一步描述超时的精确执行时序,建议围绕以下问题核对源码, 再补充对应实现细节。
谁更新等待时间?
确认 Tick 或其他时间处理路径是否递减 wait_tick,以及高速任务是否采用独立计时逻辑。
谁检测超时并调用唤醒函数?
定位超时比较、结果标志传递和 wake_task() 调用点,确认其真实执行顺序。
超时结果如何定义?
核对 WAIT_TIMEOUT 等宏的定义及所有相关调用点,避免混淆不同等待操作的结果语义。
如何避免重复恢复?
检查超时处理与资源唤醒之间的竞态、等待记录清理条件,以及重复调用唤醒函数时的计数一致性。
当前提供的 wake_task() 在修改资源等待计数之前,并没有先验证对应等待位是否确实存在; 此外,提前返回分支与 EA 的恢复方式也值得结合调用上下文审查。 这些属于源码审查事项,不应在没有确认设计约束前直接等同于已发生的故障。
机制小结
把时间、结果和任务状态分开理解
HRTOS 的等待超时机制不能只用一个计数器概括。 等待上下文记录任务正在等待什么以及等待参数; 时间管理路径负责判断等待期限; 唤醒路径负责处理等待结束后的结果和任务状态; 调度器则决定何时实际恢复任务执行。
对于普通任务与高速任务,还需要分别理解其延时路径。 只有将这些环节与真实源码调用链对应起来, 才能准确说明超时的边界条件、返回语义和实时行为。