linux系统内核流转浅析
生活随笔
收集整理的這篇文章主要介紹了
linux系统内核流转浅析
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
SJTUBEAR ?原創作品轉載請注明出處 《Linux內核分析》MOOC課程http://mooc.study.163.com/course/USTC-1000029000
?
我們通過簡單地內核來模擬一下linux的系統調度,代碼如下:
/** linux/mykernel/mymain.c** Kernel internal my_start_kernel** Copyright (C) 2013 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 int my_need_sched = 0;void my_process(void);void __init my_start_kernel(void) {int pid = 0;int i;/* 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 = (unsigned long)my_process;task[pid].thread.sp = (unsigned long)&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 = (unsigned long)&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];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*/); } void my_process(void) {int i = 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);} } }這是我們模擬kernel的主程序mymain.c/
linux啟動后,系統初始化完成,mymain.c開始運行。
通過將my_process的地址傳入結構體中的ip,再將ip壓棧后ret,將地址pop給eip,將系統引導至myprocess開始運行。
其中while1,保證kernel死循環。
每執行10000000次檢查全局變量my_need_sche,通過my_schedule()來進行進程的切換。
而對于my_need_sche的修改和my_schedule()函數具體的實現是在時鐘中斷中模擬進行的。
1 contributor RawBlameHistory 93 lines (86 sloc) 2.452 kb /** linux/mykernel/myinterrupt.c** Kernel internal my_timer_handler** Copyright (C) 2013 Mengning**/ #include <linux/types.h> #include <linux/string.h> #include <linux/ctype.h> #include <linux/tty.h> #include <linux/vmalloc.h>#include "mypcb.h"extern tPCB task[MAX_TASK_NUM]; extern tPCB * my_current_task; extern volatile int my_need_sched; volatile int time_count = 0;/** Called by timer interrupt.* it runs in the name of current running process,* so it use kernel stack of current running process*/ void my_timer_handler(void) { #if 1if(time_count%1000 == 0 && my_need_sched != 1){printk(KERN_NOTICE ">>>my_timer_handler here<<<\n");my_need_sched = 1;} time_count ++ ; #endifreturn; }void my_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 */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{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)); } return; }我們看到,每一千次中斷,就模擬切換一次進程。
通過對當前環境的保存以及建立新的堆棧,來完成對進程的切換。
?
實驗結果:
?
通過實驗結果我們可以得知,就是這樣通過使用堆棧,對進程的數據進行封存,并建立新的堆棧開啟新的進程的過程,使得進程可以自由的切換。
通過對ret指令,將下一條進程的eip首地址賦eip,完成進程的調度!
轉載于:https://www.cnblogs.com/sjtubear/p/4338427.html
總結
以上是生活随笔為你收集整理的linux系统内核流转浅析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 转 互联网推送服务原理:长连接+心跳机制
- 下一篇: CSUOJ 1525 Algebraic