Linux內核2.6和2.4中內核堆棧的比較

Linux內核 2.42.6的進程內核堆棧和task描述符存儲不太一樣,這兒總結一下。

在內核2.4
中堆棧是這麼定義的:
union task_union {
        struct task_struct task;
        unsigned long stack[INIT_TASK_SIZE/sizeof(long)];
    };
INIT_TASK_SIZE只能是8K

內核爲每個進程分配一個task_struct結構時,實際上分配兩個連續的物理頁面(8192),如圖所示。底部用作task_struct結構(大小約爲1K字節),結構的上面用作內核堆棧(大小約爲7K字節)訪問進程自身的task_struct結構,使用宏操作current, 2.4中定義如下:

#define current get_current()
static inline struct task_struct * get_current(void)
{
      struct task_struct *current;
      __asm__("andl %%esp,%0; ":"=r" (current) : "" (~8191UL));
      return current;
}

  ~8191UL
表示最低13位爲0, 其餘位全爲1 %esp指向內核堆棧中,當屏蔽掉%esp的最低13後,就得到這個兩個連續的物理頁面的開頭,而這個開頭正好是task_struct的開始,從而得到了指向task_struct的指針。


在內核2.6中堆棧這麼定義:
union thread_union {
      struct thread_info thread_info;
      unsigned long stack[THREAD_SIZE/sizeof(long)];
};

根據內核的配置,THREAD_SIZE既可以是4K字節(1個頁面)也可以是8K字節(2個頁面)thread_info52個字節長。

下圖是當設爲
8KB時候的內核堆棧:Thread_info在這個內存區的開始處,內核堆棧從末端向下增長。進程描述符不是在這個內存區中,而分別通過taskthread_info指針使thread_info與進程描述符互聯。所以獲得當前進程描述符的current定義如下:

#define current get_current()
static inline struct task_struct * get_current(void)
{
      return current_thread_info()->task;
}
static inline struct thread_info *current_thread_info(void)
{
       struct thread_info *ti;
       __asm__("andl %%esp,%0; ":"=r" (ti) : "" (~(THREAD_SIZE - 1)));
       return ti;
}
    
根據THREAD_SIZE大小,分別屏蔽掉內核棧的12-bit LSB(4K)13-bit LSB(8K),從而獲得內核棧的起始位置。

struct thread_info {
      struct task_struct    *task;       /* main task structure */
      struct exec_domain    *exec_domain; /* execution domain */
      unsigned long           flags;       /* low level flags */
      unsigned long           status;       /* thread-synchronous flags */
      ... ..
}

參考:
1.      http://hi.baidu.com/zqfazqq/blog/item/12db349980343b0b6f068c5d.html 
2.       Linux內核源代碼情景分析(上冊, Page267)

3.       深入理解Linux內核(3, Page90, Page164)


from: http://blog.csdn.net/songxueyu/article/details/17189653

發佈了12 篇原創文章 · 獲贊 77 · 訪問量 125萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章