日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

      歡迎訪問 生活随笔!

      生活随笔

      當(dāng)前位置: 首頁 > 运维知识 > linux >内容正文

      linux

      linux进程上下文切换的具体过程,Linux实验三 结合中断上下文切换和进程上下文切换分析Linux内核一般执行过程...

      發(fā)布時間:2024/7/5 linux 44 豆豆
      生活随笔 收集整理的這篇文章主要介紹了 linux进程上下文切换的具体过程,Linux实验三 结合中断上下文切换和进程上下文切换分析Linux内核一般执行过程... 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

      fork系統(tǒng)調(diào)?創(chuàng)建?進程,也就?個進程變成了兩個進程,兩個進程執(zhí)?相同的代碼,只是fork系統(tǒng)調(diào)?在?進程和?進程中的返回值不同。

      打開linux-5.4.34/arch/x86/entry/syscalls/syscall_64.tbl 文件,56、 57、 58號系統(tǒng)調(diào)?__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個系統(tǒng)調(diào)?,以及do_fork和kernel_thread內(nèi)核函數(shù)都可以創(chuàng)建?個新進程,?且都是通過_do_fork函數(shù)來創(chuàng)建進程的,只不過傳遞的參數(shù)不同。

      _do_fork函數(shù)主要完成了調(diào)?copy_process()復(fù)制?進程、獲得?wake_up_new_task將?進程加?就緒隊列等待調(diào)度執(zhí)?等。

      //_do_fork關(guān)鍵部分代碼

      long _do_fork(struct kernel_clone_args *args)

      {//復(fù)制進程描述符和執(zhí)?時所需的其他數(shù)據(jù)結(jié)構(gòu)

      p =copy_process(NULL, trace, NUMA_NO_NODE, args);

      wake_up_new_task(p);//將?進程添加到就緒隊列

      return nr;//返回?進程pid(?進程中fork返回值為?進程的pid)

      }

      copy_process()是創(chuàng)建?個進程的主要的代碼。如下是copy_process()函數(shù)的關(guān)鍵代碼,完整代碼?kernel/fork.c

      static __latent_entropy struct task_struct *copy_process(struct pid *pid,inttrace,intnode,struct kernel_clone_args *args)

      {//復(fù)制進程描述符task_struct、創(chuàng)建內(nèi)核堆棧等

      p =dup_task_struct(current, node);/*copy all the process information*/shm_init_task(p);

      …//初始化?進程內(nèi)核棧和thread

      retval = copy_thread_tls(clone_flags, args->stack, args->stack_size, p,

      args->tls);

      …return p;//返回被創(chuàng)建的?進程描述符指針

      }

      copy_process函數(shù)主要完成了:

      調(diào)?dup_task_struct復(fù)制當(dāng)前進程(?進程)描述符task_struct

      信息檢查、初始化、把進程狀態(tài)設(shè)置為TASK_RUNNING(此時?進程置為就緒態(tài))、采?寫時復(fù)制技術(shù)逐?復(fù)制所有其他進程資源

      調(diào)?copy_thread_tls初始化?進程內(nèi)核棧

      設(shè)置?進程pid等。

      接下來具體看dup_task_struct和copy_thread_tls

      dup_task_struct作用:

      在專業(yè)高速緩沖內(nèi)存上分配task_struct,并完成初始化

      在普通內(nèi)存中分配thread_info及連續(xù)的兩個頁面,完成初始化

      將task_struct和thread_info聯(lián)系起來

      主要代碼:

      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作用:

      負(fù)責(zé)構(gòu)造fork系統(tǒng)調(diào)?在?進程的內(nèi)核堆棧,也就是fork系統(tǒng)調(diào)?在??進程各返回?次,?進程中和其他系統(tǒng)調(diào)?的處理過程并??致,?在?進程中的內(nèi)核函數(shù)調(diào)?堆棧需要特殊構(gòu)建,為?進程的運?準(zhǔn)備好上下?環(huán)境。

      主要代碼:

      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?總結(jié)

      進程的創(chuàng)建過程?致是?進程通過fork系統(tǒng)調(diào)?進?內(nèi)核_do_fork函數(shù),如下圖所示復(fù)制進程描述符及相關(guān)進程資源(采?寫時復(fù)制技術(shù))、分配?進程的內(nèi)核堆棧并對內(nèi)核堆棧和thread等進程關(guān)鍵上下?進?初始化,最后將?進程放?就緒隊列, fork系統(tǒng)調(diào)?返回;??進程則在被調(diào)度執(zhí)?時根據(jù)設(shè)置的內(nèi)核堆棧和thread等進程關(guān)鍵上下?開始執(zhí)?。

      2?execve系統(tǒng)調(diào)用

      execve(執(zhí)行文件)在父進程中fork一個子進程,在子進程中調(diào)用exec函數(shù)啟動新的程序。exec函數(shù)一共有六個,其中execve為內(nèi)核級系統(tǒng)調(diào)用,其他(execl,execle,execlp,execv,execvp)都是調(diào)用execve的庫函數(shù)。

      表頭文件:

      #include

      定義函數(shù):

      int execve(const char * filename,char * const argv[ ],char * const envp[ ]);

      execve()用來執(zhí)行參數(shù)filename字符串所代表的文件路徑,第二個參數(shù)是利用指針數(shù)組來傳遞給執(zhí)行文件,并且需要以空指針(NULL)結(jié)束,最后一個參數(shù)則為傳遞給執(zhí)行文件的新環(huán)境變量數(shù)組。成功無返回值,失敗返回-1。

      execve系統(tǒng)調(diào)過程:

      sys_execve-->do_execve-->do_execveat_common-->__do_execve_file-->search_binary_handler-->load_elf_binary-->start_thread

      execve陷入內(nèi)核,傳入命令行參數(shù)和shell上下文環(huán)境

      sys_execve調(diào)用do_execve封裝命令行參數(shù)和shell上下文

      調(diào)用do_execveat_common,do_execveat_common調(diào)用__do_execve_file,打開ELF文件并把信息的裝入linux_binprm結(jié)構(gòu)體

      __do_execve_file中調(diào)用search_binary_handler,尋找解析ELF文件的函數(shù)

      search_binary_handler找到ELF文件解析函數(shù)load_elf_binary,解析ELF文件,把ELF文件裝入內(nèi)存,修改進程的用戶態(tài)堆棧,修改進程的數(shù)據(jù)段代碼段

      load_elf_binary調(diào)用start_thread修改進程內(nèi)核堆棧

      返回用戶態(tài),此時ip指向ELF文件的main函數(shù)地址

      三?Linux的一般執(zhí)行過程

      1) 正在運?的?戶態(tài)進程X。

      2) 發(fā)?中斷(包括異常、系統(tǒng)調(diào)?等), CPU完成load cs:rip(entry of a specific ISR),即跳轉(zhuǎn)到中斷處理程序??。

      3) 中斷上下?切換,具體包括如下?點:

      swapgs指令保存現(xiàn)場,可以理解CPU通過swapgs指令給當(dāng)前CPU寄存器狀態(tài)做了?個快照。

      rsp point to kernel stack,加載當(dāng)前進程內(nèi)核堆棧棧頂?shù)刂返絉SP寄存器。快速系統(tǒng)調(diào)?是由系統(tǒng)調(diào)???處的匯編代碼實現(xiàn)?戶堆棧和內(nèi)核堆棧的切換。

      save cs:rip/ss:rsp/rflags:將當(dāng)前CPU關(guān)鍵上下?壓?進程X的內(nèi)核堆棧,快速系統(tǒng)調(diào)?是由系統(tǒng)調(diào)???處的匯編代碼實現(xiàn)的。

      此時完成了中斷上下?切換,即從進程X的?戶態(tài)到進程X的內(nèi)核態(tài)。

      4) 中斷處理過程中或中斷返回前調(diào)?了schedule函數(shù),其中完成了進程調(diào)度算法選擇next進程、進程地址空間切換、以及switch_to關(guān)鍵的進程上下?切換等。

      5) switch_to調(diào)?了__switch_to_asm匯編代碼做了關(guān)鍵的進程上下?切換。將當(dāng)前進程X的內(nèi)核堆棧切換到進程調(diào)度算法選出來的next進程(本例假定為進程Y)的內(nèi)核堆棧,并完成了進程上下?所需的指令指針寄存器狀態(tài)切換。之后開始運?進程Y(這?進程Y曾經(jīng)通過以上步驟被切換出去,因此可以從switch_to下??代碼繼續(xù)執(zhí)?)。

      6) 中斷上下?恢復(fù),與(3)中斷上下?切換相對應(yīng)。注意這?是進程Y的中斷處理過程中,?(3)中斷上下?切換是在進程X的中斷處理過程中,因為內(nèi)核堆棧從進程X切換到進程Y了。

      7) 為了對應(yīng)起?中斷上下?恢復(fù)的最后?步單獨拿出來(6的最后?步即是7) iret - pop cs:rip/ss:rsp/rflags,從Y進程的內(nèi)核堆棧中彈出(3)中對應(yīng)的壓棧內(nèi)容。此時完成了中斷上下?的切換,即從進程Y的內(nèi)核態(tài)返回到進程Y的?戶態(tài)。注意快速系統(tǒng)調(diào)?返回sysret與iret的處理略有不同。

      8) 繼續(xù)運??戶態(tài)進程Y。

      總結(jié)

      以上是生活随笔為你收集整理的linux进程上下文切换的具体过程,Linux实验三 结合中断上下文切换和进程上下文切换分析Linux内核一般执行过程...的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

      如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。