liteos定时器回调时间过长造成死机问题解决思路

项目需求

原代码是稳定的,现我实现EMQ平台断开连接的时候,把HSL的模拟点位数据采集到网关,然后存入Flash,当EMQ平台连接的时候,把Flash里面的点位数据放在消息队列里面,不影响实时采集。

核心1:EMQ平台断开,保持存储稳定

核心2:不影响实时采集的前提下去把flash的数据读出来在空闲的时候发出去

核心3:进入断点续传的条件是连续5次发布失败进入断点续传

问题描述

核心1遇到了问题,就是EMQ断开20分钟左右会死机,没日志输出。

最后的日志,然后就一直在进行度队列操作,队列ID是垃圾值

初步分析

1.队列可能在使用的时候没有创建

2.队列的id存的地方被覆盖了

c 复制代码
[2024-07-24 17:20:49.179]# RECV ASCII>
[INFO][556][Plc_s7_Task:1404] RDataCnt:30,RWarnCnt:0 CDataCnt:30,CWarnCnt:0 Tol:30,elaps: 251ms
[INFO][556][getNetSignalValue:1037] EC20 Get Net Signle: "25"
[INFO][556][print_memory_usage:594] m_aucSysMem0      2000d4f8 Memory Used:5992, Free:135072, Tol:141064, MallocCnt: 21082, FreeCnt: 20964, Malloc-Free: 118
[WARN]osSwTmrTask:111 timer_handler(080540fd) cost too many ms(5995)


代码

c 复制代码
void point_timer_Callback(UINT32 arg)
{
	UINT32 uwReportRet = LOS_OK;
	UINT32 uwCollectRet = LOS_OK;
	uint16_t ep_resources[] = {RESOURCES_STATUS};
	char buff[64] = {0};
	char *buf[1] = {buff};

	LOS_SwtmrStop(point_pusSwTmrID);

    // 反写任务正在执行,跳过本次检查
    if (g_reverse_write_processing == true) {
//		 if (g_reverse_write_processing == true) {	
        //重新开启定时器,准备下一次检查
	    LOS_SwtmrStart(point_pusSwTmrID);
        return;
    }

	if (!Get_Point_Status())
	{
		LOS_SwtmrStart(point_pusSwTmrID);	
		return;
	}

	//启动上报任务
	uwReportRet = start_report_task();
	if(LOS_OK != uwReportRet)
	{	
		ATINY_LOG(LOG_ERR, "start_report_task Error!");
		stop_report_task();
	}

	//启动采集任务
	uwCollectRet = start_collect_task();
	if (LOS_OK != uwCollectRet)
	{
		ATINY_LOG(LOG_ERR, "start_collect_task Error!");
		stop_collect_task();
	}

	if (LOS_OK != uwCollectRet || LOS_OK != uwReportRet)
	{
		//检查是否绑定
		if(0 == read_resoures(LWM2M_EP_OBJECT_ID, 0, ep_resources, buf, 1, RESOURCES_POINT_SAVE_STRING_MAX))
		{
			if(0 == atoi(buf[0]))
			{
				ATINY_LOG(LOG_INFO, "Wait Bing!");
			}
			else
			{
				ATINY_LOG(LOG_INFO, "Restart Report || Collect!");
			}
		}
		else
		{
			ATINY_LOG(LOG_ERR, "File System Error, Need Clean Config & Restart!");
		}
	}

	//检查系统异常
	//TODO:是否应该独立为一个检测线程,但上报通道依赖mqtt,mqtt又和数据点采集耦合在一起。应先解耦mqtt和数据采集
	if(LOS_OK == check_report_task())
	{
		check_sys_warning();
	}

    south_report_gateway();

	print_memory_usage();

	//重新开启定时器,准备下一次检查
	LOS_SwtmrStart(point_pusSwTmrID);	
}

解决方法

080540fd 地址定位到回调函数是void point_timer_Callback(UINT32 arg)

根据日志知道是这个回调时间有点长。

那为啥不是立即死而是过了几十分钟死呢?

代码优化等级从2调为0,进一步调试

c 复制代码
LOS_SwtmrStop(point_pusSwTmrID);

他知道他自己耗时还在函数这里把定时器关了,怒。那为啥会调试的时候死在读队列(队列操作)里面呢?因为定时器的回调函数其实都是存在定时器回调队列里面的,如果一个回调过长,因为定时器的回调优先级0,其他高优先级任务都执行不下去。在实时性操作系统里会紊乱系统,加上屎山代码,就会死机。所以在liteos这种系统里面,多加日志输出,不可完全信调试。调试只是一瞬间的观察,调试可以判断这一段时间进而想一下自己的改动点和日志做分析得出怀疑点。

上面判断条件

c 复制代码
if (g_reverse_write_processing == true )

改为

c 复制代码
if (g_reverse_write_processing == true || BreakPoint_State == BreakPointSaveOnline)

OK,不要动不动在回调函数写耗时操作,一两次可能没问题,但是一直进行回调的话,会造成奇怪的紊乱。

相关推荐
阿川!4 分钟前
嵌入式软件--stm32 DAY7 I2C通讯上
stm32·单片机·嵌入式硬件·mcu
O。o.尊都假都33 分钟前
socket套接字的超时控制
单片机·嵌入式硬件·网络协议
码农黛兮_4641 分钟前
SQL 索引优化指南:原理、知识点与实践案例
数据库·sql
爆肝疯学大模型42 分钟前
SQL server数据库实现远程跨服务器定时同步传输数据
运维·服务器·数据库
我来整一篇1 小时前
用Redis的List实现消息队列
数据库·redis·list
加什么瓦2 小时前
Redis——数据结构
数据库·redis·缓存
神仙别闹2 小时前
基于C#+SQL Server开发(WinForm)租房管理系统
数据库·oracle·c#
528302 小时前
MySQL主从复制
数据库·mysql
qq_12498707532 小时前
原生小程序+springboot+vue医院医患纠纷管理系统的设计与开发(程序+论文+讲解+安装+售后)
java·数据库·spring boot·后端·小程序·毕业设计
jie188945758662 小时前
ubuntu----100,常用命令2
数据库·ubuntu