私が理解したように、シェルに "ls"などのコマンドを入力するたびに、親プロセス(つまり私のシェル)はfork()システムコールを使用して自分自身をコピーし、exec()システムコールを使用して置き換えますします。この場合、「ls」が終了すると、コントロールは私のシェルに返されます。
しかし、 "ls"でstraceを実行すると、execve()呼び出しのみが表示され、フォークは表示されず、コントロールはまだシェルに戻されます。ここで少し混乱しています...
$ 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
答え1
あなたの理解は正しいです。実行時にstrace ls
2つのフォークもあります。シェルはそれ自体が分岐してexec()
実行に使用され、strace
straceは実行に対して同じことを行いますls
。
strace は次から発生するすべてのシステムコールを印刷するため、strace 出力に分岐は表示されません。straceのサブプロセスその頃はすでにフォークが発生していました。
bash
フォークアンドランstrace
strace
フォーク親プロセスは、
strace
すべてのシステムコールを傍受するために子プロセスに接続されます。この時点から、システムコールのみが表示されます。
子供が走る
strace
ときにls
使用execve()
strace
フォークが発生することを確認する1つの方法は、「外部から」接続することです。
echo $$
シェルのプロセスIDを取得するために使用されます。- 実行時に
strace -f --attach=PID
「PID」を上記のプロセスIDに置き換えます。他のコンソールから。 ls
最初のシェルで実行- 他のコンソールウィンドウには、シェルと分岐サブキーから発生したすべてのシステムコール(
fork()
/clone()
呼び出しを含む)が表示されます。 - straceを停止するには、2番目のコンソールでCTRL + Cを使用してください。
言及するもう1つの点は、fork()
現在のLinuxカーネルではこれがclone()
システムコールを使用して実装されているため、代わりにstrace出力でこれを見ることができるということですclone(…)
。fork()