地址空間:
32位linux系統上,進程的地址空間為4G,包括1G的核心地址空間,和3G的使用者地址空間。
核心棧:
進程式控制制塊task_struct中儲存了2個page大小的資訊。
為什麼每一個進程都是用各自的核心棧呢?
引用(http://hi.baidu.com/iruler/blog/item/0c3363f377ccc5c90a46e023.html)“
假設某個進程通過系統調用運行在核心態(使用這個全域核心堆棧),此時如果被搶佔,發生一次切換,另一個進程開始運行,如果這個當前進程又通過系統調用陷入核心,那麼這個進程也將使用這個全域核心堆棧,這樣的話就把以前那個進程的核心空間堆棧給破壞了。
而如果進程使用獨立的核心棧,就避免了這種情況的發生
”
核心線程:
擁有自己獨立核心棧的調度單元,可以參與調度,在核心空間執行。
使用者棧:
每一個線程有一個使用者棧,由ss和esp指向。
===================================================
進程1 進程2
核心代碼區 kcode (0xc0001000)
kcode (0xc0001000)
核心棧區 kstack(0xc000F000) kstack(0xc001F000)
核心棧區 kstack(0xc000D000) kstack(0xc001D000)
...
核心資料區 kdata (0xc0003000) kdata (0xc0003000)
---------------------------------------------------------------------------------------------
使用者代碼區 ucode (0x70001000) ucode (0x70001000)
使用者棧區 ustack (0x7000F000) ustack (0x7000F000)
使用者棧區 ustack (0x7000D000) ustack (0x7000D000)
...
使用者資料區 udata (0x70003000) udata (0x70003000)
===================================================
合理的解釋:
核心1G空間的映射頁表(256個entries*4M)只有一份,n個進程共用(都複製了一份在自己的進程頁表內, 256個核心的entries+768個使用者空間的entries, 總共1024個entries,假定使用4M頁面,並且一開始就全都分配好)。
每個進程使用者空間的這些entries各不相同,比如說,同樣的0x70001000虛擬位址, 進程1指向實體記憶體0x2000, 而進程2指向0x1000。
每個線程對應的核心棧的虛擬位址不重疊。
thread1's kernel stack = 0f000,
thread2's
kernel stack = 0d000,
thread3's
kernel stack = 1f000,
thread4's
kernel stack = 1d000
...
思考1:
如果核心棧不是預先分配好的(分配的意思是指"在核心空間中分出一段一段不重疊空間作為各個線程的棧", e.g. kmalloc調用),那麼步入核心態的時候, 壓棧,發生缺頁異常,必須對核心棧佔用的這個頁進行換頁,而換頁曆程的調用必然涉及參數的壓棧出棧,而這個時候核心棧沒有就緒,異常發生嵌套,系統出錯!
思考2:
在核心裡面做kmalloc是可以的,添加一個entries,關聯一塊實體記憶體,ok可以用了。
思考3:
如果希望進程共用某一個虛擬記憶體地址0x80001000的資料, 那麼在需要共用的進程p1,p2的頁表中添加1個entries(0x80001000->0x3000)。
另外核心是天然的共用對象,所以才在每一個進程中頁表中設定核心空間頁表的一份拷貝。
如果有個傢伙特立獨行,建立n個關於核心空間的頁表,指向n個實體記憶體塊,那麼他就需要再在這n個實體記憶體中"鋪設"n分核心代碼和資料的副本(真是自找麻煩)。
思考4:
核心棧確實不適合共用(一個特殊的記憶體地區)。怎麼辦?像使用者空間棧一樣固定在某一個虛擬位址,安插頁表項entries指向不同的實體記憶體?顯然不行! 只有一個辦法,在核心空間內分配n個不重疊的空間出來。
思考5:
核心步入的時候最初的“核心棧”並不是真正的核心棧,這個棧是全域的,每個cpu一個,是過渡到真正的核心棧使用的。(http://bbs.pediy.com/archive/index.php?t-87518.html)
思考6:
獨立核心棧的情境, at first 我們分析一下如果共用一個核心棧會出現什麼情況,假設有A、B三個進程,A調用系統調用read(1,...)讀按鍵,此時正好又沒有按鍵,
所以A被阻塞在核心,此時核心調度B執行,此時B也調用一個系統調用被阻塞了,而此時按鍵事件到來,進程A被喚醒,A繼續執行。我們想想B進入核心
已經破壞了A進入核心的核心棧,那此時A能正常返回嗎?所以從上面分析A、B肯定是擁有各自的核心棧。此核心棧好像是和task_struct以前分配的
一共分配了3個頁面,除了task_struct佔得記憶體外,其餘的就是核心棧。而在x86上這個棧等指標儲存在TSS斷的SS0和Esp0中。(http://bbs.chinaunix.net/thread-1930753-1-1.html)
參考資料:
1, 核心棧的使用(http://tech.ddvip.com/2008-09/122095404362368.html)