【kernel】进程以及进程调度、进程管理
貌似只有硬件中断才是真正意义上的 异步,会在程序意想不到的位置发生,其他的机制诸如信号、系统调用、软中断等等,总是在某个 同步 的位置去处理他们
进程调度的时机
系统发生调度的时机如下:
-
调用cond_resched()时
-
显式调用schedule()时
-
从系统调用或者异常中断返回用户空间时
-
从中断上下文返回用户空间时
如果开启了内核抢占,那么会多出几个时机
- 在系统调用或者异常中断上下文中调用preempt_enable()时(多次调用preempt_enable()时,系统只会在最后一次调用时会调度)
- 在中断上下文中,从中断处理函数返回到可抢占的上下文时(这里是中断下半部,中断上半部实际上会关中断,而新的中断只会被登记,由于上半部处理很快,上半部处理完成后才会执行新的中断信号,这样就形成了中断可重入)
系统并不是每时每刻都允许调度的发生
当处于硬中断期间的时候,调度是被系统禁止的,之后硬中断过后才重新允许调度。而对于异常,系统并不会禁止调度,也就是在异常上下文中,系统是有可能发生调度的。
我们经常说到各种调度策略,FIFO、RR、CFS之类的,内核会根据不同的调度策略在发生进程切换的时候选择合适的下一个进程去运行
所以以上的算法策略以及使用,往往发生在有新进程就绪的时候(此时,将新进程根据进程分类、初始设置的优先级等等参数,根据对应的调度策略,在对应的调度类实体下的就绪队列排序和组织)
当系统在上述进程切换的timing,调度器往往会工作,并且在不同的rq(dl_rq、rt_rq、cfs_rq分别对应deadline进程就绪队列,实时进程就绪队列,普通进程队列)中选择一个进程,并通过context_switch切换到该进程的上下文,选择的顺序自然是dl-》rt-》cfs,比如dl类对应的进程队列为空,那么就从下一个里面去找。每一个进程队列的就绪进程都是排好序的,通过什么排的呢?就是通过我们的调度策略。
全局的pick_next_task函数会从按照优先级遍历所有调度器类的pick_next_task函数, 去查找即将运行的那个进程, 当然因为大多数情况下, 系统中全是CFS调度的非实时进程, 因而linux内核也有一些优化的策略
其执行流程如下:
如果当前cpu上所有的进程都是cfs调度的普通非实时进程, 则直接用cfs调度, 如果无程序可调度则调度idle进程
否则从优先级最高的调度器类sched_class_highest(目前是stop_sched_class)开始依次遍历所有调度器类的pick_next_task函数, 选择最优的那个进程执行
进程中所有的调度器类, 是通过next域链接域链接在一起的, 调度的顺序为 :stop -> dl -> rt -> fair -> idle
总结:当一个高优先级进程(比当前运行进程的优先级高)到达了,不会立即抢占当前进程,依旧要等到进程调度的timing,才会有机会执行