20135132陳雨鑫 + 原創做品轉載請註明出處 + 《Linux內核分析》MOOC課程http://mooc.study.163.com/course/USTC-1000029000 」linux
1、進程調度與進程調度的時機分析算法
一、進程調度shell
不一樣類型的進程有不一樣的調度需求架構
第一種分類:
I/O-bound
頻繁的進行I/O
一般會花費不少時間等待I/O操做的完成
CPU-bound
計算密集型
須要大量的CPU時間進行運算
第二種分類:
批處理進程(batch process)
沒必要與用戶交互,一般在後臺運行
沒必要很快響應
典型的批處理程序:編譯程序、科學計算
實時進程(real-time process)
有實時需求,不該被低優先級的進程阻塞
響應時間要短、要穩定
典型的實時進程:視頻/音頻、機械控制等
交互式進程(interactive process)
須要常常與用戶交互,所以要花不少時間等待用戶輸入操做
響應時間要快,平均延遲要低於50~150ms
典型的交互式程序:shell、文本編輯程序、圖形應用程序等框架
內核中的調度算法相關代碼使用了相似OOD的策略模式。函數
二、進程調度的時機學習
中斷處理過程(包括時鐘中斷、I/O中斷、系統調用和異常)中,直接調用schedule(),或者返回用戶態時根據need_resched標記調用schedule();spa
內核線程能夠直接調用schedule()進行進程切換,也能夠在中斷處理過程當中進行調度,也就是說內核線程做爲一類的特殊的進程能夠主動調度,也能夠被動調度;操作系統
用戶態進程沒法實現主動調度,僅能經過陷入內核態後的某個時機點進行調度,即在中斷處理過程當中進行調度。線程
2、進程上下文切換相關代碼分析
一、進程的切換
1)爲了控制進程的執行,內核必須有能力掛起正在CPU上執行的進程,並恢復之前掛起的某個進程的執行,這叫作進程切換、任務切換、上下文切換;
2)掛起正在CPU上執行的進程,與中斷時保存現場是不一樣的,中斷先後是在同一個進程上下文中,只是由用戶態轉向內核態執行;
3)進程上下文包含了進程執行須要的全部信息
用戶地址空間:包括程序代碼,數據,用戶堆棧等
控制信息:進程描述符,內核堆棧等
硬件上下文(注意中斷也要保存硬件上下文只是保存的方法不一樣)
4)schedule()函數選擇一個新的進程來運行,並調用context_switch進行上下文的切換,這個宏調用switch_to來進行關鍵上下文切換
•next = pick_next_task(rq, prev);//進程調度算法都封裝這個函數內部
•context_switch(rq, prev, next);//進程上下文切換
•switch_to利用了prev和next兩個參數:prev指向當前進程,next指向被調度的進程
二、代碼分析
關鍵彙編代碼:
outout: thread.sp:內核態,sp是內核堆棧的棧頂
thread.ip:當前進程的eip
input: prev_sp:下一個進程的內核堆棧的棧頂
prev_ip:下一個進程執行的起點
這兩句完成了內核堆棧的切換,將當前內核堆棧的棧頂保存起來,把下一個next進程的棧頂放到ESP寄存器中,以後的壓棧動做都是在next進程堆棧中完成:
next_ip通常是$1f,對於新建立的子進程是ret_from_fork。
3、Linux系統的通常執行過程
一、最通常的狀況:正在運行的用戶態進程X切換到運行用戶態進程Y的過程
二、幾種特殊狀況
next_ip=ret_from_fork
三、進程的地址空間一共有4G,其中0——3G是用戶態能夠訪問,3G以上只有內核態能夠訪問
4、系統架構和執行過程概述
一、系統架構
二、典型的Linux操做系統的架構
三、最簡單也是最複雜的操做——ls
四、CPU和內存的角度看Linux系統的執行
從內存角度看,全部的物理地址都會被映射到3G以上的地址空間:由於這部分對全部進程來講都是共享的
0xc0000000如下是3G的部分,用戶態。
5、實驗
使用gdb跟蹤分析一個schedule()函數 ,驗證對Linux系統進程調度與進程切換過程的理解
關閉QEMU窗口,在shell窗口中,cd LinuxKernel回退到LinuxKernel目錄,使用下面的命令啓動內核並在CPU運行代碼前停下以便調試:
qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img -s -S
接下來,咱們就能夠水平分割一個新的shell窗口出來,依次使用下面的命令啓動gdb調試
gdb
(gdb) file linux-3.18.6/vmlinux
(gdb) target remote:1234
並在內核函數schedule的入口處設置斷點,接下來輸入c繼續執行,則系統便可停在該函數處,接下來咱們就可使用命令n或者s逐步跟蹤,能夠詳細瀏覽pick_next_task,switch_to等函數的執行過程
設置斷點在schedule處:
6、總結
經過學習,咱們瞭解到Linux使用了堆棧進行了進程調度。schedule()在須要的時候從新得到大內核鎖、從新啓用內核搶佔、並檢查是否一些其餘的進程已經設置了當前進程的tlf_need_resched標誌,若是是,整個schedule()函數從新開始執行,不然,函數結束。linux調度的核心函數爲schedule,schedule函數封裝了內核調度的框架。細節實現上調用具體的調度類中的函數實現。當切換進程已經選好後,就開始用戶虛擬空間的處理,而後就是進程的切換switch_to()。所謂進程的切換主要就是堆棧的切換,這是由宏操做switch_to()完成的。