0x00前言

笔者当时使用的是FreeRTOS 9,而在设备在某一些时刻会出现异常的通讯问题,且问题呈现概率式的分布,笔者查看了很长时间才找到问题点。所以在这里作为记录,聊以备忘并且希望可以给一些遇到差不多的问题的同志一些思路

阅读本文,您可能需要掌握的知识:

技能熟练度
FreeRTOS熟悉
C语言了解

0x10 前情提要

在工厂内实现的一个之前就完整实现功能的程序的机器。工厂的小哥找到笔者,表示当前的特定测试项每次都出现问题导致无法通过,而且出现问题的时候都是随机的,每次也不知道成不成功。但是之后随便传输什么都可以完成。

0x20 排查

过去看看,笔者在测试了很多次后,确实每次出现的概率算是不定的,但是似乎都是某些数据无法下发到当前的芯片内部。可因为某些原因导致问题边界很难确认,也就是说笔者不知道到底是哪边没有发送还是这边没有接受到。而当前的设备无法使用外部监视的方式进行调试。而完全概率性的问题又使笔者无法使用在线调试的方式进行排错。可谓是遇到了一个棘手的问题。

有道是:解决问题10块钱,知道如何解决问题10万块。现在就是一个10万的大难题在这里,到那时笔者硬着头皮也要上的。

而笔者在进行连续不断的测试下,笔者也还是没有发现问题有什么规律性,但是概率大概试验出约为10%。也就是大概10次就会出现一次。

在仔细进行了代码审计之后。笔者尝试恢复到很久之前的代码,发现概率确实减小了很多。也就是说,确实是一定的更新软件的问题。

在测试了几十次的情况下,还是无法得到比较完整的错误原因。而一次偶然的测试让笔者发现,当前的错误的查找路径完完全全偏离了正确的路线,因为原本笔者们所有人都以为是某个测试项下的固定流程出现了某个流程上的问题。但是再一次偶然的测试中,出现了更加随机的错误的设置项,这也代表了问题从某些特定的测试项下的错误变成了通讯的整体问题,只不过在某些测试项下的复现概率很高。

0x21 纠正的误区

确认了当前错误的判断方向后,转换方向的笔者很快在代码审计中发现了可能出现问题点的代码。尝试修复后,似乎解决了这个问题。但是从检索代码发现,在之前完全无法复现的错误,其实也是因为完全的幸运使然。

0x30 问题原因

当前代码出现问题的主要原因其实是老生常谈的优先级反转,只不过这次的反转让人无法预料。

熟悉RTOS的人知道,信号量是现在RTOS常用的进程间通信的方式,也是可以保证当前进程保证实时性与可重入性的措施。

而在FreeRTOS中,因为常用的芯片内部都有中断的情况,所以其在这种可能超出RTOS操作下的情况加入了一个FromISR的接口,这个接口可以保证在有FreeRTOS控制权之外的中断接口下操作系统内部的数据。但是因为原本的RTOS维护着相关的调度,而接口内部的数据都是实时的,根本不存在等待的情况。

这个时候就会有一种可能:当前任务运行中,其他的任务从中断内部切换进去,当检测到信号量正在被使用后,直接导致当前的参数无法继续运行而退出。这样就会造成如上文提到的可能的错误。

这种错误的出发完全依靠进入中断内部的发送次数决定。而且数据的切换导致指令越复杂数据越多,错误的触发率越高。举例如下:

void inputrrupt()
{
  	xSemaphoreTakeFromISR(test,NULL);
	xSemaphoreGiveFromISR(test,NULL);  
    
}

void task()
{
	xSemaphoreTakeFromISR(test,NULL);
	xSemaphoreGiveFromISR(test,NULL);
}

其实这个问题也不难想到,但是原本在FreeRTOS中,这个参数是由FreeRTOS维护,在切换时会重新进入最高的任务。但是在中断内部并没有在FreeRTOS的管理下,也就没办法保证现在的任务是最新的,也就是在出现异常时就会丢失一个可能的发送。

且在接口中signed BaseType_t *pxHigherPriorityTaskWoken·中,这个API参数为pdTRUE是就必须要切换一下保证当前可以顺利的将信号量切换过去,但是在null时无法保证能够切换,一般情况下也不会出现问题,因为只是会概率性的出现很短时间内(一个任务时间片)的翻转。而且在7.3之后官方明确表明可以发送NULL进入。

但是在实际测试中,似乎如果不能保证在最快的切换时,还是会出现异常的误报。因为毕竟会在某次真的无法切换过去导致当前的发送无法进行。

void vTimerISR( void * pvParameters )
{
	static signed BaseType_t xHigherPriorityTaskWoken = pdFALSE;

        
    xSemaphoreGiveFromISR( xSemaphore, &xHigherPriorityTaskWoken );

    if (xHigherPriorityTaskWoken == pdTRUE)
	    portYIELD_FROM_ISR();
}

标题:记:一次FreeRTOS信号量与中断错误的使用导致意外的记录
作者:GreenDream
地址:HTTPS://greendreamer.work/articles/2021/08/01/1627806729097.html
  • 版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明出处!