fork() の代わりに execve() 呼び出しで 'ls' が生成される理由

fork() の代わりに execve() 呼び出しで 'ls' が生成される理由

私が理解したように、シェルに "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 ls2つのフォークもあります。シェルはそれ自体が分岐してexec()実行に使用され、stracestraceは実行に対して同じことを行いますls

strace は次から発生するすべてのシステムコールを印刷するため、strace 出力に分岐は表示されません。straceのサブプロセスその頃はすでにフォークが発生していました。

  1. bashフォークアンドランstrace

  2. straceフォーク

  3. 親プロセスは、straceすべてのシステムコールを傍受するために子プロセスに接続されます。

    この時点から、システムコールのみが表示されます。

  4. 子供が走る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()

関連情報