董 昀, 李 穗
(安徽文达信息工程学院电子电气工程学院,安徽 合肥 230039)
嵌入式多任务实时操作系统如今广泛的应用在各个领域,系统的稳定性和可靠性始终是最为重要的问题之一,特别在一些条件比较恶劣,电磁干扰严重的场合,常会出现系统死机或程序跑飞现象。多年来,围绕着提高嵌入式系统的抗干扰能力,以及系统受到干扰后如何恢复,在硬件和软件方面都提出了很多有效的方法,其中比较常用就是看门狗技术[1]。看门狗分为硬件看门狗和软件看门狗:硬件看门狗通常指的是集成在处理器内部的看门狗定时器或外置的专用看门狗芯片或电路;软件看门狗和硬件看门狗类似,不过它采用处理器内部的定时器,无需额外的硬件电路。典型的看门狗应用就是将看门狗芯片的复位信号输出引脚接到处理器的复位引脚,当处理器正常运行时系统会周期性地执行“喂狗”操作,将看门狗计数器定期清零,一旦系统出现故障,程序跑飞,“喂狗”操作长时间未得到执行,看门狗计数器将会溢出,导致系统重启[2]。这种方法每次只能监测到系统的一部分,即主进程,因此在单任务系统中得到了广泛应用[3]。然而现在的嵌入式系统功能越来越复杂,往往需要采用多任务的嵌入式操作系统进行开发。这种情况下,仅对主进程进行监控对提高嵌入式产品的稳定性来说收效甚微。文中提出了一种基于多任务实时操作系统的看门狗框架,可以根据用户的实际情况,对系统中任意任务进行灵活的监控,保障了系统运行的稳定可靠。
多任务环境下的看门狗监测问题叶帮利在Windows系统中已经进行了探索和尝试[4],初步提出了多进程软件看门狗的设计思路。戴积发、胡玉霞等人在嵌入式系统中也提出了类似的解决方案[5],他们设计的看门狗主要实现以下功能:(1)当某个任务出现异常时重启该任务;(2)多次重启某一个任务失败或者所有的任务均出现异常时,重启系统;(3)当操作系统本身或硬件电路出现异常时,由软件看门狗或硬件看门狗重启处理器[4-5]。Abaffy等人针对Linux操作系统提出了一种多硬件看门狗的框架[6]。包明磊、姚艳松在FPGA平台上也提出了多任务硬件看门狗的容错技术[7]。上述工作在一定程度上为多任务环境下的看门狗应用提供了方案。但在实际应用中,系统中运行的各个任务重要性未必相同,某些任务出现异常后可能经过适当的纠错处理重新恢复运行,或者即使无法正常运行,对整个系统也不会带来不可接受的后果;这样的情况就无需重启系统。此外,某些系统可能有更复杂的应用场景,比如要求只有在任务1和任务2都发生异常时才必须重启,或者任务喂狗过于频繁也意味着某种异常。
文中针对上述问题提出了一种新的多任务环境下看门狗框架,即用户可以根据需求自定义异常处理函数和关联规则来决定系统在任务发生异常时如何处理异常,并决定在什么情况下需要重新启动系统。
文中结合了软件看门狗和硬件看门狗技术的优势[8],针对多任务操作系统环境下的看门狗应用提出了一种灵活的框架。其中利用软件看门狗对系统中运行的任务进行监控,而硬件看门狗则用于对软件看门狗本身进行监控,有效的保障了系统的可靠性。
用户可以为想要监控的每一个任务(进程)创建一个软件看门狗,指定超期时间和最小喂狗间隔,以及关联规则,同时用户可以自定义任务异常处理例程。所有的软件看门狗通过适当的方式进行管理,如链表或者队列。此外,系统在启动阶段创建一个优先级最高的任务作为软件看门狗管理器。每个被监测的任务在设定的超期时间和最小喂狗时间间隔范围内对其相应的软件看门狗清零,即“喂软件狗”。
系统节拍定时器中断处理函数周期性的检查每个软件看门狗是否超时[9],以及是否喂狗过于频繁。如果任务由于异常导致未能正常喂软件狗,系统节拍定时器中断处理函数将调用对应的异常处理例程进行处理,如果异常成功的得到处理,则跳过该软件看门狗,如果异常没有得到解决,中断处理函数记录下该软件看门狗监控的任务发生了不可修复的异常。在检查完所有的软件看门狗的状态后,如果有不可修复的异常,中断处理函数唤醒软件看门狗管理器任务。
正常情况下,软件看门狗管理器周期性的对硬件看门狗进行喂狗,即“喂硬件狗”,防止硬件看门狗超时导致系统复位。但是如果被监控的任务发生不可修复的异常,系统节拍定时器中断服务程序将会唤醒软件看门狗管理器检查异常任务的软件看门狗关联规则,如果满足关联规则,则停止喂硬件狗,重启系统。另外当管理器任务本身出现错误时,也不能及时“喂硬件狗”,系统也将重启。具体的监控原理框图如图1所示:
为验证设计的框架,作者以RT-Thread操作系统和STM32F103开发板为平台实现了一个原型系统。在实现中软件看门狗定义如下:
struct {
int due_time; //看门狗到期时间
int last_feed, current_feed; //上次和本次喂狗时间
int (*Handle)(void *arg); //任务异常处理函数
void *data;//传递给异常处理函数的参数
list_head list; //用于将所有软件看门狗连 接为一个双向循环链表
int min_interval;//看门狗最小喂狗间隔
int mask;//关联规则
int watchdog_id; //软件看门狗编号
}soft_watchdog;
int map;//全局标志位
图1 监控原理框图
其中map是一个全局变量标示所有软件看门狗的状态,它的每一个位对应一个软件看门狗的状态,若该软件看门狗监控的任务发生不可修复的异常,则将其对应位标识为1,否则标识为0。mask是一个由用户自定义的关联规则,比如mask=5,其二进制数第1位和第3位为1,其他位为0,这表示软件看门狗1和软件看门狗3是关联的,即都处于触发状态,也就是说任务1和任务3均出现不可修复异常时,软件看门狗管理器将重启系统。due_time与min_interval是到期时间和最小喂狗间隔,如果min_interval为0则表示对喂狗频率没有限制。handle即为自定义的异常处理例程,用户可以根据实际情况进行可能的异常检测、处理、修复等操作,如果成功处理异常,该函数返回0,否则返回-1。所有这些软件看门狗通过类型为list_head的成员变量list连接成双向循环链表,如图2所示。list_head的定义如下:
struct list_head {
struct list_head *next, *prev;
} ;
软件看门狗管理器由watchdog_daemon()实现,该任务周期性的休眠指定的时间间隔timeout,该时间应小于硬件看门狗溢出间隔。当管理器被唤醒运行时首先检查唤醒原因:如果是因为timeout时间超时,则喂硬件狗,再次休眠等待下一次唤醒;如果唤醒的原因是系统节拍定时器中断处理函数检测到有软件看门狗被触发,则进行异常处理。
软件看门狗管理器检查map标志的每一位,如果该位为1,则表示对应的软件看门狗被触发。管理器获取被触发软件看门狗的mask关联规则,与map进行比较。如果规则指定的关联软件看门狗均被触发,那么我们称关联规则被触发,此时,管理器不再喂硬件狗,触发系统复位。管理器的执行流程如图3所示。
图2 软件看门狗链表结构
图3 管理器执行流程图
每个被监控任务需要周期性的喂软件狗,其喂狗间隔必须小于到期时间due_time,且大于最小喂狗间隔min_interval,软件看门狗数据结构中的current_feed和last_feed分别记录本次和上次喂狗的时间。系统节拍定时器中断处理函数依次检查每个软件看门狗监控的任务是否异常。方法是:如果当前时间与current_feed的差大于due_time,则软件看门狗溢出;同样,如果current_feed与last_feed的差小于min_interval则说明喂狗过于频繁。这两种情况下,中断处理函数均调用对应的异常处理例程handler。该例程是用户自定义的,用于对发生异常的任务进行处理,包括检查具体异常原因,生成异常日志,尝试修复异常,或者重启任务等。如果handler成功解决了异常,则返回0,否则返回-1。在返回-1的情况下,系统认为该任务发生了不可修复的错误,设置map标志对应位为1,称之为触发软件看门狗。中断处理函数在检查完所有的软件看门狗后,如果有任何看门狗被触发,则唤醒软件看门狗管理器任务。系统节拍中断处理函数的执行流程如图4所示。
图4 系统节拍中断服务程序流程图
提出了一种新的多任务RTOS环境下软硬件看门狗框架,论述了工作原理,并在RT-Thread实时操作系统上实现了该框架。该框架提供了一种灵活的高度可定制的多任务管理的软硬件看门狗结合方案,与传统的硬件看门狗和多任务看门狗技术相比具有如下优势:
1)利用软件看门狗可监控系统任意任务(一个,多个或全部),实现成本低;
2)监控方案配置灵活,可方便添加待监控的任务,理论上该任务数量没有上限,管理器可对出现异常的任务调用自定义的处理例程进行处理,这样可以对某些不严重问题进行修复,而无需重启任务或系统。
3)用户可以自定义关联规则,管理器分析当前异常情况,在满足用户设定的关联规则时才重启系统。