概述
本章所述中斷管理主要是針對中斷處理程序的管理。
RTOS中,中斷處理程序由用戶自定義,是類似於TASK一樣的存在,中斷處理程序有自己的棧,可以支持低優先級中斷處理程序被高優先級中斷處理程序打斷。實際上,個人認爲TASK就是以中斷處理程序爲原型演進而來。
考慮到OS的很多功能,如時間片機制、TASK切換(後邊將會講到)都是基於中斷處理程序來完成的。
如之前所述,中斷處理程序具有比常規用戶指令集合更高的處理優先級,當中斷髮生時,CPU會立即執行中斷處理程序。TASK就處於常規用戶指令集合之中,因此中斷髮生時,TASK必然被中斷處理程序打斷,如下圖所示,
其中,
· t1時刻,TASK 1開始在CPU上執行
· t2時刻,CPU檢測到中斷,開始執行中斷處理程序
· t3時刻,中斷處理程序執行完成,CPU在切換回TASK 1繼續執行
中斷嵌套
某些嵌入式系統中,支持低優先級中斷處理程序被高優先級中斷處理程序打斷,即爲中斷嵌套,如下圖所示,
其中
· t1時刻,TASK 1開始在CPU上執行
· t2時刻,CPU檢測到中斷1,開始執行其對應的 中斷處理程序
· t3時刻,CPU檢測到中斷2,由於其優先級較高,開始執行其對應的 中斷處理程序
· t4時刻,CPU完成中斷2的中斷處理程序,恢復執行中斷1的中斷處理程序
· t5時刻,CPU完成中斷1的中斷處理程序,恢復執行TASK1
基於中斷的任務切換
大部分的RTOS中,都使用基於中斷的TASK切換方式:
· 當TASK需要觸發TASK切換時,其觸發產生一次中斷(記爲SWI),SWI的中斷處理程序即爲包含壓棧、出棧的任務切換處理過程。
· 當中斷處理程序需要觸發TASK切換時,可在中斷處理程序執行過程中,將出棧處理恢復的寄存器直接替換爲新切換TASK的寄存器
這樣做的好處在於保證TASK切換不會中斷處理程序打斷導致異常。
此時TASK切換過程如下圖所示,
當然,這並非唯一方式,任何能夠保證TASK切換正常執行的方式也是可行的 :如TASK觸發的TASK切換,可以採用後邊提到的臨界區機制;又如對於不支持中斷嵌套的系統,以上兩種情況都可採用直接觸發switch interrupt的方式。
基於中斷的時間片機制
時間片機制,即外部的硬件定時器週期性地向CPU發送一箇中斷(記爲TickINT),該中斷的ISR即OS的時間片處理過程:嘗試進行TASK切換並統計OS的狀態信息。
如下圖所示
其中,
· t1~t2時間段,TASK 1在CPU上執行
· t2時刻,時間片超時,OS發現存在更高優先級的TASK2,因此觸發TASK切換,切換到TASK 2
· t2~t3時間段,TASK 2在CPU上執行
· t3時刻,時間片超時,OS發現沒有更高優先級的TASK,不觸發TASK切換
其中的TASK切換過程細節可參考之前提到的ISR觸發的TASK切換過程。
中斷處理程序
由於ISR的特殊性(ISR優先於TASK執行,且部分OS功能如時間片和TASK切換基於ISR實現),freeRTOS爲ISR設計了一套特殊的API函數,即後綴爲“FromISR”的API函數,以保證ISR在使用API時不會出現異常,如下表所示(其中只給出了常用的部分),
功能 | TASK使用API | ISR使用API |
觸發TASK切換 | portYIELD | portYIELD_FROM_ISR |
發送消息 | xMessageBufferSend | xMessageBufferSendFromISR |
接收消息 | xMessageBufferRecv | xMessageBufferRecvFromISR |
xSemaphoreTake | xSemaphoreTakeFromISR | |
釋放互斥信號量 | xSemaphoreGive | xSemaphoreGiveFromISR |
獲取信號量 | xSemaphoreTake | xSemaphoreTakeFromISR |
釋放信號量 | xSemaphoreGive | xSemaphoreGiveFromISR |
它們的區別再去,TASK使用API會立即嘗試觸發TASK切換,而ISR使用API只會返回一個BOOL值,指示是否需要觸發TASK切換——ISR觸發的TASK切換需要在其執行完成後在進行。