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

《Linux内核分析》MOOC课程


大体上是在 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 unrunnable
1/设置%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,%esp
movl %2,%ebp
看来%esp和%ebp是一样的,都是next->thread.sp,都是stack[4095]
pushl %3
ret
修改了%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 %%ebp
movl %%esp,%0
movl $1f,%1 
//问题1:为什将 1f(即当前的%eip),这个数值 1f 保存到 prev->thread.ip 中?这个数值代表什么?

注意:

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值