原创作品转载请注明出处 +《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000
一、实验要求
分析并理解Linux中进程调度与进程切换过程,仔细分析进程的调度时机、switch_to及对应的堆栈状态。需要总结并阐明自己对“Linux系统一般执行过程”的理解
二、实验内容
理解Linux系统中进程调度的时机,可以在内核代码中搜索schedule()函数,看都是哪里调用了schedule(),判断我们课程内容中的总结是否准确;
使用gdb跟踪分析一个schedule()函数 ,验证您对Linux系统进程调度与进程切换过程的理解。
- 特别关注并仔细分析switch_to中的汇编代码,理解进程上下文的切换机制,以及与中断上下文切换的关系;
三、实验环境
本地linux环境(ubuntu14.04 64bit)
主要优点:使用方便,方便保存,不受网络影响。
四、实验过程
1.打开shell终端,执行以下命令:
cd LinuxKernel
rm -rf menu
git clone https://github.com/mengning/menu.git
cd menu
mv test_exec.c test.c
make rootfs
2.通过增加-s -S启动参数打开调试模式
qemu -kernel ../linux-3.18.6/arch/x86/boot/bzImage -initrd ../rootfs.img -s -S
3.打开gdb进行远程调试
gdb
file ../linux-3.18.6/vmlinux
target remote:1234
4.设置断点
根据云课堂上的知识,这次我们主要通过调试跟踪linux内核中的schedule函数,进而分析linux系统进行进程调度和进程切换的过程。
运行MenuOS,设置3个断点:schedule、context_switch、switch_to。
b schedule
b context_switch
b switch_to
按c(/continue)后,模拟器继续运行,在第一个断点处停止,即schedule函数处,使用l(/list)命令查看其代码,s(/step)命令逐条分析。
继续运行,到第二个断点处停止了,即context_switch处停下。与上相同,继续单步执行。在这个过程中,要留心一下switch_to。
switch_to试了好几次都进不去,每次都是在中断点2和1之间进行跳转。
后来通过list查看代码发现, context_switch中调用了switch_to函数。
在该行添加了一个断点,停下的地方却是__switch_to函数。switch_to是个宏定义,在预处理阶段就把宏定义命令转换了,导致没办法调试到该断点。
五、代码分析
0.在switch_to函数中,通过嵌入如下的汇编代码实现进程上下文的切换以及与中断上下文的切换:
asm volatile("pushfl\n\t" /* 保存标志位 */
"pushl %%ebp\n\t" /* 保存 EBP */
"movl %%esp,%[prev_sp]\n\t" /* 保存 ESP */
"movl %[next_sp],%%esp\n\t" /* 恢复 ESP */
"movl $1f,%[prev_ip]\n\t" /* 保存 EIP */
"pushl %[next_ip]\n\t" /* 恢复 EIP */
__switch_canary
"jmp __switch_to\n" /* 跳转l */
"1:\t"
"popl %%ebp\n\t" /* 恢复 EBP */
"popfl\n" /* 恢复标志位*/
/* output parameters */
: [prev_sp] "=m" (prev->thread.sp),
[prev_ip]