基于时间片轮转程序分析进程调度
?
?張雨梅 ??原創作品轉載請注明出處
《Linux內核分析》MOOC課程http://mooc.study.163.com/course/USTC-10000
?
背景知識
? ? ? ?一般程序運行過程中都會發生中斷,發生中斷時,CPU先把當前的內容保存,然后執行中斷程序,中斷返回時,根據保存的內容恢復現場。這次實驗用一個簡單的時間片輪轉程序分析進程調度的過程。
?
實驗過程
? ? ?使用實驗樓的虛擬機操作,實驗代碼在mykernel中找,包括3個c文件,mypcb.h,mymain.c,myinterrupt.c。
? ? ?打開實驗樓的shell,修改mykernel文件夾中的三個文件,然后make
cd LinuxKernel/linux-3.9.4 cd mykernel vi mymain.c vi myinterrupt.c vi mypcb.h cd .. make allnoconfig make運行結果的部分截圖如下,可以看到此時進程3切換到進程0
?
代碼分析
? ? ?實驗用到三個c文件,?mypcb.h,mymain.c,myinterrupt.c。其中,
? ? ?mypcb.h的主要功能:
? ? ? ? ? 1.PCB結構體
? ? ? ? ? 2.Thread結構體
? ? ? ? ? 3.聲明了my_schedule函數
? ? ?mymain.c的主要功能:
? ? ? ? ? 1.my_start_kernel函數創建進程0,也是入口函數
? ? ? ? ? 2.復制進程
? ? ? ? ? 3.進程函數my_process,其中有my_schedule函數的調用
? ? ?myinterrupt.c的主要功能:
? ? ? ? ? 1.my_timer_handler產生時鐘中斷
? ? ? ? ? 2.my_schedule切換進程
?
? ? 下面分析程序的執行過程
? ? ? ? ? mypcb.h中設置MAX_TASK_NUM的值為4,也就是共有四個進程,分別為0,1,2,3.
? ? ? ? ? 程序從my_start_kernel開始執行,? ??
int pid = 0;int i;/* Initialize process 0*/task[pid].pid = pid;/*進程0*/task[pid].state = 0;/* -1 unrunnable, 0 runnable, >0 stopped 進程0的初始狀態為可運行 */task[pid].task_entry = task[pid].thread.ip = (unsigned long)my_process;/*進程0的eip指向my_process*/task[pid].thread.sp = (unsigned long)&task[pid].stack[KERNEL_STACK_SIZE-1];/*初始時sp指向分配給進程0的堆棧的最高地址*/task[pid].next = &task[pid];/*初始進程0的下一個進程是進程0*/? ? ? ? ? 然后復制了三個進程,注意
task[i].state = -1;/*進程1,2,3的初始狀態不可執行*/ task[i].next = task[i-1].next;task[i-1].next = &task[i];? ? ? ? 這兩句代碼設置了進程的切換方式,比如進程0切換到進程1,進程1切換到進程2。
? ? ? ? ?
/* start process 0 by task[0] */pid = 0;my_current_task = &task[pid];asm volatile("movl %1,%%esp\n\t" /* set task[pid].thread.sp to esp */"pushl %1\n\t" /* push ebp */"pushl %0\n\t" /* push task[pid].thread.ip */"ret\n\t" /* pop task[pid].thread.ip to eip */"popl %%ebp\n\t":: "c" (task[pid].thread.ip),"d" (task[pid].thread.sp) /* input c or d mean %ecx/%edx*/);? ? ? ? ? 現在執行的是進程0,這段代碼是把esp指向分配給進程0的堆棧段的最高地址,把當前ebp入棧保存,eip指向task[pid].thread.ip,也就是my_process,開始執行my_process函數。這里ret執行以后,轉到my_process函數,"popl %%ebp\n\t"這一句不執行。
if(i%10000000 == 0) { printk(KERN_NOTICE "this is process %d -\n",my_current_task->pid); if(my_need_sched == 1) { my_need_sched = 0;/*置為0,不能進行進程調度,直到再次發生時鐘中斷置為1*/ my_schedule(); } printk(KERN_NOTICE "this is process %d +\n",my_current_task->pid);}
? ? ? ? ??結合my_timer_handler函數一起分析
if(time_count%1000 == 0 && my_need_sched != 1){printk(KERN_NOTICE ">>>my_timer_handler here<<<\n");my_need_sched = 1;/*置為1*/}? ? ? ? ?初始my_need_sched值為0,my_timer_handler函數發生時鐘中斷時,置my_need_sched值為1,my_process函數中滿足進程調度條件,調用my_schedule()。進程0的next是進程1,初始時,進程1,2,3的state均為-1,故執行else段。也就是說初次切換到進程1,2,3時都是先執行else段的代碼。? ?
else{next->state = 0;my_current_task = next;printk(KERN_NOTICE ">>>switch %d to %d<<<\n",prev->pid,next->pid); /* switch to new process */asm volatile( "pushl %%ebp\n\t" /* save ebp */ "movl %%esp,%0\n\t" /* save esp */ "movl %2,%%esp\n\t" /* restore esp */ "movl %2,%%ebp\n\t" /* restore ebp */ "movl $1f,%1\n\t" /* save eip */ "pushl %3\n\t" "ret\n\t" /* restore eip */: "=m" (prev->thread.sp),"=m" (prev->thread.ip): "m" (next->thread.sp),"m" (next->thread.ip));}? ? ? ? 1.state:先把進程1的state置為0,下次切換到進程1的時候,就是執行if段。
? ? ? ? 2.ebp、esp:目前依然在進程0的堆棧中,先把進程0的ebp入棧保存,設置pre->thread.sp為進程0的當前esp,然后esp、ebp都指向進程1的esp,其被初始化為分配給進程1的堆棧的最高地址。ebp、esp值相同,因為進程1初次使用,堆棧為空。
? ? ? ? 3.eip:設置進程0的eip為$1f,用pre->thread.ip保存,表示if代碼段1:處,即下次切換到進程0時,從1:處開始執行。eip指向eip指向進程1的eip,其被初始化為my_process。
? ? ? ? 這時即完成了進程0向進程1的切換。進程1切換進程2,進程2切換到進程3的執行過程與之類似。
?
? ? ? ? 當進程3切換到進程0時,由于進程0已經被執行過一次,其state為0,此時執行if代碼段。??
if(next->state == 0)/* -1 unrunnable, 0 runnable, >0 stopped */{ /* switch to next process */asm volatile("pushl %%ebp\n\t" /* save ebp */"movl %%esp,%0\n\t" /* save esp */ "movl %2,%%esp\n\t" /* restore esp */"movl $1f,%1\n\t" /* save eip */ "pushl %3\n\t""ret\n\t" /* restore eip */"1:\t" /* next process start here */"popl %%ebp\n\t": "=m" (prev->thread.sp),"=m" (prev->thread.ip): "m" (next->thread.sp),"m" (next->thread.ip));my_current_task = next;printk(KERN_NOTICE ">>>switch %d to %d<<<\n",prev->pid,next->pid);}? ? ? ? ? 這段代碼與else段代碼大體過程相同,就是保存進程3的ebp,esp,eip,然后對esp,eip重新賦值。不同的是:
? ? ? ? ? 1.if沒有設置ebp的值,此時進程0的棧非空
? ? ? ? ? 2.if中設置的eip為進程0的eip,也就是執行到1:處,注意此時是已經轉到了進程0的堆棧中。然后執行pop %%ebp,由于進程0的棧頂元素是進程0被中斷時保存的ebp,此時進程0的堆棧情況和被中斷時的堆棧情況一樣。
? ? ? ? ? 繼續執行下面的代碼,是在進程0的堆棧中執行的。
? ? ? ? ? 程序繼續運行,以后發生的進程切換執行的都是if段代碼,和上述過程相同。
? ? ? ? ??
? ? ? ? ? 進程切換的執行過程可以表示為
? ? ? ? ? ? ??
? ? ? ? ? ? ?另外可以看出,進程的next,prev是變化的,當前的prev進程,在以后的進程調度中,會變成next進程。
?
轉載于:https://www.cnblogs.com/icecri/p/4339641.html
總結
以上是生活随笔為你收集整理的基于时间片轮转程序分析进程调度的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 任务调度
- 下一篇: 保税区哪里给电动车上牌在哪?