本文介绍 Linux 看门狗的用户态接口,包括
/dev/watchdog基本操作、Magic Close、完整 ioctl API 及环境监测功能。内容基于 Linux Watchdog 驱动程序 API 官方文档。
一、Watchdog 简介
看门狗定时器(WDT,Watchdog Timer)是一种硬件电路,在发生软件故障时可以自动复位系统。
工作原理:
用户空间守护进程
│ 定期向 /dev/watchdog 写入数据(喂狗)
▼
内核看门狗驱动
│ 通知硬件:系统正常,重置倒计时
▼
硬件看门狗定时器
│ 若超时内未收到喂狗信号
▼
强制复位系统(reboot)
如果用户空间发生故障(进程崩溃、死锁、内存错误等),喂狗停止,硬件看门狗在超时后自动重启系统。
二、基本使用
2.1 打开设备即启动
打开 /dev/watchdog 后,看门狗立即启动。必须在超时时间内持续喂狗,否则系统会被复位。
一个最简单的看门狗守护进程(来自 samples/watchdog/watchdog-simple.c):
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
int main(void)
{
int fd = open("/dev/watchdog", O_WRONLY);
if (fd == -1) {
perror("watchdog");
exit(EXIT_FAILURE);
}
while (1) {
write(fd, "", 1); /* 喂狗:向设备写入任意数据 */
sleep(10);
}
close(fd);
return 0;
}
实际生产中,守护进程通常在喂狗前先检查关键服务是否正常(如 HTTP 服务器是否响应),确认系统整体健康后再喂狗。
2.2 nowayout:禁止关闭
正常情况下,关闭 /dev/watchdog 文件会停止看门狗。但这有风险——如果守护进程崩溃导致文件被关闭,看门狗也跟着停了,失去保护作用。
CONFIG_WATCHDOG_NOWAYOUT=y(编译时配置)或 nowayout=1(模块参数)可以禁止这种行为:一旦启动,看门狗就无法被关闭,只能持续喂狗。
2.3 Magic Close:安全关闭
支持 Magic Close 的驱动提供了一种安全关闭机制:关闭文件之前,必须先向 /dev/watchdog 写入字符 'V',驱动才会正常停止看门狗。
write(fd, "V", 1); /* 魔术字,告知驱动这是主动关闭 */
close(fd); /* 此时看门狗正常停止 */
如果关闭时没有发送 'V',驱动会认为守护进程异常退出,不会停止看门狗,超时后系统将重启。这是一种故障安全(fail-safe)机制。
三、ioctl API 速查
所有符合规范的看门狗驱动都支持 ioctl 接口:
| ioctl 命令 | 方向 | 说明 |
|---|---|---|
WDIOC_GETSUPPORT | 读 | 查询设备能力(struct watchdog_info) |
WDIOC_GETSTATUS | 读 | 获取当前状态标志 |
WDIOC_GETBOOTSTATUS | 读 | 获取上次启动的状态(是否由看门狗触发重启) |
WDIOC_KEEPALIVE | 写 | 喂狗(等效于向设备写入数据) |
WDIOC_SETTIMEOUT | 读写 | 设置超时时间(秒) |
WDIOC_GETTIMEOUT | 读 | 获取当前超时时间(秒) |
WDIOC_SETPRETIMEOUT | 读写 | 设置预超时时间(秒) |
WDIOC_GETPRETIMEOUT | 读 | 获取当前预超时时间(秒) |
WDIOC_GETTIMELEFT | 读 | 获取距离下次复位的剩余秒数 |
WDIOC_GETTEMP | 读 | 获取温度(华氏度,部分驱动支持) |
WDIOC_SETOPTIONS | 写 | 控制看门狗启停 |
四、ioctl 详解
4.1 喂狗(KEEPALIVE)
ioctl(fd, WDIOC_KEEPALIVE, 0);
效果与 write(fd, "", 1) 完全相同,参数被忽略。喂狗循环示例:
while (1) {
ioctl(fd, WDIOC_KEEPALIVE, 0);
sleep(10);
}
4.2 设置/获取超时时间
/* 设置超时时间(秒)。注意:驱动会将 timeout 修改为实际生效值 */
int timeout = 30;
ioctl(fd, WDIOC_SETTIMEOUT, &timeout);
printf("实际超时时间:%d 秒n", timeout); /* 硬件粒度可能导致与设置值不同 */
/* 获取当前超时时间 */
ioctl(fd, WDIOC_GETTIMEOUT, &timeout);
printf("当前超时时间:%d 秒n", timeout);
⚠️
WDIOC_SETTIMEOUT调用后,timeout变量会被驱动修改为实际生效值。硬件计数器的精度可能导致实际值与请求值不同,务必读回确认。
4.3 预超时(PRETIMEOUT)
部分看门狗支持预超时(Pre-timeout):在正式复位之前,先触发一个 NMI 或中断,让内核有机会记录 panic 信息、生成 coredump 等。
/* 设置预超时。预超时 = 超时前 N 秒触发 */
int pretimeout = 10;
ioctl(fd, WDIOC_SETPRETIMEOUT, &pretimeout);
/* 例:超时 60s,预超时 10s → 第 50s 触发预超时,第 60s 复位 */
/* 获取预超时 */
ioctl(fd, WDIOC_GETPRETIMEOUT, &pretimeout);
printf("预超时时间:%d 秒n", pretimeout);
将预超时设为 0 可禁用该功能。并非所有驱动都支持预超时。
4.4 获取剩余时间
int timeleft;
ioctl(fd, WDIOC_GETTIMELEFT, &timeleft);
printf("距下次复位还剩:%d 秒n", timeleft);
4.5 查询设备能力(GETSUPPORT)
struct watchdog_info ident;
ioctl(fd, WDIOC_GETSUPPORT, &ident);
printf("驱动标识:%sn", ident.identity);
printf("固件版本:%dn", ident.firmware_version);
printf("支持能力:0x%08xn", ident.options);
ident.options 各标志位含义:
| 标志 | 含义 |
|---|---|
WDIOF_OVERHEAT | 支持检测 CPU 过热,上次复位因过热触发 |
WDIOF_FANFAULT | 支持检测风扇故障 |
WDIOF_EXTERN1 | 支持外部监控继电器/源 1 |
WDIOF_EXTERN2 | 支持外部监控继电器/源 2 |
WDIOF_POWERUNDER | 支持检测欠电压 |
WDIOF_POWEROVER | 支持检测过电压 |
WDIOF_CARDRESET | 上次复位由看门狗触发(可通过 GETBOOTSTATUS 查询) |
WDIOF_KEEPALIVEPING | 上次查询后收到过喂狗信号 |
WDIOF_SETTIMEOUT | 支持设置/获取超时时间 |
WDIOF_PRETIMEOUT | 支持预超时 |
4.6 查询状态(GETSTATUS / GETBOOTSTATUS)
int flags;
/* 获取当前状态 */
ioctl(fd, WDIOC_GETSTATUS, &flags);
/* 获取上次启动时的状态(判断是否由看门狗触发重启) */
ioctl(fd, WDIOC_GETBOOTSTATUS, &flags);
if (flags & WDIOF_CARDRESET)
printf("上次重启由看门狗触发n");
注意:并非所有设备都同时支持两个调用,部分驱动只支持 GETBOOTSTATUS。
4.7 获取温度
int temperature;
ioctl(fd, WDIOC_GETTEMP, &temperature);
printf("当前温度:%d °Fn", temperature); /* 返回值单位为华氏度 */
仅部分带温度传感器的看门狗卡支持。
4.8 控制启停(SETOPTIONS)
int options;
options = WDIOS_DISABLECARD;
ioctl(fd, WDIOC_SETOPTIONS, &options); /* 停止看门狗定时器 */
options = WDIOS_ENABLECARD;
ioctl(fd, WDIOC_SETOPTIONS, &options); /* 启动看门狗定时器 */
options = WDIOS_TEMPPANIC;
ioctl(fd, WDIOC_SETOPTIONS, &options); /* 温度触发时执行 kernel panic */
参考资料
延伸阅读
Watchdog 是系统可靠性的一环,可结合启动流程和 Platform 驱动模型继续阅读。
- 返回嵌入式 Linux 学习路线,确认本文在完整知识结构中的位置。
- 芯片上电到 Linux 启动全流程
- Linux Platform 设备驱动模型




