爲什麼中斷上下文不可以休眠

不可在中斷例程中休眠的原因

     如果在某個系統調用中把當前進程休眠,是有明確目標的,這個目標就是過來call這個系統調用的進程(注意這個進程正在running)。

     但是中斷和進程是異步的,在中斷上下文中,當前進程大部分時候和中斷代碼可能一點關係都沒有。要是在這裏調用了休眠代碼,把當前進程給休眠了,那就極有可能把無關的進程休眠了。再者,如果中斷不斷到來,會殃及許多無辜的進程。

    在中斷中休眠某個特定進程是可以實現的,通過內核的task_struct鏈表可以找到的,不論是根據PID還是name。但是隻要這個進程不是當前進程,休眠它也可能沒有必要。可能這個進程本來就在休眠;或者正在執行隊列中但是還沒執行到,如果執行到他了可能又無須休眠了。

    還有一個原因是中斷也是所謂的原子上下文,有的中斷例程中會禁止所有中斷,有的中斷例程還會使用自旋鎖等機制,在其中使用休眠也是非常危險的。 下面會介紹。


--------------------------------------------------------------------------------


1. 中斷處理的時候,不應該發生進程切換,因爲在中斷context中,唯一能打斷當前中斷handler的只有更高優先級的中斷,它不會被進程打斷(這點對 於softirq,tasklet也一樣,因此這些bottom half也不能休眠),如果在中斷context中休眠,則沒有辦法喚醒它,因爲所有的 wake_up_xxx都是針對某個進程而言的,而在中斷context中,沒有進程的概念,沒有一個task_struct(這點對於softirq和 tasklet一樣),因此真的休眠了,比如調用了會導致block的例程,內核幾乎肯定會死.


2.schedule()在切換進程時,保存當前的進程上下文(CPU寄存器的值、進程的狀態以及堆棧中的內容),以便以後恢復此進程運行。中斷髮生後,內核會先保存當前被中斷的進程上下文(在調用中斷處理程序後恢復);

但在中斷處理程序裏,CPU寄存器的值肯定已經變化了吧(最重要的程序計數器PC、堆棧SP等),如果此時因爲睡眠或阻塞操作調用了schedule(),則保存的進程上下文就不是當前的進程context了.所以不可以在中斷處理程序中調用schedule()。


3.2.4內核中schedule()函數本身在進來的時候判斷是否處於中斷上下文:
if(unlikely(in_interrupt()))
BUG();

因此,強行調用schedule()的結果就是內核BUG,但我看2.6.18的內核schedule()的實現卻沒有這句,改掉了.


4.中斷handler會使用被中斷的進程內核堆棧,但不會對它有任何影響,因爲handler使用完後會完全清除它使用的那部分堆棧,恢復被中斷前的原貌.


5.處於中斷context時候,內核是不可搶佔的,因此,如果休眠,則內核一定掛起.


------------------------------------------------------------------------------------------------------------------------------------


先把中斷處理流程給出來
1.進入中斷處理程序--->2.保存關鍵上下文---->3.開中斷(sti指令)--->4.進入中斷處理程序的handler--->5.關中斷(cli指令)---->6.寫EOI寄存器(表示中斷處理完成)---->7.開中斷。
複製代碼


硬中斷:
對應於上圖的1、2、3步驟,在這幾個步驟中,所有中斷是被屏蔽的,如果在這個時候睡眠了,操作系統不會收到任何中斷(包括時鐘中斷),系統就基本處於癱瘓狀態(例如調度器依賴的時鐘節拍沒有等等……)


軟中斷:
對應上圖的4(當然,準確的說應該是4步驟的後面一點,先把話說保險點,免得思一克又開始較真 )。這個時候不能睡眠的關鍵是因爲上下文。
大家知道操作系統以進程調度爲單位,進程的運行在進程的上下文中,以進程描述符作爲管理的數據結構。進程可以睡眠的原因是操作系統可以切換不同進程的上下文,進行調度操作,這些操作都以進程描述符爲支持。
中斷運行在中斷上下文,沒有一個所謂的中斷描述符來描述它,它不是操作系統調度的單位。一旦在中斷上下文中睡眠,首先無法切換上下文(因爲沒有中斷描述符,當前上下文的狀態得不到保存),其次,沒有人來喚醒它,因爲它不是操作系統的調度單位。
此外,中斷的發生是非常非常頻繁的,在一箇中斷睡眠期間,其它中斷髮生並睡眠了,那很容易就造成中斷棧溢出導致系統崩潰。


如果上述條件滿足了(也就是有中斷描述符,併成爲調度器的調度單位,棧也不溢出了,理論上是可以做到中斷睡眠的),中斷是可以睡眠的,但會引起很多問題.例如,你在時鐘中斷中睡眠了,那操作系統的時鐘就亂了,調度器也了失去依據;例如,你在一個IPI(處理器間中斷)中,其它CPU都在死循環等你答覆,你確睡眠了,那其它處理器也不工作了;例如,你在一個DMA中斷中睡眠了,上面的進程還在同步的等待I/O的完成,性能就大大降低了……還可以舉出很多例子。所以,中斷是一種緊急事務,需要操作系統立即處理,不是不能做到睡眠,是它沒有理由睡眠。


----------------------------------------------------------



通過int 0x80只是實現系統調用的一種方式,而且是最古老的一種方式。應用程序利用int指令進行主動陷入內核,更應該稱之爲軟件中斷,這與前面提到的下半部的軟中斷不是一個概念。應用程序執行系統調用進入到內核後,內核處於進程上下文,是可以阻塞/睡眠的,是中斷上下文不能睡眠。


-----------------------------------------------------------



這個說起來有點多,一一來看:
1,中斷要根據前後文來說,一般說中斷上下文中不能睡眠,這個中斷是指硬件事件發生,觸發CPU停止當前活動轉而去處理硬件請求.
2,根據硬件請求響應處理邏輯的實時緊要與否,將整個中斷處理過程分爲上半部和下半部.
3,上半部也就是所謂的硬中斷處理邏輯,其要求cpu在收到硬件請求後必須馬上處理的事情,比如網卡收到數據包了,把數據包從網卡緩存拷貝到主存(可以由DMA完成,但寄存器的修改以及資源設定還是要由cpu去做)的邏輯就需要cpu立即去做,不做的話,網絡新來的數據包就可能丟失.所以這些緊要操作邏輯爲硬中斷處理.
4,下半部有很多種機制,其中就包括軟中斷,還有tasklet,workqueue等,軟中斷只是其中的一種,由於歷史的原因,有時候是混淆稱呼下半部和軟中斷的.
5,軟中斷處理的邏輯並不那麼嚴格要求及時,比如對網絡數據包的處理,因爲邏輯複雜,不適合放到硬中斷裏去做,因爲要儘量保證硬中斷短小精悍.
6,linux調度是以進程(或者說線程)來的,即做調度是不同進程上下文的切換.
7,而可以看到軟中斷邏輯不屬於任何進程,所以纔不能睡眠,因爲一旦睡眠,cpu切換出去,就切不回來了(和6一起理解).並不是說無法做到在軟/硬中斷睡眠,只是目前Linux的實現就是這樣的,不允許你這麼做,要是這麼做了,你就等死.


8,系統調用是屬於軟中斷?難道是指int 0x80?這個不知道是什麼概念,但肯定不是與上面的軟中斷同一個意思.給你兩個鏈接:
http://lenky.info/2013/02/04/32% ... %E8%B0%83%E7%94%A8/
http://lenky.info/2013/02/04/64% ... %E8%B0%83%E7%94%A8/


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章