百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

深入理解watchdog1-框架_watchdog mode

haoteby 2025-02-16 20:56 24 浏览

概述

watchdog是一种硬件电路,在软件出现故障时可以重置计算机系统。

通常情况下,用户空间的守护进程通过 /dev/watchdog 设备文件定期通知 kernel watchdog驱动程序表明系统正常。如果系统异常(如内存错误、内核漏洞等)时导致无法发送心跳信号,硬件watchdog会在超时后重置系统(如重启)。

如常见的车机系统组成有MCU(控制器)和SOC(系统芯片),MCU中包含有硬件watchdog定时器,SOC会定期向MCU发送心跳(heartbeat),如果超时未发送心跳,MCU会通过引脚拉低电压重启SOC,避免车机一直卡死情况。

工作流程:

  1. 开机启动,watchdog定时器设置timeout值和timeout回调函数,当倒计时结束后会触发回调函数重启SOC;
  2. soc定时向watchdog硬件发送心跳信号(如调用driver ioctl接口),当watchdog收到信号后重置定时器为最初的时间;此过程反复循环,watchdog便无法倒计时结束,从而无法触发回调函数;
  3. SOC系统异常后无法向watchdog发送心跳信号。watchdog计时器结束后触发了回调函数,从而重启系统。

框架

分为3个部分:

  • 硬件:对应具体的硬件型号,以raspberry pi4为例,对应的型号为bcm2835_wdt,驱动实现为:bcm2835_wdt.c;
  • kernel:包括watchdog框架(core)、kthread内核线程和基于软件的实现softdog;
  • user:通过watchdog driver提供给用户空间的字符设备实现心跳;

watchdog硬件驱动

linux源码提供了较多的watchdog实现,如stm32_iwdg、qcom_wdt等。

raspberry pi4采用的为博通bcm2835型号,启动watchdog需要在config.txt中添加以下参数:

dtparam=watchdog=on

bcm2835驱动实现路径为:drivers\watchdog\bcm2835_wdt.c。

主要的结构体和函数如下:

static const struct watchdog_ops bcm2835_wdt_ops = {
	.owner =	THIS_MODULE,
	.start =	bcm2835_wdt_start,
	.stop =		bcm2835_wdt_stop,
	.get_timeleft =	bcm2835_wdt_get_timeleft,
	.restart =	bcm2835_restart,
};

操作集合,供上层使用

  • start:通过writel_relaxed接口向硬件寄存器写入timeout值并启动;
  • stop:通过writel_relaxed接口向对应位写入PM_RSTC_RESET;
  • get_timeleft:获取倒计时剩余时间;
  • restart:重启采用的方法同start,只是timeout设置为10 ticks (~150us),会立刻重启;
static struct watchdog_device bcm2835_wdt_wdd = {
	.info =		&bcm2835_wdt_info,
	.ops =		&bcm2835_wdt_ops,
	.min_timeout =	1,
	.max_timeout =	WDOG_TICKS_TO_SECS(PM_WDOG_TIME_SET),
	.timeout =	WDOG_TICKS_TO_SECS(PM_WDOG_TIME_SET),
};

具体硬件的抽象结构体,供kernel core使用。这里主要说明下timeout,默认值为0x000fffff>>16=15,即超时时间为15s,另外有一些驱动是通过dts配置的。

static int bcm2835_wdt_probe(struct platform_device *pdev)
{
...
	watchdog_init_timeout(&bcm2835_wdt_wdd, heartbeat, dev);
	watchdog_set_nowayout(&bcm2835_wdt_wdd, nowayout);

	if (bcm2835_wdt_is_running(wdt)) {
		set_bit(WDOG_HW_RUNNING, &bcm2835_wdt_wdd.status);
	}
  watchdog_stop_on_reboot(&bcm2835_wdt_wdd);
	err = devm_watchdog_register_device(dev, &bcm2835_wdt_wdd);

当设备被系统探测到会执行probe方法进行设备初始化,有如下步骤:

  1. watchdog_init_timeout:初始化timeout,可以通过module install传递,也可以解析dts字段timeout-sec(如果存在),以上2种情况都不存在,则使用默认值15s。
  2. watchdog_set_nowayout:设置nowayout特性,开启后watchdog将无法停止。
  3. 如果watchdog没有实现stop方法,必须要设置WDOG_HW_RUNNING状态。在watchdog启动后,如果设置有该字段,kernel会通过watchdogd进程发送心跳信号,如果没有设置watchdogd则不会工作。该状态对用户空间不可见,不能通过ioctl进行设置,只能在驱动中设置。
  4. 更新status为WDOG_STOP_ON_REBOOT,即启动的时候需要停止计时;
  5. devm_watchdog_register_device:注册设备节点/dev/watchdogX,注意如果只有一个硬件,命名为/dev/watchdog0,并且同时会创建/dev/watchdog(id为0的情况下才会创建,为了兼容老版本),watchdog0和watchdog表示同一个设备。如果有2个硬件,第二个会注册为/dev/watchdog1。注册完成后会通过hrtimer定时器投递一个ping work到队列中,watchdogd获取后执行ping work发送心跳信号。

watchdog内核框架

框架层是用户空间和硬件驱动的桥梁,用户空间通过框架层提供的接口执行驱动中的具体实现。框架层提供了操作集合,供用户空间使用,从这里入手,更容易梳理。

// drivers\watchdog\watchdog_dev.c
static const struct file_operations watchdog_fops = {
	.owner		= THIS_MODULE,
	.write		= watchdog_write,
	.unlocked_ioctl	= watchdog_ioctl,
	.open		= watchdog_open,
	.release	= watchdog_release,
};
  1. watchdog_open

用户空间打开设备时open("/dev/watchdogX")最终会调用到该函数。

  • 设备只能打开一次,若已经打开直接返回;
  • 判断硬件设备是否存在,不存在返回;
  • 判断watchdog是否激活(WDOG_ACTIVE),不同于WDOG_HW_RUNNING,该状态是对用户空间可见的。
  • 如果没有激活,则调用ping或start进行激活。ping和start对应具体的硬件驱动实现。
  1. watchdog_write
  • 判断写入的字符是否为'V',若是则在下次用户空间调用close(fd)时会stop watchdog(nowayout没设置情况下)。注意close(watchdog_fd)和watchdog stop没有必然的关联性,若想在close的时候stop watchdog需要满足一定的条件。
  • 写入的字符非'V',则发送心跳信号ping,status更改为保活状态(_WDOG_KEEPALIVE);
  • 计算心跳时间是否满足条件(心跳间隔要大于min_hw_heartbeat_ms,心跳之间最小时间间隔的硬件限制),若最接近的一次心跳信号时间还没有满足,则通过hrtimer_start启动定时器把ping work放到workqueue中,最终通过kthread来完成;若时间已经满足则发送心跳信号。
  • 发送心跳信号后,需要更新下次心跳的时间。这里有个判断为watchdog_need_worker,即当硬件启动后并且用户空间没有专门的发送心跳进程的情况下是需要worker(kthread),这时就需要启动定时器把ping work放到对应的workqueue等待kthread调度。
  1. watchdog_ioctl

该接口提供了丰富的功能,用户空间可以使用该接口获取更多信息:

  • WDIOC_SETOPTIONS:stop or start watchdog;
  • WDIOC_KEEPALIVE:ping watchdog;
  • WDIOC_SETTIMEOUT:设置timeout值;
  • WDIOC_GETTIMEOUT:获取timeout值;
  • WDIOC_GETTIMELEFT:剩余到期时间;
  • WDIOC_GETSUPPORT:获取watchdog info;
  • WDIOC_GETSTATUS:获取watchdog status;
  • WDIOC_SETPRETIMEOUT:设置预超时时间(pretimeout),用于在超时启动前需要收集一些调试信息。预超时间是在超时范围内,如timeout=10s,pretimeout=1s,在倒计时达到9s的时候会触发预超时回调函数进行收集信息。
  1. watchdog_release

在没有设置nowayout特性的前提下,通过写入'V'会设置可释放标志位_WDOG_ALLOW_RELEASE。当用户空间close(fd)时会通过系统调用走到驱动侧的watchdog_release,watchdog_release会检测status是否设置有可释放标志位,若成立则调用watchdog_stop。

用户空间实现

内核源码中提供了一个简单的demo:

// samples\watchdog\watchdog-simple.c
int main(void)
{
	int fd = open("/dev/watchdog", O_WRONLY);
	...
	while (1) {
		ret = write(fd, "\0", 1);
		...
		sleep(10);
	}
	close(fd);
	return ret;
}

逻辑比较简单,循环中每隔10s发送心跳信号(俗称'喂狗')。实际项目中间隔需要结合硬件中定义的timeout值,该进程一般拥有较高的优先级,如果系统中出现了异常导致进程无法运行,watchdog超时后会重置系统。

kthread内核进程

这里在单独对kthread的作用说明下,可能有些人会比较疑惑该进程具体是什么作用。

设想一个场景:当硬件watchdog启动后,timeout比较小1s,用户空间的喂狗进程启动比较慢5s,那么开机后用户空间定义的喂狗进程还没有启动,硬件watchdog超时后会马上重启系统,系统就会一直处于重启的循环中。为了在用户空间进程接手之前或者未定义用户空间喂狗进程的情况下保证系统正常喂狗,内核默认会创建一个内核进程进行该工作。

kthread其实是一个kworker,对应的work为watchdog_ping_work,即发送心跳信号:

这里以raspberry pi4为例说明:

  1. bcm2835 probe初始化时会调用devm_watchdog_register_device注册字符设备,并且会启动一个定时器立刻发送心跳信号:
// devm_watchdog_register_device-...->watchdog_cdev_register
	if (watchdog_hw_running(wdd)) {
    ...
		if (handle_boot_enabled)
			hrtimer_start(&wd_data->timer, 0,HRTIMER_MODE_REL_HARD);
	...
	}
  1. 定时器的回调函数为 watchdog_timer_expired,会把watchdog_ping_work放入到workqueue中等待kthread执行:
// 1. 定义work
kthread_init_work(&wd_data->work, watchdog_ping_work);
// 2. 赋值定时器到期回调函数
wd_data->timer.function = watchdog_timer_expired;
// 3. 回调函数把work放入到workqueue
static enum hrtimer_restart watchdog_timer_expired(struct hrtimer *timer)
{
  ...
	kthread_queue_work(watchdog_kworker, &wd_data->work);
}
  1. watchdog_ping_work发送信号需要满足条件之一:
  • 存在用户空间喂狗进程并且执行了open(即status为active);
  • 没有用户空间喂狗进程,硬件watchdog处于运行状态(running),需要借助kthread进行喂狗。
static bool watchdog_worker_should_ping(struct watchdog_core_data *wd_data)
{
	...
	if (watchdog_active(wdd))
		return true;
	return watchdog_hw_running(wdd) && !watchdog_past_open_deadline(wd_data);
}

static void watchdog_ping_work(struct kthread_work *work)
{
  ...
	if (watchdog_worker_should_ping(wd_data))
		__watchdog_ping(wd_data->wdd);
}
  1. 在执行完__watchdog_ping后需要更新下次发送心跳信号的时间watchdog_update_worker,这里有个关键的信息,是否需要kthread工作watchdog_need_worker:
  • 用户设定的timeout值比硬件支持的最大心跳时间还要大,那么就没必要单独使用用户空间喂狗进程了,kthread就能满足,kthread的喂狗间隔永远不会超时;
  • 不存在用户空间喂狗进程,需要kthread进行喂狗;
static inline void watchdog_update_worker(struct watchdog_device *wdd)
{

	if (watchdog_need_worker(wdd)) {
		ktime_t t = watchdog_next_keepalive(wdd);

		if (t > 0)
			hrtimer_start(&wd_data->timer, t,
				      HRTIMER_MODE_REL_HARD);
	} else {
		hrtimer_cancel(&wd_data->timer);
	}
}
  1. kthread的喂狗间隔有watchdog_next_keepalive控制,为硬件定义的timeout值的一半,如timeout为15s,kthread每7.5s就会喂狗一次。
	hw_heartbeat_ms = min_not_zero(timeout_ms, wdd->max_hw_heartbeat_ms);
	keepalive_interval = ms_to_ktime(hw_heartbeat_ms / 2);

相关推荐

Chrome OS 41 用 Freon 取代 X11_chrome os atom

在刚发布的ChromeOS41里,除了常规的Wi-Fi稳定性提升(几乎所有系统的changelog里都会包含这一项)、访客模式壁纸等之外,还存在底层改变。这一更新中Google移除...

苹果iPad Pro再曝光 有望今年六月发布

自进入2015年以后,有关大屏iPad的消息便一直不绝于耳,之前就有不少媒体猜想这款全新的平板电脑将会在三月发布,不过可惜的是我么只在那次发布会上看到了MacBookPro。近日@Ubuntu团队便...

雷卯针对香橙派Orange Pi 5 Max开发板防雷防静电方案

一、应用场景高端平板、边缘计算、人工智能、云计算、AR/VR、智能安防、智能家居、Linux桌面计算机、Linux网络服务器、Android平板、Android游戏机...

Ubuntu Server无法更新问题解决_ubuntu server not found

上周老家的一台运行UbuntuServer的盒子无法连接上了,中秋这两天回来打开,顺手更新一下发现更新报错。提示`E:Releasefileforhttps://mirrors.aliyun...

虚幻引擎5正式版发布:古墓丽影&巫师新作采用、新一代实时渲染

机器之心报道编辑:杜伟、陈萍虚幻引擎5的目标是「助力各种规模的团队在视觉领域和互动领域挑战极限,施展无限潜能」。...

AMD Milan-X双路霄龙7773X平台基准测试曝光 CPU缓存总量超1.5GB

OpenBenchmarking基准测试数据库刚刚曝光了AMDMilan-X双路霄龙7773X平台的跑分成绩,虽然很快就被撤下,但我们还是知晓了高达1.6GB的总CPU缓存。早些时...

ROS机器人建模_ros机器人硬件搭建

...

全网最新的Dify(1.7.2)私有化离线部署教程(ARM架构)

Hello,大家好!近期工作中有涉及到Dify私有化离线部署,特别是针对于一些国产设备。因此特别整理了该教程,实测有效!有需要的小伙伴可以参考下!本文主要针对Dify1.7.2最新版本+国产操作系...

在ubuntu下新建asp.net core项目_创建ubuntu

本文一步步讲述在ubuntu下用visualstudiocode创建asp.netcore项目的过程。step1:环境操作系统:virtualbox下安装的lubuntu。请不要开启“硬件...

在晶晨A311D2处理器上进行Linux硬件视频编码
在晶晨A311D2处理器上进行Linux硬件视频编码

在KhadasVIM4AmogicA311D2SBC上,我更多的时间是在使用Ubuntu22.04。它的总体性能还不错,只不过缺少3D图形加速和硬件视...

2025-08-26 17:22 haoteby

Nacos3.0重磅来袭!全面拥抱AI,单机及集群模式安装详细教程!

之前和大家分享过JDK17的多版本管理及详细安装过程,然后在项目升级完jdk17后又发现之前的注册和配置中心nacos又用不了,原因是之前的nacos1.3版本的,版本太老了,已经无法适配当前新的JD...

电影质量级渲染来了!虚幻引擎5.3正式发布:已开放下载

快科技9月8日消息,日前,Unrealengine正式发布了虚幻引擎5.3,带来了大量全方位的改进。...

2025如何选购办公电脑?极摩客mini主机英特尔系列选购指南

当下,迷你主机的性能越来越强,品类也越来越多。但是CPU是不变的,基本都是AMD和英特尔的。有一个小伙伴在评论区提问,我应该如何在众多机器中选购一台符合自己的迷你主机呢?那今天我们优先把我们的系列,分...

ubuntu 20.04+RTX4060 Ti+CUDA 11.7+cudnn

ububtu添加国内源sudocp/etc/apt/sources.list/etc/apt/sources.list.backupsudovim/etc/apt/sources.lis...

Linux Mint 18将重新基于Ubuntu 16.04 带来更好硬件支持

项目负责人ClementLefebvre在本月6日披露了关于LinuxMint18“Sarah”操作系统的大量信息,包括带来全新扁平化体验的Mint-Y主题。而现在,这款将于年底之前上线的操作...