FreeRTOS 原理 --- 最少剩余可用任务栈 与 任务栈溢出检查

最少剩余可用任务栈

函数 uxTaskGetStackHighWaterMark() 可用于获取任务的最少剩余可用栈

复制代码
#if ( INCLUDE_uxTaskGetStackHighWaterMark == 1 )

    UBaseType_t uxTaskGetStackHighWaterMark( TaskHandle_t xTask )
    {
    TCB_t *pxTCB;
    uint8_t *pucEndOfStack;
    UBaseType_t uxReturn;

        pxTCB = prvGetTCBFromHandle( xTask );

        #if portSTACK_GROWTH < 0 // 对于 M3/M4 内核,为-1,表示栈是从高地址向低地址方向增长
        {
            pucEndOfStack = ( uint8_t * ) pxTCB->pxStack;
        }
        #else
        {
            pucEndOfStack = ( uint8_t * ) pxTCB->pxEndOfStack;
        }
        #endif

        uxReturn = ( UBaseType_t ) prvTaskCheckFreeStackSpace( pucEndOfStack ); // pucEndOfStack 是栈底

        return uxReturn;
    }

#endif /* INCLUDE_uxTaskGetStackHighWaterMark */
复制代码

 任务创建时,把任务栈的值都初始化为 tskSTACK_FILL_BYTE

#define tskSTACK_FILL_BYTE    ( 0xa5U )
    /* Avoid dependency on memset() if it is not required. */
    #if( tskSET_NEW_STACKS_TO_KNOWN_VALUE == 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 ) );
    }
    #endif /* tskSET_NEW_STACKS_TO_KNOWN_VALUE */

函数 prvTaskCheckFreeStackSpace() 从栈底往栈顶一个字节一个字节读数据,直到读出的值不等于 tskSTACK_FILL_BYTE,如果栈被使用,其值不等于 tskSTACK_FILL_BYTE

复制代码
    static uint16_t prvTaskCheckFreeStackSpace( const uint8_t * pucStackByte )
    {
    uint32_t ulCount = 0U;

        while( *pucStackByte == ( uint8_t ) tskSTACK_FILL_BYTE )
        {
            pucStackByte -= portSTACK_GROWTH; // 栈底是最后被使用的栈内存,从栈底往栈顶延申
            ulCount++; // 退出 while 后,ulCount 等于栈未被使用的字节数
        }

        ulCount /= ( uint32_t ) sizeof( StackType_t ); /*lint !e961 Casting is not redundant on smaller architectures. */

        return ( uint16_t ) ulCount;
    }
复制代码

函数 vTaskGetInfo() 也可以获取栈使用情况在内的其他信息。

任务栈溢出检查

检查点

PendSV 中断里,获取要执行的任务的函数 vTaskSwitchContext()

检查原理1

栈顶地址是否小于等于栈底

复制代码
#if( ( configCHECK_FOR_STACK_OVERFLOW == 1 ) && ( portSTACK_GROWTH < 0 ) )

    /* Only the current stack state is to be checked. */
    #define taskCHECK_FOR_STACK_OVERFLOW()                                                                \
    {                                                                                                    \
        /* Is the currently saved stack pointer within the stack limit? */                                \
        if( pxCurrentTCB->pxTopOfStack <= pxCurrentTCB->pxStack )                                        \
        {                                                                                                \
            vApplicationStackOverflowHook( ( TaskHandle_t ) pxCurrentTCB, pxCurrentTCB->pcTaskName );    \
        }                                                                                                \
    }

#endif /* configCHECK_FOR_STACK_OVERFLOW == 1 */
复制代码

检查原理2

栈底的4个word的在任务创建赋值的初始值,是否被修改

复制代码
#if( ( configCHECK_FOR_STACK_OVERFLOW > 1 ) && ( portSTACK_GROWTH < 0 ) )

    #define taskCHECK_FOR_STACK_OVERFLOW()                                                                \
    {                                                                                                    \
        const uint32_t * const pulStack = ( uint32_t * ) pxCurrentTCB->pxStack;                            \
        const uint32_t ulCheckValue = ( uint32_t ) 0xa5a5a5a5;                                            \
                                                                                                        \
        if( ( pulStack[ 0 ] != ulCheckValue ) ||                                                \
            ( pulStack[ 1 ] != ulCheckValue ) ||                                                \
            ( pulStack[ 2 ] != ulCheckValue ) ||                                                \
            ( pulStack[ 3 ] != ulCheckValue ) )                                                \
        {                                                                                                \
            vApplicationStackOverflowHook( ( TaskHandle_t ) pxCurrentTCB, pxCurrentTCB->pcTaskName );    \
        }                                                                                                \
    }

#endif /* #if( configCHECK_FOR_STACK_OVERFLOW > 1 ) */
复制代码

 

posted @   流水灯  阅读(650)  评论(0编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
历史上的今天:
2017-11-16 单例 ------ C++实现
2017-11-16 C++ ------ static变量
2017-11-16 C++ ------ 拷贝构造函数
2017-11-16 C++ ------ 引用
2017-11-16 C++ ------ 互斥锁、原子操作的性能测试
点击右上角即可分享
微信分享提示