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 ) */
标签:
FreeRTOS
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 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++ ------ 互斥锁、原子操作的性能测试