内核堆栈和用户空间堆栈

内核堆栈和用户堆栈的区别是什么?为什么使用内核堆栈?如果在 ISR 中声明了一个局部变量,它将被存储在哪里?每个进程都有自己的内核堆栈吗?那么这两个堆栈之间的进程如何协调呢?

65980 次浏览
  1. 内核堆栈和用户堆栈的区别是什么?

简而言之,除了在内存中使用不同的位置(因此堆栈指针寄存器的值也不同) ,以及通常不同的内存访问保护之外,什么也没有。也就是说,在用户模式下执行时,即使映射也不能访问内核内存(其中一部分是内核堆栈)。反之亦然,如果没有内核代码的明确请求(在 Linux 中,通过像 copy_from_user()这样的函数) ,用户内存(包括用户堆栈)通常不能直接访问。

  1. 为什么使用[一个单独的]内核堆栈?

特权与安全的分离。首先,用户空间程序可以使它们的堆栈(指针)任何他们想要的东西,并且通常没有架构需求甚至有一个有效的。内核因此不能 信任用户空间堆栈指针是有效的或可用的,因此将需要一个在自己控制下的集合。不同的 CPU 体系结构以不同的方式实现这一点; 当特权模式切换发生时,x86 CPU 自动切换堆栈指针,并且用于不同特权级别的值是可配置的——通过特权代码(即只有内核)。

  1. 如果在 ISR 中声明了一个局部变量,它将存储在哪里?

在内核堆栈上。内核(即 Linux 内核)执行 没有将 ISR 直接挂钩到 x86体系结构的 打断闸门,而是将中断分派委托给一个通用的内核中断进入/退出机制,该机制在调用注册处理程序之前保存预中断寄存器状态。当分派一个中断时,CPU 本身可能会执行一个特权和/或堆栈切换,这是由内核使用/设置的,因此公共中断条目代码已经可以依赖于存在的内核堆栈。
也就是说,在执行内核代码时发生的中断将只是(继续)使用此时的内核堆栈。如果中断处理程序具有深度嵌套的调用路径,这可能导致堆栈溢出(如果深度内核调用路径被中断,处理程序导致另一个深度路径; 在 Linux 中,使用 iptables 活动的网络代码中断文件系统/软件 RAID 代码,已知会在未调优的旧内核中触发这种情况... ... 解决方案是为这种工作负载增加内核堆栈大小)。

  1. 每个进程都有自己的内核堆栈吗?

不仅仅是每个进程——每个 线都有自己的内核堆栈(实际上,还有自己的用户堆栈)。请记住,进程和线程(对于 Linux)之间的唯一区别是,多个线程可以共享一个地址空间(形成一个进程)。

  1. 流程如何在这两个堆栈之间进行协调?

一点也不,不需要。调度(如何/何时运行不同的线程,如何保存和恢复它们的状态)是操作系统的任务,进程不需要关心这些。当创建线程时(每个进程必须至少有一个线程) ,内核为它们创建内核堆栈,而用户空间堆栈要么显式创建/由用于创建线程的任何机制提供(类似 makecontext()pthread_create()的函数允许调用者指定用于“子”线程堆栈的内存区域) ,要么继承(通过访问内存克隆,在创建新进程时通常称为“写入时复制”/COW)。
也就是说,进程 可以影响其线程的调度和/或影响 背景(状态,其中包括线程的堆栈指针)。有多种方法可以解决这个问题: UNIX 信号、 setcontext()pthread_yield()/pthread_cancel(),...-但是这有点偏离了最初的问题。

我的答案是从其他所以问题收集与我的东西。

What's the difference between kernel stack and user stack?

作为一个内核程序员,您知道内核应该受到错误用户程序的限制。假设对于内核和用户空间保持相同的堆栈,那么用户应用程序中的简单 Segfault 会导致内核崩溃,并且需要重新启动。

每个 CPU 有一个“内核堆栈”,比如 ISR 堆栈,每个进程有一个“内核堆栈”。每个进程都有一个“用户堆栈”,尽管每个线程都有自己的堆栈,包括用户线程和内核线程。

Http://linux.derkeiler.com/mailing-lists/kernel/2004-10/3194.html

Why kernel stack is used?

因此,当我们处于内核模式时,堆栈类型的机制对于处理函数调用(类似于用户空间的局部变量)是必要的。

Http://www.kernel.org/doc/documentation/x86/kernel-stacks

If a local variable is declared in an ISR, where it will be stored?

它将存储在 ISR 堆栈(IRQSTACKSIZE)中。只有在硬件支持的情况下,ISR 才能在单独的中断堆栈上运行。否则,ISR 堆栈帧将被推送到中断线程的堆栈上。

用户空间不知道,而且坦率地说,也不关心中断是在当前进程的内核堆栈中提供,还是在单独的 ISR 堆栈中提供。由于中断来自每个 CPU,因此 ISR 堆栈必须是每个 CPU。

 Does each process has its own kernel stack ?

是的,每个进程都有自己的内核堆栈。

 Then how the process coordinates between both these stacks?

@ FrankH 的回答对我来说很棒。

  1. 内核堆栈和用户堆栈的区别是什么

参考 Robert Love 的 Linux 内核开发,主要的区别在于大小:

用户空间可以在堆栈上静态分配许多变量,包括 巨大的结构和千元阵列。
此行为是合法的,因为用户空间具有 可以动态增长的大堆栈。
内核堆栈既不大,也不是动态的; 它很小,大小固定。
内核堆栈的确切大小因体系结构而异。
在 x86上,堆栈大小可以在 并且可以是4KB 或8KB。
历史上,内核堆栈是两页, 这通常意味着在32位体系结构上它是8KB,在64位体系结构上它是16KB 大小是固定和绝对的。
每个进程都接收自己的堆栈。

内核堆栈还包含一个指向 thread _ info 结构的指针,该结构包含有关线程的信息。