第八章 进程的切换和系统的一般执行过程
进程调度的时机
- ntel定义的中断类型
- 硬中断:CPU的两根引脚(可屏蔽中断和不可屏蔽中断)。若是高电平,则有中断请求。
- 软中断:包括零错误、系统调用、调试断点等,在CPU执行指令过程中发生的各种特殊情况,也称为异常。异常可以分为3种:故障、退出、陷阱。
- 进程调度时机
- linux内核通过schedule函数实现进程调度,schedule函数在运行队列中找到一个进程。把CPU分配给他。每调用一次schedule函数就实现一次进程调度,调用schedule函数就是进程调度的时机。调用schedule函数:
- 进程主动调用:进程调用阻塞的系统调用等待外设或主动睡眠,最终会在内核中调用到schedule函数。
- 松散调用:内核代码中可以随时调用schedule函数使当前内核路径让出CPU;也会根据need_resched标记做进程调度,内核检测到need_resched决定是否调用schedule函数。
- 进程调度时机情况
- 用户进程通过特定的系统调用主动让出CPU;
- 中断处理程序在内核返回用户态时进行调度;
- 内核线程主动调用schedule函数让出CPU;
- 中断处理程序主动调用schedule函数让出CPU(包括以上两点)。
- CPU在任何时刻都处于以下3种情况之一:
- 运行于用户空间,执行用户进程上下文。
- 运行于内核空间,处于进程上下文。
- 运行于内核空间,处于中断上下文。
- linux内核通过schedule函数实现进程调度,schedule函数在运行队列中找到一个进程。把CPU分配给他。每调用一次schedule函数就实现一次进程调度,调用schedule函数就是进程调度的时机。调用schedule函数:
调度策略与算法
- 基本调度策略
- 实时进程的调度策略(优先级0~99,静态设定)
- SCHED_FIFO 先进先出
- SCHED_RR 轮转策略(时间片)
- 普通进程的调度类 —— SCHED_NORMAL,只有nice值,映射到优先级为100~139。按优先级占比计算占用CPU的时间。
- 实时进程的调度策略(优先级0~99,静态设定)
- CFS调度算法
- 调度周期:进程越多,周期越长;上限默认8ms;一个时间周期内队列的所有进程都会至少被调度一次。
__sched_period = nr_running(进程数)*sysctl_sched_min_granularity(默认值)
+ 理论运行时间:每次可获取CPU后最长可占用时间为ideal_runtime.
ideal_runtime = __sched_period * 进程权重/队列运行总权重
+ 虚拟运行时间:每个进程拥有一个vruntime,每次需要调度时就运行队列中拥有最小的vruntime的进程来运行,最长运行时间为ideal_runtime.
vruntime = 实际运行时间 * NICE_0_LOAD / 进程权重
= 实际运行时间 * 1024 / 进程权重
NICE_0_LOAD = 1024, 表示nice值为0的进程权重
+ 时钟中断周期:1/CONFIG_HZ秒
+ Linux传统优先级与权重的转化关系是经验值。
+ Linux采用红黑树来存储就绪进程指针,插入时根据vruntime排序,调度时选择最左边的即可。
进程上下文切换
- 为了控制进程的执行,内核必须有能力挂起正在CPU中运行的进程,并恢复执行以前挂起的进程,这个行为称为进程切换。
- 进程上下文包含了进程执行的所有信息:
- 用户地址空间:进程代码、数据和用户堆栈等
- 控制信息:进程描述符、内核堆栈
- 硬件上下文:存储相关寄存器的值
- 实际代码中进程切换由两个步骤组成:
- 切换页全局目录(RC3)以安装一个新的地址空间,这样不同的虚拟地址经过不同的页表转为不同的物理地址。
- 切换内核态堆栈和硬件上下文
Linux系统的构架
实验
cd LinuxKernel
rm menu -rf
git clone https://github.com/mengning/menu.git
cd menu
ls
make rootfs
cd..
qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img -S -s
gdb
file linux-3.18.6/vmlinux
target remote:1234
b schedule
b context_switch
b __switch_to
b pick_next_task
配置运行MenuOS系统
配置gdb远程调试和设置断点
使用gdb跟踪分析schedule()函数
执行程序,程序分别停在schedule函数、pick_next_task函数断点、context_switch处,查看代码: