1、什麼是中斷?異步
中斷有兩種,一種是CPU自己在執行程序的過程當中產生的,一種是由CPU外部產生的。 cpu外部中斷,就是一般所講的「中斷」(interrupt)。對於執行程序來講,這種「中斷」的發生徹底是異步的,由於不知道何時會發生。CPU對其的響應也徹底是被動的, 能夠經過「關中斷」指令關閉對其的響應。 然而由軟件產生的中斷通常是由專設的指令,如X86中的「INT n」在程序中有意產生的, 是主動的,同步的。只要CPU執行一條INT指令,在開始執行下一條指令以前必定會進入中 斷服務程序。這種主動的中斷稱爲「陷阱」(trap)async
從物理學的角度看,中斷是一種電信號,由硬件設備產生,並直接送入中斷控制器的輸入引腳上,而後再由中斷控制器向處理器發送相應的信號。處理器一經檢測到該信號,便中斷本身當前正在處理的工做,轉而去處理中斷。此後,處理器會通知 OS 已經產生中斷。這樣,OS 就能夠對這個中斷進行適當的處理。不一樣的設備對應的中斷不一樣,而每一箇中斷都經過一個惟一的數字標識,這些值一般被稱爲中斷請求線(IRQ)。
中斷可分爲同步(synchronous)中斷和異步(asynchronous)中斷:函數
1. 同步中斷是當指令執行時由 CPU 控制單元產生,之因此稱爲同步,是由於只有在一條指令執行完畢後 CPU 纔會發出中斷,而不是發生在代碼指令執行期間,好比系統調用。ui
2. 異步中斷是指由其餘硬件設備依照 CPU 時鐘信號隨機產生,即意味着中斷可以在指令之間發生,例如鍵盤中斷。spa
2、什麼是異常?操作系統
同步中斷又稱爲異常(exception);異步中斷則被稱爲中斷(interrupt)。咱們一般講的中斷指的都是異步中斷,即cpu外部中斷。
1.中斷可分爲可屏蔽中斷(Maskable interrupt)和非屏蔽中斷(Nomaskable interrupt)。
2.異常可分爲故障(fault)、陷阱(trap)、終止(abort)三類。線程
這些類別之間的異同點以下:指針
類別 緣由 異步/同步 返回行爲
中斷 來自I/O設備的信號 異步 老是返回到下一條指令
陷阱 有意的異常 同步 老是返回到下一條指令
故障 潛在可恢復的錯誤 同步 返回到當前指令
終止 不可恢復的錯誤 同步 不會返回code
3、中斷處理過程blog
當中斷產生時,處理器將按以下的順序執行:
• 保存當前處理機狀態信息
• 載入異常或中斷處理函數到PC寄存器
• 把控制權轉交給處理函數並開始執行
• 當處理函數執行完成時,恢復處理器狀態信息
• 從異常或中斷中返回到前一個程序執行點
中斷使得CPU能夠在事件發生時才予以處理,而沒必要讓CPU接二連三地查詢是否有相應的事件發生。經過兩條特殊指令:關中斷和開中斷可讓處理器不響應或響應中斷(在關閉中斷期間,一般處理器會把新產生的中斷掛起,當中斷打開時馬上進行響應)。在執行中斷服務例程的過程當中,若是有更高優先級別的中斷源觸發中斷,因爲當前處於中斷處理上下文環境中,根據不一樣的處理器構架可能有不一樣的處理方式:好比新的中斷等待掛起直到當前中斷處理離開後再行響應,但這在硬實時環境中不容許發生;或者新的高優先級中斷打斷當前中斷處理過程,而去直接響應這個更高優先級的新中斷源,這稱爲中斷嵌套,而中斷是否可以嵌套,通常由MCU處理器的中斷機制決定,如stm32中只有新中斷的搶佔優先級比當前中斷高時,才能打斷當前中斷進入新的中斷服務函數。
在系統響應中斷前,軟件代碼(或處理器)須要把當前線程的上下文保存下來(一般保存在當前線程的線程棧中),再調用中斷服務例程進行中斷響應、處理。在進行中斷處理時(實質是調用用戶的中斷服務例程函數),中斷處理函數中極可能會有本身的局部變量,這些都須要相應的棧空間來保存,因此中斷響應依然須要一個棧空間來作爲上下文運行中斷處理函數。中斷棧能夠保存在打斷的線程棧中,當從中斷中退出時,返回相應的線程繼續執行。中斷棧也能夠與打斷線程棧徹底分離開來,即每次進入中斷時,在保存完被打斷的線程上下文後,切換到新的中斷棧中獨立運行;在中斷退出時,再作相應的上下文恢復。
使用獨立中斷棧相對來講更容易實現,而且對於線程棧使用狀況也比較容易瞭解掌握(不然必需要爲中斷棧預留空間,若是系統支持中斷嵌套,還須要考慮應該爲嵌套中斷預留多大的空間)。RT-Thread採用的方式是提供獨立的中斷棧,即中斷髮生時,中斷的前期處理程序會將用戶的棧指針更換到系統事先留出的中斷棧空間中,等中斷退出時再恢復用戶的棧指針。這樣中斷就不會佔用線程的棧空間,從而提升了內存空間的利用率,且隨着任務的增長,這種減小內存佔用的的效果也越明顯。以stm32的cotex-M3/M4爲例,cotex-M3/M4中擁有兩個堆棧指針,然而它們是banked,所以任一時刻只能使用其中的一個:
主堆棧指針(MSP):復位後缺省使用的堆棧指針,用於操做系統內核,以及異常與中斷處理。
進程堆棧指針(PSP):由用戶的應用程序代碼(如線程切換)使用。堆棧指針的最低兩位永遠是0,這意味着堆棧老是4 字節對齊的。
由此能夠看出,在一個實際運行系統裏有兩大部分:一是操做系統和中斷,一是用戶應用程序。它們使用的資源是不同的,從中斷(線程調度時產生的中斷)返回到用戶應用程序線程時,系統使用的堆棧指針也從MSP變成PSP。
4、與操做系統相關的中斷接口:在src/irq.c中
void rt_interrupt_enter(void); void rt_interrupt_leave(void); 當整個系統被中斷打斷,進入中斷處理函數時,OS須要知道當前已經進入到中斷狀態。 rt_interrupt_enter函數用於通知OS,當前已經進入了中斷狀態;rt_interrupt_leave函數用於通知OS,已經離開中斷狀態。一般來講,OS須要知道這樣的運行狀態,這樣在中斷服務例程中,若是調用了OS相關的調用,OS好及時調整相應的行爲,例如進行任務切換時應該採起中斷中任務切換的策略,而不是當即進行切換。可是若是中斷服務例程很顯然、很必然地不會去調用OS相關的函數,此時也能夠不調用rt_interrupt_enter/leave函數。 rt_uint8_t rt_interrupt_get_nest(void); 獲取當前中斷嵌套計數值,大於0說明處於中斷服務中,大於1說明存在中斷嵌套
5、與MCU相關的中斷接口:以stm32f4爲例
關閉中斷:在libcpu/arm/cotex-m4/context_rvds.S中用匯編語言實現 rt_base_t rt_hw_interrupt_disable(void); 函數返回中斷前的系統中斷狀態。 當系統關閉了中斷時,就意味着當前線程/代碼不會被其餘事件所打斷(由於整個系統已經再也不對外部事件響應),也就是當前線程不會被搶佔(由於線程切換時用到了PendSV_Handler),除非這個線程主動讓出處理器。 打開中斷:在libcpu/arm/cotex-m4/context_rvds.S中用匯編語言實現 void rt_hw_interrupt_enable(rt_base_t level); 調用這個函數接口將恢復調用rt_hw_interrupt_disable前的中斷狀態,level是上一次關閉中斷時返回的值。打開中斷每每是和關閉中斷成對使用的,用於恢復關閉中斷前的狀態。 注意:調用這個接口並不表明着確定打開中斷,而是恢復關閉中斷前的狀態,若是調用rt_hw_interrupt_disable()前是關中斷狀態,那麼調用此函數後依然是關中斷狀態。