1. 程式人生 > >FreeRTOS 任務棧大小確定及其溢位檢測

FreeRTOS 任務棧大小確定及其溢位檢測

FreeRTOS 的任務棧設定
不管是裸機程式設計還是 RTOS 程式設計,棧的分配大小都非常重要。 區域性變數,函式呼叫時的現場保護和返
回地址,函式的形參,進入中斷函式前和中斷巢狀等都需要棧空間,棧空間定義小了會造成系統崩潰。
裸機的情況下,使用者可以在這裡配置棧大小: 

為什麼是堆中的?因為我們採用的就是動態建立任務的方式。如果靜態建立,就和我們自己開闢的空間有關,通常靜態建立任務用陣列作為容器,但是通常靜態建立的方式我們都不使用。

FreeRTOS 的系統棧設定
上面跟大家講解了什麼是任務棧,這裡的系統棧又是什麼呢?裸機的情況下,凡是用到棧空間的地方
都是在這裡配置的棧空間:

在 RTOS 下,上面兩個截圖中設定的棧大小有了一個新的名字叫系統棧空間

,而任務棧是不使用這裡的空間的。 任務棧不使用這裡的棧空間,哪裡使用這裡的棧空間呢?答案就在中斷函式和中斷巢狀。 

 由於 Cortex-M3 和 M4 核心具有雙堆疊指標,MSP 主堆疊指標和 PSP 程序堆疊指標,或者叫 PSP
任務堆疊指標也是可以的。在 FreeRTOS 作業系統中,主堆疊指標 MSP 是給系統棧空間使用的,進
程堆疊指標 PSP 是給任務棧使用的。 也就是說,在 FreeRTOS 任務中,所有棧空間的使用都是通過
PSP 指標進行指向的。 一旦進入了中斷函式以及可能發生的中斷巢狀都是用的 MSP 指標。這個知識
點要記住它,當前可以不知道這是為什麼,但是一定要記住。
 實際應用中系統棧空間分配多大,主要是看可能發生的中斷巢狀層數,下面我們就按照最壞執行情況
進行考慮,所有的暫存器都需要入棧,此時分為兩種情況: 

 64 位元組
對於 Cortex-M3 核心和未使用 FPU(浮點運算單元)功能的 Cortex-M4 核心在發生中斷時需
要將 16 個通用暫存器全部入棧,每個暫存器佔用 4 個位元組,也就是 16*4 = 64 位元組的空間。
可能發生幾次中斷巢狀就是要 64 乘以幾即可。 當然,這種是最壞執行情況,也就是所有的寄存
器都入棧。
注:任務執行的過程中發生中斷的話,有 8 個暫存器是自動入棧的,這個棧是任務棧,進入中
斷以後其餘暫存器入棧以及發生中斷巢狀都是用的系統棧
 200 位元組
對於具有 FPU(浮點運算單元)功能的 Cortex-M4 核心,如果在任務中進行了浮點運算,那麼
在發生中斷的時候除了 16 個通用暫存器需要入棧,還有 34 個浮點暫存器也是要入棧的,也就是


(16+34)*4 = 200 位元組的空間。當然,這種是最壞執行情況,也就是所有的暫存器都入棧。
注:任務執行的過程中傳送中斷的話,有 8 個通用暫存器和 18 個浮點暫存器是自動入棧的,
這個棧是任務棧,進入中斷以後其餘通用暫存器和浮點暫存器入棧以及發生中斷巢狀都是用的系
統棧

FreeRTOS 的任務狀態
FreeRTOS 的執行支援以下四種狀態:
 Running—執行態
當任務處於實際執行狀態被稱之為執行態,即 CPU 的使用權被這個任務佔用。
 Ready—就緒態
處於就緒態的任務是指那些能夠執行(沒有被阻塞和掛起) ,但是當前沒有執行的任務,因為同優先
級或更高優先順序的任務正在執行。
 Blocked—阻塞態
由於等待訊號量,訊息佇列,事件標誌組等而處於的狀態被稱之為阻塞態,另外任務呼叫延遲函式也
會處於阻塞態。
 Suspended—掛起態
類似阻塞態,通過呼叫函式 vTaskSuspend()對指定任務進行掛起,掛起後這個任務將不被執行,只
有呼叫函式 xTaskResume()才可以將這個任務從掛起態恢復。 
使用如下函式即可啟動 FreeRTOS:
 vTaskStartScheduler(); 
函式原型:
void vTaskStartScheduler( void );
函式描述:
函式 vTaskStartScheduler 用於啟動 FreeRTOS 排程器,即啟動 FreeRTOS 的多工執行。
使用這個函式要注意以下幾個問題:
1. 空閒任務和可選的定時器任務是在呼叫這個函式後自動建立的。
2. 正常情況下這個函式是不會返回的,執行到這裡極有可能是用於定時器任務或者空閒任務的 heap 空
間不足造成建立失敗,此時需要加大 FreeRTOSConfig.h 檔案中定義的 heap 大小:
#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 17 * 1024 ) ) 

FreeRTOS 的任務恢復 

使用如下函式可以實現 FreeRTOS 的任務恢復:
 xTaskResume() 

使用如下函式可以實現 FreeRTOS 的任務恢復(中斷方式):
 xTaskResumeFromISR()

任務棧大小的確定
在基於 RTOS 的應用設計中,每個任務都需要自己的棧空間,應用不同,每個任務需要的棧大小也是
不同的。 將如下的幾個選項簡單的累加就可以得到一個粗略的棧大小:
 函式的巢狀呼叫,針對每一級函式用到棧空間的有如下四項:
 函式區域性變數。
 函式形參,一般情況下函式的形參是直接使用的 CPU 暫存器,不需要使用棧空間,但是這個函
數中如果還嵌套了一個函式的話,這個儲存了函式形參的 CPU 暫存器內容是要入棧的。 所以建
議大家也把這部分算在棧大小中。
 函式返回地址,針對 M3 和 M4 核心的 MCU,一般函式的返回地址是專門儲存到 LR(Link
Register)暫存器裡面的,如果這個函式裡面還呼叫了一個函式的話,這個儲存了函式返回地址
的 LR 暫存器內容是要入棧的。 所以建議大家也把這部分算在棧大小中。
 函式內部的狀態儲存操作也需要額外的棧空間。
 任務切換,任務切換時所有的暫存器都需要入棧,對於帶 FPU 浮點處理單元的 M4 核心 MCU 來說,
FPU 暫存器也是需要入棧的。
 針對 M3 核心和 M4 核心的 MCU 來說,在任務執行過程中,如果發生中斷:
 M3 核心的 MCU 有 8 個暫存器是自動入棧的,這個棧是任務棧,進入中斷以後其餘暫存器入棧
以及發生中斷巢狀都是用的系統棧。 
 M4 核心的 MCU 有 8 個通用暫存器和 18 個浮點暫存器是自動入棧的,這個棧是任務棧,進入
中斷以後其餘通用暫存器和浮點暫存器入棧以及發生中斷巢狀都是用的系統棧。
 進入中斷以後使用的區域性變數以及可能發生的中斷巢狀都是用的系統棧,這點要注意。
實際應用中將這些都加起來是一件非常麻煩的工作,上面這些棧空間加起來的總和只是棧的最小需求,
實際分配的棧大小可以在最小棧需求的基礎上乘以一個安全係數,一般取 1.5-2。上面的計算是我們使用者
可以確定的棧大小,專案應用中還存在無法確定的棧大小,比如呼叫printf函式就很難確定實際的棧消耗。
又比如通過函式指標實現函式的間接呼叫,因為函式指標不是固定的指向一個函式進行呼叫,而是根據不
同的程式設計可以指向不同的函式,使得棧大小的計算變得比較麻煩。
另外還要注意一點,建議不要編寫遞迴程式碼,因為我們不知道遞迴的層數,棧的大小也是不好確定的。
一般來說,使用者可以事先給任務分配一個大的棧空間,然後通過第 8 章介紹的除錯方法列印任務棧的
使用情況,執行一段時間就會有個大概的範圍了。這種方法比較簡單且實用些。

 函式棧大小確定
函式的棧大小計算起來是比較麻煩的, 那麼有沒有簡單的辦法來計算呢? 有的,一般 IDE 開發環境都
有這樣的功能,比如 MDK 會生成一個 htm 檔案,通過這個檔案使用者可以知道每個被呼叫函式的最大棧
需求以及各個函式之間的呼叫關係。但是 MDK 無法確定通過函式指標實現函式呼叫時的棧需求。另外,
發生中斷或中斷巢狀時的現場保護需要的棧空間也不會統計。 關於 MDK 生成的 map 和 htm 檔案的使用,安富萊電子有出過一期視訊教程,可以在這裡檢視:
http://bbs.armfly.com/read.php?tid=15408

什麼是棧溢位
前面為大家講解了如何確定任務棧的大小,那什麼又是棧溢位呢?簡單的說就是使用者分配的棧空間不
夠用了,溢位了。 下面我們舉一個簡單的例項,棧生長方向從高地址向低地址生長(M4 和 M3 是這種方
式)。 

FreeRTOS 的棧溢位檢測機制
FreeRTOS 提供了兩種棧溢位檢測機制,這兩種檢測都是在任務切換時才會進行:
 方法一
在任務切換時檢測任務棧指標是否過界了,如果過界了,在任務切換的時候會觸發棧溢位鉤子函
數。
void vApplicationStackOverflowHook( TaskHandle_t xTask,
signed char *pcTaskName );
使用者可以在鉤子函式裡面做一些處理。這種方法不能保證所有的棧溢位都能檢測到。比如任務在執行
的過程中出現過棧溢位。任務切換前棧指標又恢復到了正常水平,這種情況在任務切換的時候是檢測
不到的。又比如任務棧溢位後,把這部分棧區的資料修改了,這部分棧區的資料不重要或者暫時沒有
用到還好,但如果是重要資料被修改將直接導致系統進入硬體異常,這種情況下,棧溢位檢測功能也
是檢測不到的。
使用方法一需要使用者在 FreeRTOSConfig.h 檔案中配置如下巨集定義:
#define configCHECK_FOR_STACK_OVERFLOW 1 

 方法二
任務建立的時候將任務棧所有資料初始化為 0xa5,任務切換時進行任務棧檢測的時候會檢測末
尾的 16 個位元組是否都是 0xa5,通過這種方式來檢測任務棧是否溢位了。相比方法一,這種方法的速
度稍慢些,但是這樣就有效地避免了方法一里面的部分情況。 不過依然不能保證所有的棧溢位都能檢
測到,比如任務棧末尾的 16 個位元組沒有用到,即沒有被修改,但是任務棧已經溢位了,這種情況是
檢測不到的。 另外任務棧溢位後,任務棧末尾的 16 個位元組沒有修改,但是溢位部分的棧區資料被修
改了,這部分棧區的資料不重要或者暫時沒有用到還好,但如果是重要資料被修改將直接導致系統進
入硬體異常,這種情況下,棧溢位檢測功能也是檢測不到的。
使用方法二需要使用者在 FreeRTOSConfig.h 檔案中配置如下巨集定義:
#define configCHECK_FOR_STACK_OVERFLOW 2

 鉤子函式
鉤子函式的主要作用就是對原有函式的功能進行擴充套件,使用者可以根據自己的需要往裡面新增相關的測
試程式碼, 大家可以在 FreeRTOS 工程中檢索這個鉤子函式 vApplicationStackOverflowHook 所在的位
置。 
對於這種溢位檢測,我測試了幾種情況,確實不容易檢測到,多半進入硬體錯誤中斷,所以以後要是遇到程式硬體中斷死迴圈,清注意檢測堆疊大小。不確定的時候,先使用printf除錯列印任務棧的剩餘,選擇一個合理安全的值作為堆疊設定,這確實是個難以簡單計算的東西。

相關推薦

FreeRTOS 任務大小確定及其溢位檢測

FreeRTOS 的任務棧設定不管是裸機程式設計還是 RTOS 程式設計,棧的分配大小都非常重要。 區域性變數,函式呼叫時的現場保護和返回地址,函式的形參,進入中斷函式前和中斷巢狀等都需要棧空間,棧空間定義小了會造成系統崩潰。裸機的情況下,使用者可以在這裡配置棧大小: 為什麼

FreeRTOS 任務大小確定及其溢出檢測

發送 創建 lock art 消息 阻塞 image img mage FreeRTOS 的任務棧設置不管是裸機編程還是 RTOS 編程,棧的分配大小都非常重要。 局部變量,函數調用時的現場保護和返回地址,函數的形參,進入中斷函數前和中斷嵌套等都需要棧空間,棧空間定義小了會

uCOS-III任務堆疊溢位檢測及統計任務堆疊使用量的方法【轉載】

此文章轉載於點選進入原創地址 uCOS-III任務堆疊溢位檢測及統計任務堆疊使用量的方法 在作業系統任務設計的時候,通常會遇到一個比較麻煩的問題,也就是任務堆疊大小設定的問題,為此我們我需要知道一些問題: 1.1. 任務堆疊一但溢位,意味著系統的崩潰,在有MMU或者MPU的

MapReduce 中 map 分片大小確定 和map任務數的計算

Hadoop中在計算一個JOB需要的map數之前首先要計算分片的大小。計算分片大小的公式是: goalSize = totalSize / mapred.map.tasks minSize = max {mapred.min.split.size, minSplitS

詳解μC/OS-II如何檢測任務堆疊實際使用情況——即如何設定ucosii任務堆疊大小

不少屌絲同學都有類似經歷吧,在使用ucosii建立任務時,關於任務堆疊大小設為多大合適搞的不清不楚,鬱悶之下就隨便整個數,比如就1024吧,呵呵,反正也沒見得出問題,那就不多想了。         我想大多數同學都是這樣做的吧。這樣只是因為在一般情況下,1024確實已經足夠

TI-RTOS Sys-Bios作業系統:task溢位檢測方法

1. 示例程式碼 Task_Stat statbuf; /* declare buffer */ Task_stat(Task_self(), &statbuf); /* call func

SylixOS線程堆大小淺析

參考資料 寄存器 多線程 操作系統 優先級 目錄1. SylixOS線程、線程棧介紹 11.1 線程的介紹 11.2 線程棧的介紹 12. SylixOS線程棧大小的分配 12.1 線程、線程棧相關屬性的設置 22.2 線程棧大小

39 _ 隊列5 _ 循環隊列需要幾個參數來確定 及其含義的講解.swf

關系 執行 第一個 是否 alt 循環 規律 及其 比較 上面講解都是循環隊列,如果是鏈表實現的話就很簡單,隊列只有循環隊列才比較復雜 此時隊列中只存儲一個有效元素3,當在刪除一個元素的時候,隊列為空,pFont向上移動,pFont等於pRear,但是此時pF

Android零基礎入門第77節:Activity任務和啟動模式

csdn rpi activit 元素 進入 see 簡單 auto mar 通過前面的學習,Activity的基本使用都已掌握,接下來一起來學習更高級的一些內容。 Android采用任務棧(Task)的方式來管理Activity的實例。當啟動一個應用時,A

進程空間分配和堆大小

windows -a 情況下 info 電腦 左右 inux 運行 str 1. Linux中進程空間的分配情況如下: 從上圖可以看出,進程的空間分配:與進程相關的數據結構(頁表、內核棧、task) ---> 物理內存 ---> 內核代碼和數據 --->

【Android-3】Android中的任務(Task)

集合 情況下 清除 bsp 生命周期方法 任務棧 保存 sin 也會 一、Android任務棧 概述:Android中的任務棧其實就是Activity的集合,在Android中退出程序的時候必須把任務棧中的所有Activity清除出棧,此時才能安全的完全的退出程序, 任務棧

2、FreeRTOS任務相關API函數

ret get 相關 main eat 定時器 ref ati 安全 1.任務相關的API函數 函數存在於task.c中,主要的函數有: xTaskCreate():使用動態的方法創建一個任務; xTaskCreatStatic():使用靜態的方法創建一個任務(用

android的activity任務

網站 默認 其中 命令 應用 認識 不存在 com systemui   activity的任務棧和啟動模式,看了各種網站和書還是感覺不得其法。於是網上找到了adb的一條命令:    adb shell dumpsys activity activities  

轉載:/etc/security/limits.conf 控制文件描述符,進程數,大小

linu 大數據 works 5-0 管理 file-max etc 性能 mit 原文地址:http://ilikedo.iteye.com/blog/1554822 linux下安裝Oracle 一般都會修改/etc/security/limits.conf這個文件,但

第二節:FreeRTOS 任務的建立、刪除、掛起、恢復

https://www.freertos.org/ https://download.csdn.net/download/zennaiheqiao/10665003 1.任務建立 1.1函式描述 BaseType_t xTaskCreate(TaskFunction_t pvT

FreeRTOS 任務與排程器(1)

 前言: Task.c和Task.h檔案內是FreeRTOS的核心內容,所有任務和排程器相關的API函式都在這個檔案中,它包括下圖這些內容FreeRTOS檔案如下: Task.c和Task.h檔案內是FreeRTOS的核心內容,所有任務和排程器相關的API函式都在這個檔案中,它包括下圖這些內

基於式的緩衝區溢位

   緩衝區溢位攻擊是一個老生常談的問題了,實際上我們所在的這個世界上,每天無時無刻不在發生各種各樣的緩衝區溢位的攻擊,隨著反制技術的不斷升級,這些攻擊技巧都在大量進行升級還貸,但,所謂哪裡有壓迫哪裡就有反抗!    ASLR(地址隨機化)、DEP(資料執

freertos- 任務基本概念與任務掛起和恢復解析

1、任務狀態        任務實體 2、任務的優先順序 3、任務掛起和恢復的情形 4、任務掛起和恢復實現           掛起任務列表 5、任務掛起和阻塞,認識恢復和

freertos- 任務切換-pendSv異常(筆記)

1,為什麼需要任務切換 異常高於任何一個任務,任務亦可劃分優先順序,(0-31級;高 - 底;其中5-31級由FreeRTOS的管理排程)。 搶佔核心要求,使更高優先順序的任務及時得到相應,不著急的任務延後執行。 2,任務切換場合(任務上下文切換的場合) &nb

【linux】Valgrind工具集詳解(十):SGCheck(檢查和全域性陣列溢位

一、概述 SGCheck是一種用於檢查棧中和全域性陣列溢位的工具。它的工作原理是使用一種啟發式方法,該方法源於對可能的堆疊形式和全域性陣列訪問的觀察。 棧中的資料:例如函式內宣告陣列int a[10],而不是malloc分配的,malloc分配的記憶體是在堆中。 SGCheck和Me