为什么可能导致睡眠的函数都不能在中断上下文中使用呢?【转】
轉自:http://www.cnblogs.com/hoys/archive/2012/06/28/2567622.html
轉自:http://blog.chinaunix.net/u1/49093/showart_1910189.html
這個問題有很多人問過,我看了下Linux得內核代碼,原因如下:(當然我不能保證一定對,如果有牛人理解得更好,歡迎指正)
1、 中斷處理的時候,不應該發生進程切換,因為在中斷context中,唯一能打斷當前中斷handler的只有更高優先級的中斷,它不會被進程打斷,如果在 中斷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時候,內核是不可搶占的。因此,如果休眠,則內核一定掛起。
-------------------------------------------------------
?
原帖地址:http://bbs.chinaunix.net/thread-2115820-1-1.html
?
這里引用個人認為比較OK的解析:
?
呵呵,我最喜歡這種討論了。先來獻丑了,說說我的看法。
先把中斷處理流程給出來
?
硬中斷:
對應于上圖的1、2、3步驟,在這幾個步驟中,所有中斷是被屏蔽的,如果在這個時候睡眠了,操作系統不會收到任何中斷(包括時鐘中斷),系統就基本處于癱瘓狀態(例如調度器依賴的時鐘節拍沒有等等……)
軟中斷:
對應上圖的4(當然,準確的說應該是4步驟的后面一點,先把話說保險點,免得思一克又開始較真?)。這個時候不能睡眠的關鍵是因為上下文。
大家知道操作系統以進程調度為單位,進程的運行在進程的上下文中,以進程描述符作為管理的數據結構。進程可以睡眠的原因是操作系統可以切換不同進程的上下文,進行調度操作,這些操作都以進程描述符為支持。
中斷運行在中斷上下文,沒有一個所謂的中斷描述符來描述它,它不是操作系統調度的單位。一旦在中斷上下文中睡眠,首先無法切換上下文(因為沒有中斷描述符,當前上下文的狀態得不到保存),其次,沒有人來喚醒它,因為它不是操作系統的調度單位。
此外,中斷的發生是非常非常頻繁的,在一個中斷睡眠期間,其它中斷發生并睡眠了,那很容易就造成中斷棧溢出導致系統崩潰。
如 果上述條件滿足了(也就是有中斷描述符,并成為調度器的調度單位,棧也不溢出了,理論上是可以做到中斷睡眠的),中斷是可以睡眠的,但會引起很多問題.例 如,你在時鐘中斷中睡眠了,那操作系統的時鐘就亂了,調度器也了失去依據;例如,你在一個IPI(處理器間中斷)中,其它CPU都在死循環等你答復,你確 睡眠了,那其它處理器也不工作了;例如,你在一個DMA中斷中睡眠了,上面的進程還在同步的等待I/O的完成,性能就大大降低了……還可以舉出很多例子。 所以,中斷是一種緊急事務,需要操作系統立即處理,不是不能做到睡眠,是它沒有理由睡眠。
======================================================
?
另一篇:
?
http://blog.openrays.org/blog.php?do=showone&tid=455
?
其結論:
?
5. 中斷處理時可否睡眠問題
Linux 設計中,中斷處理時不能睡眠,這個內核中有很多保護措施,一旦檢測到內核會異常。
當 一個進程A因為中斷被打斷時,中斷處理程序會使用 A 的內核棧來保存上下文,因為是“搶”的 A 的CPU,而且用了 A 的內核棧,因此中斷應該盡可能快的結束。如果 do_IRQ 時又被時鐘中斷打斷,則繼續在 A 的內核棧上保存中斷上下文,如果發生調度,則 schedule 進 switch_to,又會在 A 的 task_struct->thread_struct 里保存此時時種中斷的上下文。
假如其是在睡眠時被時鐘中斷打斷,并 schedule 的話,假如選中了進程 A,并 switch_to 過去,時鐘中斷返回后則又是位于原中斷睡眠時的狀態,拋開其擾亂了與其無關的進程A的運行不說,這里的問題就是:該如何喚醒之呢??
另外,和該中斷共享中斷號的中斷也會受到影響。
?
======================================================
?
再一篇,也分析的很到位:
?
http://blog.csdn.net/maray/article/details/5770889
?
其結論:
Linux是以進程為調度單位的,調度器只看到進程內核棧,而看不到中斷棧。在獨立中斷棧的模式下,如果linux內核在中斷路徑內發生了調度(從技術上講,睡眠和調度是一個意思),那么linux將無法找到“回家的路”,未執行完的中斷處理代碼將再也無法獲得執行機會。
本文轉自張昺華-sky博客園博客,原文鏈接:http://www.cnblogs.com/sky-heaven/p/5343933.html,如需轉載請自行聯系原作者
總結
以上是生活随笔為你收集整理的为什么可能导致睡眠的函数都不能在中断上下文中使用呢?【转】的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 巧用Windows Phone应用商城中
- 下一篇: 测试工具大全