- What's the difference between kernel stack and user stack ?
简而言之,除了在内存中使用不同的位置(因此堆栈指针寄存器的值不同),以及通常不同的内存访问保护之外,什么都没有.也就是说,在用户模式下执行时,内核内存(内核堆栈的一部分)即使被映射也无法访问.反之亦然,没有内核代码的明确请求(在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 ?
On the kernel stack. The kernel (Linux kernel, that is) does not hook ISRs directly to the x86 architecture's interrupt gates but instead delegates the interrupt dispatch to a common kernel interrupt entry/exit mechanism which saves pre-interrupt register state before calling the registered handler(s). The CPU itself when dispatching an interrupt might execute a privilege and/or stack switch, and this is used/set up by the kernel so that the common interrupt entry code can already rely on a kernel stack being present.
That said, interrupts that occur while executing kernel code will simply (continue to) use the kernel stack in place at that point. This can, if interrupt handlers have deeply nested call paths, lead to stack overflows (if a deep kernel call path is interrupted and the handler causes another deep path; in Linux, filesystem / software RAID code being interrupted by network code with iptables active is known to trigger such in untuned older kernels ... solution is to increase kernel stack sizes for such workloads).
- Does each process have its own kernel stack ?
不仅仅是每个进程——每个进程都有自己的内核堆栈(事实上,还有自己的用户堆栈).请记住,进程和线程(对于Linux)之间的唯一区别是,多个线程可以共享一个地址空间(形成一个进程).
- How does the process coordinate between both these stacks ?
Not at all - it doesn't need to. Scheduling (how / when different threads are being run, how their state is saved and restored) is the operating system's task and processes don't need to concern themselves with this. As threads are created (and each process must have at least one thread), the kernel creates kernel stacks for them, while user space stacks are either explicitly created/provided by whichever mechanism is used to create a thread (functions like makecontext()
or pthread_create()
allow the caller to specify a memory region to be used for the "child" thread's stack), or inherited (by on-access memory cloning, usually called "copy on write" / COW, when creating a new process).
That said, the process can influence scheduling of its threads and/or influence the context (state, amongst that is the thread's stack pointer). There are multiple ways for this: UNIX signals, setcontext()
, pthread_yield()
/ pthread_cancel()
, ... - but this is digressing a bit from the original question.