内核栈和用户栈有什么区别?为什么使用内核堆栈?如果在 ISR 中声明了局部变量,它将存储在哪里?每个进程都有自己的内核堆栈吗?那么进程如何在这两个堆栈之间进行协调?
最佳答案
- What's the difference between kernel stack and user stack ?
简而言之,没什么——除了在内存中使用不同的位置(因此堆栈指针寄存器的值不同),以及通常不同的内存访问保护。 IE。在用户模式下执行时,即使映射,内核内存(其中一部分是内核堆栈)也将不可访问。反之亦然,如果内核代码没有明确请求(在 Linux 中,通过 copy_from_user()
等函数),用户内存(包括用户堆栈)通常不能直接访问。
- Why is [ a separate ] kernel stack used ?
权限和安全性分离。其一,用户空间程序可以使他们的堆栈(指针)成为他们想要的任何东西,而且通常甚至没有有效的架构要求。因此,内核不能相信用户空间堆栈指针是有效的或可用的,因此将需要一组在它自己的控制下。不同的 CPU 架构以不同的方式实现这一点;当发生特权模式切换时,x86 CPU 会自动切换堆栈指针,并且用于不同特权级别的值是可配置的 - 通过特权代码(即仅内核)。
- If a local variable is declared in an ISR, where will it be stored ?
在内核堆栈上。内核(即 Linux 内核)不将 ISR 直接挂接到 x86 架构的中断门,而是将中断调度委托(delegate)给一个通用的内核中断进入/退出机制,该机制在调用已注册的处理程序之前保存中断前寄存器状态。调度中断时,CPU 本身可能会执行特权和/或堆栈切换,这是由内核使用/设置的,因此公共(public)中断入口代码已经可以依赖于存在的内核堆栈。
也就是说,在执行内核代码时发生的中断将简单地(继续)使用此时的内核堆栈。如果中断处理程序具有深层嵌套的调用路径,这会导致堆栈溢出(如果深层内核调用路径被中断并且处理程序导致另一个深层路径;在 Linux 中,文件系统/软件 RAID 代码被 iptables 事件的网络代码中断是已知会在未调整的旧内核中触发此类......解决方案是增加此类工作负载的内核堆栈大小)。
- Does each process have its own kernel stack ?
不仅仅是每个进程——每个线程 都有自己的内核栈(事实上,还有自己的用户栈)。请记住,进程和线程(对于 Linux)之间的唯一区别是多个线程可以共享一个地址空间(形成一个进程)。
- How does the process coordinate between both these stacks ?
一点也不——不需要。调度(如何/何时运行不同的线程,如何保存和恢复它们的状态)是操作系统的任务,进程不需要关心这个。随着线程的创建(每个进程必须至少有一个线程),内核为它们创建内核堆栈,而用户空间堆栈要么由用于创建线程的任何机制显式创建/提供(函数如 makecontext ()
或 pthread_create()
允许调用者指定一个内存区域用于“子”线程的堆栈),或继承(通过按访问内存克隆,通常称为“写时复制”/COW,在创建新进程时)。
也就是说,进程可以影响其线程的调度和/或影响上下文(状态,其中包括线程的堆栈指针)。有多种方法:UNIX 信号、setcontext()
、pthread_yield()
/pthread_cancel()
,... - 但这是有点偏离原来的问题。
关于linux - 内核栈和用户空间栈,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54248326/