| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587 |
- /******************************************************************************
- 版权所有:
- 文件名称: watchdog.c
- 文件版本: 01.00
- 创建作者: sunxi
- 创建日期: 2022-05-19
- 功能说明:
- watchdog 的使用说明:
- 1.本看门狗只侦察本进程中的各个线程的运行情况;
- 2.如何使用,请参考watchdog_test();
- 3. 在阻塞型的线程中,不能加入watchdog;
- 4. 本狗为应用狗;
- 其它说明:
- 修改记录:
- */
- /*------------------------------- 头文件 --------------------------------------
- */
- #include <stdio.h>
- #include <unistd.h>
- #include <string.h>
- #include <stdlib.h>
- #include <errno.h>
- #include <signal.h>
- #include <pthread.h>
- #include <time.h>
- #include <dirent.h>
- #include <signal.h>
- #include <sys/prctl.h>
- #include "../include/bspconfig.h"
- #include "rt.h"
- #include "watchdog.h"
- #include "shm_comm_packet.h"
- #include "shm.h"
- //#define WD_PATH "/tmp/wdt_record"
- #define WD_PATH "/app/data/wdt_record" //noted by sunxi: 保存在flash中,重启后,不会掉失
- #define WDT_MAX_ITEMS 64
- #define wd_info_str ""
- //心跳结构体
- typedef struct HB_T
- {
- uint16_t A;
- uint16_t B;
- uint16_t heartbeat_A; //每秒加1
- uint16_t heartbeat_B; //与heartbeat_A相同
- uint16_t crc;
- }HB_T;
- //裸核程序空间写完标志结构体
- typedef struct SHM_E907_PRO_W_F_T
- {
- uint16_t A;
- uint16_t B;
- uint16_t finish_flag; //裸核程序空间写完时,0x55写入finish_flag.
- uint32_t len;//裸核程序的实际长度
- uint16_t crc;
- }SHM_E907_PRO_W_F_T;
- typedef struct _wdt_item {
- const char *name;
- uint8_t feed;
- uint32_t runing;//计时器
- uint32_t period;//秒
- }wdt_item_t;
- struct ap_watchdog_t
- {
- int (*add_item)(const char *name, uint32_t *id, uint32_t period);
- int (*remove_item)(uint32_t id);
- int (*feed)(uint32_t id);
- int (*set_period)(uint32_t id, uint32_t seconds);
- uint32_t (*get_period)(uint32_t id);
- int (*start)(void);
- int (*stop)(void);
- int (*is_start)(void);
- int (*record)(const char *name);
- void (*set_debug)(int set);
- char appName[128];
- int _debug;
- wdt_item_t items[WDT_MAX_ITEMS];
- uint8_t runing_flag;
- pthread_mutex_t mutex;
- };
- static pthread_t pthread_tid = 0;
- int watchdog_feed_flag = 0;//放到心跳线程(与db进行心跳握手),以确保watchdog_thread线程运行正常
- struct ap_watchdog_t ap_watchdog;
- extern uint32_t wdt_id_mainloop;
- //检查文件夹是否存在
- //不存在,创建
- int CreateNewFolder(char* path)
- {
- DIR *dir;
- if(path == NULL)
- {
- return -1;
- }
- //检查文件夹是否存在
- dir = opendir(path);
- if(NULL == dir)
- {
- //不存在,创建
- mkdir(path,0775);
-
- }
- else
- {
- closedir(dir);
- }
- return 0;
- }
- int watchdog_init(void)
- {
- int i;
- CreateNewFolder(WD_PATH);
- memset(ap_watchdog.items, 0, sizeof(ap_watchdog.items));
- for(i=0; i<WDT_MAX_ITEMS; i++)
- ap_watchdog.items[i].feed = 1;
- ap_watchdog.runing_flag = 0;
- ap_watchdog._debug = 0;
- strcpy(ap_watchdog.appName, "dtu_t536");
- pthread_mutex_init(&ap_watchdog.mutex, NULL);
- ap_watchdog.start();
- return 0;
- }
- int watchdog_exit(void)
- {
- ap_watchdog.stop();
- pthread_join(pthread_tid, NULL);
- return 0;
- }
- //period:周期,单位为秒
- static int add_item(const char *name, uint32_t *id, uint32_t period)
- {
- int i;
-
- if(name == NULL)
- return -1;
- int ret = -1;
- // try to get mutex
- struct timespec tout;
- clock_gettime(CLOCK_REALTIME, &tout);
- tout.tv_sec += 5; //5s default
- if(pthread_mutex_timedlock(&ap_watchdog.mutex, &tout) != 0)
- return -1;
- for(i=0; i<WDT_MAX_ITEMS; i++)
- {
- if(ap_watchdog.items[i].name == NULL)
- {
- ap_watchdog.items[i].feed = 1;
- ap_watchdog.items[i].runing = 0;
- ap_watchdog.items[i].period = period;
- *id = i;
- ap_watchdog.items[i].name = name;
- rt_printf("WDT add_item i=%d,name= %s \r\n",i, ap_watchdog.items[i].name);
- ret = 0;
- break;
- }
- }
- pthread_mutex_unlock(&ap_watchdog.mutex);
-
- return ret;
- }
- static int remove_item(uint32_t id)
- {
- if(id > WDT_MAX_ITEMS)
- return -1;
- // try to get mutex
- struct timespec tout;
- clock_gettime(CLOCK_REALTIME, &tout);
- tout.tv_sec += 5; //5s default
- if(pthread_mutex_timedlock(&ap_watchdog.mutex, &tout) != 0)
- return -1;
- ap_watchdog.items[id].name = NULL;
- ap_watchdog.items[id].feed = 1;
- ap_watchdog.items[id].runing = 0;
- pthread_mutex_unlock(&ap_watchdog.mutex);
- return 0;
- }
- static int feed(uint32_t id)
- {
- if(id > WDT_MAX_ITEMS)
- return -1;
- ap_watchdog.items[id].feed = 1;
- return 0;
- }
- static int set_period(uint32_t id, uint32_t seconds)
- {
- if(id > WDT_MAX_ITEMS)
- return -1;
- ap_watchdog.items[id].period = seconds;
- return 0;
- }
- static uint32_t get_period(uint32_t id)
- {
- if(id > WDT_MAX_ITEMS)
- return -1;
- return ap_watchdog.items[id].period;
- }
- //设置心跳
- static int write_freq_hb(uint8_t *data)
- {
- int ret = 0;
- int cnt = 0;
- if(data == NULL)
- return -1;
-
- while(1)
- {
- ret = shm_comm_packet_write(SHM_ADDR_D_HB, data, sizeof(HB_T));
- if(ret > 0)
- {
- break;
- }
- if(++cnt > 3)
- break;
- usleep(30);
- }
- return ret;
- }
- static int get_e907_PRO_W_F(void)
- {
- SHM_E907_PRO_W_F_T flag;
- int ret = 0;
- int cnt = 0;
-
- while(1)
- {
- ret = shm_comm_packet_read(SHM_ADDR_U_PRO_W_F, sizeof(flag), (uint8_t *)&flag, sizeof(flag));
- if(ret > 0)
- {
- if(flag.finish_flag == 0x55)
- return flag.len;
- else
- return -1;
- }
- if(++cnt > 3)
- break;
- usleep(30);
- }
- return ret;
- }
- static void *watchdog_thread(void *arg)
- {
- int i = 0;
- static HB_T hb;
- int ret = 0;
- static int read_flag = 0;
- struct file * pfile;
- loff_t pos;
- memset(&hb,0,sizeof(hb));
- pthread_detach(pthread_self());
- prctl(PR_SET_NAME, "watchdog_thread");
- while (ap_watchdog.is_start()) {
- watchdog_feed_flag = 1;
- sleep(1);
- //把裸核程序读出来,并写到tmp文件夹中。
- if(read_flag == 0)
- {
- ret = get_e907_PRO_W_F();
- if(ret > 100)//返回裸核程序的实际长度,所以一定会大于100才有意义
- {
- //finish
- read_flag = 1;
- //从shm中读取裸核程序
- // 创建数据文件
- pfile = rt_file_open("/tmp/amp_rv0.bin",O_CREAT|O_RDWR,0);
- if(!IS_ERR(pfile))
- {
- pos = 0;
- rt_file_write(pfile, SHM_BASE_R+SHM_ADDR_U_E907_PRO, ret, &pos);
- rt_file_close(pfile,0);
- }
- }
- }
- hb.heartbeat_A++;
- hb.heartbeat_B = hb.heartbeat_A;
- write_freq_hb((uint8_t *)&hb); //给裸核的心跳
- for(i=0; i<WDT_MAX_ITEMS; i++)
- {
- if(ap_watchdog.items[i].name != NULL)
- {
- if(++ap_watchdog.items[i].runing > ap_watchdog.items[i].period)
- {
- if(ap_watchdog.items[i].feed != 1)
- {
- ap_watchdog.record(ap_watchdog.items[i].name);
- rt_printf("WDT-------%s is timeout!!!\r\n",ap_watchdog.items[i].name);
- system("reboot -f");
- //exit(EXIT_FAILURE);//TODO. noted by sunxi: 这里需要确认是,是重启应用程序,还是系统reboot!!!
- }
- else
- {
- if(ap_watchdog._debug)
- {
- rt_printf("WDT-------%s is Runing.\r\n",ap_watchdog.items[i].name);
- }
- }
-
- ap_watchdog.items[i].feed = 0;
- ap_watchdog.items[i].runing = 0;
- }
-
- }
- }
- }
- return NULL;
- }
- static int start(void)
- {
- int ret;
- if(ap_watchdog.runing_flag == 1)
- {
- return 0;
- }
- ap_watchdog._debug = 0;
- ap_watchdog.runing_flag = 1;
- ret = pthread_create(&pthread_tid, NULL, watchdog_thread, NULL);
- if(ret != 0) {
- rt_printf("can not create thread any more: %d\r\n",errno);
- ap_watchdog.runing_flag = 0;
- return -1;
- }
- return 0;
- }
- static int stop(void)
- {
- ap_watchdog.runing_flag = 0;
- return 0;
- }
- static int is_start(void)
- {
- return ap_watchdog.runing_flag;
- }
- static int record(const char *name)
- {
- time_t tt;
- char buf[512];
- FILE * f = NULL;
- char rec[256];
- char tmpBuf[128];
- int size;
- if(name == NULL)
- return -1;
- tt = time(NULL);
- memset(buf,0,sizeof(buf));
- sprintf(buf, "%s/wdt_record_%s", WD_PATH,ap_watchdog.appName);
- f = fopen(buf, "a");
- if(f == NULL) {
- perror("fopen");
- rt_printf("fopen is error!!!\r\n");
- return -1;
- }
- memset(tmpBuf, 0, sizeof(tmpBuf));
- strftime(tmpBuf, 128, "%Y-%m-%d %H:%M:%S", localtime(&tt));
- memset(rec, 0, sizeof(rec));
- size = snprintf(rec, sizeof(rec), "%s %s fuck you up; \r\n", tmpBuf, name);
- fwrite(rec, size, 1, f);
- fclose(f);
- return 0;
- }
- static void set_debug(int set)
- {
- ap_watchdog._debug = set;
- }
- struct ap_watchdog_t ap_watchdog =
- {
- .add_item = add_item,
- .remove_item = remove_item,
- .feed = feed,
- .set_period = set_period,
- .get_period = get_period,
- .start = start,
- .stop = stop,
- .is_start = is_start,
- .record = record,
- .set_debug = set_debug,
- };
- /*
- period: 看门狗的喂狗周期
- 因为可能存在某些线程,其运行过程很长,运行的中间,没有合里加sleep等休息函数,
- 造成占用时间较长。
- 于是,这里的period,可以尽量设置长一点的时间。
- */
- int watchdog_add_item(const char *name, uint32_t *id, uint32_t period)
- {
- int ret = 0;
- ret = ap_watchdog.add_item(name, id,period);
- return ret;
- }
- int watchdog_feed(uint32_t id)
- {
- int ret = 0;
- ret = ap_watchdog.feed(id);
-
- return ret;
- }
- int watchdog_remove_item(uint32_t id)
- {
- int ret = 0;
- ret = ap_watchdog.remove_item(id);
-
- return ret;
- }
- //===================================================================================================================
- //test
- void *watchdog_test_pthread(void *arg)
- {
- pthread_detach(pthread_self());
- uint32_t wdt_id;
- int rc = watchdog_add_item("watchdog_test_pthread", &wdt_id,10);
- if(rc != 0) {
- printf("can not add watchdog_test_pthread task to wdt\r\n");
- return NULL;
- }
- while(1)
- {
- //把喂狗操作放在首行,确保每个循环都有喂狗
- watchdog_feed(wdt_id);// 去掉本行喂狗,就可以产生记录
-
- sleep(1);
-
- }
- watchdog_remove_item(wdt_id);
- return NULL;
- }
- int watchdog_test(void)
- {
- int ret;
- watchdog_init();
- pthread_t ConnectCheck_id;
- ret = pthread_create(&ConnectCheck_id, NULL, watchdog_test_pthread, NULL);
- if(ret != 0) {
- printf("can not create watchdog_test_pthread\r\n");
- return -1;
- }
- return 0;
- }
- void watchdog_feed_mainloop(void)
- {
- watchdog_feed(wdt_id_mainloop);
- }
- void watchdog_feed_protect(void)
- {
- }
- void watchdog_reset_cpu(int i)
- {
- printf("reboot code: %d .\n", i);
- system("reboot -f");
- }
- void watchdog_feed_mainloop_50s(void)
- {
- watchdog_feed(wdt_id_mainloop);
- }
- /*------------------------------- 文件结束 -------------------------------*/
|