从用户模式切换时,非抢占和抢占内核有什么区别?

5
我正在阅读《深入理解Linux内核(第三版)》的第5章“内核可抢占”,其中有这样一句话:
所有进程切换都是通过switch_to宏完成的。在不可抢占和可抢占内核中,当一个进程完成了内核活动的某个线程并调用了调度程序时,进程就会发生切换。然而,在不可抢占内核中,除非当前进程即将切换到用户模式,否则不能替换当前进程。
我仍然没有看出非抢占和可抢占内核之间的区别,因为无论如何,您都需要等待当前进程切换到用户模式。
假设有一个进程p在内核模式下运行,并且其时间片到期,然后调用scheduler_tick()函数,该函数设置p的NEED_RESCHED标志。但只有当p切换到用户模式时才会调用schedule()(对吗?)。
那么如果p永远不切换到用户模式怎么办?
如果它切换到用户模式,但在scheduler_tick()设置NEED_RESCHED标志和p实际切换到用户模式之间花费了很长时间,则超过了它的时间片吗?

当你说“永远不要切换到用户模式”时,你想到了什么?一个进程长时间运行在内核模式下的情况是不太可能的,因为它要么被阻塞或处于等待状态,要么只运行短暂的时间(或者内核设计得很糟糕)。 - Jean-Baptiste Yunès
@nos只是设置一个标志,不会调用schedule()函数。 - Mano Mini
@ManoMini,很多地方都要检查那个标志。 - nos
@nos "除非当前进程即将切换到用户模式,否则无法替换当前进程" - Mano Mini
@ManoMini 这里是一个地方 http://lxr.free-electrons.com/source/fs/eventfd.c#L247 ,这里是另一个地方 http://lxr.free-electrons.com/source/lib/klist.c#L256 ,如果你四处看看,开发人员已经找到了许多适合调用schedule()的地方。另请参见 https://kernelnewbies.org/FAQ/Preemption 和 http://matroid.org/resources/KernelPreemption/PreemptiveKernel_v1.1_no_background.pdf。 - nos
显示剩余3条评论
2个回答

2
在非抢占式内核中,schedule()会在返回用户空间时调用(以及任何系统调用阻塞的地方,也包括空闲任务)。
在抢占式内核中,schedule()会在从任何中断返回时调用,在一些其他地方也会调用,例如在mutex_unlock()慢速路径上,在接收网络数据包时的某些条件下等等。
举个例子,假设有一个进程A发出一个被设备生成的中断打断的系统调用,然后被一个计时器中断打断:
 process A userspace → process A kernelspace → device ISR → timer ISR
                  syscall               device IRQ    timer IRQ

当定时器ISR结束时,它返回到另一个ISR,然后返回到内核空间,然后返回到用户空间。抢占式内核在每次返回时检查是否需要重新调度进程。非抢占式内核只在返回到用户空间时进行该检查。


-1

有两种切换进程的方式:

  1. 进程让出CPU;或者
  2. 操作系统告诉进程“你现在完成了”。

第一种情况发生在进程执行某些不允许它继续执行的操作时。例如,执行SLEEP类型的函数或执行I/O(例如,向磁盘或终端输出并等待用户响应)。

第二种情况发生在操作系统的内部定时器触发时,作为处理定时器中断的一部分,操作系统确定另一个进程应该运行。

只处理第一种上下文切换类型的内核是非抢占式的。同时处理两种上下文切换类型的内核是抢占式的。

请注意,让出需要执行系统服务。这需要触发异常以调用内核模式系统服务处理程序。

抢占需要中断。在大多数非英特尔系统上,异常和中断的处理方式相同(英特尔提供了多种处理异常的方式)。在大多数系统上,从中断和异常返回的过程是相同的。

在两种情况下,上下文切换都发生在进程返回到用户模式之前。当进程恢复执行时,它首先要做的就是从内核模式返回到用户模式。

然而,在非抢占内核中,当前进程除非即将切换到用户模式,否则无法被替换。
这是一个定性的陈述。正常的让出序列如下:
1. 触发异常 2. 进入内核模式 3. 调度到系统服务处理程序 4. 做一些事情 5. 告诉操作系统要让出CPU。 6. 上下文切换 7. 一些事件发生,告诉操作系统该进程可以再次运行。 8. 操作系统在内核模式下恢复进程。 9. 进程退出内核模式 10. 进程在用户模式下继续运行。
书中的说法是在第7步和第8步之间没有或者很少发生任何事情。这通常是正确的,但系统服务可能会在那里放更多的工作。只是通常不会发生。

Linux一直以来都可以处理你所描述的两种进程切换方式。但在相对较远的过去(v 2.5.4之前),在内核代码中执行的Linux进程除了在内核中的一个特定代码路径外,无法被抢占(被调度程序替换)-人们称之为非抢占内核,以区别于补丁(和当前Linux工作方式)使内核能够在进程执行内核代码时的许多其他点上抢占进程。 - nos
这是显式地让出CPU。 - user3344003

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接