Linux kernel Analysis: Complete a simple time slice rotation multi-channel program kernel code

Source: Internet
Author: User
Tags switches volatile

PS. He Bong Original works reproduced please specify the source "Linux kernel Analysis" MOOC course http://mooc.study.163.com/course/USTC-1000029000

1.mykernelExperimental Guidance (how the operating system works)

Use the lab building virtual machine to open the shell and enter the following code

    • 1 CD linuxkernel/linux-3.9.4
    • 2 Qemu-kernel Arch/x86/boot/bzimage

You can see the initial kernel running as follows:

The kernel is constantly executing my_start_kernel (), interrupted at intervals by My_timer_handler (), and executes a print statement: PRINTK (kern_notice "\n>>>>>> >>>>>>>>>>>my_timer_handler here<<<<<<<<<<< <<<<<<<\n\n ");

And then back to My_start_kernel () to continue execution.

Open the Mymain.c file and you can see that there is only one of the following functions. It acts as the starting position of the kernel startup, starting from this function and looping indefinitely.

Open the Myinterrupt.c file, there is only one my_timer_handler (), it is called periodically by the Linux kernel, resulting in a periodic interrupt mechanism.

2. Modify the kernel code so that it becomes a simple time slice and rotate the multi-channel program kernel and then recompile the run.

Download mypcb.h;mymain.c;myinterrupt.c from Https://github.com/mengning/mykernel;
Then replace the mymain.c;myinterrupt.c located in the home/shiyanlou/linuxkernel/linux-3.9.4/mykernel/;
Put the mypcb.h here, too.

Then execute make and recompile the kernel. The effect is as follows:

Then type again:

    • Qemu-kernel arch/x86/boot/bzimage Command

Boot the kernel. You can see that both the jump and the time slice have a noticeable change.

The experimental results were consistent with the expected results and the experiment was successful.

3. Key code Understanding

Mymain.c

Void__init My_start_kernel (void) {

Int pid = 0;

Int i;

/* Initialize Process 0*/

Task[pid].pid = pid;//task[0].pid=0;

Ask[pid].state = 0;/*-1 unrunnable, 0 runnable, >0 stopped * *

Task[pid].task_entry = Task[pid].thread.ip = (unsignedlong) my_process;// The entry address for process 0 is My_process ();

TASK[PID].THREAD.SP = (unsignedlong) &task[pid].stack[kernel_stack_size-1];//0 the stack top of the process is stack[] The last element of the array

Task[pid].next = &task[pid];//next pointer points to itself /*fork More Process * /

for (i=1;i<max_task_num;i++)// based on process number 0 , copy a few processes that are numbered differently

{

memcpy (&task[i],&task[0],sizeof (TPCB));//void *memcpy (void *dest, const void *SRC, size_t n); from the source src The starting position of the referred memory address begins copying N bytes to a target dest The starting position of the referred memory address.

Task[i].pid = i; Task[i].state = -1;//The status of these processes is set to not run.

TASK[I].THREAD.SP = (unsignedlong) &task[i].stack[KERNEL_STACK_SIZE-1]; Task[i].next = task[i-1].next;//The newly created process next points to the first address of process number 0

Task[i-1].next = &task[i];// Next of the previous process points to the first address of the newly created process, thus becoming a circular linked list.

Mypcb.h

#define MAX_TASK_NUM 4// max process number, set here for 4 .

#define KERNEL_STACK_SIZE 1024*8// the size of the kernel stack for each process.

/* Cpu-specific State of this task */

Structthread {unsignedlongip;// the EIP used to save the process

unsignedlongsp;// The user save process esp};

ID number of the typedefstructpcb{intpid;//process

Volatilelongstate; /* Status of Process:-1 unrunnable, 0 runnable, >0 stopped * /

the stack of charstack[kernel_stack_size];//processes has only one core stack. /* cpu-specific State of this task * /

Structthread thread;// Only one thread per process.

The starting entry address of the unsignedlongtask_entry;//process.

Myinterrupt.c

if (next->state = = 0)/* If the next process that will run is already running -1 unrunnable, 0 runnable, >0 stopped * /

{

/* Switch to Next process */

ASM volatile (

"PUSHL%%ebp\n\t"/* saves the current process's EBP to its own stack. Save EBP * /

"Movl%%esp,%0\n\t"/* saves the current process's ESP to its own stack. Save ESP * /

             "movl %2,%%esp\n\t"      /*  NEXT->THREAD.SP popped the next process esp restore  esp */

             "movl $1f,%1\n\t"        /*  eip set to 1f Span style= "font-family: the song Body;" > $1f Span style= "font-family: ' Times New Roman ';" > 1: SAVE&NBSP;EIP&NBSP;*/&NBSP;&NBSP;&NBSP;

"Pushl%3\n\t"/ * Presses the next->thread.ip into the stack of the current process. */

"Ret\n\t"/* pops the Next->thread.ip that was just pressed in from the stack of the current process .  Complete the process switch. Restore EIP * /

"1:\t"/* is The location pointed to by $1f. Next Process Start here * /

"Popl%%ebp\n\t"/* switch to the process to eject ebp from the stack to the ebp Register. correspond to the first sentence. */

: "=m" (PREV->THREAD.SP), "=m" (PREV->THREAD.IP)

: "M" (NEXT->THREAD.SP), "M" (NEXT->THREAD.IP)

);

My_current_task = Next; the current process switches to next

PRINTK (kern_notice ">>>switch%d to%d<<<\n", prev->pid,next->pid); Print Toggle Information

}

else// If the next process that is going to run has never been run.

{

Next->state = 0;// sets it to the running state.

My_current_task = next;//// The current process is switched to next

PRINTK (kern_notice ">>>switch%d to%d<<<\n", prev->pid,next->pid);// print switch information

/* 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"        /*  ip set to $1f Span style= "font-family: the song Body;" > Wait a minute. When it is switched back (must be running) it will definitely go to if Judging branch, which can be from the if 1 save eip */    

             "pushl %3\n\t"           /*  Span style= "font-family: ' Times New Roman ';" >next->thread.ip next->thread.ip my_process () */

*/* ret\n\t the next->thread.ip just pressed into the EIPtocomplete the process switch. Restore EIP * /

4. Analyze the start of the process and the switching mechanism of the process.

First, the kernel starts __init my_start_kernel (void), creates 4 processes, namely the 0,1,2,3 number, sets No. 0 as the running state, and the other 3 processes as non-running states.

The entrance to process No. 0 is initialized to Task[pid].task_entry = Task[pid].thread.ip = (unsigned long) my_process; that is, point to my_process ().
The stack top of process No. 0 is initialized to TASK[I].THREAD.SP = (unsigned long) &task[i].stack[KERNEL_STACK_SIZE-1];
Subsequent processes are also copied according to the number No. 0 process, so their starting entrance is also my_process (), and the top of the initial stack points to their own stack[kernel_stack_size-1];

My_current_task = &task[pid]; Sets the current process to process number No. 0. Then run from process No. 0.
"Movl%1,%%esp\n\t"
Put the stack top of process # No. 0 into the ESP register.
"PUSHL%1\n\t"/* Push EBP */
The current ESP points to the end of the stack array, which is also the top of the stack, because the stack is empty, so esp==ebp.
"PUSHL%0\n\t"/* Push TASK[PID].THREAD.IP */
"Ret\n\t"/* pop task[pid].thread.ip to EIP */
Switch to the entry address of process No. 0 to begin execution.
"Popl%%ebp\n\t"
This sentence is superfluous and will not be executed after Ret.
:
: "C" (Task[pid].thread.ip), "D" (TASK[PID].THREAD.SP)

After that, process No. 0 continues to execute my_process (). After some time, My_timer_handler () is called by the kernel, triggering interrupts, my_need_sched = 1, and setting the global variable my_need_sched to 1.

Thereafter, when the No. 0 process executes to the IF (my_need_sched = = 1), it enters the IF condition branch, executes the My_schedule (), and executes the process scheduler.

The next pointer to process number NO. 0 points to process number 1th, so the next pointer in My_schedule () points to process 1th, and the Prev pointer points to the process number No. 0.
Because the 1th process is not currently running, the else conditional branch is executed: next->state = 0;//Sets the 1th process to the running state.
My_current_task = next;//The current process switches to 1th process PRINTK (kern_notice ">>>switch%d to%d<<<\n", Prev->pid, NEXT->PID);//print switch 0 to 1
"PUSHL%%ebp\n\t"/* Save EBP */
"Movl%%esp,%0\n\t"/* Save ESP */
Save the EBP and ESP for process No. 0 to the stack on process # No. 0.
"Movl%2,%%esp\n\t"/* Restore ESP */
"Movl%2,%%ebp\n\t"/* Restore EBP */
Storing the value of the ESP stored in the 1th process structure in process 1th NEXT->THREAD.SP the ESP register and the EBP register, since the 1th process has not yet been run, esp still points to the stack[kernel_stack_size-1 of Stack 1th].
"Movl $1f,%1\n\t" sets the EIP for process No. 0 to If.
"Pushl%3\n\t"
"Ret\n\t"
The EIP of process 1th was added to the stack of process No. 0, and then the EIP was popped out of the No. 0 process stack via the RET instruction, which was deposited into the EIP register and the switch from process No. 0 to number 1th was completed. Similar thereafter.

5. An understanding of how the operating system works.

The operating system's kernel has a starting position, starting at this starting position. At the beginning of the work, the CPU is assigned to the first process, the first process is executed, and then through a certain scheduling algorithm, such as the time slice rotation, after a time slice, an interrupt occurs,

The first process is blocked, and the CPU is assigned to the next process after the save site is completed and the next process is executed. In this way, the operating system completes the basic process scheduling function.

Linux kernel Analysis: Complete a simple time slice rotation multi-channel program kernel code

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.