ltrace -S
(バージョン5.4.0)でコンパイルされた2つのプログラムgcc
(vfork()
もう一方を呼び出す)を実行した後、呼び出しが同時に呼び出されるfork()
ことがわかりました。どこでもこの特定の動作に関する情報を見つけることができません(一部のソースではそれぞれ、およびがその名前の呼び出しで実装されると言い、他のソースでは3つの呼び出しすべてを使用して実装されると言います。vfork()
SYS_vfork
fork()
SYS_clone
fork()
vfork()
clone()
sys_
sys_clone
ソースコード:
#include<stdio.h>
main()
{
int pid;
pid=vfork();
}
出力ltrace -S
:
...
__libc_start_main([some stuff here] <unfinished ...>
vfork([more stuff] <unfinished ...>
SYS_vfork([more stuff])
--- SIGCHLD (Child exited) ---
SYS_vfork
libcがforを使用してvfork()
いるがforを使用しないSYS_fork
理由はありますかfork()
?私は読んだThomas Nymanの答え到着
カーネルでsys_clone()システムコールを使用してfork()、vfork()を指定するファイルは何ですか?、内容は次のとおりです。
vfork()
その逆は別のフラグによってCLONE_VFORK
達成され、これは子プロセスが信号を介して目覚めるまで親プロセスをスリープ状態にします。子は、呼び出されるか終了するまで、親の名前空間で唯一の実行スレッドになりますexec()
。子供はメモリに書き込むことはできません。そのclone()
呼び出しは次のとおりです。
clone(CLONE_VFORK | CLONE_VM | SIGCHLD, 0)
これは私が観察している結果と一致しないようですltrace -S
。
私は何かを台無しにしたのか、それともglibcの作者が何らかの理由で意図的に代わりに使用することを選んだのでしょうかvfork()
?これはいつでも変更できると見なされますか、それとも信頼できますか?SYS_vfork
SYS_clone
答え1
私は台無しにしたのでしょうか、それともglibcの作者が何らかの理由でvfork()を実装するために意図的にSYS_cloneの代わりにSYS_vforkを使用することを選択しましたか?
vfork
歴史的に見ると、これは変更する必要がない結果である可能性が高いと思います。vfork
最初は両方ともfork
同等のシステムコールを使用します。 NPTLスレッドを実装するとき、fork
使用する変更の実装clone
、なぜならCライブラリはスレッドIDをリセットする必要があります。。スレッドは使用目的でのみ使用されるため(すべての状態がリセットされます)、変更されていないままになるため、vfork
心配する必要はありません。execve
NPTLデザインファイルfork
スレッドが利用可能な場合、システムコールがライブラリコールを実装するのに十分でない理由を説明します。fork
メモリリークなしで機能を実装するには、スタック
fork
で使用されるメモリとスレッド呼び出しを除くすべてのスレッドの内部情報を回収する必要があります。fork
この状況でカーネルができることは何もありません。
これはいつでも変更できると見なされますか、それとも信頼できますか?
Cライブラリを使用すると、Cライブラリが提供するAPIに文書化されている動作にのみ依存でき、特定の実装には依存しません。代わりにシステムコールをvfork(3)
使用したり、syscallの代わりにsyscallを使用したりしないでください。使用されるシステムコールは、アーキテクチャによって異なる場合があります。vfork(2)
clone(2)
fork(3)
clone(2)
fork(2)
特定のシステムコールに本当に依存する必要がある場合は、それを直接使用してCライブラリラッパーを破棄する必要があります。
答え2
Cライブラリ/カーネルの違い
バージョン2.3.3以降、NPTLスレッドの実装の一部として提供されているglibc fork()ラッパーは、カーネルのfork()システムコールを呼び出すのではなく、同じ効果を提供するフラグを使用してclone(2)を呼び出します。伝統的なシステムコール。 (fork()への呼び出しは、フラグSIGCHLDを指定するclone(2)への呼び出しと同じです。)glibcラッパーは、pthread_atfork(3)を使用して設定されたすべてのフォークハンドラを呼び出します。