內核堆棧和用戶堆棧 小結

轉載至:【http://www.cnblogs.com/longdouhzt/archive/2012/10/13/2722969.htmlhtml

 

每個進程(包括普通進程和內核進程)的地址空間都分爲用戶地址空間和內核地址空間兩部分,在32位的x86機器上,用戶地址空間的範圍是0~3G,內核 地址空間的範圍是3G~4G.對於不一樣的進程,其用戶地址空間會隨着進程不一樣而不一樣,但全部進程的內核地址空間則都是同樣的。對於內核進程,因爲其始終運 行在內核態,因此沒有用戶地址空間,其對應的tast_struct結構體中的mm域也就被賦值爲NULL。而堆的概念應該是隻存在於進程的用戶地址空間 中,因此內核進程是沒有堆一說的。內核線程能夠用kmalloc 或vmalloc在運行時申請內存。kmalloc或vmalloc申請到的內存在整個內核中均可以使用。比方說 內核線程a申請到了一塊內存A, 只要把該內存的首地址傳給另外一個內核線程b,則在b中一樣也可使用這塊內存。dom

 

全部進程(包括內核進程和普通進程)都有一個內核棧,在x86的32位機器上內核棧大小能夠爲4KB或8KB,這個能夠在編譯內核的時候配置。內核棧的用 途有兩個:1)當進程陷入內核態,即內核表明進程執行系統調用時,系統調用的參數就放在內核棧上,內核棧記錄着進程的在內核中的調用鏈;2)在內核棧被配 置成8KB大小的狀況下,當中斷服務程序中斷當前進程時,它將使用當前被中斷進程的內核棧。
對於用戶進程,其既有用戶地址空間中的棧,也有它本身的內核棧。而內核進程就只有內核棧。spa

 

[轉] http://blog.csdn.net/dongmianshu/article/details/5979244.net

 

------------------------------------線程

進程內核棧、用戶棧指針

1.進程的堆棧htm

     內核在建立進程的時候,在建立task_struct的同事,會爲進程建立相應的堆棧。每一個進程會有兩個棧,一個用戶棧,存在於用戶空間,一個內核棧,存在於內核空間。當進程在用戶空間運行時,cpu堆棧指針寄存器裏面的內容是用戶堆棧地址,使用用戶棧;當進程在內核空間時,cpu堆棧指針寄存器裏面的內容是內核棧空間地址,使用內核棧。blog

2.進程用戶棧和內核棧的切換進程

    當進程由於中斷或者系統調用而陷入內核態之行時,進程所使用的堆棧也要從用戶棧轉到內核棧。內存

    進程陷入內核態後,先把用戶態堆棧的地址保存在內核棧之中,而後設置堆棧指針寄存器的內容爲內核棧的地址,這樣就完成了用戶棧向內核棧的轉換;當進程從內核態恢復到用戶態之行時,在內核態之行的最後將保存在內核棧裏面的用戶棧的地址恢復到堆棧指針寄存器便可。這樣就實現了內核棧和用戶棧的互轉。

    那麼,咱們知道從內核轉到用戶態時用戶棧的地址是在陷入內核的時候保存在內核棧裏面的,可是在陷入內核的時候,咱們是如何知道內核棧的地址的呢?

    關鍵在進程從用戶態轉到內核態的時候,進程的內核棧老是空的。這是由於,當進程在用戶態運行時,使用的是用戶棧,當進程陷入到內核態時,內核棧保存進程在內核態運行的相關信心,可是一旦進程返回到用戶態後,內核棧中保存的信息無效,會所有恢復,所以每次進程從用戶態陷入內核的時候獲得的內核棧都是空的。因此在進程陷入內核的時候,直接把內核棧的棧頂地址給堆棧指針寄存器就能夠了。

3.內核棧的實現

        內核棧在kernel-2.4和kernel-2.6裏面的實現方式是不同的。

 在kernel-2.4內核裏面,內核棧的實現是:

 Union task_union {

                   Struct task_struct task;

                   Unsigned long stack[INIT_STACK_SIZE/sizeof(long)];

 };

 其中,INIT_STACK_SIZE的大小隻能是8K。

     內核爲每一個進程分配task_struct結構體的時候,實際上分配兩個連續的物理頁面,底部用做task_struct結構體,結構上面的用做堆棧。使用current()宏可以訪問當前正在運行的進程描述符。

 注意:這個時候task_struct結構是在內核棧裏面的,內核棧的實際能用大小大概有7K。

 

內核棧在kernel-2.6裏面的實現是(kernel-2.6.32):

 Union thread_union {

                   Struct thread_info thread_info;

                   Unsigned long stack[THREAD_SIZE/sizeof(long)];

 };

 其中THREAD_SIZE的大小能夠是4K,也能夠是8K,thread_info佔52bytes。

     當內核棧爲8K時,Thread_info在這塊內存的起始地址,內核棧從堆棧末端向下增加。因此此時,kernel-2.6中的current宏是須要更改的。要經過thread_info結構體中的task_struct域來得到於thread_info相關聯的task。更詳細的參考相應的current宏的實現。

 struct thread_info {

                   struct task_struct *task;

                   struct exec_domain *exec_domain;

                   __u32 flags;

        __u32 status;

                   __u32 cpu;

                   …  ..

 };

 注意:此時的task_struct結構體已經不在內核棧空間裏面了。

相關文章
相關標籤/搜索