进程控制块的存放和当前进程的确定
当一个进程从用户态进入内核态,CPU自动设置该进程的内核栈,这个栈位于内核数据段上。同时,为节省空间,Linux把内核栈和一个紧挨近PCB的小数据结构thread-info放在一起,占用8KB的内存区。
在Intel系统中,栈起始于末端,并朝这个内存区开始的方向“增长”。刚切换过来,内核栈是空的,堆栈寄存器ESP直接指向此内存区的顶端。通过找到thread-info来找到当前运行的task-struct(PCB)(,那么是怎样找到的呢?下边介绍)。
但是要注意,实际上进程的PCB所占内存是由内核动态分配的,更确切的说,内核根本不给PCB分配内存,而仅仅给内核栈分配8KB的内存,并把其中的一部分让给PCB使用。
因为thread-info结构和内核栈放在一起,内核就很容易从ESP寄存器的值获取当前在CPU上正在运行的thread-info结构的地址。实际上,如果thread-union结构(即内核栈和thread-info联合组成的一个混合结构)长度为8KB(2^13字节),则内核通过屏蔽ESP寄存器的的低13位有效位就可以获得thread-info结构的基地址;这可以由current-thread-info()函数来完成。而其实进程最常用的是task-struct结构的地址而不是什么thread-info结构的地址,于是为了获得当前CPU上运行进程的PCB指针 ,内核需要调用current宏,该宏本质上等价于current-thread-info()->task。同时对于当前进程父进程的PCB可通过下面代码获得。
struct task_struct *my_parent = current->parent;
#define pid_hashfn(x) ((((x) >> 8) ^ (x)) & (PIDHASH_SZ – 1))