看门狗的功能是让跑飞的系统回复到操作状态. 它通过周期性的检查系统脉冲,如果检测不到的话就会发出复位信号. 大多数嵌入式控制器都支持内部看门狗模块. 也有外部看门狗芯。
下列代码实现了一个假想的嵌入式控制器内置的看门狗设备驱动.
在2.6.0内核文件中的 drivers/char/watchdog.c中
/*
* Handle commands from user-space.
*/
static int at91_wdt_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
void __user *argp = (void __user *)arg;
int __user *p = argp;
int new_value;
switch(cmd) {
case WDIOC_KEEPALIVE:
at91_wdt_reload(); /* pat the watchdog */
return 0;
case WDIOC_GETSUPPORT:
return copy_to_user(argp, &at91_wdt_info, sizeof(at91_wdt_info)) ? -EFAULT : 0;
case WDIOC_SETTIMEOUT:
if (get_user(new_value, p))
return -EFAULT;
if (at91_wdt_settimeout(new_value))
return -EINVAL;
/* Enable new time value */
at91_wdt_start();
/* Return current value */
return put_user(wdt_time, p);
case WDIOC_GETTIMEOUT:
return put_user(wdt_time, p);
case WDIOC_GETSTATUS:
case WDIOC_GETBOOTSTATUS:
return put_user(0, p);
case WDIOC_SETOPTIONS:
if (get_user(new_value, p))
return -EFAULT;
if (new_value & WDIOS_DISABLECARD)
at91_wdt_stop();
if (new_value & WDIOS_ENABLECARD)
at91_wdt_start();
return 0;
default:
return -ENOTTY;
}
}
/*
* Reload the watchdog timer. (ie, pat the watchdog)
*/
static void inline at91_wdt_reload(void)
{
at91_sys_write(AT91_ST_CR, AT91_ST_WDRST);
}
选通看门狗通常在用户空间中做,因为看门狗的目标是检测并响应应用程序和内核挂起. 关键程序如图形引擎打开看门狗驱动并周期对其写.如果在看门狗超时时由于应用程序挂起或者内核崩溃而没有写操作, 看门狗将触发系统复位. 下列程序中的看门狗将重启系统如果: 应用程序在process_graphics()里面挂起或内核死掉并导致应用程序死掉.
#include <fcntl.h>
#include <asm/types.h>
#include <linux/watchdog.h>
#include <pthread.h>
void process_graphics();
void process_graphics_F();
int main()
{
int new_timeout;
pthread_t thread_watchdog;
pthread_t thread_F;
/* Set the watchdog timeout to 20 seconds */
// new_timeout = 5;
//ioctl(wfd, WDIOC_SETTIMEOUT, &new_timeout);
pthread_create(&thread_watchdog, NULL, (void *)process_graphics, NULL);
pthread_create(&thread_F, NULL, (void *)process_graphics_F, NULL);
while(1)
{
;
}
}
void process_graphics()
{
int wfd;
wfd = open("/dev/watchdog", O_WRONLY);
while(1)
{
/* Graphics processing */
//process_graphics();
/* Pet the watchdog */
ioctl(wfd, WDIOC_KEEPALIVE, 0);
printf("I'm fat watchdog/n");
/* Or instead do: write(wfd, "/0", 1); */
fsync(wfd);
}
}
void process_graphics_F()
{
while(1)
{
printf("this is thread_F.../n");
}
}
当应用程序打开/dev/watchdog时看门狗启动滴答. 关闭设备结点就会停止看门狗除非你在配置内核时设置了CONFIG_WATCHDOG_NOWAYOUT. 设置改选项可以帮助你克服看门狗监控进程在系统正在运行时被信号杀死的可能.
外部看门狗
为确保系统在处理器发生故障时仍可以恢复, 调整策略仍可保证可以使用外部看门狗芯片. 由于这种需要,嵌入式设备有时使用一个便宜的基于硬连线而不是寄存器接口的看门狗芯片(如Maxim的MAX6730).看门狗在固定复位超时时如果检测到输入引脚没有电压脉冲就声明一个复位引脚. 复位引脚接向处理器的复位逻辑, 输入引脚连向处理器的GPIO口. 如果你要为这样的设备写驱动,则和ioctl()函数无关. 通过改动处理器GPIO引脚来禁止看门狗. 这些芯片通常允许更大的初始化超时值来说明是引导时间,接着是更短的复位超时值.
对于不支持硬件看门狗模块的平台,内核实现了软件看门狗,称为softdog。softdog驱动在drivers/char/watchdog/softdog.c中,是一个伪杂项驱动因为它不对真实硬件操作. softdog驱动做了两件看门狗驱动不做的事,其中后者是在硬件里面完成的:
1. 实现超时机制.
2. 如果系统出故障了就初始化软件重启.
这个是通过延迟执行定时器处理函数做到的,无论应用程序何时向softdog写数据. 如果在超时时间内对softdog没有写发生,定时器处理函数生效并重启系统.
2.6内核里面的相关支持是软件锁,它是调度没有在10秒或10秒开外发生时的实例. 一个内核线程watchdog/N,N为CPU数目,每秒都为每个CPU创建时间戳. 如果线程在10秒之后没有创建时间戳,系统肯定是锁了它. 软件锁检测(实现在kernel/softlockup.c)可以帮助我们调试内核崩溃.