一个互斥量引发的宕机

嵌入式实时操作系统一方面让mcu更高效的利用起来,另一方面让开发者可以把不同的软件功能模块进行解耦,更快捷清晰的开发整个项目。

但是用的好就是得力助手,用不好就是杀手。因为操作系统将会面临裸机下面更多的资源重入问题,以及内存分配,优先级分配,IPC通信等等需要谨慎对待的小细节……

那么就从卡了一天的一次调试宕机事件来说道说道,一个互斥量如何搬起石头砸向了自己的脚。故事的开始,源于自己想借用一套更加现成的at处理框架,来用于mcu和nb模块进行通信。

于是乎,看了alios的at,rt-thread的at,liteos的at,可是没有一套可以直接用在freertos上的组件。所以干起了搬运工的工作,决定把liteos下面的at组件移植到freertos下来运行。alios底层串口接收处理不够高效,rtt 的at和操作系统交织的比较多,而liteos中操作系统的API几乎可以从freertos中找到相对应的,所以就决定对liteos 下的at下手了。

分析了下大概代码的框架如下:

大体上可以分为以上四层,但是每一层都会调用操作系统的信号量、互斥量、创建任务等相关接口,想要移植成功,就要把和操作系统的接口抽象出来,替换为freertos相关的代码。

AT_OS适配层代码做好了,然后针对我使用的MCU进行AT_HAL串口发送接收的移植,最后编写针对我使用的通信模组的驱动代码。最后暴露给上层应用的就是通用的AT_API接口。

至此,大体框架已经完成了,但是就在这时出现了一个不愿意相见的BUG。在调用AT命令发送并等待回调处理接收的过程,然后就没有然后了……

加大任务栈空间没用……

调整任务优先级,没用……

而该代码的关键部分都在AT_MAIN核心处理中,本来想用现成的,现在还要把AT_MAIN的整个实现思路分析一遍。然后顺着一步步在线调试,当运行到mutex释放的时候程序飞了调试无法跟踪到下一步……尼玛,bug去哪儿了?

停止调试的时候,发现程序最终停止在了freertos task.c的xTaskPriorityDisinherit() 函数中,该函数是freertos避免出现任务优先级反转针对持有互斥量的任务进行高优先级继承。

考虑之前也正好是运行到了互斥量释放的地方挂掉了,这里又卡在检查任务持有互斥量的地方,那么几乎可以判断和AT_MAIN中刚才使用的信号量有关系了。

一个个排查,最终发现了一个小细节。在一个cmd发送函数中只调用了mutex获取函数,而看不到成对出现的mutex释放函数。而搜索整个代码发现在另一个函数中mutex释放就是我刚才卡死的地方。

一般互斥量的使用都是成对的出现,即针对不同任务可能会同时访问的资源进行互斥,避免同时访问。使用完以后要立即释放muxtex。随机想到获取mutex难道和释放mutex的两个函数是在不同的任务中运行?最终去查了freertos的mutex说明不能在一个任务中获取另一个任务中释放,最终果不其然,还是被我扒开了它的真面目:大体框图如下:(我相信你去看它代码远比我这框图乱太多)

发送端发送一条at命令,同时获取了mutex,但是它并没有释放mutex,而是等待接收端接收到数据进行一些处理以后才释放了互斥量。我想说这地方为什么用互斥量?这明显是一个同步作用而不像是互斥的作用啊。还有难道liteos的互斥量支持不同任务中分别执行获取和释放。哦买噶!!!!!!

所以这个地方我一定要吐槽一下,要明确同步和互斥的不同,要不然干嘛再细分信号量和互斥量呢。

so,我决定给AT_MAIN进行改头换面了,但是坑还是要解决的,把使用mutex实现的同步功能替换成用信号量实现就可以了。

您可能还喜欢...