[英]Who calls IRET after context switch in Linux Kernel?
我一直試圖理解上下文切換在Linux內核中是如何工作的。 在我看來,有一種情況(后面會解釋)導致在中斷后沒有調用IRET指令(我確信有些東西我錯過了!)。 我假設在中斷之后調用IRET是非常必要的,因為在調用IRET之前你不能得到相同的中斷。 我只擔心在x86 arch上運行的單處理器內核。
我認為可能導致所述行為的情況如下:
進程在內核模式下運行會自動調用schedule()
(例如,在嘗試獲取已鎖定的互斥鎖時)。
schedule()
決定執行上下文切換到進程B,因此調用context_switch()
context_switch()
通過調用switch_mm()
將虛擬內存從A切換到B.
context_switch()
運行宏switch_to()
來切換堆棧並實際將運行進程從A更改為B.注意,進程A現在卡在switch_to()
內,進程A的堆棧看起來像(堆棧向下增長):
...
[mutex_lock()]
[schedule()]
[context_switch()] (Stack Top)
進程B開始運行。 稍后,它會收到定時器中斷,定時器中斷處理程序決定進程B需要重新安排。
從定時器中斷返回(但在調用IRET之前),調用preempt_schedule_irq()
。
preempt_schedule_irq()
調用schedule()
。
schedule()
決定上下文切換到進程A並調用context_switch()
。
context_switch()
調用switch_mm()
來切換虛擬內存。
context_switch()
調用switch_to()
來切換堆棧。 此時,進程B的堆棧如下所示:
...
[IRET return frame]
[ret_from_interrupt()]
[preempt_schedule_irq()]
[schedule()]
[context_switch()] (Stack top)
現在進程A正在運行,其堆棧已恢復。 由於A中的context_switch()函數由於定時器中斷而未被調用,因此進程A不會調用IRET並繼續執行mutex_lock()。 這種情況可能會導致永久阻止定時器中斷。
我在這里錯過了什么?
真實時間經濟,非linux特定解釋/示例:
線程A不必調用IRET - 內核代碼調用IRET將執行返回給線程A,畢竟,這是它可能首先丟失它的一種方式 - 來自某些外圍設備的硬件中斷。
通常,當線程A由於某些其他硬件中斷或sycall而在之前丟失執行時,線程A的堆棧指針被保存在指向A堆棧上的IRET返回幀的內核TCB中,然后切換到所有內部調度程序的內核堆棧古比斯。 如果由於使用了特定的系統調用機制而不存在精確的IRET幀,則會組裝一個。 當內核需要恢復A時,內核將帶有線程A的存儲SP和IRET的硬件SP重新加載到用戶空間。 已完成工作 - 已啟用中斷運行的恢復。
然后內核失去了控制權。 當它被下一個硬件中斷/驅動程序或系統調用再次輸入時,它可以將其內部SP設置為其自己的私有堆棧的頂部,因為它在調用之間不保留任何狀態數據。
這只是它可以工作的一種方式:)顯然,確切的機制是依賴於ABI /架構。
我不了解Linux,但在許多操作系統中,上下文切換通常由調度程序執行,而不是中斷處理程序。 如果中斷沒有導致掛起的上下文切換,它就會返回。 如果需要中斷觸發的上下文切換,則保存當前狀態,並通過調度程序退出中斷(調度程序執行IRET)。 如果允許嵌套中斷,則會變得更復雜,因為初始中斷是進入調度程序的中斷,無論哪個嵌套中斷處理程序觸發上下文切換條件。 中斷需要檢查保存的狀態以查看它是否是嵌套中斷,如果不是,它可以禁用中斷以防止在檢查時發生嵌套中斷,並可選擇通過調度程序退出以執行上下文切換。 如果中斷是嵌套中斷,則只需要在需要時設置上下文切換標志,並依靠初始中斷進行檢查和上下文切換。
通常,除非要發生上下文切換,否則不需要中斷來在內核TCB中保存線程狀態。
調度程序還處理上下文切換由非中斷條件觸發的情況,例如互斥,信號量,....
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.