陳民禾 原創做品轉載請註明出處 《Linux內核分析》MOOC課程 http://mooc.study.163.com/course/USTC-1000029000linux
一.關於進程調度的基本知識git
進程的幾種不一樣分類:第一種分類:類型一:I/O-bound:頻繁的進行I/O,一般會花費不少的時間等待I/O操做的完成;類型二:CPU-bound:計算密集型 ,須要大量的CPU時間進行運算第二種分類:類型一:批處理進程 ;類型二:實時進程;類型三:交互式進程。github
調度策略:是一組規則,它們決定何時以怎樣的方式選擇一個新的進程運行,Linux的調度基於分時和優先級:隨着版本的變化,分時技術在不斷變化,Linux既支持普通的分時進程,也支持實時進程,Linux中的調度是多種調度策略和調度算法的混合。算法
nice getpriority sched_getscheduler/sched_setscheduler sched_getparam/sched_setparam sched_yield sched_get_priority_min/sched_get_priority_max
sched_rr_get_interval
31#define switch_to(prev, next, last) 32do { 33 /* 34 * Context-switching clobbers all registers, so we clobber 35 * them explicitly, via unused output variables. 36 * (EAX and EBP is not listed because EBP is saved/restored 37 * explicitly for wchan access and EAX is the return value of 38 * __switch_to()) 39 */ 40 unsigned long ebx, ecx, edx, esi, edi; 41 42 asm volatile("pushfl\n\t" /* save flags */ //保存當前進程的flags 43 "pushl %%ebp\n\t" /* save EBP */ //把當前進程的堆棧基址壓棧 44 "movl %%esp,%[prev_sp]\n\t" /* save ESP */ //把當前的棧頂保存到prev->thread.sp 45 "movl %[next_sp],%%esp\n\t" /* restore ESP */ //把下一個進程的棧頂保存到esp中,這兩句完成了內核堆棧的切換 46 "movl $1f,%[prev_ip]\n\t" /* save EIP */ //保存當前進程的EIP,能夠從這恢復 47 "pushl %[next_ip]\n\t" /* restore EIP */ //把下一個進程的起點位置壓到堆棧,就是next進程的棧頂。next_ip通常是$1f,對於新建立的子進程是ret_from_fork //通常用return直接把next_ip pop出來 48 __switch_canary 49 "jmp __switch_to\n" /* regparm call */ //jmp經過寄存器傳遞參數,即後面的a,d。 函數__switch_to也有return把next_ip pop出來 50 "1:\t" //認爲從這開始執行next進程(EIP角度),第一條指令是next_ip這個起點,但前面已經完成內核堆棧的切換,早就是next進程的內核堆棧(算prev進程,比較模糊) 51 "popl %%ebp\n\t" /* restore EBP */ //next進程曾經是prev進程,壓棧過ebp 52 "popfl\n" /* restore flags */ 53 54 /* output parameters */ 55 : [prev_sp] "=m" (prev->thread.sp), //當前進程的,在中斷內部,在內核態,sp是內核堆棧的棧頂 56 [prev_ip] "=m" (prev->thread.ip), //當前進程的EIP 57 "=a" (last), 58 59 /* clobbered output registers: */ 60 "=b" (ebx), "=c" (ecx), "=d" (edx), 61 "=S" (esi), "=D" (edi) 62 63 __switch_canary_oparam 64 65 /* input parameters: */ 66 : [next_sp] "m" (next->thread.sp), //下一個進程的內核堆棧的棧頂 67 [next_ip] "m" (next->thread.ip), //下一個進程的執行起點 68 69 /* regparm parameters for __switch_to(): */ 70 [prev] "a" (prev), //寄存器的傳遞 71 [next] "d" (next) 72 73 __switch_canary_iparam 74 75 : /* reloaded segment registers */ 76 "memory"); 77} while (0)
2.ls命令——最簡單與最複雜的操做shell
1.從在CPU執行指令的角度看:網絡
2.從內存的角度看架構
五.實驗過程截圖及分析函數
搭建實驗環境:學習
cd LinuxKernel rm menu -rf git clone https://github.com/mengning/menu.git cd menu mv test_exec.c test.c make rootfs
gdb調試spa
qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img -s -S gdb file ../linux-3.18.6/vmlinux target remote:1234 設置斷點: b schedule b pick_next_task b context_switch b switch_to
3.在schedule處設置斷點,運行,並用list展開函數
4.單步運行,直至__schedule()
5.在context_switch處設立斷點,執行
六.知識總結
進程調度程序是內核重要的組成部分,由於運行着的進程首先在使用計算機(至少在咱們大多數人看來)。然而,知足進程調度的各類須要毫不是垂手可得的,很難找到「一刀切」的算棒,既適合衆多的可運行進程,又具備可伸縮性,還能在調度週期和吞吐量之間求得平衡,同時還知足各類負載的需求。不過, Linux 內核的新CFS 調度程序儘可能知足了各個方面的需求,並以較完善的可伸縮性和新穎的方挫提供了最佳的解決方案。前面的章節覆蓋了進程管理的相關內容,本章則考察了進程調度所遵循的基本原理、具體實現、調度算能以及目前Linux 內核所使用的接口。