标志位被篡改"/>
FreeRTOS 标志位被篡改
调试程序是遇到了一个很奇葩的问题,设置好的静态全局标志位被意外篡改了。
起初以为是栈溢出覆盖了,于是在该变量前后定义静态全局变量,两个周都没变动过,就标志位被修改了。于是确定不是堆栈的问题。
分析:
记录一下这个容易犯的错误,也可以说是小漏洞。
如果存在A线程正在等待队列X(及线程正阻塞在xQueueReceive函数中)。此时如果有B线程执行xQueueSend 函数执行时,B线程在将数据拷贝入队列后会立即释放B线程的执行,转而执行A线程。只有当A线程主动释放线程或者到任务调度的时间,B线程才有机会被执行。
如下代码,当xQueueSend 执行后, 【waitqueue_flag=false;】不会被紧接着执行,而是跳到xQueueReceive函数继续执行,如果该线程不主动释放CUP,再次执行了【can_read_until】函数,则继续执行【 waitqueue_flag = true;】命令,运行到xQueueReceive函数才会主动释放一次CPU,此时系统调动回来执行xQueueSend后面的语句,及【 waitqueue_flag=false;】。此时就会出现waitqueue_flag刚设置的标志位被莫名其妙的清除了,也就是xQueueSend后的语句干的坏事。他来的太慢了!!!
最简单的办法就是把 waitqueue_flag=false;放在xQueueSend执行前执行。
总结:
根据以上分析,得出两个血淋淋的教训:
1、全局变量多线程操作时,尽量保证一方读一方写,如果需要同时写的情况,请加锁。
2、在调用FreeRTOS函数时,可能会存在系统提前触发上下文切换。所以之前做好切换前的数据准备。
异常部分代码如下:
其中一个线程:
回调函数设置应答队列:cmd_queue
static int can_receive_callback(void *msg, int size)
{can_node_t node = (can_node_t)msg;if(waitqueue_flag){if(waitqueue_address == node->address && waitqueue_cmd==node->can.cmd){xQueueSend(cmd_queue, node,0);waitqueue_flag=false;return 0;}}
。。。。。。
另一个线程:
等待队列中数据更新
bool can_read_until(can_node_t node, int timeout)
{waitqueue_flag = true;if (xQueueReceive(cmd_queue, node, timeout) == pdTRUE){return true;}return false;
}
更多推荐
FreeRTOS 标志位被篡改
发布评论