Zhang Yumei Original works reproduced please specify the source
"Linux kernel Analysis" MOOC course http://mooc.study.163.com/course/USTC-10000
Background knowledge
The general program will be interrupted during the operation, when an interruption occurs, the CPU first saves the current content, and then executes the interrupt program, when the interrupt returns, according to the saved content to restore the scene. This experiment uses a simple time-slice rotation program to analyze the process of process scheduling.
Experimental process
Using the virtual machine operation of the lab building, the experiment Code was found in Mykernel, including 3 C files and mypcb.h,mymain.c,myinterrupt.c.
Open the shell of the lab building, modify the three files in the Mykernel folder, and make
CD linuxkernel/linux-3.9. 4 CD Mykernelvi MYMAIN.CVI MYINTERRUPT.CVI MYPCB.HCD. Make Allnoconfigmake
The part that runs the results is as follows, and you can see that process 3 switches to process 0 at this point
Code Analysis
The experiment used three C files, mypcb.h,mymain.c,myinterrupt.c. which
Main functions of Mypcb.h:
1.PCB Structural Body
2.Thread Structural Body
3. The My_schedule function is declared and used for mymian.c,myinterrupt.c.
Main functions of MYMAIN.C:
The 1.my_start_kernel function creates process 0, which is also an entry function
2. Replication process
3. Process function my_process, where there is a call to the My_schedule function
Main functions of MYINTERRUPT.C:
1.my_timer_handler Clock Interrupt Generation
2.my_schedule Switching process
The following analysis of the program's execution process
The value of setting Max_task_num in Mypcb.h is 4, which is a total of four processes, respectively, 0,1,2,3.
The program starts from My_start_kernel,
intPID =0; inti; /*Initialize Process 0*/Task[pid].pid= PID;/*Process 0*/task[pid].state=0;/*-1 unrunnable, 0 runnable, >0 stopped the initial state of process 0 is operational*/Task[pid].task_entry= Task[pid].thread.ip = (unsignedLong) my_process;/*Process 0 EIP points to my_process*/TASK[PID].THREAD.SP= (unsignedLong) &task[pid].stack[kernel_stack_size-1];/*Initial SP points to the highest address of the stack assigned to process 0*/Task[pid].next= &task[pid];/*the next process in the initial process 0 is process 0*/
Then three processes were copied, note
Task[i].state =-1; / * Initial state of the process, not enforceable */
Task[i].next = task[i-1].next; Task[i-1].next = &task[i]; /* */
These two lines of code set the way the process is switched, such as process 0 switching to process 1, and process 1 switching to process 2.
/*START process 0 by task[0]*/PID=0; My_current_task= &Task[pid]; ASMvolatile( "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*/ );
Now executing is process 0, this code is to point esp to the stack segment assigned to process 0 The highest address, the current EBP into the stack to save, the Eip point to Task[pid].thread.ip, that is, My_process, began to execute the my_process function. Here ret executes, go to my_process function, "popl%%ebp\n\t" This sentence does not execute.
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;/ * is set to 0 and cannot be scheduled until the clock interrupt is reset to 1*/my_schedule (); }PRINTK (Kern_notice"This is process%d +\n",my_current_task->pid);
}
Combined with My_timer_handler function analysis
if(time_count%01) {">>>my _timer_handler here<<<\n"); 1 ; / * Reset to 1*/ }
When the initial my_need_sched value is a clock break for the 0,my_timer_handler function, the my_need_sched value is the 1,my_process function that satisfies the process scheduling condition and calls My_schedule (). the next of process 0 is process 1, and at the initial time, the state of the process is 1, so the else segment is executed. This means that the first time you switch to the process, it is the code that executes the else segment first.
Else{Next->state =0; My_current_task=Next; PRINTK (Kern_notice">>>switch%d to%d<<<\n",prev->pid,next->pid); /*switch to New process*/ASMvolatile( "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: The state of Process 1 is first set to 0, the next time you switch to process 1, it is to execute the IF segment.
2.EBP, esp: Still in the stack of process 0, the EBP of process 0 is saved, set PRE->THREAD.SP to the current ESP of process 0, then ESP, EBP all point to Process 1 ESP, which is initialized to the highest address of the stack allocated to process 1. The EBP and ESP values are the same because process 1 is used for the first time and the stack is empty.
3.EIP: Set the EIP for process 0 to $1f, save with PRE->THREAD.IP, indicate if code Segment 1: Place, that is, the next time you switch to process 0 o'clock, starting at 1: Start execution. The EIP points to the EIP that the EIP points to process 1, which is initialized to my_process.
This completes the process 0 switch to process 1. Process 1 switches to process 2, and process 2 switches to process 3, which is similar to the execution process.
When process 3 switches to process 0 o'clock, because process 0 has been executed once and its state is 0, the if code snippet is executed at this time.
if(Next->state = =0)/*-1 unrunnable, 0 runnable, >0 stopped*/ { /*switch to Next process*/ASMvolatile("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); }
This code is roughly the same as the Else section code, which is to save the ebp,esp,eip of Process 3 and then reassign the ESP,EIP. The difference is:
1.if the value of EBP is not set, at which time the stack of process 0 is not empty
The EIP set in 2.if is the EIP for process 0, which is executed to 1: Note that this is the stack that has been transferred to process 0. Then the pop%%ebp is executed, because the stack top element of process 0 is the EBP that was saved when process 0 was interrupted, and the stack condition for process 0 is the same as the stack at the time of the interrupt.
Continue execution of the following code, which is performed in the stack of process 0.
The program continues to run, and subsequent process transitions are performed with the If segment code, which is the same as the previous procedure.
Process switching execution can be expressed as
It can also be seen that the next,prev of the process is a change, the current prev process, in the subsequent process scheduling, will become next process.
Analysis of process scheduling based on time slice rotation program