Linux 内核抢占

抢占的含义

抢占指的是强制使一个任务让出 CPU 给其他任务。

抢占是调度器做的,每次执行schedule()就可能发生一次抢占,所以 抢占发生的地点是内核,也就是schedule()的执行环境。

用户抢占

与内核抢占相对应的是用户抢占,用户抢占不是指抢占发生的地点,因为 上面说了抢占发生的地点一定是内核。

所以用户抢占的含义是:抢占的时机是用户态,换句话说就是抢占发生之前, 系统正处于用户态。

用户抢占的经典场景是时钟中断,用户进程 1 执行的好好地,被时钟中断打断 然后中断返回时执行重调度,选择了新的用户进程 2。其他的可能用户抢占的场景 还有系统调用返回时, 总之是内核返回用户态时都会发生用户抢占

内核抢占

启用内核抢占增加了系统中发生抢占的点,即抢占前系统正处于内核。

当一个进程正处于内核态执行任务时,比如执行mmap()系统调用的任务,在 未开启内核抢占的情况下,中断返回时只可能继续执行当前进程的任务,不会 发生调度。

当启用内核抢占时,上述情况下若发生中断,系统在退出中断后,即使此时不是 返回用户态,也可以执行schedule(),即可以发生抢占。此之谓内核抢占。

抢占发生的条件

启用内核抢占之后,其实抢占的过程也不区分用户态和内核态,只要满足条件都会 执行schedule()

执行重调度的条件有两个:

  1. 是否需要重调度?
  2. 是否可以重调度?

是否需要重调度也就是何时执行schedule()的问题,大概包含以下的场景:

  • 时钟中断
  • 新进程创建
  • 修改进程的 nice 值
  • 中断返回内核态
  • 内核恢复为可抢占(下面会介绍)

然而有一些情况不可以重新调度,比如内核中一些关键的步骤,那些不能被打断的 原子操作。

在关键步骤之前,需要调用preempt_disable(),此时 linux 会在 tcb 中会改变 preempt_count的值,这个操作不是关闭中断,而是在中断返回时即使有更高优先级的其他进程, 只要该值不符合要求,重调度也不会发生。

关键步骤执行完,调用preempt_enable(),此时为了去满足关键区域内可能 有新加入的高优先级进程,会调用一次重调度,这也正是上面所说需要重调度的场景之一。


创建于: 2023-04-13T23:51:49, Lastmod: 2023-09-24T18:08:59