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

一.什么是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 <khollis@bitgate.com>
 *
 */
#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();








 

 

 

  • 7
    点赞
  • 98
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值