博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Linux内核分析-2/时间片轮转多道程序
阅读量:4284 次
发布时间:2019-05-27

本文共 4234 字,大约阅读时间需要 14 分钟。

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

  • 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/内嵌汇编怎么写?请查阅 

装载一个进程

  • -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 中?这个数值代表什么?

注意:

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

转载地址:http://mtigi.baihongyu.com/

你可能感兴趣的文章
重要重要》》》》》springcloud fegin的基本使用,实现consumer通过fegin访问provider!!!!!
查看>>
spring cloud 远程仓库配置文件(yml或properties)中有server.port参数就无法访问,这是一个大坑吗?
查看>>
es 2.3.3 向es添加数据报NoNodeAvailableException[None of the configured nodes are available
查看>>
springboot 的@RequestBody JSONObject 与@RequestBody Object 的区别
查看>>
springboot pom文件设置<packaging>pom</packaging> 对于application.yml无法加载读取的问题
查看>>
springboot加载resouce下面的静态文件,templates目录的访问,以及经过controller后跳转页面问题
查看>>
shiro的通过md5+salt+hash散列进行注册操作
查看>>
springboot整合applicationContext实现上下文获取实例bean
查看>>
shiro目前问题记录
查看>>
shiro实现本地内存Ehcache实现将菜单权限进行缓存
查看>>
shiro使用redis实现将菜单权限进行缓存
查看>>
cmd窗口下执行jar包 logger.info输出乱码,out语句输出正常解决办法
查看>>
springboot启动初始化实例,后面进行使用
查看>>
shiro实现加载验证码
查看>>
springboot 搭建多模块调用以及打包执行
查看>>
shiro实现不使用密码加密器进行登录
查看>>
权限管理系统笔记
查看>>
java8 新特性 拼接字符串
查看>>
springboot中mybaits自动返回新增数据的主键
查看>>
shiro的使用freemark实现前端控制权限
查看>>