一个看门狗保护多线程的简单方案

发布于 2020-07-01 21:58:34
在OS中,如何使用看门狗对多线程进行保护是一个问题。

这里我的做法是使用一个较高优先级的线程作为守护进程。每个需要看门狗保护的线程均进行注册,守护线程将注册过的线程维护在链表中,同时在循环中等待每个注册过的线程的喂狗事件。若在规定时间内有任意线程没有喂狗则打印出线程名称,并停止喂狗,等待看门狗复位MCU。

更完善可以添加对应的处理机制如“重启进程”“调用回调”等。

#define LOG_TAG "DAEMON"
#include
#include
#include
#include "daemon.h"

static uint32_t daemon_wd_flag_get(struct daemon_object *daemon);
static void daemon_watchdog_init(struct daemon_object *daemon);
static void daemon_wd_feed(struct daemon_object *daemon);
static struct daemon_register_thread* daemon_find_thread(struct daemon_object *daemon, uint8_t index);
static inline uint32_t daemon_wd_flag_clear(struct daemon_object *daemon);

void daemon_thread_entry(void * param){
uint32_t threadFlag = 0;
struct daemon_object *daemon = (struct daemon_object *)param;
uint32_t time = daemon->wdtTimeout*1000;;
while(1){
threadFlag = daemon_wd_flag_get(daemon);
if(threadFlag !=0){
rt_err_t err = rt_event_recv(&daemon->event, threadFlag,
RT_EVENT_FLAG_AND | RT_EVENT_FLAG_CLEAR,
time, RT_NULL);
if (err == RT_EOK){
daemon_wd_flag_clear(daemon);
LOG_D("All threads are running, feed the watch dog");
daemon_wd_feed(daemon);
rt_thread_mdelay(1000);
}else if(err == -RT_ETIMEOUT){
daemon->threadFlag = ~daemon->threadFlag;
for(uint8_t i=0; i < daemon->daemonNum; i++){
if(daemon->threadFlag & 0x01){
struct daemon_register_thread* temp = daemon_find_thread(daemon, i);
if(temp != RT_NULL)
LOG_E("Thread [%s] is not running", temp->thread->name);
}
daemon->threadFlag >>=1;
}
daemon_wd_flag_clear(daemon);
LOG_E("Wait watch dog reset the mcu");
while(1){
rt_thread_mdelay(1000);
}
}else{
LOG_E("Event recv err:%d", err);
rt_thread_mdelay(100);
}
}else{
LOG_D("No thread register..");
daemon_wd_feed(daemon);
rt_thread_mdelay(1000);
}
}
}

static uint32_t daemon_wd_flag_get(struct daemon_object *daemon){
uint32_t flag = 0;
for(uint8_t i=0; idaemonNum; i++){
flag <<= 1;
flag |= 0x01;
}
return flag;
}

static inline uint32_t daemon_wd_flag_clear(struct daemon_object *daemon){
daemon->threadFlag = 0;
}

APP_ErrType daemon_init(struct daemon_object *daemon, const char *wd_device_name, uint32_t timeout){
APP_ErrType err = APP_OK;
rt_err_t result;
rt_slist_init(&daemon->threadHead);
daemon->daemonNum = 0;
daemon->threadFlag = 0;

daemon->iwgDevice = rt_device_find(wd_device_name);
if(daemon->iwgDevice == RT_NULL){
LOG_D("Cant find watch dog device");
return APP_ERR;
}
daemon->wdtTimeout = timeout;
daemon_watchdog_init(daemon);
result = rt_event_init(&daemon->event, "wd_event", RT_IPC_FLAG_FIFO);
if (result != RT_EOK){
err = APP_ERR;
goto errend;
}
daemon->daemonThread = rt_thread_create("daemon", daemon_thread_entry, daemon, 1024, 3, 40);
if(daemon->daemonThread == RT_NULL)
err = APP_OUT_OF_MEM;
rt_thread_startup(daemon->daemonThread);
errend:
return err;
}

uint32_t daemon_thread_register(struct daemon_object *daemon, rt_thread_t tid){
uint32_t flag = 0;
if(daemon->daemonNum < 32){
struct daemon_register_thread *temp = rt_malloc(sizeof(struct daemon_register_thread));
if(temp != RT_NULL){
daemon->daemonNum ++;
temp->thread = tid;
rt_slist_append(&daemon->threadHead, &temp->list);
flag = (1<<(daemon->daemonNum-1));
}
}
return flag;
}

void daemon_fd_wd(struct daemon_object *daemon, uint32_t flag){
rt_event_send(&daemon->event, flag);
daemon->threadFlag |= flag;
}

static struct daemon_register_thread* daemon_find_thread(struct daemon_object *daemon, uint8_t index){
struct daemon_register_thread* thread = RT_NULL;
rt_slist_t *temp_list;
if(index < daemon->daemonNum){
temp_list = rt_slist_next(&daemon->threadHead);
for(uint8_t i=0; i < index; i++){
if(temp_list != RT_NULL)
temp_list = rt_slist_next(temp_list);
else
break;
}
if(temp_list != RT_NULL)
thread = rt_slist_entry(temp_list, struct daemon_register_thread, list);
}
return thread;
}

static void daemon_watchdog_init(struct daemon_object *daemon){
rt_device_t iwgDevice;
iwgDevice = daemon->iwgDevice;
rt_err_t ret = rt_device_init(iwgDevice);
if (ret != RT_EOK){
LOG_E("Init wdt failed!\n");
return;
}
ret = rt_device_control(iwgDevice, RT_DEVICE_CTRL_WDT_SET_TIMEOUT, &daemon->wdtTimeout + 3);
if (ret != RT_EOK){
LOG_E("Set wdt timeout failed!\n");
return;
}
ret = rt_device_control(iwgDevice, RT_DEVICE_CTRL_WDT_START, RT_NULL);
if (ret != RT_EOK){
LOG_E("start wdt failed!\n");
return;
}
}

static void daemon_wd_feed(struct daemon_object *daemon){
rt_device_control(daemon->iwgDevice, RT_DEVICE_CTRL_WDT_KEEPALIVE, NULL);
}

#ifndef _DAEMON_H
#define _DAEMON_H
#include
#include
#include "app_def.h"

struct daemon_object{
uint8_t daemonNum;
uint32_t threadFlag;
uint32_t wdtTimeout;
rt_thread_t daemonThread;
rt_device_t iwgDevice;
struct rt_event event;
rt_slist_t threadHead;
};

struct daemon_register_thread{
rt_slist_t list;
rt_thread_t thread;
};

APP_ErrType daemon_init(struct daemon_object *daemon, const char *wd_device_name, uint32_t timeout);
uint32_t daemon_thread_register(struct daemon_object *daemon, rt_thread_t tid);
void daemon_fd_wd(struct daemon_object *daemon, uint32_t flag);
inline uint8_t daemon_is_watchdog_reset(void);
inline void daemon_reset_flag_clear(void);
#endif




查看更多

关注者
0
被浏览
524
2 个回答
JQRR_7669
JQRR_7669 认证专家 2020-07-01
你没看到系统看守组件吗?
bernard
bernard 2020-07-01
楼主可以去发一个软件包,让更多人(包括自己)未来在项目中更好、更方便的用起来

撰写答案

请登录后再发布答案,点击登录

发布
问题

分享
好友