FreeRTOS 软件看门狗与任务死锁监控机制设计实战
·
FreeRTOS 软件看门狗与任务死锁监控机制设计实战

在嵌入式多任务实时操作系统(RTOS)中,硬件看门狗(Hardware Watchdog)虽然能够在整机硬件死锁或时钟停振时提供最后的“断电复位保护”,但对于纯软件逻辑层面的任务局部死锁(Task-Level Deadlock),硬件看门狗往往形同虚设。
例如:
- 任务 A(负责 4G 网络数据上传)由于在获取互斥量时发生死锁,或者卡死在一个没有设置超时的外部阻塞 API 中;
- 任务 B(负责本地低优先级的 LED 闪烁与硬件看门狗喂狗)依然在欢快地以每 500ms 一次的节奏正常翻转 WDI 引脚;
- 此时硬件看门狗被持续喂饱,根本不会触发复位,而系统的核心通信业务却早已彻底瘫痪!
构建一套基于 FreeRTOS 软件看门狗(Software Watchdog Daemon)与全任务心跳打卡(Heartbeat Check-In Table)机制的工业级监控体系,能够以微秒级的开销在单任务发生卡死时实现精准定位、现场快照捕获与系统自愈。
软件看门狗与硬件看门狗的二级联动拓扑
软件看门狗扮演着“各业务任务与底层硬件看门狗之间的监考官”角色:
两级看门狗协同防御架构:
[ 业务任务 1: Task_Sensor (周期 50ms) ] ──► 定期向【监控总表】刷新自身心跳时间戳 (Check-in)
[ 业务任务 2: Task_Network (周期 100ms)] ──► 定期向【监控总表】刷新自身心跳时间戳 (Check-in)
[ 业务任务 3: Task_Motor (周期 10ms) ] ──► 定期向【监控总表】刷新自身心跳时间戳 (Check-in)
│
▼ (全局共享打卡状态表)
+=========================================================================+
| 【软件看门狗守护任务 (Software Watchdog Daemon, 优先级最高)】 |
| - 每 500ms 周期性唤醒并严格审查监控总表 |
| - 检查每一个被注册的任务: (当前系统时间 - 任务最后打卡时间) > 最大容忍超时?|
+=========================================================================+
│
├─► 场景 A (所有任务全部健康打卡):
│ └──► 软件看门狗向【外部硬件看门狗引脚】发送喂狗脉冲!(整机安全)
│
└─► 场景 B (发现 Task_Network 已超过 5 秒未打卡!):
├──► 1. 立即锁定现场,向 Flash 写入死锁诊断日志 (记录死锁任务 ID 与调用栈);
└──► 2. 软件看门狗【故意停止向硬件看门狗喂狗】!
3. 坐等外部硬件看门狗在 1.6 秒后执行整机硬核物理复位!
工业级软件看门狗 C 语言核心实现
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include "FreeRTOS.h"
#include "task.h"
#define MAX_WATCHDOG_TASKS 8
typedef struct {
TaskHandle_t task_handle;
const char *task_name;
TickType_t max_allowed_delay_ticks; // 该任务允许的最大未打卡超时阈值
TickType_t last_checkin_tick; // 任务最后一次打卡的时间戳
bool is_registered;
} WatchdogEntry_t;
typedef struct {
WatchdogEntry_t entries[MAX_WATCHDOG_TASKS];
uint32_t active_count;
} SoftwareWatchdogManager_t;
static SoftwareWatchdogManager_t g_sw_wdt;
// 1. 注册一个待监控的任务
int register_task_to_watchdog(TaskHandle_t handle, const char *name, uint32_t max_delay_ms) {
if (g_sw_wdt.active_count >= MAX_WATCHDOG_TASKS) {
return -1; // 表满
}
int slot = g_sw_wdt.active_count;
g_sw_wdt.entries[slot].task_handle = handle;
g_sw_wdt.entries[slot].task_name = name;
g_sw_wdt.entries[slot].max_allowed_delay_ticks = pdMS_TO_TICKS(max_delay_ms);
g_sw_wdt.entries[slot].last_checkin_tick = xTaskGetTickCount();
g_sw_wdt.entries[slot].is_registered = true;
g_sw_wdt.active_count++;
pr_info("[SW_WDT] Registered task [%s] with timeout %u ms\n", name, max_delay_ms);
return slot;
}
// 2. 业务任务在正常循环体内调用的打卡函数 (耗时仅需数纳秒!)
void watchdog_task_checkin(int wdt_slot_id) {
if (wdt_slot_id >= 0 && wdt_slot_id < MAX_WATCHDOG_TASKS) {
// 原子更新打卡时间戳
g_sw_wdt.entries[wdt_slot_id].last_checkin_tick = xTaskGetTickCount();
}
}
// 3. 软件看门狗审查守护任务 (赋予系统最高优先级 configMAX_PRIORITIES - 1)
void SoftwareWatchdog_Supervisor_Task(void *pvParameters) {
while (1) {
vTaskDelay(pdMS_TO_TICKS(500)); // 每 500ms 审查一次全表
TickType_t current_tick = xTaskGetTickCount();
bool all_tasks_alive = true;
for (uint32_t i = 0; i < g_sw_wdt.active_count; i++) {
WatchdogEntry_t *entry = &g_sw_wdt.entries[i];
if (!entry->is_registered) continue;
// 计算该任务距离上次打卡已经过去了多长时间
TickType_t elapsed_ticks = current_tick - entry->last_checkin_tick;
if (elapsed_ticks > entry->max_allowed_delay_ticks) {
// 核心故障捕获: 发现某一个业务任务发生死锁卡死!
pr_err("==============================================================\n");
pr_err("[SOFTWARE WATCHDOG ALARM] Task DEADLOCK Detected!\n");
pr_err("Task Name : [%s]\n", entry->task_name);
pr_err("Elapsed Inactive: %u ms (Allowed Max: %u ms)\n",
pdTICKS_TO_MS(elapsed_ticks), pdTICKS_TO_MS(entry->max_allowed_delay_ticks));
pr_err("Action : Ceasing hardware kick to force full system reboot!\n");
pr_err("==============================================================\n");
all_tasks_alive = false;
break; // 只要有一个任务死锁,整机判定失败!
}
}
if (all_tasks_alive) {
// 所有任务均在健康生命周期内,向外部物理硬件看门狗执行喂狗!
kick_hardware_watchdog_pin();
} else {
// 核心决绝动作: 故意停止喂狗!
// 坐等 1.6 秒后硬件看门狗执行冷复位,并让出 CPU 记录 Flash 崩溃现场
record_deadlock_crash_to_flash();
while (1) {
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
}
}
业务任务集成示例
在编写各个业务任务时,打卡操作必须嵌入在每次完整循环处理的末尾:
void NetworkTask(void *pvParameters) {
// 注册自身,允许最大未打卡超时为 5000ms (5秒)
int my_wdt_slot = register_task_to_watchdog(xTaskGetCurrentTaskHandle(), "NetworkTask", 5000);
while (1) {
// 执行网络数据包轮询与上传 (带超时的安全阻塞)
process_mqtt_publish_pipeline();
// 核心打卡: 证明本轮业务成功跑完!
watchdog_task_checkin(my_wdt_slot);
vTaskDelay(pdMS_TO_TICKS(100));
}
}
将软件层面的任务健康状态表与底层硬件看门狗紧密缝合,系统才能彻底消除“局部死锁而整体不复位”的隐形故障,保障多任务固件的绝对健壮性。
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐



所有评论(0)