FreeRTOS栈最大剩余深度#

任务在创建时就将其栈内存写入了特定的初始化值 0xA5 检测任务最大入栈的原理是,从栈顶开始按照栈增长方向开始依次检测内存是否为初始化值。 如果是侧继续循环检测; 如果不是侧停止检测,最大剩余空间就是刚刚循环检测的次数。

备注

如果该值越接近于0,哪么该任务就越接近栈溢出

flowchart LR 1(pxTCB->pxStack) 2{当前地址下值 是否为0xA5} 3(循环次数加1 当前地址沿栈增长 反方向加1) 4(返回 当前循环次数) 1 --> 2 --是--> 3 --> 2; 2 --否--> 4;

流程图#

task.c ‣ uxTaskGetStackHighWaterMark#
3916#if ( INCLUDE_uxTaskGetStackHighWaterMark == 1 )
3917
3918UBaseType_t uxTaskGetStackHighWaterMark( TaskHandle_t xTask )
3919{
3920    TCB_t * pxTCB;
3921    uint8_t * pucEndOfStack;
3922    UBaseType_t uxReturn;
3923
3924    pxTCB = prvGetTCBFromHandle( xTask );
3925
3926    #if portSTACK_GROWTH < 0
3927    {
3928        pucEndOfStack = ( uint8_t * ) pxTCB->pxStack;
3929    }
3930    #else
3931    {
3932        pucEndOfStack = ( uint8_t * ) pxTCB->pxEndOfStack;
3933    }
3934    #endif
3935
3936    uxReturn = ( UBaseType_t ) prvTaskCheckFreeStackSpace( pucEndOfStack );
3937
3938    return uxReturn;
3939}
3940
3941#endif /* INCLUDE_uxTaskGetStackHighWaterMark */
task ‣ prvTaskCheckFreeStackSpace#
3856#if ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark2 == 1 ) )
3857
3858static configSTACK_DEPTH_TYPE prvTaskCheckFreeStackSpace( const uint8_t * pucStackByte )
3859{
3860    uint32_t ulCount = 0U;
3861
3862    while( *pucStackByte == ( uint8_t ) tskSTACK_FILL_BYTE )
3863    {
3864        pucStackByte -= portSTACK_GROWTH;
3865        ulCount++;
3866    }
3867
3868    ulCount /= ( uint32_t ) sizeof( StackType_t ); /*lint !e961 Casting is not redundant on smaller architectures. */
3869
3870    return ( configSTACK_DEPTH_TYPE ) ulCount;
3871}
3872
3873#endif /* ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark2 == 1 ) ) */

函数 uxTaskGetStackHighWaterMark 将任务控制块的 pxStack 值传给了函数 prvTaskCheckFreeStackSpace 然后 prvTaskCheckFreeStackSpace 沿着内存增长的反方向开始循环检测内存是否为初始化值 循环检测的次数即为最大剩余栈深度。

备注

任务控制(TCB)的 pxStack 记录的是栈顶值吗?