1、进程描述符及其结构
内核在创建进程的时候,在创建两个栈,一个用户栈,存在于用户空间,一个内核栈,存 在于内核空间。当进程在用户空间运行时,cpu堆栈指针寄存器里面的内容是用户堆栈地址,使用用户栈;当进程在内核空间时,cpu堆栈指针寄存器里面的内 容是内核栈空间地址,使用内核栈。
什么是进程的内核栈:
在每一个进程的生命周期中,必然会通过到系统调用陷入内核。在执行系统调用陷入内核之后,这些内核代码所使用的栈并不是原先用户空间中的栈,而是一个内核空间的栈,这个称作进程的“内核栈”。 内核栈是内核固有的一块区域,用来保护中断现场,内核中 函数 之间相互调用的参数,返回值等。
注意:一开始我以为内核栈只有一个,所有进程公用,但是现在的理解是,一个进程就对应一个内核栈。
比如,有一个简单的字符驱动实现了open方法。在这个驱动挂载后,应用程序对那个驱动所对应的设备节点执行open操作,这个应用程序的open其实就通过glib库调用了Linux的open系统调用,执行系统调用陷入内核后,处理器转换为了特权模式,此时使用的栈指针就是内核栈指针,他指向内核为每个进程分配的内核栈空间。进程的内核栈一般只有8K大小。
在linux进程的内核栈中,包含了thread_info 结构体的指针,thread_info 结构体中又包含了一个成员,指向了task_struct。
在linux下task_struct结构体是PCB(Process Control Block,进程控制块)
task_struct是一个很庞大的结构体,里面包含了一个stack指针,用于指向内核栈:
这个stack指向的内核栈是一个union联合体:
其中stack成员就是内核栈,如果内核栈溢出,thread_info的数据就会被破坏,系统就奔溃了。当时使用union主要是考虑节省内存。
【疑问】
1、对于上面这个union有个疑问,如果cpu是小端的,那thread_info成员和stack的地位是重叠的,那stack必须要从高位开始写才不会破快thread_info结构。如果CPU是大端的,则必须要从stack成员的低位开始写。不知道是否有这样的逻辑。
2、thread_info中的成员指向了task_struct,但是这个task_struct是存放在哪里的呢?猜测是不是存放在内核态的堆中的?内核态的堆又是怎么管理的?
进程包含了以下几种状态: