Linux内核分析-2/时间片轮转多道程序

来源:互联网 发布:网络黑白txt百度云盘 编辑:程序博客网 时间:2024/05/25 19:57

《Linux内核分析》MOOC课程

  • 课程采用了mykernel的代码进行讲解

  • git地址 : https://github.com/mengning/mykernel.git

  • 下面就是对mykernel代码的分析


大体上是在 start_kernel 中调用了 time_init,然后调用了my_start_kernel而在time_init中将my_timer_handler 作为处理时钟中断的函数,每1ms?调用一次?在my_start_kernel中建立了10个task结构体,并初始化,并形成了循环链表.然后将第一个task装载到进程中.装载的过程下面讲,然后就开始了A进程注意:每个进程的task结构体中的ip成员都是一样的,都是my_process函数的地址,所以不管是哪个进程,都是跑的my_process,虽然跑的指令一样,但是跑的数据不一样//此时内核所有的精力都在A进程中.除了偶尔接收一下时钟中断//设计的思路就在于在时钟中断的中断处理函数中.将A进程环境保存,装载B进程.然后B进程就在跑,内核所有的精力都在B进程,除了接收一下时钟中断.//所以,除了更底层的东西,我们需要关注的是1/装载一个进程(分为两种,一种是-1 unrunnable ,一种是0 runnable)2/保存一个进程环境(只有一种)我们可以在函数中看到,不管是装载进程,还是保存进程环境,都是用汇编写的所以我们要知道1/为什么要用汇编写这些东西    1/汇编写这些东西改变了3个寄存器,难道用C语言不能改变吗?可以,用fork和exec        1/之前装载一个进程是用fork和exec族,为什么不用fork和exec?            1/fork和exec是怎么实现的?2/内嵌汇编怎么写?请查阅 <AT&T汇编语言与GCC内嵌汇编简介>

装载一个进程

  • -1 unrunnable
//装载一个进程 -1 unrunnable1/设置%esp寄存器2/设置%ebp寄存器3/设置%eip寄存器//而在第0个进程中,是这么做的    pid = 0;    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*/            );  //一步一步分析movl %1,%esp//这个是将task[pid].thread.ip stack[4095]的地址放入 esp ,因为数组是往高处增长的,所以高处的地址更大.pushl %1//压栈,将esp的值压栈到stack[4094]位置//其实一般这个位置应该是 push %ebp ,但是写了push %1 ,所以就代表 %1 的值就是%ebp的值,这个是老的ebp的值pushl %0//压栈,将task[pid].thread.ip 即 my_process 的地址 压栈到stack[4093]位置ret//弹栈,将my_process的地址转入eip,并esp+4,此时esp指向stack[4094]下一步就应该执行my_process然而popl %ebp 这个什么时候做呢???//这个永远不会做//问题来了,既然%esp,%eip都设置了,那么%ebp呢?进程0中没有设置%ebp,是不是这样子?mykernel/myinterrupt.c中也有一个加载新进程的例子        /* 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)                );我把无关的注释掉了,movl %2,%espmovl %2,%ebp看来%esp和%ebp是一样的,都是next->thread.sp,都是stack[4095]pushl %3ret修改了%esp//可以看出来,这个mykernel/myinterrupt.c 是一个完整的修改  3个寄存器 的例子.但是之前的mymain.c没有修改%ebp
  • 0 runnable
        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)                );//这个是mykernel/myinterrupt.c中的例子,我把无关的注释掉了可以看到,这里面并没有修改%ebp,为什么呢?//这里虽然在栈顶,可是没有popl %ebp 得到 %ebp//所以下次调用函数的时候 或者 ret的时候第一句就要执行 pushl %ebp ,那么这个ebp 是多少呢? 是上一个环境的ebp????因为后面可以看到,对于runnable 进程,ebp被压栈了,所以ebp一直都在栈里面而且还多了一个 1: 和 popl %%ebp 为什么呢?1: 好像是个标号.
  • 可见上面加载一个unrunnable进程 和 runnable进程的区别主要是 在加载一个新进程的环境中 对 ebp的加载 有区别
  • 而且在装载0进程 和 装载 runnable 进程的时候,我认为 %ebp都有问题,是不是这样子???

保存一个进程环境

1/保存%esp寄存器2/保存%ebp寄存器3/保存%eip寄存器mykernel/myinterrupt.c中也有两个加载新进程的例子,本质其实一样,我把无关的注释了        /* 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)                );//可见ebp被堆栈了,且放到了栈顶,所以下次恢复的时候,直接popl %ebp 就可以了//esp 和eip被保存到task结构体里面了.pushl %%ebpmovl %%esp,%0movl $1f,%1 //问题1:为什将 1f(即当前的%eip),这个数值 1f 保存到 prev->thread.ip 中?这个数值代表什么?

注意:

//在系统中,中断是调度的前提条件,如果屏蔽了中断,那么就不会再有调度可见,调度时由定时器中断的中断处理函数做的.由此可见,该中断的优先级一定不能低,如果低了的话,被禁止了,那么就没有调度了
阅读全文
0 0
原创粉丝点击