HRTOS Debug:8051实时操作系统任务Delay阻塞状态监控
在实时操作系统中,任务并不是始终处于运行状态。
当任务需要等待一段时间后再次执行时,通常会进入Delay阻塞状态。在这段时间内,任务不参与正常运行,由系统负责管理其剩余等待时间。
对于开发人员而言,仅仅知道某个任务当前没有运行是不够的,还需要进一步了解:
-
哪些任务正在Delay阻塞?
-
当前有多少任务处于Delay状态?
-
某个任务还需要等待多少时间片?
-
任务为什么没有进入运行状态?
针对这些问题,HRTOS Debug提供了 Delay Wait任务阻塞状态监控功能。
该模块直接读取HRTOS任务控制块中的状态信息,对普通任务的Delay阻塞状态进行分析。
与其他Debug模块一样:
本模块只读取内核任务控制块,不修改内核数据。
一、什么是Delay阻塞
在RTOS中,一个任务执行延时操作后,并不需要一直占用CPU等待。
例如:
HRTOS_Delay(100);
任务进入Delay状态后:
任务运行
│
▼
请求Delay
│
▼
进入WAIT_DELAY
│
▼
任务暂时阻塞
│
│ 等待Tick
│
▼
等待时间到达
│
▼
重新进入Ready
│
▼
等待调度运行
这种机制能够避免任务在延时期间持续占用CPU。
因此,Delay本质上是一种基于系统Tick的时间阻塞机制。
二、HRTOS Debug如何判断Delay状态
HRTOS Debug并不需要重新建立一套任务状态管理机制。
它直接读取HRTOS内部任务控制块:
extern OS_TCB xdata OS_TASK[HRTOS_DEBUG_TASK_MAX];
当前普通任务数量配置为:
#define HRTOS_DEBUG_TASK_MAX 16
因此Debug模块可以直接分析:
Task 0
Task 1
Task 2
...
Task 15
任务是否处于Delay阻塞,主要依据:
OS_TASK[id].wait_type
当:
wait_type == WAIT_DELAY
即可判断该任务当前处于Delay阻塞状态。
三、WAIT_DELAY状态
模块定义:
#define WAIT_DELAY 1
因此判断逻辑非常直接:
if (OS_TASK[task_id].wait_type == WAIT_DELAY)
{
return 1;
}
整体可以表示为:
OS_TASK[id]
│
▼
wait_type
│
├── WAIT_DELAY
│ │
│ ▼
│ Delay阻塞
│
└── 其他状态
│
▼
非Delay
这种设计直接复用了HRTOS内核已有的任务状态信息。
Debug模块不参与任务调度,也不改变任务状态。
四、判断指定任务是否处于Delay阻塞
模块提供:
unsigned char HRTOS_DEBUG_DelayWait_IsWaiting(
unsigned char task_id)
用于判断指定任务当前是否处于Delay状态。
例如:
if (HRTOS_DEBUG_DelayWait_IsWaiting(3))
{
/* Task 3 正处于 Delay 阻塞 */
}
函数首先检查任务ID:
if (task_id >= HRTOS_DEBUG_TASK_MAX)
{
return 0;
}
当前有效任务ID范围:
0 ~ 15
如果ID超出范围,则直接返回0。
随后读取任务控制块:
if (OS_TASK[task_id].wait_type == WAIT_DELAY)
{
return 1;
}
这样就可以非常直接地获取指定任务的Delay状态。
五、获取任务剩余等待时间
知道任务正在Delay还不够。
在实际调试过程中,一个非常重要的信息是:
这个任务还需要等待多久?
HRTOS任务控制块中保存了:
wait_tick
用于记录等待相关的Tick信息。
Debug模块提供:
unsigned int HRTOS_DEBUG_DelayWait_GetTick(
unsigned char task_id)
读取指定任务剩余等待时间片。
核心代码:
if (OS_TASK[task_id].wait_type != WAIT_DELAY)
{
return 0;
}
return OS_TASK[task_id].wait_tick;
这里有一个重要的判断:
只有 WAIT_DELAY 状态
│
▼
wait_tick
才作为 Delay 信息解释
如果任务当前并不是Delay状态,则返回0。
这样可以避免将其他等待类型下的wait_tick错误解释为Delay剩余时间。
六、为什么剩余Tick很重要
假设Debug显示:
Task 3
State : Delay
Wait Tick : 500
说明Task 3当前并没有参与正常运行,而是在等待相应的Tick时间到达。
如果进一步观察:
Task 3
Wait Tick : 500
随后:
Task 3
Wait Tick : 300
再到:
Task 3
Wait Tick : 100
就可以直观看到任务的等待过程。
最终:
Wait Tick : 0
任务退出Delay等待状态,重新进入后续调度流程。
因此,wait_tick比单纯的任务状态信息更加具体。
七、统计当前Delay阻塞任务数量
除了分析单个任务,Debug还提供:
unsigned char HRTOS_DEBUG_DelayWait_GetCount(void)
用于统计当前所有普通任务中处于Delay状态的任务数量。
核心实现:
unsigned char i;
unsigned char count;
count = 0;
for (i = 0; i < HRTOS_DEBUG_TASK_MAX; i++)
{
if (OS_TASK[i].wait_type == WAIT_DELAY)
{
count++;
}
}
它会扫描全部16个普通任务:
Task 0 → 检查
Task 1 → 检查
Task 2 → 检查
...
Task 15 → 检查
最终得到当前Delay阻塞任务数量。
例如:
Delay Wait Count : 7
表示当前16个普通任务中,有7个处于Delay阻塞状态。
八、获取第一个Delay阻塞任务
如果Debug界面只需要快速判断:
当前有没有任务处于Delay状态?
可以使用:
unsigned char HRTOS_DEBUG_DelayWait_GetFirst(void)
函数从Task 0开始扫描:
for (i = 0; i < HRTOS_DEBUG_TASK_MAX; i++)
{
if (OS_TASK[i].wait_type == WAIT_DELAY)
{
return i;
}
}
找到第一个Delay任务后,直接返回对应任务ID。
如果没有找到:
return 0xFF;
因此返回值定义为:
0 ~ 15
表示找到对应Task
0xFF
表示当前没有Delay阻塞任务
这种接口适合Shell或简单状态监控。
九、三个接口的关系
Delay Wait模块主要提供三个层次的信息。
第一层:判断状态
HRTOS_DEBUG_DelayWait_IsWaiting(task_id)
回答:
这个任务是不是Delay状态?
第二层:获取剩余Tick
HRTOS_DEBUG_DelayWait_GetTick(task_id)
回答:
这个任务还要等待多少Tick?
第三层:统计整体状态
HRTOS_DEBUG_DelayWait_GetCount()
回答:
当前系统有多少任务处于Delay阻塞?
此外:
HRTOS_DEBUG_DelayWait_GetFirst()
可以快速找到第一个Delay任务。
因此整个模块可以概括为:
Delay Wait
│
┌──────────┼──────────┐
│ │ │
Is GetTick GetCount
│ │ │
▼ ▼ ▼
状态 剩余时间 总数量
十、与Task Monitor结合
Delay Wait模块单独使用已经能够提供任务时间阻塞信息,但与Task Monitor结合后会更加有价值。
例如Task Monitor发现:
Task 5
State : WAIT
这时可以进一步查询Delay Wait:
Task 5
Delay : YES
Wait Tick : 120
这样就可以确定:
Task 5
│
▼
处于等待状态
│
▼
WAIT_DELAY
│
▼
剩余120 Tick
从而把“任务没有运行”进一步解释成:
任务正在进行时间等待。
这对于系统运行状态分析非常重要。
十一、与Resource Debug结合
HRTOS Debug还可以分析Resource状态。
因此,当任务处于WAIT状态时,可以进一步区分:
Task
│
▼
WAIT
│
├── WAIT_DELAY
│ │
│ └── 时间阻塞
│
└── Resource Wait
│
└── 等待资源
这就形成了不同等待类型之间的区分。
例如:
Task 3
WAIT
│
└── Delay
└── 200 Tick
而另一个任务:
Task 5
WAIT
│
└── Resource
├── Resource 2
└── Wait Mask
通过不同Debug模块,可以逐步分析任务为什么没有运行。
十二、8051平台下的实现特点
HRTOS Debug Delay Wait模块并没有引入复杂的数据结构。
它直接读取:
OS_TASK[]
中的已有任务控制块信息。
核心数据主要包括:
wait_type
wait_tick
因此Debug模块本身不需要维护另一份任务状态。
这种设计可以避免:
内核任务状态
+
Debug任务状态
形成两套数据源。
而是直接采用:
HRTOS Kernel
│
▼
OS_TASK[]
│
▼
HRTOS Debug
这样Debug显示的信息来源就是HRTOS当前实际运行状态。
十三、为什么采用只读方式
与Resource Debug一样,Delay Wait模块不会修改:
OS_TASK[]
中的任务状态。
Debug模块只进行:
读取
↓
判断
↓
统计
↓
输出
不会进行:
修改任务状态
修改等待Tick
强制唤醒任务
改变调度状态
这样可以尽量降低Debug功能对被测系统运行状态的影响。
Debug的职责是:
观察系统,而不是控制系统。
十四、完整核心代码
Delay Wait模块完整实现如下:
#include "HRTOS_Debug.h"
#define HRTOS_DEBUG_TASK_MAX 16
#define WAIT_DELAY 1
extern OS_TCB xdata OS_TASK[HRTOS_DEBUG_TASK_MAX];
unsigned char HRTOS_DEBUG_DelayWait_IsWaiting(
unsigned char task_id)
{
if (task_id >= HRTOS_DEBUG_TASK_MAX)
{
return 0;
}
if (OS_TASK[task_id].wait_type == WAIT_DELAY)
{
return 1;
}
return 0;
}
unsigned int HRTOS_DEBUG_DelayWait_GetTick(
unsigned char task_id)
{
if (task_id >= HRTOS_DEBUG_TASK_MAX)
{
return 0;
}
if (OS_TASK[task_id].wait_type != WAIT_DELAY)
{
return 0;
}
return OS_TASK[task_id].wait_tick;
}
unsigned char HRTOS_DEBUG_DelayWait_GetCount(void)
{
unsigned char i;
unsigned char count;
count = 0;
for (i = 0; i < HRTOS_DEBUG_TASK_MAX; i++)
{
if (OS_TASK[i].wait_type == WAIT_DELAY)
{
count++;
}
}
return count;
}
unsigned char HRTOS_DEBUG_DelayWait_GetFirst(void)
{
unsigned char i;
for (i = 0; i < HRTOS_DEBUG_TASK_MAX; i++)
{
if (OS_TASK[i].wait_type == WAIT_DELAY)
{
return i;
}
}
return 0xFF;
}
十五、总结
HRTOS Debug Delay Wait模块直接利用HRTOS任务控制块中的状态信息,对普通任务的时间阻塞状态进行分析。
目前提供:
IsWaiting()
判断指定任务是否处于Delay状态
GetTick()
获取Delay剩余等待Tick
GetCount()
统计当前Delay阻塞任务数量
GetFirst()
获取第一个Delay阻塞任务
核心判断依据为:
OS_TASK[id].wait_type == WAIT_DELAY
而剩余等待时间则通过:
OS_TASK[id].wait_tick
获取。
整个模块的工作方式可以概括为:
OS_TASK[]
│
├── wait_type
│ └── 判断是否Delay
│
└── wait_tick
└── 获取剩余等待时间
│
▼
HRTOS Debug
对于实时系统来说,任务处于等待状态本身并不是异常。
真正重要的是能够知道:
任务为什么等待,以及还需要等待多久。
通过Task Monitor、Delay Wait和Resource Monitor等Debug功能,可以逐步把HRTOS内部的任务运行状态、时间等待状态以及资源等待状态展示出来,为8051实时系统的调试和运行分析提供更加完整的信息。
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐

所有评论(0)