vfork()はSYS_vforkを呼び出しますが、fork()はSYS_cloneを呼び出しますか?

vfork()はSYS_vforkを呼び出しますが、fork()はSYS_cloneを呼び出しますか?

ltrace -S(バージョン5.4.0)でコンパイルされた2つのプログラムgccvfork()もう一方を呼び出す)を実行した後、呼び出しが同時に呼び出されるfork()ことがわかりました。どこでもこの特定の動作に関する情報を見つけることができません(一部のソースではそれぞれ、およびがその名前の呼び出しで実装されると言い、他のソースでは3つの呼び出しすべてを使用して実装されると言います。vfork()SYS_vforkfork()SYS_clonefork()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_vforklibcが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_vforkSYS_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

man 2 fork:

Cライブラリ/カーネルの違い
バージョン2.3.3以降、NPTLスレッドの実装の一部として提供されているglibc fork()ラッパーは、カーネルのfork()システムコールを呼び出すのではなく、同じ効果を提供するフラグを使用してclone(2)を呼び出します。伝統的なシステムコール。 (fork()への呼び出しは、フラグSIGCHLDを指定するclone(2)への呼び出しと同じです。)glibcラッパーは、pthread_atfork(3)を使用して設定されたすべてのフォークハンドラを呼び出します。

関連情報