【潘恆 原創做品轉載請註明出處 《Linux內核分析》MOOC課程 "http://mooc.study.163.com/course/USTC 1000029000 " 】linux
使用gdb跟蹤分析一個schedule()函數,理解Linux系統中進程調度的時機。git
登錄實驗樓虛擬機http://www.shiyanlou.com/courses/195github
打開shell終端,執行如下命令:算法
cd LinuxKernel rm -rf menu git clone https://github.com/mengning/menu.git cd menu mv test_exec.c test.c make rootfs
能夠看到編譯出來的系統已經有了exec命令shell
能夠經過增長-s -S啓動參數打開調試模式函數
qemu -kernel ../linux-3.18.6/arch/x86/boot/bzImage -initrd ../rootfs.img -s -S
打開gdb進行遠程調試spa
gdb file ../linux-3.18.6/vmlinux target remote:1234
設置斷點線程
b schedule
b context_switch
b switch_to
b pick_next_task
經過實驗可知schedule()函數用來選擇一個新的進程來運行,並調用context_switch()進行上下文的切換,這個宏調用switch_to()來進行關鍵上下文切換,其中pick_next_task()函數封裝了進程調度算法。調試
進程調度時機有三:rest
一、中斷處理過程(包括時鐘中斷、I/O中斷、系統調用和異常)中,直接調用schedule(),或者返回用戶態時根據need_resched標記調用schedule();
二、內核線程能夠直接調用schedule()進行進程切換,也能夠在中斷處理過程當中進行調度,也就是說內核線程做爲一類的特殊的進程能夠主動調度,也能夠被動調度;
三、用戶態進程沒法實現主動調度,僅能經過陷入內核態後的某個時機點進行調度,即在中斷處理過程當中進行調度。
進程切換:爲了控制進程的執行,內核必須有能力掛起正在CPU上運行的進程,並恢復之前掛起的某個進程的執行。這種行爲被稱爲進程切換(process switch)、任務切換(task switch)或上下文切換(context switch)。
掛起正在CPU上執行的進程,與中斷時保存現場是不一樣的,中斷先後是在同一個進程上下文中,只是由用戶態轉向內核態執行。
進程上下文包含了進程執行須要的全部信息,包括:
一、用戶地址空間:包括程序代碼,數據,用戶堆棧等
二、控制信息:進程描述符,內核堆棧等
三、硬件上下文(與中斷保存硬件上下文的方法不一樣)
Linux系統的通常執行過程
最通常的狀況:
正在運行的用戶態進程X切換到運行用戶態進程Y的過程
一、正在運行的用戶態進程X
二、發生中斷——save cs:eip/esp/eflags(current) to kernel stack,then load cs:eip(entry of a specific ISR) and ss:esp(point to kernel stack).
三、SAVE_ALL //保存現場
四、中斷處理過程當中或中斷返回前調用了schedule(),其中的switch_to作了關鍵的進程上下文切換
五、標號1以後開始運行用戶態進程Y(這裏Y曾經經過以上步驟被切換出去過所以能夠從標號1繼續執行)
六、restore_all //恢復現場
七、iret - pop cs:eip/ss:esp/eflags from kernel stack
八、繼續運行用戶態進程Y
幾種特殊狀況:
一、經過中斷處理過程當中的調度時機,用戶態進程與內核線程之間互相切換和內核線程之間互相切換,與最通常的狀況很是相似,只是內核線程運行過程當中發生中斷沒有進程用戶態和內核態的轉換;
二、內核線程主動調用schedule(),只有進程上下文的切換,沒有發生中斷上下文的切換,與最通常的狀況略簡略;
三、建立子進程的系統調用在子進程中的執行起點及返回用戶態,如fork;
四、加載一個新的可執行程序後返回到用戶態的狀況,如execve;