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調度 進入睡眠的必要條件是要有子進程。