Linux调度分析(6)调度core之调度时机
为了提供系统的利用率,在某个线程由于资源或条件没有达到时,通常会选择让其让出CPU,让其他的线程运行,这个过程成为调度过程。
线程被调度的时机有如下情况:
(1)进程主动调用schedule()函数;
(2)周期性调度,抢占当前进程,强迫当前进程让出处理器;
(3)唤醒进程的时候,被唤醒的进程可能抢占当前进程;
(4)创建新进程的时候,新进程可能抢占当前进程;
(5)若内核支持抢占,内核增加一些抢占点;
其中情况(1)和(5)会直接进行真正的调度,而情况(2)(3)(4)仅设置抢占标志,待特定时刻(如系统调用从内核态返回用户态,抢占内核中断返回)重新进行调度。
主动调度
进程在用户模式下运行时,无法直接调用schedule()函数,只能通过系统调用进入内核模式,如果系统调用需要等待某个资源,例如互斥锁或信号量,就会将当前进程设置为睡眠状态,然后调用schedule()函数来调度进程。
进程也可以通过系统调用sched_yield()让出处理器,这种情况下进程不会睡眠。
在内核中有以下3种主动调度方式:
(1)直接调用schedule()函数来调度进程;
(2)调用有条件重调度函数cond_resched()。在非抢占式内核中,函数cond_resched()判断当前进程是否设置了需要重新调度标志,若已设置,作进程调度;在抢占式内核中,函数cond_resched()是空函数,没有作用;
(3)如果需要等待某个资源,例如互斥锁或信号量,那么将进程的状态设置为睡眠状态,然后调用schedule()函数以调度进程;
周期调度
内核中时钟中断会检查当前进程的执行时间有没有超过时限,若超过时限,设置需要重新调度的标志。当时钟中断完成中断处理程序后,需要将处理器重新还给被打断的进程,这时如果被打断的进程在用户模式下运行时,需要检查有没有设置需要重新调度的标志,如果已设置,调用schedule()调度进程。
周期调度的函数是scheduler_tick(),它调用当前进程所属的调度类task_tick方式。如果需要重新调度,需要为当前进程的thread_info结构体的成员flags设置重新调度的标志(_TIF_NEED_RESCHED),中断处理程序在返回用户态时会检查这个标志位。

其中在调度时钟中断通过不同的调度类sched_class->task_tick()调用resched_curr()设置调度标志,在特定时机调用schedule()进行调度。
唤醒过程中的调度
在唤醒某个线程时,被唤醒的进程可能会抢占当前进程。如下图所示,在wake_up_process()中,它会调用wakeup_preempt()最终调用调度类sched_class->wakeup_preempt()检查是否抢占当前线程。

创建新线程时调度
创建新进程时新进程可能抢占当前进程。

内核抢占点调度
当内核使能抢占时除了上述抢占时机外,内核增加其它一些抢占点:
(1)调用preempt_enable()开启抢占的时候

(2)开启软中断时抢占,在调用local_bh_enale()是开启软中断的时候,如果抢占计数变成0时,并且已为当前进程设置了重新调度标志,那么执行抢占调度。

(3)释放自旋锁时抢占,在调用spin_lock()释放自旋锁时,调用函数preempt_enable()开启抢占,如果抢占计数变成0且已为当前进程设置了重新调度标志,那么执行抢占调度。

(4)中断处理程序返回内核模式时抢占,如果进程运行在内核态时,中断入口函数为el1h_64_irq_handle()。中断处理程序执行完以后,如果进程的抢占计数器为0且设置了重新调度的标志则调用preempt_schedule_irq()执行抢占。

真正执行调度的时机
上述描述的5中调度情况中,情况(1)(5)最终直接调用schedule(),属于直接调用;而情况(2)(3)(4)则调用resched_curr()设置调度标志,真正执行调度的发生在系统调用从内核态返回用户态或中断返回用户态时。
先可以看一下resched_curr()是如何设置调度标志的:

- 检查是否已经设置TIF_NEED_RESCHED,若已经设置直接返回;
- 检查被调度到的CPU为当前CPU时,设置TIF_NEED_RESCHED调度标志;
- 若需要被调度的CPU非当前CPU时,发送IPI中断到被调度的CPU,在中断返回时执行真正的调度。
接下来看如何在系统调用或中断返回时是如何执行调度的,这里以中断返回用户态为例:
![image]()
当进程在用户模式下被中断抢占时,中断处理程序入口是el0t_64_irq_handler()。在中断返回用户态之前它会检查TIF_NEED_RESCHED标志,若已设置则进行schedule()。


浙公网安备 33010602011771号