Linux內(nèi)核——進(jìn)程調(diào)度以及進(jìn)程切換過程

進(jìn)程調(diào)度的時(shí)機(jī)


明確一點(diǎn):一般來說,進(jìn)程調(diào)度都是發(fā)生在進(jìn)程外的(即進(jìn)程運(yùn)行的時(shí)候會(huì)持續(xù)執(zhí)行代碼),當(dāng)執(zhí)行代碼中斷跳到其他代碼段(系統(tǒng)調(diào)用函數(shù),中斷處理函數(shù)等)時(shí)會(huì)觸發(fā)進(jìn)程調(diào)度函數(shù)(schedule)使得進(jìn)程(此時(shí)在內(nèi)核態(tài))得以切換,切換的實(shí)際是兩個(gè)進(jìn)程的內(nèi)核堆棧的切換。

一般有四個(gè)進(jìn)程調(diào)度的時(shí)機(jī)
1. 用戶調(diào)用特點(diǎn)系統(tǒng)調(diào)用主動(dòng)讓出CPU
2. 中斷處理函數(shù)返回用戶態(tài)時(shí)固定時(shí)機(jī)點(diǎn)
3. 內(nèi)核線程主動(dòng)調(diào)用schedule
4. 中斷處理函數(shù)主動(dòng)調(diào)用schedule

中斷類型


  1. 硬中斷(Interrupt)
    CPU兩個(gè)引腳(可屏蔽中斷,不可屏蔽中斷),高電平表示有中斷。類似時(shí)鐘,鍵盤等會(huì)使用硬中斷方式。
  2. 軟中斷(Exception)
    • 故障(Fault)
    • 退出(Abort)
    • 陷阱(Trap)
      系統(tǒng)調(diào)用屬于該類軟中斷

進(jìn)程上下文切換


進(jìn)程上下文包括

  • 用戶地址空間:程序代碼段,數(shù)據(jù)段,用戶堆棧等內(nèi)存信息
  • 控制信息:進(jìn)程描述符、內(nèi)核堆棧
  • 硬件上下文:寄存器

關(guān)鍵寄存器切換

  • CR3 地址空間寄存器
  • ESP
  • EIP

thread_struct thread

每個(gè)進(jìn)程描述符都有一個(gè)類型thread_stuct的thread字段,該字段在進(jìn)程被切出去的時(shí)候保存了當(dāng)時(shí)硬件上下文信息

切換步驟

  1. 切換CR3,切換后兩個(gè)進(jìn)程相同的虛擬地址對(duì)應(yīng)了不物理地址
  2. 切換內(nèi)核堆棧和硬件上下文信息

代碼分析

schedele函數(shù)調(diào)用context_switch進(jìn)行上下文切換

context_switch(struct rq *rq, struct task_struct *prev, struct task_struct *next)
{
  switch_mm(oldmm,mm,next) //內(nèi)存CR3寄存器切換
  switch_to(prev, next, prev) //內(nèi)核堆棧和硬件上下文切換
}
switch_mm(struct mm_struct *prev, struct mm_struct *next, struct task_struct *tsk)
{
  load_cr3(newxt->pgd);
}
//簡(jiǎn)化代碼
switch_to(prev,next last)
{
  pushfl
  pushl %ebp //0

  prev->thread.sp = %esp //1
  %esp = next->thread.sp //2
  prev->thread.ip = $1f //3
  
  push next->thread.ip //4
  jmp _switch_to //5

  1f:
  popl %ebp //6
  popfl
    
  
}

重點(diǎn)講解switch_to函數(shù)

0

將當(dāng)前進(jìn)程(prev)的硬件上下文和內(nèi)核堆棧地址保存在當(dāng)前進(jìn)程(prev)內(nèi)核堆棧中,當(dāng)當(dāng)前進(jìn)程(prev)再次被調(diào)度的時(shí)候進(jìn)行恢復(fù)

1

保存內(nèi)核堆棧地址到當(dāng)前進(jìn)程(prev)的thread結(jié)構(gòu)體中,上面有提到

2

將當(dāng)前CPU的ESP寄存器(堆棧寄存器)切換為下一個(gè)進(jìn)程(next)的內(nèi)核堆棧地址。由于進(jìn)程的內(nèi)核堆棧和進(jìn)程控制塊(PCB,即進(jìn)程描述符)保存在連續(xù)的8K內(nèi)存空間,因此當(dāng)CPU的ESP寄存器切換到下一個(gè)進(jìn)程(next)的內(nèi)核堆棧地址時(shí),可以理解為當(dāng)前已經(jīng)切換到了next進(jìn)程。

3

將上一個(gè)進(jìn)程(prev)的thread.ip設(shè)置為1f的地址,這是當(dāng)該進(jìn)程再次被調(diào)度時(shí)開始執(zhí)行的代碼行。

4&5

在next進(jìn)程的內(nèi)核堆棧中壓入thread.ip的代碼段地址(即該進(jìn)程在上次被調(diào)度出去在第三步保存的地址),然后使用jmp _switch_to來控制CPU的EIP寄存器跳轉(zhuǎn)到1f的代碼段地址??梢詫⑦@兩步(4、5)理解為將地址裝載然后控制EIP跳轉(zhuǎn)的功能。

6

此時(shí)進(jìn)入進(jìn)程恢復(fù)階段,對(duì)應(yīng)第0步?;謴?fù)進(jìn)程的堆棧,硬件上下文信息。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容