Sjtubear Original works reproduced please specify the source "Linux kernel Analysis" MOOC course http://mooc.study.163.com/course/USTC-1000029000
We can simulate the Linux system scheduling by simply the kernel, the code is as follows:
/** LINUX/MYKERNEL/MYMAIN.C * * Kernel Internal My_start_kernel * * Copyright (c) mengning **/#include<linux/types.h>#include<linux/string.h>#include<linux/ctype.h>#include<linux/tty.h>#include<linux/vmalloc.h>#include"Mypcb.h"TPCB TASK[MAX_TASK_NUM];TPCB* My_current_task =NULL;volatile intmy_need_sched =0;voidMy_process (void);void__init My_start_kernel (void){ intPID =0; inti; /*Initialize Process 0*/Task[pid].pid=pid; Task[pid].state=0;/*-1 unrunnable, 0 runnable, >0 stopped*/Task[pid].task_entry= Task[pid].thread.ip = (unsignedLong) my_process; TASK[PID].THREAD.SP= (unsignedLong) &task[pid].stack[kernel_stack_size-1]; Task[pid].next= &Task[pid]; /*Fork More Process*/ for(i=1; i<max_task_num;i++) {memcpy (&task[i],&task[0],sizeof(TPCB)); Task[i].pid=i; Task[i].state= -1; TASK[I].THREAD.SP= (unsignedLong) &task[i].stack[kernel_stack_size-1]; Task[i].next= task[i-1].next; Task[i-1].next = &Task[i]; } /*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*/ );} voidMy_process (void){ inti =0; while(1) {i++; 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; My_schedule (); } PRINTK (Kern_notice"This is process%d +\n",my_current_task->pid); } }}
This is our main program for simulating kernel mymain.c/
After the Linux boot, the system initialization is complete and MYMAIN.C starts to run.
By passing the address of the my_process to the IP in the struct, and then the IP stack after ret, the address POPs to the EIP, booting the system to myprocess to start running.
Which while1, to ensure that kernel die cycle.
The global variable My_need_sche is checked every 10 million times, and the process is switched through My_schedule ().
The implementation of the My_need_sche Modification and my_schedule () function is simulated in the clock interrupt.
1contributorrawblamehistory theLines ( theSloc2.452KB/** LINUX/MYKERNEL/MYINTERRUPT.C * * Kernel Internal My_timer_handler * * Copyright (c) mengning **/#include<linux/types.h>#include<linux/string.h>#include<linux/ctype.h>#include<linux/tty.h>#include<linux/vmalloc.h>#include"Mypcb.h"externTPCB Task[max_task_num];externTPCB *My_current_task;extern volatile intmy_need_sched;volatile intTime_count =0;/** Called by timer interrupt. * It runs with the name of the current running process, * so it use kernel stacks of current R Unning Process*/voidMy_timer_handler (void){#if1if(time_count% +==0&& my_need_sched! =1) {PRINTK (Kern_notice">>>my_timer_handler here<<<\n"); My_need_sched=1; } Time_count++ ; #endif return; }voidMy_schedule (void) {TPCB*Next; TPCB*prev; if(My_current_task = =NULL|| My_current_task->next = =NULL) { return; } PRINTK (Kern_notice">>>my_schedule<<<\n"); /*Schedule*/Next= my_current_task->Next; Prev=My_current_task; 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); } 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)); } return; }
We see that every 1000 interrupts, the simulation switches one process at a time.
The transition to the process is accomplished by saving the current environment and creating a new stack.
Experimental results:
We can learn from the experimental results that this is how the process can be switched freely by using the stack, storing the process data, and creating a new stack to open a new process.
By the RET instruction, the next process of the EIP first address to the EIP to complete the process of scheduling!
Analysis of kernel flow in Linux system