引用する

引用する

システムコールの追跡に使用すると、ltracefork()がsys_fork()の代わりにsys_clone()を使用していることがわかります。しかし、それを定義するLinuxソースコードが見つかりません。

私のプログラムは次のとおりです

#include<stdio.h>

main()
{
        int pid,i=0,j=0;
        pid=fork();
        if(pid==0)
                printf("\nI am child\n");
        else
                printf("\nI am parent\n");

}

出力はltrace次のとおりです

SYS_brk(NULL)                                                                               = 0x019d0000
SYS_access("/etc/ld.so.nohwcap", 00)                                                        = -2
SYS_mmap(0, 8192, 3, 34, 0xffffffff)                                                        = 0x7fe3cf84f000
SYS_access("/etc/ld.so.preload", 04)                                                        = -2
SYS_open("/etc/ld.so.cache", 0, 01)                                                         = 3
SYS_fstat(3, 0x7fff47007890)                                                                = 0
SYS_mmap(0, 103967, 1, 2, 3)                                                                = 0x7fe3cf835000
SYS_close(3)                                                                                = 0
SYS_access("/etc/ld.so.nohwcap", 00)                                                        = -2
SYS_open("/lib/x86_64-linux-gnu/libc.so.6", 0, 00)                                          = 3
SYS_read(3, "\177ELF\002\001\001", 832)                                                     = 832
SYS_fstat(3, 0x7fff470078e0)                                                                = 0
SYS_mmap(0, 0x389858, 5, 2050, 3)                                                           = 0x7fe3cf2a8000
SYS_mprotect(0x7fe3cf428000, 2097152, 0)                                                    = 0
SYS_mmap(0x7fe3cf628000, 20480, 3, 2066, 3)                                                 = 0x7fe3cf628000
SYS_mmap(0x7fe3cf62d000, 18520, 3, 50, 0xffffffff)                                          = 0x7fe3cf62d000
SYS_close(3)                                                                                = 0
SYS_mmap(0, 4096, 3, 34, 0xffffffff)                                                        = 0x7fe3cf834000
SYS_mmap(0, 4096, 3, 34, 0xffffffff)                                                        = 0x7fe3cf833000
SYS_mmap(0, 4096, 3, 34, 0xffffffff)                                                        = 0x7fe3cf832000
SYS_arch_prctl(4098, 0x7fe3cf833700, 0x7fe3cf832000, 34, 0xffffffff)                        = 0
SYS_mprotect(0x7fe3cf628000, 16384, 1)                                                      = 0
SYS_mprotect(0x7fe3cf851000, 4096, 1)                                                       = 0
SYS_munmap(0x7fe3cf835000, 103967)                                                          = 0
__libc_start_main(0x40054c, 1, 0x7fff47008298, 0x4005a0, 0x400590 <unfinished ...>
fork( <unfinished ...>
SYS_clone(0x1200011, 0, 0, 0x7fe3cf8339d0, 0)                                               = 5967
<... fork resumed> )                                                                        = 5967
puts("\nI am parent" <unfinished ...>
SYS_fstat(1, 0x7fff47008060)                                                                = 0
SYS_mmap(0, 4096, 3, 34, 0xffffffff
)                                                        = 0x7fe3cf84e000
I am child
SYS_write(1, "\n", 1
)                                                                       = 1
SYS_write(1, "I am parent\n", 12)                                                           = -512
--- SIGCHLD (Child exited) ---
SYS_write(1, "I am parent\n", 12I am parent
)                                                           = 12
<... puts resumed> )                                                                        = 13
SYS_exit_group(13 <no return ...>
+++ exited (status 13) +++

ベストアンサー1

fork()glibc のラッパーはシステムコールvfork()によってclone()実装されます。fork()との関係をよりよく理解するには、clone()Linuxのプロセスとスレッド間の関係を考慮する必要があります。

伝統的に、fork()親プロセスが所有するすべてのリソースはコピーされ、コピーは子プロセスに割り当てられます。このアプローチはかなりのオーバーヘッドを引き起こし、子供がすぐに呼び出す場合はすべて意味がないかもしれませんexec()fork()Linuxでは書き込み中のコピーページを使用して、親プロセスと子プロセス間で共有できるデータのコピーを遅延または完全に防止できます。したがって、一般的な状況で発生する唯一のオーバーヘッドは、親プロセスのページテーブルをコピーし、子プロセスに独自のプロセス記述子fork()構造を割り当てることです。task_struct

Linuxはまた、スレッドに対して特別なアプローチをとります。 Linuxでは、スレッドは一部のリソースを他のプロセスと共有する一般的なプロセスです。これは、プロセスやスレッドがまったく異なる種類の獣であるWindowsやSolarisなどの他のオペレーティングシステムとはまったく異なるスレッドアプローチです。 Linuxでは、各スレッドには独自の一般的なスレッドがありtask_struct、これは親プロセスと特定のリソース(アドレス空間など)を共有するように設定されています。

flagsシステムコールのパラメータには、clone()親プロセスと子プロセスが共有する必要があるリソースを表すフラグのセットが含まれます。プロセスとスレッドは両方を介して生成され、clone()唯一の違いはに渡されるフラグのセットですclone()

法線は次fork()のように実装できます。

clone(SIGCHLD, 0);

SIGCHLDこれにより、親アイテムとリソースを共有しないジョブが作成され、終了時に親アイテムに終了信号を送信するように設定されます。

代わりに、アドレス空間、ファイルシステムリソース、ファイル記述子、およびシグナルハンドラを親プロセスと共有すること、つまりワイヤーは、次の方法で作成できます。

clone(CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND, 0);

vfork()その逆は別のフラグによってCLONE_VFORK達成され、これは子プロセスが信号を介して目覚めるまで親プロセスをスリープ状態にします。子は、呼び出されるか終了するまで、親の名前空間で唯一の実行スレッドになりますexec()。子供はメモリに書き込むことはできません。そのclone()呼び出しは次のとおりです。

clone(CLONE_VFORK | CLONE_VM | SIGCHLD, 0)

実装はsys_clone()アーキテクチャによって異なりますが、ほとんどの操作はkernel_clone()定義内で発生しますkernel/fork.c。この関数は、copy_process()親プロセスのコピーで新しいプロセスを作成しますが、まだ起動していないstaticを呼び出します。copy_process()レジスタをコピーし、新しいジョブにPIDを割り当て、指定されたプロセス環境の適切な部分を複製または共有しますflagscopy_process()戻ると、kernel_clone()新しく作成されたプロセスが起動して実行されるようにスケジュールされます。

引用する

kernel/fork.cLinux v5.19-rc5, 2022-07-03kernel_clone()改行にすぎないシステムコール、およびの定義については、2606行と2727行を参照してください。fork()vfork()clone()clone3()kernel_clone()

おすすめ記事