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次切换时候就发生了堆栈溢出。

  • 相关阅读:
    Apache 虚拟主机 VirtualHost 配置
    EAX、ECX、EDX、EBX寄存器的作用
    Python中文文档 目录(转载)
    八度
    POJ 3268 Silver Cow Party (最短路)
    POJ 2253 Frogger (求每条路径中最大值的最小值,Dijkstra变形)
    2013金山西山居创意游戏程序挑战赛——复赛(1) HDU 4557 非诚勿扰 HDU 4558 剑侠情缘 HDU 4559 涂色游戏 HDU 4560 我是歌手
    HDU 4549 M斐波那契数列(矩阵快速幂+欧拉定理)
    UVA 11624 Fire! (简单图论基础)
    HDU 3534 Tree (树形DP)
  • 原文地址:https://www.cnblogs.com/pingwen/p/7448349.html
Copyright © 2011-2022 走看看