Linux
為什麼 ’ls’ 是由 execve() 呼叫而不是 fork() 創建的
據我了解,每當您在 shell 中鍵入諸如“ls”之類的命令時,作為我的 shell 的父程序使用 fork() 系統呼叫複制自身,然後使用 exec() 系統呼叫將其替換為新程序,在這種情況下’ls’一旦退出,控制權就會交還給我的shell。
但是,當我在 ’ls’ 上執行 strace 時,我只看到 execve() 呼叫而沒有 fork,並且控制權仍然交還給我的 shell。這裡有點糊塗…
$ strace ls execve("/usr/bin/ls", ["ls"], 0x7ffd938934e0 /* 25 vars */) = 0 brk(NULL) = 0x1134000 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f6ea9e38000 access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory) open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3 fstat(3, {st_mode=S_IFREG|0644, st_size=23255, ...}) = 0
你的理解是正確的。當你跑步
strace ls
時,甚至有兩個叉子。shell fork 自己並使用exec()
to runstrace
和 strace 做同樣的事情 to runls
。您在 strace 輸出中看不到分叉,因為 strace 列印了源自strace 的子程序的所有系統呼叫,並且此時分叉已經發生:
bash
分叉和執行strace
strace
叉子- 父
strace
程序附加到子程序以攔截所有系統呼叫。從此時起,您只能看到系統呼叫。 4. 孩子使用
strace
_ls``execve()
查看分叉發生的一種方法是
strace
“從外部”附加:
- 用於
echo $$
獲取shell的程序id- 在另一個控制台
strace -f --attach=PID
中用上面的程序 ID 替換“PID”執行。ls
在第一個 shell 中執行- 在另一個控制台視窗中,您將看到 shell 中發生的所有系統呼叫和分叉的子項(包括
fork()
/clone()
呼叫)。- 在第二個控制台中使用 CTRL+C 停止 strace。
要提到的另一件事是,
fork()
目前的 Linux 核心是使用clone()
系統呼叫實現的,因此您可能會看到clone(…)
而不是fork()
在 strace 輸出中看到。