2022-2023-1 20222813《Linux内核原理与分析》第九周作业

实验八:理解进程调度时机跟踪分析进程调度与进程切换的过程

实验内容:

1. 理解 Linux 系统中进程调度的时机,可以在内核代码中搜索 schedule()函数,看都是哪里调用了 schedule(),判断我们课程内容中的总结是否准确。
(1)进程调度的时机:

  • 中断处理过程直接调用schedule(),或者返回用户态时根据need_resched标记调用schedule()。
  • 内核线程是一个特殊的进程,只有内核态没有用户态,可以直接调用schedule()进行进程切换,也可以在中断处理过程中进行调度(内核线程可以直接访问内核函数,所以不会发生系统调用)。内核线程作为一类的特殊的进程可以主动调度,也可以被动调度。
  • 用户态进程无法实现主动调度,仅能在中断处理过程中进行调度(schedule是一个内核函数,不是一个系统调用)。

(2)挂起正在CPU上执行的进程,与中断时保存现场不同。中断前后是在同一个进程上下文中,只是由用户态转向内核态执行。进程上下文包含了进程执行需要的所有信息:

  • 用户地址空间:包括程序代码,数据,用户堆栈等
  • 控制信息:进程描述符,内核堆栈等
  • 硬件上下文

(3)schedule()函数选择一个新的进程来运行,并调用context_switch进行上下文的切换,context_switch中的一个关键宏switch_to来进行关键上下文切换。
(4)0到3G用户可以访问,3G以上只有内核态可以访问。所有进程3G以上都是完全共享的,比如进程X切换到进程Y,但是地址空间仍然是3G以上的部分,只是把进程描述符和其他的进程上下文切换了,只有在返回的时候才不同。哪一个进程都可以“招手”进入内核态,走了一段以后便可以返回到用户态,空车的时候就进入idle进程空转。

2.使用 gdb 跟踪分析一个 schedule()函数
启动内核,在shell1中执行如下命令,启动Menu:

cd LinuxKernel
rm menu -rf
git clone https://github.com/mengning/menu.git
cd menu
mv test_exec.c test.c
make rootfs

在这里插入图片描述
3.配置gdb
在shell1打开调试模式,并且在shell2中进行gdb调试
在这里插入图片描述
4.设置断点
schedule是进程调度的主体函数。在gdb模式下输入c,MenuOS运行至schedule函数处停下来

b schedule
b context_switch
b switch_to
b pick_next_task

在这里插入图片描述
在这里插入图片描述

5.查看内嵌汇编代码
switch_to为宏定义,不能设置断点,查看其内联汇编代码:

asm volatile(
             "pushfl\n\t"  //保存当前进程flags
             "pushl %%ebp\n\t"  //当前进程堆栈基址压栈
             "movl %%esp,%[prev_sp]\n\t"  //保存ESP,将当前堆栈栈顶保存起来
             "movl %[next_sp],%%esp\n\t"  //更新ESP,将下一栈顶保存到ESP中
                     // 完成内核堆栈的切换
             "movl $1f,%[prev_ip]\n\t"    //保存当前进程的EIP
             "pushl %[next_ip]\n\t"       //将next进程起点压入堆栈,即next进程的栈顶为起点
             __switch_canary              //next_ip一般为$1f,对于新创建的子进程是ret_from_fork      
             "jmp __switch_to\n"    //prve进程中,设置next进程堆栈,jmp与call不同,是通过寄存器传递参数(call通过堆栈),所以ret时弹出的是之前压入栈顶的next进程起点
             //完成EIP的切换
             "1:\t"            //next进程开始执行       
             "popl %%ebp\n\t"  //restore EBP
             "popfl\n"         //restore flags

             //输出量
             : [prev_sp] "=m" (prev->thread.sp),   //保存当前进程的esp
               [prev_ip] "=m" (prev->thread.ip),     //保存当前进仓的eip
               "=a" (last),

               //要破坏的寄存器
               "=b" (ebx), "=c" (ecx), "=d" (edx),
               "=S" (esi), "=D" (edi)

               __switch_canary_oparam

              //输入量
             : [next_sp]  "m" (next->thread.sp),   //next进程的内核堆栈栈顶地址,即esp
               [next_ip]  "m" (next->thread.ip),     //next进程的eip

               // regparm parameters for __switch_to(): 
               [prev]     "a" (prev),
               [next]     "d" (next)

               __switch_canary_iparam

             : //重新加载段寄存器
            "memory");

6.理解进程上下文的切换机制,以及与中断上下文切换的关系
一般来说,CPU在任何时刻都处于以下三种情况之一:
运行于用户空间,执行用户进程上下文。
运行于内核空间,处于进程上下文。
运行于内核空间,处理中断上下文。
应用程序通过系统调用陷入内核,或者当外部设备产生中断时,抬高CPU中断引脚电平,CPU就会调用相应的中断处理程序来处理该中(包括系统调用),此时CPU处于中断上下文。
中断上下文代表当前进程执行,所以中断上下文中的get_current可获取一个指向当前进程的指针,是指向被中断进程或即将运行的就绪进程的,相应的硬件上下文件切换信息也存储于该进程的内核堆校中。由于中新的级别不同,有不可屏蔽中断、可屏蔽中断、陷阱(系统调用)、异常等。为了整个系统的运行效率,中断上下文中调用其他内核代码有一定的限制。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值