XV6上下文切換
上下文切換分為兩種情況
- 使用者程式陷入到核心,再從核心返回
- 兩個應用程式之間的上下文切換
使用者程式陷入到核心
使用者程式陷入到核心通過中斷INT指令,在xv6中系統呼叫的號為64
作業系統在初始化的時候會建立IDT表以及GDT表
通過INT找到IDT中的項,通過IDT中的項找到GDT中的項,最後定位到程式碼。
在執行陷入指令的時候首先會到trapasm.S中的alltraps中,將trapframe存入到應用程式的核心棧中。將esp的地址存入棧中作為trap函式的輸入,然後呼叫trap。注意trapframe中有的欄位會自動存入,比如int指令會通過CPU存入ss,esp,eflags,cs,eip,errorcode,trapno。系統呼叫號存在暫存器eax中。應用程式在初始化的時候作業系統會為每個應用程式保留一個核心棧,其中TSS斷記錄核心棧的一些資訊比如核心棧的入口地址esp0。
系統呼叫將返回值存入到暫存器eax中。返回的時候通過trapret將原來的狀態返回。最後一條指令iret回到使用者程式。
兩個應用程式之間的上下文切換
兩個應用程式不能直接進行上下文切換,必須通過核心進行上下文切換。上下文切換通過proc中的資料結構context進行的。上下文切換的過程首先從 shell使用者棧->shell程式的核心棧->scheduler的核心棧->cat的核心棧->cat的使用者程式。記住第一執行的程式為shell
由於shell沒有返回值,因此程式會卡在紅色線的地方。注意在shell中呼叫fork會釋放ptable.lock鎖
CPU在每一個時鐘中斷的時候會呼叫
yield中會呼叫
注意此時鎖已經釋放了,
讓出當前程序的CPU資源。將上下文切換到scheduler的上下文,由於上下文切換了因此下一條指令跳轉到了scheduler的swtch下一條指令(還記得上面提到的卡在scheduler中的swtch,因此已經將swtch的返回eip地址壓入棧中)。然後通過for迴圈找要runable的程序進行切換cpu->scheduler到要切換的程序上下文切換,到此就可以執行要執行的程序了。
應用程式第一次建立的時候,在返回值設定為trapret。context指向forkret因此在scheduler第一次swtch到forkret函式,在forkret函式中呼叫執行結束後執行trapret進行從核心棧返回到使用者棧。