linux进程上下文切换的具体过程,Linux实验三 结合中断上下文切换和进程上下文切换分析Linux内核一般执行过程...
fork系統調?創建?進程,也就?個進程變成了兩個進程,兩個進程執?相同的代碼,只是fork系統調?在?進程和?進程中的返回值不同。
打開linux-5.4.34/arch/x86/entry/syscalls/syscall_64.tbl 文件,56、 57、 58號系統調?__x64_sys_clone、 __x64_sys_fork、__x64_sys_vfork,即如下kernel/fork.c代碼。
進入linux-5.4.34/kernel/fork.c 查看 fork 源代碼:
/** Create a kernel thread.*/pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned longflags)
{return _do_fork(&args);
}
SYSCALL_DEFINE0(fork)
{return _do_fork(&args);
}
SYSCALL_DEFINE0(vfork)
{return _do_fork(&args);
}
SYSCALL_DEFINE5(clone, unsignedlong, clone_flags, unsigned long, newsp,
{return _do_fork(&args)
}
通過上?的代碼可以看出fork、vfork和clone這3個系統調?,以及do_fork和kernel_thread內核函數都可以創建?個新進程,?且都是通過_do_fork函數來創建進程的,只不過傳遞的參數不同。
_do_fork函數主要完成了調?copy_process()復制?進程、獲得?wake_up_new_task將?進程加?就緒隊列等待調度執?等。
//_do_fork關鍵部分代碼
long _do_fork(struct kernel_clone_args *args)
{//復制進程描述符和執?時所需的其他數據結構
p =copy_process(NULL, trace, NUMA_NO_NODE, args);
wake_up_new_task(p);//將?進程添加到就緒隊列
return nr;//返回?進程pid(?進程中fork返回值為?進程的pid)
}
copy_process()是創建?個進程的主要的代碼。如下是copy_process()函數的關鍵代碼,完整代碼?kernel/fork.c
static __latent_entropy struct task_struct *copy_process(struct pid *pid,inttrace,intnode,struct kernel_clone_args *args)
{//復制進程描述符task_struct、創建內核堆棧等
p =dup_task_struct(current, node);/*copy all the process information*/shm_init_task(p);
…//初始化?進程內核棧和thread
retval = copy_thread_tls(clone_flags, args->stack, args->stack_size, p,
args->tls);
…return p;//返回被創建的?進程描述符指針
}
copy_process函數主要完成了:
調?dup_task_struct復制當前進程(?進程)描述符task_struct
信息檢查、初始化、把進程狀態設置為TASK_RUNNING(此時?進程置為就緒態)、采?寫時復制技術逐?復制所有其他進程資源
調?copy_thread_tls初始化?進程內核棧
設置?進程pid等。
接下來具體看dup_task_struct和copy_thread_tls
dup_task_struct作用:
在專業高速緩沖內存上分配task_struct,并完成初始化
在普通內存中分配thread_info及連續的兩個頁面,完成初始化
將task_struct和thread_info聯系起來
主要代碼:
static struct task_struct *dup_task_struct(struct task_struct *orig, intnode)
{…//實際完成進程描述符的拷?,具體做法是*tsk = *orig
err =arch_dup_task_struct(tsk, orig);
…
tsk->stack =stack;
...//實際完成進程描述符的拷?,具體做法是*tsk = *orig
setup_thread_stack(tsk, orig);
clear_user_return_notifier(tsk);
clear_tsk_need_resched(tsk);
set_task_stack_end_magic(tsk);…
}
copy_thread_tls作用:
負責構造fork系統調?在?進程的內核堆棧,也就是fork系統調?在??進程各返回?次,?進程中和其他系統調?的處理過程并??致,?在?進程中的內核函數調?堆棧需要特殊構建,為?進程的運?準備好上下?環境。
主要代碼:
int copy_thread_tls(unsigned long clone_flags, unsigned longsp,
unsignedlong arg, struct task_struct *p, unsigned longtls)
{
frame->ret_addr = (unsigned long) ret_from_fork;
p->thread.sp = (unsigned long) fork_frame;*childregs = *current_pt_regs();
childregs->ax = 0;
.../** Set a new TLS for the child thread?*/
if (clone_flags &CLONE_SETTLS) {
err= do_arch_prctl_64(p, ARCH_SET_FS, tls);
do_fork?總結
進程的創建過程?致是?進程通過fork系統調?進?內核_do_fork函數,如下圖所示復制進程描述符及相關進程資源(采?寫時復制技術)、分配?進程的內核堆棧并對內核堆棧和thread等進程關鍵上下?進?初始化,最后將?進程放?就緒隊列, fork系統調?返回;??進程則在被調度執?時根據設置的內核堆棧和thread等進程關鍵上下?開始執?。
2?execve系統調用
execve(執行文件)在父進程中fork一個子進程,在子進程中調用exec函數啟動新的程序。exec函數一共有六個,其中execve為內核級系統調用,其他(execl,execle,execlp,execv,execvp)都是調用execve的庫函數。
表頭文件:
#include
定義函數:
int execve(const char * filename,char * const argv[ ],char * const envp[ ]);
execve()用來執行參數filename字符串所代表的文件路徑,第二個參數是利用指針數組來傳遞給執行文件,并且需要以空指針(NULL)結束,最后一個參數則為傳遞給執行文件的新環境變量數組。成功無返回值,失敗返回-1。
execve系統調過程:
sys_execve-->do_execve-->do_execveat_common-->__do_execve_file-->search_binary_handler-->load_elf_binary-->start_thread
execve陷入內核,傳入命令行參數和shell上下文環境
sys_execve調用do_execve封裝命令行參數和shell上下文
調用do_execveat_common,do_execveat_common調用__do_execve_file,打開ELF文件并把信息的裝入linux_binprm結構體
__do_execve_file中調用search_binary_handler,尋找解析ELF文件的函數
search_binary_handler找到ELF文件解析函數load_elf_binary,解析ELF文件,把ELF文件裝入內存,修改進程的用戶態堆棧,修改進程的數據段代碼段
load_elf_binary調用start_thread修改進程內核堆棧
返回用戶態,此時ip指向ELF文件的main函數地址
三?Linux的一般執行過程
1) 正在運?的?戶態進程X。
2) 發?中斷(包括異常、系統調?等), CPU完成load cs:rip(entry of a specific ISR),即跳轉到中斷處理程序??。
3) 中斷上下?切換,具體包括如下?點:
swapgs指令保存現場,可以理解CPU通過swapgs指令給當前CPU寄存器狀態做了?個快照。
rsp point to kernel stack,加載當前進程內核堆棧棧頂地址到RSP寄存器。快速系統調?是由系統調???處的匯編代碼實現?戶堆棧和內核堆棧的切換。
save cs:rip/ss:rsp/rflags:將當前CPU關鍵上下?壓?進程X的內核堆棧,快速系統調?是由系統調???處的匯編代碼實現的。
此時完成了中斷上下?切換,即從進程X的?戶態到進程X的內核態。
4) 中斷處理過程中或中斷返回前調?了schedule函數,其中完成了進程調度算法選擇next進程、進程地址空間切換、以及switch_to關鍵的進程上下?切換等。
5) switch_to調?了__switch_to_asm匯編代碼做了關鍵的進程上下?切換。將當前進程X的內核堆棧切換到進程調度算法選出來的next進程(本例假定為進程Y)的內核堆棧,并完成了進程上下?所需的指令指針寄存器狀態切換。之后開始運?進程Y(這?進程Y曾經通過以上步驟被切換出去,因此可以從switch_to下??代碼繼續執?)。
6) 中斷上下?恢復,與(3)中斷上下?切換相對應。注意這?是進程Y的中斷處理過程中,?(3)中斷上下?切換是在進程X的中斷處理過程中,因為內核堆棧從進程X切換到進程Y了。
7) 為了對應起?中斷上下?恢復的最后?步單獨拿出來(6的最后?步即是7) iret - pop cs:rip/ss:rsp/rflags,從Y進程的內核堆棧中彈出(3)中對應的壓棧內容。此時完成了中斷上下?的切換,即從進程Y的內核態返回到進程Y的?戶態。注意快速系統調?返回sysret與iret的處理略有不同。
8) 繼續運??戶態進程Y。
總結
以上是生活随笔為你收集整理的linux进程上下文切换的具体过程,Linux实验三 结合中断上下文切换和进程上下文切换分析Linux内核一般执行过程...的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: html5怎么跟安卓交互,html5怎么
- 下一篇: linux chmod修改权限失败,【L