题目
RTOS和ARM 开发过程每个任务都需要自己的栈空间,应用不同,每个任务需要的栈大小也是不同的。总结了几个方法
方法一 (手动统计)
我初步将估算如下的几个选项简单的累加就可以得到粗略的栈大小:
- 局部变量
- 函数行参
- 函数返回地址
- 任务切换
- 执行过程中,中断发生
在局部变量和形参在代码运行过程中,如果在嵌套一个函数的时候,这个就发生入栈的操作,所以计算的时候大家要考虑一下。
函数返回地址使用的专用寄存器LR (link register )寄存器里面的,如果函数其他函数的话,这个也是要入栈的。
任务切换的时候,也是保存当前任务的所有寄存器的状态或者值。
发生中断时候,有一部分寄存器会自动入栈(这里的咱是任务栈),发生在中断中的嵌套都是系统栈。
计算的时候加这些能考虑全部加上,然后为了保险期间还是留有余量。建议在乘以一个安全系统(这个值一般是2)。当然这是我们能考虑到一些栈的使用,还有一些无法确定情况,比如使用printf函数、还有就是函数指针间接调用。
所有在实际使用过程中还是比较麻烦的。
方法二 —(使用IDE)
一般 IDE 开发环境都有这样的功能,比如 MDK 会生成一个 htm 文件,通过这个文件用户可以知道每个被调用函数的最大栈需求以及各个函数之间的调用关系。但是 MDK无法确定通过函数指针实现函数调用时的栈需求。(好像也是有风险)
方法三 (使用填充数据)
任务创建的时候将任务栈所有数据初始化为 0xa5,任务切换时进行任务栈检测的时候会检测末尾的 16 个字节是否都是 0xa5,通过这种方式来检测任务栈是否溢出了。相比方法一,这种方法的速度稍慢些,但是这样就有效地避免了方法一里面的部分情况。不过依然不能保证所有的栈溢出都能检测到,比如任务栈末尾的 16 个字节没有用到,即没有被修改,但是任务栈已经溢出了,这种情况是检测不到的。另外任务栈溢出后,任务栈末尾的 16 个字节没有修改,但是溢出部分的栈区数据被修改了,这部分栈区的数据不重要或者暂时没有用到还好,但如果是重要数据被修改将直接导致系统进入硬件异常,这种情况下,栈溢出检测功能也是检测不到的。
/* Avoid dependency on memset() if it is not required. */
#if( ( configCHECK_FOR_STACK_OVERFLOW > 1 ) || ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) )
{
/* Fill the stack with a known value to assist debugging. */
( void ) memset( pxNewTCB->pxStack, ( int ) tskSTACK_FILL_BYTE, ( size_t ) ulStackDepth * sizeof( StackType_t ) );
}
```