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

深入理解watchdog1-框架_watchdog mode

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

概述

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);

相关推荐

Python爬虫进阶教程(二):线程、协程

简介线程线程也叫轻量级进程,它是一个基本的CPU执行单元,也是程序执行过程中的最小单元,由线程ID、程序计数器、寄存器集合和堆栈共同组成。线程的引入减小了程序并发执行时的开销,提高了操作系统的并发性能...

A320-V2500发动机系统FADEC介绍(2)

目的全权数字发动机控制(FADEC)系统在所有飞行和运行阶段提供全范围发动机控制。...

三国志战棋版:玩家“二叔”用这套群DOT在比武中拿下31胜5负

声明:本文首发于今日头条,而后发布于“鼎叔闯三棋”的微信公众号、抖音、哔哩哔哩和小红书平台,如果在其他平台就是抄袭。...

真正的独一无二:Dot One 推出 DNA 定制系列 139英镑起

相信很多人在挑选衣物时有着这样的困扰,综合了性价比、面料等因素后好不容易找到了心仪的款式,还要担心是否会撞衫,不管是擦肩而过的陌生人还是身边的熟人,都令人尴尬。小部分人为此热衷于购买少量的古着或者限量...

崩铁:周年庆福利再升级,老角色加强时间确定,3.xdot体系反转

#埃安UT大一圈高级很多#...

Dotgo推出RBMHub,扩大了CPaaS提供商的覆盖范围和功能

据telecompaper网7月15日报道,用于商业消息传递的RichCommunicationServices(RCS)解决方案的领先提供商Dotgo宣布推出RBMHub。RBMHub的推出扩大了C...

深度解析:快照取消Dot职业的将何去何从

写在前面曾几何时,术士的出现便被冠以dot大师的名头,从远古时期的献祭腐蚀虹吸不如暗牧一个痛,到TBC上满dot=荣誉击杀+1,到wlk接近全暴击的冰晶腐蚀,再到CTM就算了吧MOP的各种变态吸x放...

星穹铁道:抽卡芙卡之前,你必须了解什么是dot!

卡妈终于上线了,可还是有很多人不明白什么是dot伤害,抽了卡妈直接玩起了直伤流,把一个持续伤害的引爆器玩成了打手,卡妈打dot伤害是远高于直伤的,有了卡妈的玩家一直了解dot,不然这卡妈就真被玩成四不...

游戏界的闪耀星辰陨落:悼念知名游戏博主″dotα牛娃″

无尽哀思!在数字时代浪潮中,游戏不仅是消遣娱乐的代名词,更是连接心灵的桥梁,构筑了无数人的青春回忆。在这片浩瀚无垠的游戏宇宙中,有这样一位博主,他以独特的风采、深邃的洞察力和无尽的热情,成为了玩家心中...

直击2017新加坡同性恋聚会Pink Dot,自由爱!

今年的“粉红点”又来啦~这个支持LGBT群体(男女同志、双性恋、跨性别等)群体的活动,从2009年起,已经在新加坡举办8年了!”这个非营利的同性恋权益活动,主要是希望大家了解到,不管一个人的性倾向或...

python-dotenv,一款超级实用处理环境变量python库

python-dotenv,一款超级实用处理环境变量python库python-dotenv概述:...

亚马逊语音助手毫无征兆发笑 诡异至极吓坏用户

来源:新华网美国电商亚马逊7日承诺,将更改名下“亚历克萨”语音系统设置,令它不会莫名发笑,免得吓坏用户。“亚历克萨”是亚马逊开发的语音助手软件,可服从用户语音指令完成对话、播放音乐等任务。依照原来设计...

2022最火英文网名男女生

精选好听英文昵称带翻译1.moveon(离开)2.Monster(怪物)3.Solo吉他手4.Finish.(散场)...

智能家具 RecycleDot 的出现给传统家具厂商带来新的挑战

从可穿戴手环、手表到智能衣服,智能硬件逐步渗透到每一个领域。最近有一对父子MikeSandru和JohnSandru在自家的车库中设计了一款智能家具RecycleDot,给日渐萧条的家具行...

欧洲通信卫星公司 OneWeb 敦促印度DoT尽早批准提供卫星宽带服务

据telecomtalk2月17日报道,欧洲通信卫星公司EutelsatOneWeb近日敦促印度电信部(DoT)尽快批准其在印度部署双地球站网关的计划,以便连接其近地轨道(LEO)全球卫星星座,并...