什么是Watchdog?最全解释!直接贴代码!

标签: Linux系统  linux  多线程

一.什么是Watchdog?

Watchdog,又称watchdog timer,是计算机可靠性(dependability)领域中一个极为简单同时非常有效的检测(detection)工具。其基本思想是针对被监视的目标设置一个计数器和一个阈值,watchdog会自己增加计数值,并等待被监视的目标周期性地重置计数值。一旦目标发生错误,没来得及重置计数值,watchdog会检测到计数值溢出,并采取恢复措施(通常情况下是重启)。总结一下就是计数——溢出——触发。

Watchdog的工作方式是事件触发的,它可以对任何合理的事件计数(如CPU指令)。其中时间事件(timeout)最常使用,这也是为什么watchdog又叫做watchdog timer。但无论watchdog统计什么事件,它的思想都是一样的。

归根结底,Watchdog是一种检测手段,它监视的目标可以是一个进程也可以是整个操作系统。Watchdog的合理性基于这样的假设:一个正常运行的系统,它的执行流应该是可预测的,因此可以在它正常执行路径上设置一些周期性重置watchdog的点;但如果系统发生故障,它可能执行不到下一个重置watchdog的点,此时故障将被watchdog捕捉到。看到这儿,您应该想到watchdog对于检测死循环或死锁这类故障非常有效。

 

二.Watchdog的实现

针对不同的监视目标,watchdog可以采取不同的实现方法。

1)  监视一个进程

如果监视目标只是一个进程,那么利用操作系统提供的定时功能即可实现一个watchdog。

 

2)  监视一个操作系统

如果要监视操作系统,就得使用操作系统之外的工具,通常是一个附加的计数器。现代Intel CPU都包含的performance counter也可以提供这样的功能,从而不需要额外的设备就能实现监视操作系统的watchdog。

 

三.watchdog 函数接口的定义以及使用

主板上提供一个可按分或秒计时的,最长达255级的可编程看门狗定时器,WDT超时事件发生时系统复位.
本程序(w83627hf_wdt.c)是基于Winbond83627芯片的看门狗驱动程序.
驱动程序接口
wdt_open :打开设备,应用程序调用open时进入该函数.
wdt_close :关闭设备,应用程序调用close时进入该函数
wdt_write :写设备,若传入数据大小不为0则喂狗;应用程序调用write时进入该函数.
wdt_ioctl :应用程序调用ioctl时进入该函数,通过传入不同的参数实现不同的功能.主要参数如下:
WDIOC_GETSUPPORT :获取看门狗信息watchdog_info(见w83627hf_wdt.h)
WDIOC_KEEPALIVE :喂狗,同write函数功能类似
WDIOC_SETTIMEOUT :设置超时值
WDIOC_GETTIMEOUT :获取超时值
WDIOC_SETOPTIONS:设置看门狗状态,开启(WDIOS_ENABLECARD)或关闭(WDIOS_DISABLECARD)
应用程序编写
主要步骤如下(请参考代码w83627hf_test.c):
1、打开设备
调用open方法,返回值为已打开的设备,若小于0表示打开失败,以下的调用都要用该返回值做参数,表示操作该设备.
        wdt = open(WDT_DEVICE, O_RDWR);
2、开启看门狗
调用ioctl方法,传入WDIOC_SETOPTIONS参数,设置开启(WDIOS_ENABLECARD)状态,方法如下:
        ioctl(wdt, WDIOC_SETOPTIONS, WDIOS_ENABLECARD);
3、设置看门狗超时值(可选,默认为60s)
调用ioctl方法,传入WDIOC_SETTIMEOUT参数,设置指定的超时值.
        ioctl(wdt, WDIOC_SETTIMEOUT, &timeout);//timeout为超时值
4、喂狗
一般用while(1)循环在超时时间(timeout)内定时喂狗,若在timeout内没喂狗,则系统复位.提供2种喂狗方法:
(1) 调用write方法,注意传入参数大小不要为0.
         write(wdt, &arg, sizeof(arg));//若sizeof(arg)为0则不会喂狗
(2)调用ioctl方法,传入WDIOC_KEEPALIVE参数
        ioctl(wdt, WDIOC_KEEPALIVE,0);//第3个参数驱动不用
5、关闭看门狗
若不需要使用看门狗,则关闭它,注意关闭后即使超时值到也不会复位.调用ioctl方法实现,传入WDIOC_SETOPTIONS参数,设置关闭状态
         ioctl(wdt, WDIOC_SETOPTIONS, WDIOS_DISABLECARD)
6、关闭设备
调用close方法.
         close(wdt);

 

四.配置linux系统

linux看门狗使用很简单,在应用层使用,只需要ioctl设置一下溢出时间,既可以使用看门狗,定时喂狗即可

前提是kernel支持看门狗

Device Drivers ─>

  [*] Watchdog Timer Support  --->

配置好好后,即可make

 

五.贴代码

// watchdog.h 文件
/*
 *	Generic watchdog defines. Derived from..
 *
 * Berkshire PC Watchdog Defines
 * by Ken Hollis <[email protected]>
 *
 */
#ifndef _UAPI_LINUX_WATCHDOG_H
#define _UAPI_LINUX_WATCHDOG_H

#include <linux/ioctl.h>
#include <linux/types.h>

#define	WATCHDOG_IOCTL_BASE	'W'

typedef struct watchdog_info {
	__u32 options;		/* Options the card/driver supports */
	__u32 firmware_version;	/* Firmware version of the card */
	__u8  identity[32];	/* Identity of the board */
} _info;

#define	WDIOC_GETSUPPORT	_IOR(WATCHDOG_IOCTL_BASE, 0, _info)
#define	WDIOC_GETSTATUS		_IOR(WATCHDOG_IOCTL_BASE, 1, int)
#define	WDIOC_GETBOOTSTATUS	_IOR(WATCHDOG_IOCTL_BASE, 2, int)
#define	WDIOC_GETTEMP		_IOR(WATCHDOG_IOCTL_BASE, 3, int)
#define	WDIOC_SETOPTIONS	_IOR(WATCHDOG_IOCTL_BASE, 4, int)
#define	WDIOC_KEEPALIVE		_IOR(WATCHDOG_IOCTL_BASE, 5, int)
#define	WDIOC_SETTIMEOUT        _IOWR(WATCHDOG_IOCTL_BASE, 6, int)
#define	WDIOC_GETTIMEOUT        _IOR(WATCHDOG_IOCTL_BASE, 7, int)
#define	WDIOC_SETPRETIMEOUT	_IOWR(WATCHDOG_IOCTL_BASE, 8, int)
#define	WDIOC_GETPRETIMEOUT	_IOR(WATCHDOG_IOCTL_BASE, 9, int)
#define	WDIOC_GETTIMELEFT	_IOR(WATCHDOG_IOCTL_BASE, 10, int)

#define	WDIOF_UNKNOWN		-1	/* Unknown flag error */
#define	WDIOS_UNKNOWN		-1	/* Unknown status error */

#define	WDIOF_OVERHEAT		0x0001	/* Reset due to CPU overheat */
#define	WDIOF_FANFAULT		0x0002	/* Fan failed */
#define	WDIOF_EXTERN1		0x0004	/* External relay 1 */
#define	WDIOF_EXTERN2		0x0008	/* External relay 2 */
#define	WDIOF_POWERUNDER	0x0010	/* Power bad/power fault */
#define	WDIOF_CARDRESET		0x0020	/* Card previously reset the CPU */
#define	WDIOF_POWEROVER		0x0040	/* Power over voltage */
#define	WDIOF_SETTIMEOUT	0x0080  /* Set timeout (in seconds) */
#define	WDIOF_MAGICCLOSE	0x0100	/* Supports magic close char */
#define	WDIOF_PRETIMEOUT	0x0200  /* Pretimeout (in seconds), get/set */
#define	WDIOF_ALARMONLY		0x0400	/* Watchdog triggers a management or
					   other external alarm not a reboot */
#define	WDIOF_KEEPALIVEPING	0x8000	/* Keep alive ping reply */

#define	WDIOS_DISABLECARD	0x0001	/* Turn off the watchdog timer */
#define	WDIOS_ENABLECARD	0x0002	/* Turn on the watchdog timer */
#define	WDIOS_TEMPPANIC		0x0004	/* Kernel panic on temperature trip */

#define LOMBO_WDT_IGNORE_INTERRUPT	0x0100	/* Do not reset the dog */
#define LOMBO_WDT_RESET_SYS		0x0200	/* Reset system immediately */


#endif /* _UAPI_LINUX_WATCHDOG_H */

=========================================================================================

//watchdog.c  

//初始化
ret = net_watchdog_init();
if (ret) {
	ALOGE("net watchdog init failed!!\n");
	return -1;
}

//初始化过程
int net_watchdog_init(void)
{
	pthread_t wdog_pt;
	int returnval;
	struct watchdog_info wi;

	watchdogfd = open("/dev/watchdog", O_RDWR | O_NONBLOCK);
	if (watchdogfd < 0) {
		ALOGE("cannot open the watchdog device.\n");
		return -1;
	}

	ioctl(watchdogfd, WDIOC_GETSUPPORT, &wi);
	ALOGD_IF(NET_SEVICE_DEBUG,
		"watchdog info:%d, %s\n", wi.options, wi.identity);

	returnval = pthread_create(&wdog_pt, NULL, feeddog_thread, NULL);
	if (returnval < 0) {
		net_watchdog_deinit();
		ALOGE("pthread_create feeddog_thread thread failed!!\n");
		return -1;
	}

	return 0;
}

//开始喂狗
void *feeddog_thread(void *args)
{
	int count;
	int feeddogvalue;

	feeddogvalue = 65535;
	count = 0;

	while (1) {
		count++;
		printf("feeddogthread count: %d s.\n", count);
		if (count % 10 == 0 && watchdogfd > 0) {
			if (net_watchdog_check_alive())
				write(watchdogfd, &feeddogvalue, sizeof(int));
			count = 0;
		}
		sleep(1);
	}
}

//检测是否
int net_watchdog_check_alive(void)
{
	if (watchdog_alive_check) {
		watchdog_alive_check = 0;
		return 1;
	}
	else 
		return 0;
}

//线程创建失败回收资源
void net_watchdog_deinit(void)
{
	if (watchdogfd > 0) {
		close(watchdogfd);
		watchdogfd = -1;
	}
}

//放到系统timer 函数中
void net_watchdog_alive_set(void)
{
	watchdog_alive_check++;
	if (watchdog_alive_check >= 65535)
		watchdog_alive_check = 1;
}
比如:
case MSG_TIMER:
	net_watchdog_alive_set();








 

 

 

版权声明:本文为HGJ515原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/HGJ515/article/details/108073993

智能推荐

CORDIC arithmetic

传统CORDIC算法code Verilog代码: 时钟为50Mhz; 输出设置均设置为有符号数,主要是因为计算CORDIC算法时,需要判断Z通道的符号,来得到迭代过程中旋转方向。 然后根据缩放因子和arctan 2^-n 的预定义并乘以2^16 来进行后续计算,根据迭代方程写出代码;最后将(0度到90度)中正弦值与余弦值来扩大至(0度至360度)的正弦值与余弦值。 编写的tb文件如下: 最终使用...

dubbo源码解析-线程通讯原理

本来想通过Debug从头屡,发现意义不大,还是写点主通讯流程吧 本文基于JDK1.8;dubbo2.7.5 线程通讯原理 解释总体流程: DubboInvoker#doInvoker(Invocation)发起request,进入HeaderExchangeChannel 初始化Request对象(Dubbo自己封装的),初始化DefaultFuture将Request、channel放入,并记录...

使用Intellij Idea+Gradle 搭建Java 本地开发环境

Java 本地开发环境搭建 项目搭建采用技术栈为:Spring+Spring MVC+Hibernate+Jsp+Gradle+tomcat+mysql5.6 搭建环境文档目录结构说明: 使用Intellj Idea 搭建项目过程详解 项目各配置文件讲解及部署 各层包功能讲解&项目搭建完毕最终效果演示图 项目中重要代码讲解 5.配置tomcat 运行环境 6.webapp文件夹下分层详解 ...

js中array数组除重最快的方式(100万数据量下测试)

模拟100万数据 测试1 for循环 + in 运算符 (不是 for…in 循环) 测试2 双层for循环 (太慢了) while …同理。 测试3 for循环 + arr.indexof()判断 测试4 for…in循环 + in 运算符 测试结果...

轻量级java服务器undertow

项目需求 服务器端项目是用mina写的传统socket,准备升级到支持websocket接入。 为什么采用undertow 1、Undertow 是基于 NIO 的高性能 Web 嵌入式服务器,并且支持websocket(这个很重要,只要把undertow集成到项目中,用undertow启用websokcet,然后把原来的socket切换到websocket。) 2、轻量级web服务器:多么轻量级...

猜你喜欢

Task01:基于逻辑回归的分类预测

逻辑回归模型的优劣势: 优点:实现简单,易于理解和实现;计算代价不高,速度很快,存储资源低; 缺点:容易欠拟合,分类精度可能不高 https://zhuanlan.zhihu.com/p/74874291 与 SVM 相同点 都是分类算法,本质上都是在找最佳分类超平面; 都是监督学习算法; 都是判别式模型,判别模型不关心数据是怎么生成的,它只关心数据之间的差别,然后用差别来简单对给定的一个数据进行...

Codeforces Global Round 12 C2. Errich-Tac-Toe (Hard Version)(思维)

C2. Errich-Tac-Toe (Hard Version) 题意:给一个矩阵,里面有 k 个 'X' 或 'O' 标记,现在要修改不超过 k / 3 个标记('X'改成'O','O'改成'X'),使得矩阵中没有三个连续的相同的标记 思路:对两种不同的标记分别修改(i + j)% 3 == opx,(i + j) % 3 == opo 的位置,前提是修改的个数要少于总标记数的三分之一,所以枚...

WebGL与ES6:多重二维材质绘制

在绘制WebGL材质时,中间材质到WebGL的转换弄错了,写了很长时间。由于书上的引入图片是ES5的方式,我使用WebPack在进行打包的时候总是不对,因此在ES6中如何引入图片供WebGL调用当作材质,浪费了一些时间。    ...

C语言入门

 使用Visual studio 2013 写 C  程序 求ax^2+bx+c=0的俩个根:...

3D激光slam,cartographer的使用,第一视角点云

cartographer的使用 编译安装 cartographer的安装 cartographer的安装在cartographer_ros;有详细的步骤。偶尔出现ceres库clone不了,不过也不是大问题,下载后,粘贴过去也是可以的。 point_cloud_viewer的安装 安装步骤:point_cloud_viewer,显示的部分是基于node.js的web工程。 使用说明 使用建图生成....