4.4.1進程內核棧
每個進程都有自己的內核棧。當進程從用戶態進入內核態時,CPU就自動地設置該進程的內核棧,也就是說,CPU從任務狀態段TSS中裝入內核棧指針esp(參見下一章的進程切換一節)。
X86內核棧的分布如圖4.2所示:
圖4.2 內核棧的分布圖
在Intel系統中,棧起始於末端,並朝這個內存區開始的方向增長。從用戶態剛切換到內核態以后,進程的內核棧總是空的,因此,esp寄存器直接指向這個內存區的頂端。 在圖4.2中,從用戶態切換到內核態后,esp寄存器包含的地址為0x018fc00。進程描述符存放在從0x015fa00開始的地址。只要把數據寫進棧中,esp的值就遞減。
在/include/linux/sched.h中定義了如下一個聯合結構:
union task_union {
struct task_struct task;
unsigned long stack[2408];
};
從這個結構可以看出,內核棧占8kb的內存區。實際上,進程的task_struct結構所占的內存是由內核動態分配的,更確切地說,內核根本不給task_struct分配內存,而僅僅給內核棧分配8K的內存,並把其中的一部分給task_struct使用。
task_struct結構大約占1K字節左右,其具體數字與內核版本有關,因為不同的版本其域稍有不同。因此,內核棧的大小不能超過7K,否則,內核棧會覆蓋task_struct結構,從而導致內核崩潰。不過,7K大小對內核棧已足夠。
把task_struct結構與內核棧放在一起具有以下好處:
· 內核可以方便而快速地找到這個結構,用偽代碼描述如下:
task_struct = (struct task_struct *) STACK_POINTER & 0xffffe000
· 避免在創建進程時動態分配額外的內存
· task_struct結構的起始地址總是開始於頁大小(PAGE_SIZE)的邊界。