FreeRTOS-為什么關中斷之后切換進程?


 
一. 基本問題
 
FreeRTOS會在關鍵區即taskENTER_CRITICAL()和taskEXIT_CRITICAL()包裹的區間中,執行進程切換。即在關閉中斷的時候,進行進程切換。
我們已經知道,即便關閉中斷,PowerPC的sc中斷,還是可以得到響應。但是時鍾中斷呢?這是個外部中斷,無法得到響應。
那么是何時打開的中斷呢?新進程切入之后,立即打開中斷?在多個TASK級別做開關中斷配對?
 
1.關鍵區和關鍵資源
 
或者叫競爭區間,使用PV原語保護,操作系統基本概念。在FreeRTOS中,為使用taskENTER_CRITICAL()和taskEXIT_CRITICAL()包裹的區間。
關鍵區中使用即PV原語保護的資源為關鍵資源。
 
2.基本同步機制:開關中斷
 
單核CPU存在兩個並行流程:TASK和中斷ISR。中斷可以打斷TASK的執行。所以TASK中的關鍵區間需要使用開關中斷保護,而中斷ISR就不需要再關中斷了。這是最基本的同步機制。
如果中斷存在優先級,高優先級中斷可以打斷低優先級中斷,則存在三個並行流程:TASK、低優先級中斷ISR和高優先級中斷ISR。如此僅僅關閉中斷,已經無法起到保護關鍵區的作用。需要把CPU的當前中斷響應級別提升到關鍵區間所需要的最高級別。這里的所需要,是指會使用到被保護資源的最高優先級的中斷的優先級。即便不是最高,但其上優先級的中斷ISR不使用被保護資源,則不會導致死鎖。
多核CPU除了考慮本核的同步外,還需要考慮與其他核的同步,需要使用系統級別的標志。因為多個核共享同一個內存空間,所以這個同步標志,可以是一個存在內存中的變量。
 
3.關鍵區盡量短
 
關閉中斷,會使CPU無法及時響應外部中斷。所以為了提高響應的實時性,需要使關鍵區間盡量短。也就是關閉中斷的時間盡量短。不涉及關鍵資源的操作,盡量放在關鍵區間之外執行。
 
4.PV操作成對出現,降低復雜度
 
為了降低程序的復雜度。使同步操作更易閱讀理解,同時降低出錯的概率。PV操作一般成對出現,並且出現在同一個函數中。為了保證成對出現,甚至可以使用goto語句。即使用if判斷到需要直接退出的例外情況時,不是直接在if中開中斷然后退出,而是使用goto跳轉到成對的唯一一個開中斷操作。
 
5.關鍵區間中切換進程提升了復雜度
 
所以關鍵區間中,在關閉中斷的狀態下切換進程,提升了代碼的復雜度。如何保證開關中斷的動作成對出現,變成了一個很復雜的問題。
下面我們跟蹤xSemaphoreGive/xSemaphoreTake的流程,來看何時打開的中斷。
 
二.Semaphore
 
Semaphore的使用隊列實現。xSemaphore的Give和Task分別向隊列中存和從隊列中取。
 
1.xSemaphoreGive
 
進入關鍵區之后,如果隊列不為空,則立即切換進程。從注釋可以看出,這里有兩種實現:a.立即切換進程;b.這里只記錄狀態,在退出關鍵區時執行切換。這個跟port的實現有關,跟FreeRTOS無關。
 
另外,這里也不一定會切換進程,跟進程的優先級有關。如果等待信號量的進程優先級比當前進程優先級低,則不會進行切換。這里我們假設會切換。
 
2.xSemaphoreTake
如果隊列為空則在箭頭處睡眠等待。同時,隊列被存入元素后,也是在這里被喚醒。喚醒后,執行如下代碼檢查隊列是否為空:
可以看到,這里又重新執行了一次taskENTER_CRITICAL(),取得隊列元素之后,退出時又執行了一次taskEXIT_CRITICAL(),這是成對的操作。所以不存在被切入的進程打開進程切換前關閉的中斷的情況。
問題沒有解決:中斷時何時被打開的?
 
三.中斷嵌套實現
 
FreeRTOS自帶的例子中,有兩種實現。
 
1.自定義嵌套層級變量
 
2.使用TCB中的嵌套層級變量
 
即直接使用FreeRTOS的vTaskEnterCritical/vTaskExitCritical,這兩個函數:
 
兩個的區別在於一個使用全局變量,一個使用每TASK變量存儲中斷嵌套層級。
為什么每一個TASK一個中斷嵌套層級呢?
 
四.誰的中斷嵌套層級
按常規的理解,中斷屬於CPU,而不屬於TASK,一個CPU上可以有多個TASK在執行。而CPU是全局的,所以中斷狀態也應該是全局的,所以中斷嵌套層級也應該使用全局變量存儲。
 
每個TASK一個中斷嵌套層級,如何理解?
 
我們知道每個TASK記錄自己的各個寄存器的值,是可以理解的。以便切入時恢復之前的狀態。難道每個TASK也維護執行時中斷狀態,以便切入時恢復執行?難道每個TASK也記錄中斷的開關狀態,切入時恢復之前的中斷開關狀態?
 
看一下TASK切換時保存和恢復的寄存器,以PowerPC為例。
 
五.中斷發生時保存和恢復的寄存器狀態
 
 
SRR1中保存着中斷發生前的MSR寄存器的值,也包括EE位。那么恢復時,自然也會恢復EE位。
 
六.總結
 
首先回答何時打開中斷的問題:進程切入時,即恢復進程切出前的中斷開關狀態。
另外一個結論:中斷狀態在物理上雖然是全局的,但在軟件上是每個TASK維護一份。
PS. 復雜度還是提升了,OS層需要加倍小心,好在APP層無需過多考慮

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM