解析Linux中shell執行一次命令的全過程


1.  在busybox中先進入main函數

2.  根據調用號進入ash_main(也就是busybox的shell)

3.  進入cmdloop(1)中for循環

4.  在parsecmd中解析標准輸入

5.  此時在控制台上輸入./a_static執行(a_static為我的elf格式的應用程序)

6.  shell解析出命令退出parsecmd進入evaltree再進入evalcommand

7.  調用forkshell創建子線程,該子線程用來執行a_static,而父進程我們這邊被先調用

8.  父進程進行waitpid系統調用進入wait4再進入do_wait,設置了局部變量wo->notask_error = -ECHILD;設置進程狀態TASK_INTERRUPTIBLE

9.  進入do_wait_thread因為有子進程所以進入wait_consider_task設置wait_consider_task=0退回do_wait

10.  執行到標號notask處因為局部變量wo->notask_error = 0所以會進入進程調度,而父進程進入睡眠

11.  子線程被調度后進入shellexec再進入tryexec再進行系統調用execve加載用戶空間

12.  arm中通過swi xxx (xxx為系統調用號)進入軟中斷向量,再進入vector_swi,保存硬件上下文,此時根據 lr-4 也就是swi指令的后半部

    確定系統調用號,根據sys_call_table中的調用號偏移找到入口函數這里是sys_execve並執行

13.  此時我們的用戶空間和父進程一樣,TTB中的頁表基地址是父進程的頁表基地址

14.  調用do_execve為線程申請用戶空間

15.  退出do_execve,這時我們有了新的用戶線性區(我們這邊打印出來有四個線性區)和頁表,TTB也已經指向自己的頁全局目錄

    線性區:

        8000 88000    代碼區

        8f000 90000  數據區

           90000 92000  堆區

         be9b7000 be9d9000   棧+命令行參數+環境變量

16.  退出sys_execve,pop出內核棧中的硬件上下文

17.  執行完用戶a_static程序后我們調用系統調用_exit(***)讓進程進入僵屍態

18.  進入SYSCALL_DEFINE1(exit, int, error_code)再進入do_exit進入exit_notify進入do_notify_parent喚醒父進程,退回exit_notify

19.  設置current->exit_state=EXIT_ZOMBIE,退回do_exit

19.  調度schedule

20.  父進程由於被喚醒重新調度進入標號repeat執行,進入do_wait_thread進入wait_consider_task由於子進程tsk->exit_state == EXIT_ZOMBIE

    所以調用wait_task_zombie會返回正值,回到do_wait

21.  由於返回值>0進入標號end,不再進行睡眠和進程調度,直接退出返回用戶態 

22.  回到用戶態shell又進行了waitpid調度(不知道為什么)由於沒有子進程所以不會進行進程調度直接再次返回用戶態

    所以說進程發布waitpid調度 進入睡眠的必要條件是要有子進程。

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM