天天看點

程序切換原理

什麼是CPU上下文

  Linux是一個多任務作業系統,它支援遠大于CPU核心數的任務同時進行。當然,這些任務并不是真的同時在運作,而是因為系統在很短的時間内,将CPU輪流配置設定給它們,造成多任務同時運作的錯覺。每個任務在運作前,CPU都需要知道任務從哪來加載,又從哪裡開始運作,也就是說,需要事先幫它們設定好CPU寄存器和程式計數器( Program Counter,PC )。

  CPU寄存器:是CPU内置的容量小、但速度快的記憶體,用來臨時存放指令執行運作過程中的操作數和中間(最終)的操作結果。

  程式計數器:是用來存儲CPU正在運作的指令位置、或者即将執行的下一條指令位置。

  CPU寄存器和程式計數器是CPU運作任何任務前,必須依賴的環境,也被稱作CPU上下文。

什麼是CPU上下文切換

  把前一個任務的CPU上下文(CPU寄存器和程式計數器)儲存起來,然後加載新任務的上下文到這些寄存器和程式計數器,最後再跳轉到程式計數器所指的新位置,運作新的任務。而這些儲存下來的上下文,會存儲在系統核心中,并在任務重新排程執行時再次加載進來。這樣就能保證任務原來的狀态不受影響,讓任務看起來還是連續運作。

  CPU的上下文切換可以分為幾個不同的場景:程序上下文切換、線程上線文切換、中斷上下文切換;

程序上下文切換

系統調用時的切換

  Linux按照特權等級,把程序的運作空間分為核心空間和使用者空間。一些特殊的操作如調用open()打開檔案等 都需要切換到核心空間運作,使用者空間是沒有權限調用這些的。也就是說,程序既可以在使用者空間運作,又可以在核心空間運作。在使用者空間運作即為使用者态,而陷入核心空間的時候,即為核心态。這種從使用者态切換到核心态時,必須經過系統調用來完成。

  系統調用需要上下文切換。切換時,先儲存CPU寄存器裡原來使用者态的指令位置。接着,為了執行核心态代碼,CPU寄存器需要更新為核心态執行的新位置。最後才是跳轉到核心态運作核心任務。系統調用結束後,CPU寄存器需要恢複原來儲存的使用者态,然後再切換到使用者空間,繼續運作程序。是以一次系統調用的過程,其實是發生了兩次CPU上下文切換。

  需要注意的是,系統調用過程中,并不會涉及到虛拟記憶體等程序使用者态的資源,也不會進行切換程序。這跟我們通常說的程序上下文切換是不一樣的。

  是以,系統調用過程通常稱為特權模式切換,而不是上下文切換。但實際上,系統調用過程中,CPU的上下文切換還是無法避免的。

程序的切換

  程序是由核心來管理和排程的,程序的切換隻能發生在核心态。是以,程序的上下文不僅包括虛拟記憶體、棧、全局變量等使用者空間的資源,還包括核心堆棧、寄存器等核心空間的狀态。是以,程序的上下文切換就比系統調用時多了一步:在儲存目前程序的核心狀态和CPU寄存器之前,需要先把該程序的虛拟記憶體、棧等儲存下來;而加載了下一程序的核心态後,還需要重新整理程序的虛拟記憶體和使用者棧。

  發生程序上下文切換的場景:

  • 為了保證所有程序可以得到公平排程,CPU 時間被劃分為一段段的時間片,這些時間片再被輪流配置設定給各個程序。這樣,當某個程序的時間片耗盡了,就會被系統挂起,切換到其它正在等待 CPU 的程序運作。
  • 程序在系統資源不足(比如記憶體不足)時,要等到資源滿足後才可以運作,這個時候程序也會被挂起,并由系統排程其他程序運作。
  • 當程序通過睡眠函數 sleep 這樣的方法将自己主動挂起時,自然也會重新排程。
  • 當有優先級更高的程序運作時,為了保證高優先級程序的運作,目前程序會被挂起,由高優先級程序來運作
  • 發生硬體中斷時,CPU 上的程序會被中斷挂起,轉而執行核心中的中斷服務程式。

  程序切換的視圖:

程式切換原理

  關鍵點:

  1. 發生中斷時的儲存現場,将發生中斷時的所有通用寄存器儲存到程序的核心棧,使用struct pt_regs結構。
  2. 位址空間切換将程序自己的頁全局目錄的基位址pgd儲存在ttbr0_le1中,用于mmu的頁表周遊的起始點。
  3. 硬體上下文切換的時候,将此時的調用儲存寄存器和pc, sp儲存到struct cpu_context結構中。做好了這幾個儲存工作,當程序再次被排程回來的時候,通過cpu_context中儲存的pc回到了cpu_switch_to的下一條指令繼續執行,而由于cpu_context中儲存的sp導緻目前程序回到自己的核心棧,經過一系列的核心棧的出棧處理,最後将原來儲存在pt_regs中的通用寄存器的值恢複到了通用寄存器,這樣程序回到使用者空間就可以繼續沿着被中斷打斷的下一條指令開始執行,使用者棧也回到了被打斷之前的位置,而程序通路的指令資料做位址轉化(VA到PA)也都是從自己的pgd開始進行,一切對使用者來說就好像沒有發生一樣。

  總結;

  程序切換有兩大步驟:位址空間切換和處理器狀态切換(硬體上下文切換)。前者保證了程序回到使用者空間之後能夠通路到自己的指令和資料(其中包括減小tlb清空的ASID機制),後者保證了程序核心棧和執行流的切換,會将目前程序的硬體上下文儲存在程序所管理的一塊記憶體,然後将即将執行的程序的硬體上下文從記憶體中恢複到寄存器,有了這兩步的切換過程保證了程序運作的有條不紊,當然切換的過程是在核心空間完成,這對于程序來說是透明的。

you are the best!