为什么在Linux中每个进程都要保留一个内核栈?

6

在Linux中,为什么要为每个进程保留不同的内核栈?

为什么不只保留一个栈供内核使用呢?


1
这个问题:https://dev59.com/-XNA5IYBdhLWcg3wn_bD 有一些相关信息。 - Innot Kauker
2个回答

5
在Linux中为每个进程保留不同的内核栈有什么意义呢?这简化了内核空间中进程抢占的过程。
为什么不只保留一个内核栈供内核使用呢?如果没有单独的栈,进行抢占将会是一场噩梦。
分离的内核栈并非必须。每种架构都可以自由地做出决定。如果在系统调用期间没有抢占,则单个内核栈可能是有意义的。
然而,*nix有进程,每个进程都可以进行系统调用。但是,在Linux中,允许一个任务在write()等操作期间被抢占,并且另一个任务进行调度。内核栈是正在为每个进程执行的内核工作上下文的快照。
此外,每个进程的内核栈几乎没有开销。需要一个thread_info或某种机制从汇编器中获取进程信息。这至少需要一页分配。通过将内核模式栈放置在相同位置,可以使用简单的掩码从汇编器中获取thread_info。因此,我们已经需要每个进程的变量和分配。为什么不将其用作存储内核上下文的堆栈,并允许在系统调用期间进行抢占呢?
通过上述提到的write,抢占的效率可以得到证明。如果write()是写入磁盘或网络,则需要一段时间才能完成。将5k到8k的缓冲区写入磁盘或网络将需要许多CPU周期才能完成(如果同步),并且用户进程将阻塞直到完成。在驱动程序中,这种传输可以使用DMA完成。在此期间,较低优先级的进程可以拥有CPU,并允许内核为每个进程保留不同的栈,以便在系统调用时进行抢占。这些堆栈几乎没有成本,因为内核已经需要为进程状态进行簿记,并且两者都保存在4k或8k页面中。

最后的示例展示了线程或进程的I/O并发性。微内核将驱动程序作为任务(进程),并且通信将在用户任务和驱动程序任务之间发生。驱动程序将在DMA操作期间“yield”,然后内核可以安排一些其他非阻塞任务。Linux不是微内核,驱动程序在内核空间中实现。没有堆栈,很难实现线程I/O并发性。想想Web服务器或数据库等一些示例,了解为什么I/O并发性很好。 - artless noise
我忽略了一个最终事实:大多数架构都有分段寄存器,这些寄存器在不同的处理器模式下处于活动状态。例如,用户与监管员堆栈指针。在内核空间中进行上下文切换的管理仅涉及切换监管员堆栈指针。分段堆栈位于内核可访问的内存中,并使用简单的遮罩检索“线程信息”。缺点是内核堆栈溢出将覆盖“线程信息”。 - artless noise

1

为什么不只为内核保留一个堆栈?

这样,每次只有一个进程/线程能够进入内核。

基本上,每个线程都有自己的堆栈,在用户空间和内核边界之间切换并不会改变这个事实。内核也有自己的内核线程(不属于任何用户空间进程),它们都有自己的堆栈。


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