簡體   English   中英

誰在Linux內核中進行上下文切換后調用IRET?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM