Linux内核分析——操作系统是如何工作的
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux内核分析——操作系统是如何工作的相关的知识,希望对你有一定的参考价值。
姓名:王晨光
学号:20133232
王晨光+原创作品转载请注明出处+《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000
一、进程的启动和切换源代码及分析
typedef struct PCB用于表示定义了一个进程,定义了进程管理相关的数据结构。同时也设置了用于保存EIP和ESP的数据类型。
下列代码为mymain.c部分代码:
void __init my_start_kernel(void) { int pid = 0; int i; task[pid].pid = pid;/*将进程号初始化为0*/ task[pid].state = 0; task[pid].task_entry = task[pid].thread.ip = (unsigned long)my_process; /*把进程的入口和eip都初始化为my_process函数的入口地址*/ task[pid].thread.sp = (unsigned long)&task[pid].stack[KERNEL_STACK_SIZE-1]; /*将堆栈的栈顶地址保存为栈的最后一个元素,即最高的地址*/ task[pid].next = &task[pid]; /*next指针指向自己*/ for(i=1;i<MAX_TASK_NUM;i++) { memcpy(&task[i],&task[0],sizeof(tPCB)); /*将task[0]的信息全部复制到各个新进程中*/ task[i].pid = i;/*将新进程的pid设置为变量i*/ task[i].state = -1;/*新进程的状态为unrunnable*/ 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];//将当前进程设置为0号进程 asm volatile( /*把0号进程的esp放入esp寄存器*/ "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*/ ); }
系统总是从0号进程开始启动。以上代码完成的任务主要是初始化进程,然后开始执行第一个进程,执行完RET操作之后将会跳转到下一个函数中执行。
一下代码为myinterrupt.c部分代码:
void my_timer_handler(void) { #if 1 /*函数每执行1000次,并且my_need_sched不等于1的时候执行if判断,然后把my_need_sched置为1*/ if(time_count%1000 == 0 && my_need_sched != 1) { printk(KERN_NOTICE ">>>my_timer_handler here<<<\n"); my_need_sched = 1; } time_count ++ ; #endif return; } 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; }
这段代码中,my_schedule函数是重点,它实现了时间片轮转的中断处理过程。这个函数分两次执行,第一次是0号进程跳转到1号进程,而第二次进入则是执行pop1 ebp恢复现场,然后return函数,返回到原调用者也就是0号进程的process里面。
二、实验过程
在实验楼中运用搭建好的环境打开文件
运行的程序
mymain.c程序代码
myinterrupt.c程序代码
实验总结:实验过程中源代码中的很多行代码看不懂,通过百度、观看视频有了一定的了解,也大致了解了操作系统是如何工作的。我们可以认为一个进程相当于一个堆栈,每个进程有自己的堆栈空间。如果将ebp和esp修改为另一个进程的ebp和esp,就可以完成进程的切换。当进程切换时,系统也会保存当前的工作状态,以便于下次恢复进程,使进程继续执行。
以上是关于Linux内核分析——操作系统是如何工作的的主要内容,如果未能解决你的问题,请参考以下文章
linux内核分析作业:操作系统是如何工作的进行:完成一个简单的时间片轮转多道程序内核代码