內容: |
(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即為內核堆棧棧底指針