刘森林 原创作品转载请注明出处 《Linux内核分析》MOOC课程
打开终端中输入qemu –kernel linux-3.18.6/arch/x86/boot/bzImage –initrd rootfs.img –S –s
然后打开另一个终端输入
gdb
(gdb)file linux-3.18.6/vmlinux
(gdb)target remote:1234
(gdb)b schedule
(gdb)c
进行调试跟踪schedule的执行过程。
进程调度时,首先进入schedule()函数,将一个task_struct结构体的指针tsk赋值为当前进程。
然后调用sched_submit_work(tsk)
我们进入这个函数,查看一下做了什么工作
我们在执行到sched_submit_work时,输入si进入函数。
可以看到这个函数时检测tsk->state是否为0 (runnable)若为运行态时则返回,
tsk_is_pi_blocked(tsk),检测tsk的死锁检测器是否为空,若非空的话就return。
然后检测是否需要刷新plug队列,用来避免死锁。
sched_submit_work主要是来避免死锁。
然后我们进入__schedule()函数。
__schedule()是切换进程的真正代码,我们来分析一下具体的关键代码
- 1.创建一些局部变量
struct task_struct *prev, *next;//当前进程和一下个进程的进程结构体
unsigned long *switch_count;//进程切换次数
struct rq *rq;//就绪队列
int cpu;
- 2.关闭内核抢占,初始化一部分变量
need_resched:
preempt_disable();//关闭内核抢占
cpu = smp_processor_id();
rq = cpu_rq(cpu);//与CPU相关的runqueue保存在rq中
rcu_note_context_switch(cpu);
prev = rq->curr;//将runqueue当前的值赋给prev
- 3.选择next进程