zoukankan      html  css  js  c++  java
  • FreeRtos堆栈检测应用

            Free rtos每个任务都有自己的栈空间,每个任务需要的栈大小也是不同的。如果堆栈过小就会造成栈溢出,有时候栈溢出发生在某种特定顺序的任务切换中,比较难检测出。所以前期测试和监控任务栈用量就显得尤其重要。

    • FreeRTOSConfig.h文件中配置宏定义:
    #define configCHECK_FOR_STACK_OVERFLOW	2   
    #define INCLUDE_uxTaskGetStackHighWaterMark     1
    
    • 在任务切换时检测任务栈指针是否过界了,如果过界了,在任务切换的时候会触发栈溢出钩子函数。
    void vApplicationStackOverflowHook( TaskHandle_t xTask,signed char *pcTaskName );
    
    • 用户可以在钩子函数里面做一些处理。
    • 任务创建的时候将任务栈所有数据初始化为0xa5,任务切换时进行任务栈检测的时候会检测末尾的16个字节是否都是0xa5,通过这种方式来检测任务栈是否溢出了。相比方法一,这种方法的速度稍慢些,但是这样就有效地避免了方法一里面的部分情况。不过依然不能保证所有的栈溢出都能检测到,比如任务栈末尾的16个字节没有用到,即没有被修改,但是任务栈已经溢出了,这种情况是检测不到的。另外任务栈溢出后,任务栈末尾的16个字节没有修改,但是溢出部分的栈区的数据修改了,这部分栈区的数据不重要或者暂时没有用到还不会有什么问题,但如果是重要数据被修改将直接导致系统进入硬件异常,这种情况下,栈溢出检测功能也是检测不到的。
    • 溢出检测的实现原理:
      #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 ) */
    • 实现用户的钩子函数:
    /**
      * @brief  if task overflow, it will run here.
      * @param  [IN]task handle. 
      * @param  [IN]task name string pointer.
      * @retval None
      */
    void vApplicationStackOverflowHook( TaskHandle_t xTask, signed char *pcTaskName )
    {
         while(1)
         {
             printf("task %s is stack overflow. 
    ", pcTaskName);
             vTaskDelay(500);
         }
    }
    • 测试每个任务的堆栈大小:
    /**
      * @brief  check all task stack and get the remain stack size.
      * @param  None. 
      * @retval None
      */
    void CheckTaskStack(void)
    {
        uint8_t i = 0;
        float stack_usage = 0;
        
        DEBUG_PRINT("
    ------------------------------------
    ");
        for(i=0; i<APP_TASK_NUMS; i++) 
        {
          TaskConfigStruct[i].stack_remain = uxTaskGetStackHighWaterMark( TaskConfigStruct[i].handle );
          stack_usage = 100.0f*((float)TaskConfigStruct[i].stack_max - 
    (float)TaskConfigStruct[i].stack_remain )/ (float)TaskConfigStruct[i].stack_max; DEBUG_PRINT("> id=%d, name=%8s, stack usage=%5.2f%%, free/all=%4d/%4d. ",
    TaskConfigStruct[i].id, TaskConfigStruct[i].name, stack_usage,
    TaskConfigStruct[i].stack_remain, TaskConfigStruct[i].stack_max ); } DEBUG_PRINT(
    "------------------------------------ "); }
    • 测试结果,还剩余4个u32空间,溢出检测的方法2刚好是检查最后的4个数据,此时恰好不会触发overflow。

    /**
      * @brief  check all task stack and get the remain stack size.
      * @param  None. 
      * @retval None
      */
    void CheckTaskStack(void)
    {
        uint8_t i = 0;
        uint8_t i2 = 0; // test stack overflow
        float stack_usage = 0;
        
        DEBUG_PRINT("
    ------------------------------------
    ");
        for(i=0; i<APP_TASK_NUMS; i++) 
        {
          TaskConfigStruct[i].stack_remain = uxTaskGetStackHighWaterMark( TaskConfigStruct[i].handle );
          stack_usage = 100.0f*((float)TaskConfigStruct[i].stack_max - 
    (float)TaskConfigStruct[i].stack_remain )/ (float)TaskConfigStruct[i].stack_max; DEBUG_PRINT("> id=%d, name=%8s, stack usage=%5.2f%%, free/all=%4d/%4d. ",
    TaskConfigStruct[i].id, TaskConfigStruct[i].name, stack_usage,
    TaskConfigStruct[i].stack_remain, TaskConfigStruct[i].stack_max ); } DEBUG_PRINT(
    "------------------------------------ "); }
    • 测试结果:再次定义局部变量uint8_t i2, 任务切换时候压栈会把i2入栈,此时会触发溢出检测。测试发现,任务在第2次切换时候就发生了堆栈溢出。

  • 相关阅读:
    个人:我的2011生活看板
    个人管理:公司做的稻盛阿米巴培训笔记
    使用TOGAF来做业务架构 价值驱动产品开发
    30天敏捷结果(21)正面失败,吸取教训,改善结果
    2010年12月blog汇总:敏捷个人
    30天敏捷结果(25):固定时间,灵活范围
    101与金根回顾敏捷个人:(11)执行力
    团队管理:设计团队的一周
    云:构建云计算的核心技术与平台
    读书笔记:千万别学英语
  • 原文地址:https://www.cnblogs.com/pingwen/p/7448349.html
Copyright © 2011-2022 走看看