Linux進程調度和切換過程分析


內容:

(1):從schedule()開始,幾種不同類型的進程之間的調度選擇;在相同類型的進程之間的調度選擇算法

(2):從CPU的IP值的變化上,說明在switch_to宏執行后,執行分析

(3):堆棧發生切換位置,在切換堆棧前后,current_thread_info變化

(4):地址空間發生切換,解釋地址空間的切換不會影響后續切換代碼的執行

(5):current宏所代表的進程發生變化的源碼位置

(6):任務狀態段中關於內核堆棧的信息發生變化源碼位置

 

1,從schedule()開始,說明幾種不同類型的進程之間的調度選擇;在相同類型的進程之間的調度選擇算法。

在schedule()函數中,

 

首先禁止搶占,獲取當前CPU,該CPU的執行隊列,隊列上正在執行的進程,以及該進程的交換計數信息並釋放該進程占用的鎖。之后,對禁止中斷,更新運行隊列時鍾,該隊列的自旋時鍾加鎖,后清除當前進程的thread_flag中TIF_NEED_RESCHED,

 

如果進程不在可運行狀態,並且可被搶占,若進程處於非阻塞掛起,則將其改為可運行,否則調用deactivate_task()函數,並修改上下文交換次數。其中在deactive_task()函數中調用了denqueue_task()函數:

 

P進程調用屬於自己調度類的dequeue_task()方法,將p從當前rp運行隊列上移出。例如對於公平調度隊列中的進程調用以下函數:

對p的所有實體除含有子實體的父進程外,從公平隊列中移除。

如果運行隊列上進程數是0,則先通過idle_balance函數從其他CPU上調度,進行負載均衡。

對當前運行的進程prev,通過調用它所屬的類的put_prev_task方法,將當前進程放入運行隊列的合適位置。下圖展示過程,圖為公平調度類的調度方法,之后對實時調度方法的說明(idle類方法為空):

與方法put_prev_entity()方法,將當前進程加入公平調度隊列。因為如果該類是公平調度類,則調度一定會在公平調度隊列中有一位置,更新當前實例的狀態,並入隊:

其中入隊位置有該值決定entity_key:

對於采用實時調度的類,調用update_curr_rt函數,並置當前進程執行開始時間是0

下圖為update_curr_tr函數,

計算delta_exec值為運行隊列現在的時鍾值與當前進程開始值。更改當前進程的狀態,修改當前實時進程的總運行時間與開始時間,對實時調度隊列中的實例更新時間。

之后,在運行隊列上選擇下一個進程中pick_next_task函數。

對於運行隊列,如果隊列中進程數與公平調度隊列中的進程數相同,即沒有實時進程時則在公平調度隊列中選擇進程:

對調度類中具有最高優先級的類賦值給class,調用該類的pick_next_task方法,根據不同調度類又分為:

對於實時進程則:

對於一個實例,如果它不在實時隊列組中,則返回擁有這個實例的task_struct結構為next進程並修改執行開始時間為運行隊列當時鍾前值。

對於公平調度進程則:

返回公平調度隊列上選擇不在公平調度組中的task_struct。

對於idle,返回隊列中的idle task_struct結構,在調度過程中,永遠不會返回NULL,因為至少有idle進程的存在。

在隊列中從不同類中,選擇出了將要被調度的類后,如果選擇的進程next與prev不同則,進行進程的上下文切換:

修改交換次數,將next至為當前進程,進行切換。

2,執行完switch_to后,又執行了battier函數,之后又執行finish_task_switch函數

 

另:

struct task_struct *__switch_to(struct task_struct *prev,struct task_struct *next);

將next->thread.esp中的數據存入esp寄存器中

在switch_to宏執行后,執行ret_from_fork()函數。

執行完這個函數之后,執行include/asm-x86/system.h 下的__switch_to函數()

再執行__unlazy_fpu()函數。

3,堆棧發生切換位置,在切換堆棧前后,current_thread_info變化

對於切換堆棧,在switch_to中查找修改堆棧指針代碼即可即:

圖中movel %[next_sp],%%esp 即為修改堆棧指針,指向next進程的堆棧。因為在內核態中,棧頂指針減去8K偏移(兩頁)便可得到thread_info位置,從而,在切換后current_thread_info內容為切換后的新進程的thread_info內容。

4地址空間發生切換,解釋地址空間的切換不會影響后續切換代碼的執行

切換地址空間在context_switch函數的switch_mm方法,在switch_mm中,重新加載頁表即修改cr3寄存器的值:

切換地址空間發生在切換堆棧之前,不會影響后續代碼執行,因為進程的切換發生在內核態,內核態地址空間是共用的。沒有修改堆棧指針及其他寄存器的值,即堆棧沒有變,棧內值未發生改變。

5,current宏所代表的進程發生變化的源碼位置

修改該CPU的current_task為next_p,即current宏發生了改變。

6,任務狀態段中關於內核堆棧的信息發生變化源碼位置

Tss段在_switch_to中被聲明,並被賦值:

其中,esp0即為內核堆棧棧底指針


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM