什么是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 <[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();
智能推荐
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调用当作材质,浪费了一些时间。 ...
3D激光slam,cartographer的使用,第一视角点云
cartographer的使用 编译安装 cartographer的安装 cartographer的安装在cartographer_ros;有详细的步骤。偶尔出现ceres库clone不了,不过也不是大问题,下载后,粘贴过去也是可以的。 point_cloud_viewer的安装 安装步骤:point_cloud_viewer,显示的部分是基于node.js的web工程。 使用说明 使用建图生成....
