カーネルのどのファイルがsys_clone()システムコールを使用するためにfork()、vfork()…を指定するか


9

ltraceを使用してシステムコールをトレースすると、fork()が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) +++

これはあなたに役立つかもしれません:lxr.linux.no/linux+v3.10.9
リプレイ

@ mauro.stettler lxrでそれを見つけることができませんでした
user3539

あなたは意味するかgit.kernel.org/cgit/linux/kernel/git/stable/linux-stable.git/...周りのライン1700を?何を知りたいと思っていましたか?
msw 2013

回答:


29

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

従来はfork()、親プロセスが所有するすべてのリソースを二重化し、コピーを子プロセスに割り当てていました。この方法ではかなりのオーバーヘッドが発生しますが、子がすぐにを呼び出した場合は、まったく無駄になりますexec()。Linuxでは、コピーオンライトページをfork()利用して、親プロセスと子プロセス間で共有できるデータのコピーを遅らせるか、完全に回避します。したがって、通常の間に発生する唯一のオーバーヘッドは、親のページテーブルのコピーと、子に対する一意のプロセス記述子構造体の割り当てです。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()はアーキテクチャ固有ですが、作業の大部分はでdo_fork()定義されていkernel/fork.cます。この関数はstaticを呼び出しますclone_process()。これは、親のコピーとして新しいプロセスを作成しますが、まだ起動していません。clone_process()レジスタをコピーし、PIDを新しいタスクに割り当て、クローンで指定されたプロセス環境の適切な部分を複製または共有しますflagsclone_process()戻ったときdo_clone()、新しく作成されたプロセスを起動し、実行するようにスケジュールします。


2
+1 clone()スレッドとフォークに関連するの重要性の素晴らしい説明。
goldilocks 2013

1
私のすべての疑問を解決しました
user3539 2013

2

Linuxでユーザーランドシステムコール関数をカーネルシステムコールに変換するコンポーネントはlibcです。GLibCでは、NPTLライブラリがこれをclone(2)システムコールにリダイレクトします。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.