2017-07-16 31 views

回答

4

背景

的x86 CPU有兩個(實際上有四種)堆棧(每任務):一個是用戶模式,一個用於內核模式。

當中斷在用戶模式下,CPU將設定esp到內核的堆棧的地址(見「TSS」的詳細信息)時,推動esp(用戶模式的堆棧的位置)的原來值與(內核的)堆棧。當發生中斷時,eipcseflags總是被推送到堆棧。

從中斷返回時,iret指令將彈出(內核)堆棧中的「舊」寄存器值,堆棧指針將再次指向用戶的堆棧。

甲搶先多任務操作系統通常工作方式如下:

某些任務正在運行,這意味着此任務佔用CPU負荷的100%的時間的非常小的量。當發生定時器中斷時,當前正在運行的任務的寄存器值被存儲在堆棧中(由CPU)。操作系統將push所有其他寄存器的值,並將esp值更改爲另一個任務(發生另一個定時器中斷時保存)的內核堆棧。然後它pops寄存器並執行iret所以所有寄存器包含另一個任務的值,另一個任務正在運行。

在Linux(4.12.2)中,x86-32由彙編源代碼「entry_32.S」中的函數__switch_to_asm完成。

你的問題

直接的答案。當一個新任務中創建兩個堆棧(用戶和內核堆棧),該任務和初始寄存器值是在中斷poped分配被寫入內核堆棧。這包括用戶模式的初始值esp

某些計時器中斷會在第一次啓動任務(與重新啓動已運行的任務的方式相同)。

在(舊版本)的Linux中有是用於創建新任務的兩個命令:

  • fork()會簡單地複製內核堆棧。 fork()將複製現有的任務,以便所有寄存器值(包括esp)必須與已存在的任務
  • execve()不會分配一個新的內核堆棧(現在的新任務是創建,但另一個可執行文件是在當前任務正在運行) 。 Execve將分配一個新的用戶堆棧並覆蓋內核堆棧上的值esp。 (Mark Plotnick的評論向你展示了完成這件事的位置。)
相關問題