Linux kernel Analysis (ii)--analyzing process switching principles from a simple Linux kernel __linux

Source: Internet
Author: User
Tags prev switches volatile

Author: Sandy Original works reproduced please indicate the source
"Linux kernel Analysis" MOOC course http://mooc.study.163.com/course/USTC-1000029000 "
Experimental environment: C+linux64 bit (32-bit system may result in different)
In accordance with the academic integrity of the terms, I guarantee that the answer for my original, all the references to the external materials have been marked by provenance.

Source code and operating environment to build please refer to Mykernel, which provides a simple Linux kernel source code, this article mainly analyzes the three files: Mypcb.h mymain.c myinterrupt.c

Through the analysis of these three files to understand the process of switching principle.

Note that although 4 processes are established in the source code and are cycled, the simple analysis assumes that there are only two processes, numbering 0 and 1. In addition, in the actual Linux system each process will have two stacks: User state One, kernel state one, but in this emulated kernel each process only assigns one stack. first of all, start with the mymain.c.

In the process of switching the most important is the broker's storehouses Switch and EIP (that is, program counters) the correct jump, mymain.c in the function My_start_kernel is the first code to execute, so from this function to start analysis. The My_start_kernel function first established 4 processes and initialization, such as the allocation stack, note that at the time of the first set up only No. 0 process status is runuable, the rest are unrunnable. There is the PCB structure of the THREAP.SP, each process corresponds to a stack, so here thread.sp point to the corresponding stack[kernel_stack_size-1 in the PCB, that is, using this character array as the running stack, because Stacks are grown from high addresses to low addresses , so point to stack[kernel_stack_size-1].
Next, we'll focus on this piece of code:

/* 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*/
    ) ;

The function of this inline assembler code is to complete the start of the No. 0 process, and the stack at runtime is as follows:

Before the start of the stack situation:

"Movl%1,%%esp\n\t"/     * Set TASK[PID].THREAD.SP to ESP * *

This instruction puts the current stack top address of process No. 0 into ESP, because the TASK[0].THREAD.SP points to stack[kernel_stack_size-1 when initialized, so the top of the stack that ESP points to task[0] After executing this instruction, The following figure:

"PUSHL%1\n\t"          * Push EBP *

The task[0] SP presses the stack, the schematic diagram of the stack is as follows:

"PUSHL%0\n\t"          * Push Task[pid].thread.ip *

The IP of the No. 0 process, that is, the my_process () function of the entry into the stack, at this time the situation in the stack as shown below:

"Ret\n\t"/               * Pop task[pid].thread.ip to EIP * *

Pop out of the stack just put in the my_process () function entry address assigned to the EIP, began to run the No. 0 process

My_process () will determine whether process switching is required at execution time, since we assume that there are only 0 and 12 processes in the kernel, we assume that the switching condition is met, and this directly analyzes the transition from the No. 0 process to the 1th process.
Because the pid[1].state of the current 1th process is "-1" (unrunnable), the Else branch of the My_schedule () function will be executed.
The Else branch of the My_schedule () function of the my_interrupt.c file reads as follows:

else
    {
        next->state = 0;
        My_current_task = Next;
        PRINTK (kern_notice "switch from%d process to%d process\n \
        >>>process%d running!!! <<<\n\n\n ", prev->pid,next->pid,next->pid);

     * Switch to New process *
     /ASM volatile (  
         "PUSHL%%ebp\n\t"/* Save EBP/
         "MOVL%%esp,%0\n\t"/* Save ESP */< c9/> "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)
     ;
    }

This article focuses on the embedded assembly code. Because there is an action to save the scene when switching from function my_start_kernel () to function my_process (), function my_process () Call function My_schedule () also saves the scene, so the stack before execution of the above code should be:

"PUSHL%%ebp\n\t"/* Save EBP/
"MOVL%%esp,%0\n\t"/* Save ESP * *

Save the run of process No. 0, that is, first save the current stack of the No. 0 process in the stack, and then save the value of the current ESP in the thread.sp of the No. 0 process, these field values in the back to the No. 0 process can be restored, at this time the stack of the situation:

"Movl%2,%%esp\n\t" * Restore ESP/
"MOVL%2,%%ebp\n\t"/* Restore EBP * *

Start the stack switch, that is, from Task[0].stack, switch to Task[1].stack, when the stack of the situation:

"Movl $1f,%1\n\t"/* Save EIP * *

The $1f here is a number with a special meaning, and the function of this code is that the next time the process switches back to the NO. 0 process, it will continue to execute from here.

"Pushl%3\n\t"

The process entry address of process 1th (this is the first run for the 1th process, so that is the my_process () function entry address, if not the first run, due to the execution of the previous code "MOVL $1f,%1\n\t" Then process 1 will proceed to the stack according to the code that was switched off. In this case, the situation in the stack is as shown:

"ret\n\t" * * Restore EIP * *

From the current stack Task[1].stack popped the entry address of the 1th process that you just sent, that is, execute the my_process () function, start the 1th process, similar to the start of the No. 0 process, and then determine if process switching is required. It is also assumed that the conditions for process switching are met, and then the process of switching from process 1th to process No. 0 is analyzed.
First of all, after a series of function calls, the 1th process stack has changed, the schematic diagram is as follows:

And then we start to analyze the process of switching back to process No. 0 from process # 1th.

Since the No. 0 process was run before, so its status is runnable, the dispatch process will enter the if branch of the My_schedule () method to execute the following code:

if (next->state = 0)/* 1 unrunnable, 0 runnable, >0 stopped/
    {//save current scene/
     * Switch to next proc ESS
     /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;//switch to the next task
     PRINTK (kern_notice "switch from%d process to%d PROCESS\N>>&G T;process%d running!!! <<<\n\n ", prev->pid,next->pid,next->pid);
  }

Main analysis of embedded assembly code

"PUSHL%%ebp\n\t"/* Save EBP/
"MOVL%%esp,%0\n\t"/* Save ESP * *

Implementation of the 1th process of running the stack environment to save, the specific approach is to put the current EBP into the stack, and then put the top of the stack pointer esp into the 1th process of TASK[1].THREAD.SP, after the implementation of the stack situation as shown:

"Movl%2,%%esp\n\t"/* Restore ESP * *

After this Assembly statement is executed, the stack that ESP refers to has changed, that is, the 1th process switch to the NO. 0 process, the process 0 of the THREAD.SP value to the ESP, because in the process from 0 to process 1 to save the value of the THREAD.SP, so this time the stack as shown:

    "Movl $1f,%1\n\t" * * Save EIP * * "
    PUSHL%3\n\t"

This two code is the same as the previous switch to achieve the same function, are for the next step of the preparation of the switch, after the stack as shown:

"ret\n\t" * * Restore EIP * *

This is the 1th process, which is called by the current process, My_schedule () will execute the last instruction, and subsequent statements will continue to execute the next time the process switches back to the 1th process. At this point the stack situation as shown:

At this time EIP and ESP have been switched back to the process 0 switch to the process 1 the last moment of the value, when the EIP continue to instructions, the resulting will be NO. 0 process last was switched off when the next instruction, as follows:

/* 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"/               * Process 0 here is switched away * *
        "POPL%%ebp\n\t" * Then you should execute this instruction/*: 
        "C" (Task[pid].thread.ip), "D" (TASK[PID].THREAD.SP)//   D mean%ecx/%edx*/< c15/>);

That means the following instructions are to be executed:

"Popl%%ebp\n\t"

The following stack scenario is shown below:

After that, the No. 0 process will follow the execution stream, complete the call to My_schedule (), and return the my_process () of the No. 0 process, followed by a continuous switch between process 0 and process 1.

Reference documents:
Https://github.com/mengning/mykernel/blob/master/mymain.c

Https://github.com/ExiaHan/linuxKernelStudy/blob/master/secondWeekend/processSwitch.md

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.