Provided by: manpages-ja-dev_0.5.0.0.20140515+dfsg-2_all
名前
clone, __clone2 - 子プロセスを作成する
書式
/* glibc ラッパー関数のプロトタイプ */ #include <sched.h> int clone(int (*fn)(void *), void *child_stack, int flags, void *arg, ... /* pid_t *ptid, struct user_desc *tls, pid_t *ctid */ ); /* 素のシステムコールのプロトタイプ */ long clone(unsigned long flags, void *child_stack, void *ptid, void *ctid, struct pt_regs *regs); glibc ラッパー関数の機能検査マクロの要件 (feature_test_macros(7) 参照): clone(): glibc 2.14 以降: _GNU_SOURCE glibc 2.14 より前: _BSD_SOURCE || _SVID_SOURCE /* _GNU_SOURCE も定義される */
説明
clone() は、 fork(2) と似た方法で新しいプロセスを作成する。 このページでは、 glibc の clone() ラッパー関数とその裏で呼ばれるシステムコールの両方につい て説明している。 メインの説明はラッパー関数に関するものである。 素のシステムコールにおける 差分はこのページの最後の方で説明する。 fork(2) とは異なり、clone() では、子プロセス (child process) と呼び出し元のプロセスと が、メモリ空間、ファイルディスクリプタのテーブル、シグナル・ハンドラのテーブルなどの 実行 コンテキストの一部を共有できる。 (このマニュアルにおける「呼び出し元のプロセス」は、通常は 「親プロセス」と一致する。但し、後述の CLONE_PARENT の項も参照のこと) clone() の主要な使用法はスレッド (threads) を実装することである: 一つのプログラムの中の複 数のスレッドは共有されたメモリ空間で 同時に実行される。 clone() で子プロセスが作成された時に、作成された子プロセスは関数 fn(arg) を実行する。 (この点が fork(2) とは異なる。 fork(2) の場合、子プロセスは fork(2) が呼び出された場所 から実行を続ける。) fn 引き数は、子プロセスが実行を始める時に子プロセスが呼び出す 関数への ポインタである。 arg 引き数はそのまま fn 関数へと渡される。 fn(arg) 関数が終了すると、子プロセスは終了する。 fn によって返された整数が子プロセスの終 了コードとなる。 子プロセスは、 exit(2) を呼んで明示的に終了することもあるし、致命的なシ グナルを受信した 場合に終了することもある。 child_stack 引き数は、子プロセスによって使用されるスタックの位置を指定する。 子プロセスと 呼び出し元のプロセスはメモリを共有することがあるため、 子プロセスは呼び出し元のプロセスと 同じスタックで実行することができない。 このため、呼び出し元のプロセスは子プロセスのスタッ クのためのメモリ空間を 用意して、この空間へのポインタを clone() へ渡さなければならない。 (HP PA プロセッサ以外の) Linux が動作する全てのプロセッサでは、 スタックは下方 (アドレスが 小さい方向) へと伸びる。このため、普通は child_stack は子プロセスのスタックのために用意し たメモリ空間の一番大きい アドレスを指すようにする。 flags の下位 1 バイトは子プロセスが死んだ場合に親プロセスへと送られる 終了シグナル (termination signal) の番号を指定する。このシグナルとして SIGCHLD 以外が指定された場合、親 プロセスは、 wait(2) で子プロセスを待つ際に、オプションとして __WALL または __WCLONE を指 定しなければならない。 どのシグナルも指定されなかった場合、子プロセスが終了した時に親プロ セス にシグナルは送られない。 flags には、以下の定数のうち 0個以上をビット毎の論理和 (bitwise-or) をとったものを指定でき る。これらの定数は呼び出し元のプロセスと 子プロセスの間で何を共有するかを指定する: CLONE_CHILD_CLEARTID (Linux 2.5.49 以降) 子プロセスが終了したときに子プロセスのメモリ内の ctid が指す場所にある子プロセスの スレッド ID を消去し、 そのアドレスで futex を wake (起床) させる。 このアドレスは set_tid_address(2) システムコールで変更することができる。 この機能はスレッドライブ ラリで使用される。 CLONE_CHILD_SETTID (Linux 2.5.49 以降) 子プロセスのメモリ内の ctid が指す場所に子プロセスのスレッド ID を格納する。 CLONE_FILES (Linux 2.0 以降) CLONE_FILES が設定された場合、呼び出し元のプロセスと子プロセスはファイルディスクリ プタの テーブルを共有する。 呼び出し元プロセスとその子プロセスの一方が作成した ファ イルディスクリプタは、もう一方においても有効である。 同じように、一方のプロセスが ファイルディスクリプタを閉じたり、 (fcntl(2) F_SETFD 操作を使って) ディスクリプタ に関連するフラグを変更したりすると、 もう一方のプロセスにも影響する。 CLONE_FILES が設定されていない場合、子プロセスは、 clone() が実行された時点で、呼び 出し元のプロセスがオープンしている全ての ファイルディスクリプタのコピーを継承する (子プロセスの複製されたファイルディスクリプタは、 対応する呼び出し元のプロセスの ファイルディスクリプタと 同じファイル記述 (open(2) 参照) を参照する)。 これ以降 に、呼び出し元のプロセスと子プロセスの一方が ファイルディスクリプタの操作 (ファイル ディスクリプタの オープン・クローズや、ファイルディスクリプタ・フラグの変更) を 行っても、もう一方のプロセスには影響を与えない。 CLONE_FS (Linux 2.0 以降) CLONE_FS が設定された場合、呼び出し元のプロセスと子プロセスが同じファイル・システム 情報を共有する。ファイル・システム情報は、ファイル・システムのルート (root)、 カレ ント・ワーキング・ディレクトリ (current working directory) や umask などである。 呼び出し元のプロセスや子プロセスのどちらか一方によって chroot(2), chdir(2), umask(2) が呼び出されると、もう一方のプロセスにも影響が及ぶ。 CLONE_FS が設定されていない場合、子プロセスは、 clone() が実行された時点での、呼び 出し元のプロセスのファイル・システム情報のコピーを 使用する。 これ以降は、呼び出し 元のプロセスと子プロセスの一方が chroot(2), chdir(2), umask(2) を呼び出しても、も う一方のプロセスには影響を与えない。 CLONE_IO (Linux 2.6.25 以降) CLONE_IO が設定された場合、新しいプロセスは呼び出し元のプロセスと I/O コンテキスト を共有する。 このフラグが設定されていない場合には、 (fork(2) の場合と同様) 新しい プロセスは自分専用の I/O コンテキストを持つ。 I/O コンテキストは、ディスクスケジュールの I/O スコープである (言い換えると、I/O コ ンテキストは I/O スケジューラがプロセス I/O の スケジューリングをモデル化するのに使 用される)。 複数のプロセスが同じ I/O コンテキストを共有する場合、 これらのプロセス は I/O スケジューラからは一つとして扱われる。 結果として、これらのプロセスはディス クアクセスの時間を共有するようになる。 いくつかの I/O スケジューラでは、 二つのプロ セスが I/O コンテキストを共有している場合、 これらのプロセスはディスクアクセスを交 互に行うことができる。 同じプロセスの複数のスレッドが I/O を実行している場合 (例え ば aio_read(3))、 CLONE_IO を利用することで I/O 性能を良くすることができる。 カーネルの設定が CONFIG_BLOCK オプション付きでない場合、 このフラグは何の意味も持た ない。 CLONE_NEWIPC (Linux 2.6.19 以降) CLONE_NEWIPC が設定された場合、新しい IPC 名前空間 (namespace) でプロセスを作成す る。 このフラグが設定されていない場合、 (fork(2) の場合と同様) 呼び出し元のプロセ スと同じ IPC 名前空間でプロセスが 作成される。 このフラグは、コンテナの実装での使用 を意図して用意されたものである。 IPC 名前空間は、独立の System V IPC オブジェクト空間 (svipc(7) 参照) を提供する 。 (Linux 2.6.30 以降では) 独立した POSIX メッセージキュー空間 (mq_overview(7) 参照) も提供される。 これらの IPC 機構に共通の特徴として、 IPC オブジェクトはファイルシス テムのパス名とは違った仕組みで識別されるという点がある。 ある IPC 名前空間に作成されたオブジェクトは、 その名前空間のメンバーである他のすべ てのプロセスからも見えるが、 違う IPC 名前空間のプロセスからは見えない。 IPC 名前空間が破棄される時 (すなわち、その名前空間のメンバーの最後のプロセスが終了 する時)、 その名前空間の全ての IPC オブジェクトは自動的に破棄される。 このフラグを使用するためには、 カーネルでオプション CONFIG_SYSVIPC と CONFIG_IPC_NS を有効になっていること、 プロセスが特権 (CAP_SYS_ADMIN) を持っていることが必要であ る。 このフラグは CLONE_SYSVSEM と組み合わせて使うことはできない。 CLONE_NEWNET (Linux 2.6.24 以降) (このフラグの実装は、Linux 2.6.29 あたりまでには完成した。) CLONE_NEWNET が設定された場合、新しいネットワーク名前空間 (network namaspace) でプ ロセスを作成する。 このフラグが設定されていない場合、 (fork(2) の場合と同様) 呼び 出し元のプロセスと同じネットワーク名前空間でプロセスが 作成される。 このフラグ は、コンテナの実装での使用を意図して用意されたものである。 ネットワーク名前空間は、分離されたネットワークスタックを提供するものである (ネット ワークスタックとは、 ネットワークデバイスインタフェース、IPv4 や IPv6 プロトコルス タック、 /proc/net、 /sys/class/net ディレクトリツリー、ソケットなどである)。 物理 ネットワークデバイスが所属できるネットワーク名前空間は一つだけである。 仮想ネット ワークデバイス ("veth") のペアにより パイプ風の抽象化 (abstraction) が実現されてお り、 これを使うことで、ネットワーク名前空間間のトンネルを作成したり、 別の名前空間 の物理ネットワークデバイスへのブリッジを作成したり することができる。 ネットワーク名前空間が解放される時 (すなわち、その名前空間の最後のプロセスが終了す る時)、 物理ネットワークデバイスは初期ネットワーク名前空間 (initial network namespace) に戻される (親プロセスのネットワーク名前空間に戻される訳ではない)。 このフラグを使用するためには、 カーネルでオプション CONFIG_NET_NS を有効になってい ること、 プロセスが特権 (CAP_SYS_ADMIN) を持っていることが必要である。 CLONE_NEWNS (Linux 2.4.19 以降) 子プロセスを新しいマウント名前空間 (mount namespace) で開始する。 各プロセスはある一つのマウント名前空間中に存在する。プロセスの 名前空間 (namespace) は、そのプロセスから見えるファイル階層を表すデータ (mount の集合) である。 CLONE_NEWNS フラグがセットされずに fork(2) か clone() が呼ばれると、子プロセスは 親プロセスと同じマウント名前空間に作成される。 システムコール mount(2)、 umount(2) が呼ばれると呼び出し元のプロセスのマウント名前空間が変更され、この結果 呼び出し元の プロセスと同じ名前空間にいるプロセスはすべて影響を受けるが、 異なるマウント名前空間 にいるプロセスは影響を受けない。 CLONE_NEWNS フラグがセットされて clone() が呼ばれると、clone で作成された子プロセ スは新しいマウント名前空間で 開始される。新しい名前空間は親プロセスの名前空間のコ ピーで初期化される。 特権プロセス (CAP_SYS_ADMIN ケーパビリティを持つプロセス) のみが CLONE_NEWNS フラグ を指定することができる。 一つの clone() 呼び出しで、 CLONE_NEWNS と CLONE_FS の両 方を指定することはできない。 CLONE_NEWPID (Linux 2.6.24 以降) CLONE_NEWPID が設定された場合、新しい PID 名前空間でプロセスを作成する。 このフラグ が設定されていない場合、 (fork(2) の場合と同様) 呼び出し元のプロセスと同じ PID 名 前空間で プロセスが作成される。 このフラグは、コンテナの実装での使用を意図して用意 されたものである。 PID 名前空間は、PID に関して分離された環境を提供するものである。 新しい名前空間にお ける PID は 1 から始まり (これはスタンドアロンのシステムと似たような感じ)、 fork(2), vfork(2), clone() を呼び出すと、その名前空間で一意な PID を持ったプロセス が作成される。 新しい名前空間で作成される最初のプロセス (つまり、 CLONE_NEWPID フラグを使って作成 されたプロセス) の PID は 1 であり、 このプロセスはその名前空間における "init" プロ セスとなる。 この名前空間において孤児 (orphaned) となった子プロセスについては、 init(8) ではなくこのプロセスが親プロセスとなる。 昔ながらの init プロセスとは違 い、PID 名前空間の "init" プロセスは終了 (terminated) する ことができ、その場合に は、この名前空間の全てのプロセスが終了される。 PID 名前空間間には階層構造が形成される。 新しい PID 名前空間が作成されると、その名 前空間のプロセスは、 新しい名前空間を作成したプロセスの PID 名前空間で見える。 同様 に、親の PID 名前空間自体が別の PID 名前空間の子供の場合には、 子供の PID 名前空間 と親の PID 名前空間のプロセスはどれも 親の親の PID 名前空間でも見えることになる。 反対に、「子供」の PID 名前空間のプロセスには、 親の名前空間のプロセスは見えない。 名前空間に階層構造が存在するということは、個々のプロセスは 複数の PID を持つという ことを意味している。 そのプロセスが見える名前空間一つにつき PID が一つあり、 それぞ れの PID は対応する名前空間において一意である。 (getpid(2) を呼び出すと、常にそのプ ロセスが存在している名前空間における PID が返される。) 新しい名前空間の作成後には、 子プロセスにおいて、 ps(1) といったツールが正しく動作 するように、 自身の root ディレクトリを変更し、 /proc に新しい procfs インスタンス をマウントするのがよいだろう。 (flags に CLONE_NEWNS も指定されていた場合には、root ディレクトリを変更する必要はなく、 いきなり新しい procfs インスタンスを /proc にマ ウントすることができる。) このフラグを使用するためには、 カーネルでオプション CONFIG_PID_NS を有効になってい ること、 プロセスが特権 (CAP_SYS_ADMIN) を持っていることが必要である。 このフラグ は CLONE_THREAD と組み合わせて使うことはできない。 CLONE_NEWUTS (Linux 2.6.19 以降) CLONE_NEWUTS が設定された場合、新しい UTS 名前空間でプロセスを作成する。 新しい UTS 名前空間の識別子の初期値は、呼び出し元のプロセスの UTS 名前空間の識別子を複製したも のとなる。 このフラグが設定されていない場合、 (fork(2) の場合と同様) 呼び出し元の プロセスと同じ UTS 名前空間で プロセスが作成される。 このフラグは、コンテナの実装で の使用を意図して用意されたものである。 UTS 名前空間は、 uname(2) が返す識別子の集合である。 識別子としてはドメイン名とホ スト名があり、 それぞれ setdomainname(2), sethostname(2) で修正することができる。 ある UTS 名前空間における識別子の変更は同じ名前空間の他のすべての プロセスに見える が、別の UTS 名前空間のプロセスには見えない。 このフラグを使用するためには、 カーネルでオプション CONFIG_UTS_NS を有効になってい ること、 プロセスが特権 (CAP_SYS_ADMIN) を持っていることが必要である。 CLONE_PARENT (Linux 2.3.12 以降) CLONE_PARENT が設定された場合、新しい子供の (getppid(2) で返される) 親プロセスは呼 び出し元のプロセスの親プロセスと同じになる。 CLONE_PARENT が設定されていない場合、 (fork(2) と同様に) 呼び出し元のプロセスがそ の子供の親になる。 子供が終了した時にシグナルが送られるのは getppid(2) が返す親プロセスである点に注意 すること。このため CLONE_PARENT が設定された場合、呼び出し元のプロセスではなく呼び 出し元のプロセスの 親プロセスにシグナルが送られる。 CLONE_PARENT_SETTID (Linux 2.5.49 以降) 親プロセスと子プロセスのメモリ内の ptid が指す領域に子プロセスのスレッド ID を格納 する。 (Linux 2.5.32-2.5.48 では、 同じことをする CLONE_SETTID というフラグが存在し た。) CLONE_PID (廃止予定) CLONE_PID が設定された場合、子プロセスは呼び出し元のプロセスと同じプロセス ID で作 成される。これはシステムをハッキングするのには便利だが、 それ以外にはあまり使われな い。 Linux 2.3.21 以降では、 システムのブートプロセス (PID 0) だけがこのフラグを指 定できる。 Linux 2.5.16 で削除された。 CLONE_PTRACE (Linux 2.2 以降) CLONE_PTRACE が指定され、かつ呼び出し元のプロセスが追跡 (trace) されていた場合、子 プロセスも 同様に追跡される。 (ptrace(2) を参照のこと) CLONE_SETTLS (Linux 2.5.32 以降) newtls 引き数は、新しい TLS (Thread Local Storage) ディスクリプタである。 (set_thread_area(2) を参照のこと) CLONE_SIGHAND (Linux 2.0 以降) CLONE_SIGHAND が設定された場合、呼び出し元のプロセスと子プロセスは同じシグナル・ハ ン ドラのテーブルを共有する。呼び出し元のプロセスまたは子プロセスのどちらかが sigaction(2) を呼び出してシグナルに対応する動作を変更した場合、 もう一方のプロセス のシグナル動作も変更される。 但し、呼び出し元のプロセスと子プロセスは、 プロセス毎 に、シグナル・マスク (signal mask) と処理待ちシグナルの集合 を持っている。このた め、あるプロセスは、 sigprocmask(2) を使用して、もう一方のプロセスに影響を与えずに シグナルを禁止 (block) したり許可 (unblock) したりできる。 CLONE_SIGHAND が設定されていない場合、子プロセスは clone() が実行された時点での、呼 び出し元のプロセスのシグナル・ハンドラの コピーを継承する。これ以降は、一方のプロセ スが sigaction(2) を呼び出しても、もう一方のプロセスには影響を与えない。 Linux 2.6.0-test6 以降では、 CLONE_SIGHAND を指定する場合、 CLONE_VM も flags に含 めなければならない。 CLONE_STOPPED (Linux 2.6.0-test2 以降) CLONE_STOPPED が設定されると、子プロセスは最初 (SIGSTOP シグナルを送られたかのよう に) 停止した状態となる。 子プロセスを再開させるには SIGCONT シグナルを送信しなけれ ばならない。 このフラグは Linux 2.6.25 以降では非推奨であり、 Linux 2.6.38 で完全に削除された。 CLONE_SYSVSEM (Linux 2.5.10 以降) CLONE_SYSVSEM がセットされると、子プロセスと呼び出し元プロセスは一つの System V セ マフォのアンドゥ値リスト (semop(2) 参照) を共有する。このフラグがセットされていな ければ、 子プロセスは独自のアンドゥリストを持つ (リストの初期値は空である)。 CLONE_THREAD (Linux 2.4.0-test8以降) CLONE_THREAD が設定された場合、子プロセスは呼び出し元のプロセスと同じスレッド・グ ループに 置かれる。 CLONE_THREAD についての以降の議論を読みやすくするため、 「ス レッド」という用語はスレッド・グループの中のプロセスを 参照するのに使うこととする。 スレッド・グループは、 スレッド集合で一つの PID を共有するという POSIX スレッドの概 念をサポートするために Linux 2.4 に加えられた機能であった。 内部的には、この共有 PID はいわゆるそのスレッドグループの スレッド・グループ識別子 (TGID) である。 Linux 2.4 以降では、 getpid(2) の呼び出しではそのプロセスのスレッド・グループ ID を返 す。 あるグループに属するスレッドは (システム全体で) 一意なスレッド ID (TID) で区別でき る。新しいスレッドの TID は clone() の呼び出し元へ関数の結果として返され、 スレッド は自分自身の TID を gettid(2) で取得できる。 CLONE_THREAD を指定せずに clone() の呼び出しが行われると、 生成されたスレッドはそ のスレッドの TID と同じ値の TGID を持つ 新しいスレッド・グループに置かれる。このス レッドは 新しいスレッド・グループの「リーダー」である。 CLONE_THREAD を指定して作成された新しいスレッドは、 (CLONE_PARENT の場合と同様に) clone() を呼び出し元と同じ親プロセスを持つ。 そのため、 getppid(2) を呼ぶと、一つ のスレッド・グループに属すスレッドは全て同じ値を返す。 CLONE_THREAD で作られたス レッドが終了した際に、 そのスレッドを clone() を使って生成したスレッドには SIGCHLD (もしくは他の終了シグナル) は送信されない。 また、 wait(2) を使って終了したスレッド の状態を取得することもできない (そのようなスレッドは detached (分離された) といわれ る)。 スレッド・グループに属す全てのスレッドが終了した後、 そのスレッド・グループの親プロ セスに SIGCHLD (もしくは他の終了シグナル) が送られる。 スレッド・グループに属すいずれかのスレッドが execve(2) を実行すると、スレッド・グ ループ・リーダー以外の全てのスレッドは 終了され、新しいプロセスがそのスレッド・グ ループ・リーダーの下で 実行される。 スレッド・グループに属すスレッドの一つが fork(2) を使って子プロセスを作成した場 合、 スレッド・グループのどのスレッドであっても その子供を wait(2) できる。 Linux 2.5.35 以降では、 CLONE_THREAD を指定する場合、 flags に CLONE_SIGHAND も含ま れていなければならない (Linux 2.6.0-test6 以降では、 CLONE_SIGHAND を指定する場合 CLONE_VM も指定する必要がある点に注意すること)。 kill(2) を使ってスレッド・グループ全体 (つまり TGID) にシグナルを送ることもできれ ば、 tgkill(2) を使って特定のスレッド (つまり TID) にシグナルを送ることもできる。 シグナルの配送と処理はプロセス全体に影響する: ハンドラを設定していないシグナルがあ るスレッドに配送されると、 そのシグナルはスレッド・グループの全メンバーに影響を及ぼ す (終了したり、停止したり、動作を継続したり、無視されたりする)。 各々のスレッドは独自のシグナルマスクを持っており、 sigprocmask(2) で設定できる。 だが、処理待ちのシグナルには、 kill(2) で送信されるプロセス全体に対するもの (つま り、スレッド・グループの どのメンバーにも配送できるもの) と、 tgkill(2) で送信され る個々のスレッドに対するものがありえる。 sigpending(2) を呼び出すと、プロセス全体に 対する処理待ちシグナルと呼び出し元の スレッドに対する処理待ちシグナルを結合したシグ ナル集合が返される。 kill(2) を使ってスレッド・グループにシグナルが送られた場合で、 そのスレッド・グ ループがそのシグナルに対するシグナル・ハンドラが 登録されていたときには、シグナル・ ハンドラはスレッド・グループの メンバーのうち、ただ一つのスレッドでだけ起動され る。ハンドラが 起動されるスレッドは、そのシグナルを禁止 (block) していない メンバー の中から一つだけが勝手に (arbitrarily) 選ばれる。 スレッド・グループに属す複数のス レッドが sigwaitinfo(2) を使って同じシグナルを待っている場合、 これらのスレッドの 中から一つをカーネルが勝手に選択し、 そのスレッドが kill (2) を使って送信されたシグ ナルを受信する。 CLONE_UNTRACED (Linux 2.5.46 以降) CLONE_UNTRACED が指定されると、 trace を行っているプロセスは この子プロセスに CLONE_PTRACE を適用することができない。 CLONE_VFORK (Linux 2.2 以降) CLONE_VFORK が設定された場合、 (vfork(2) と同様に) 子プロセスが execve(2) または _exit(2) によって仮想メモリを解放するまで、呼び出し元のプロセスの実行は停止され る。 CLONE_VFORK が設定されていない場合、 clone() 呼び出し後は、呼び出し元のプロセスと 子プロセスの 両方がスケジュール対象となり、アプリケーションはこれらのプロセスの 実 行順序に依存しないようにすべきである。 CLONE_VM (Linux 2.0 以降) CLONE_VM が設定された場合、呼び出し元のプロセスと子プロセスは同じメモリ空間で 実行 される。特に、呼び出し元のプロセスや子プロセスの一方がメモリに 書き込んだ内容はもう 一方のプロセスからも見ることができる。さらに、 子プロセスや呼び出し元のプロセスの一 方が mmap(2) や munmap(2) を使ってメモリをマップしたりアンマップした場合、 もう一 方のプロセスにも影響が及ぶ。 CLONE_VM が設定されていない場合、子プロセスは clone() が実行された時点での、親プロ セスのメモリ空間をコピーした 別のメモリ空間で実行される。 一方のプロセスが行ったメ モリへの書き込みや ファイルのマップ/アンマップは、 fork(2) の場合と同様、もう一方の プロセスには影響しない。 素のシステムコールのインターフェース 素の clone システムコールは、より fork(2) に近いかたちになっており、 子プロセスの実行が呼 び出しが行われた場所から続けられる。 そのため、 clone() ラッパー関数の引き数 fn と arg は 省略される。 また、 引き数の順序も違っている。 x86 と他の多くのアーキテクチャにおける、 素 のシステムコールのインターフェースは、 おおまかには次のようになっている。 long clone(unsigned long flags, void *child_stack, void *ptid, void *ctid, struct pt_regs *regs); 生のシステムコールのもう一つの違いは、 child_stack 引き数がゼロでも良いことである。この場 合には、どちらかのプロセスが スタックを変更した時に、書き込み時コピー (copy-on-write) 方式 により 子プロセスがスタック・ページの独立したコピーを得られることが保証される。 この場 合、正常に動作させるためには、 CLONE_VM オプションを指定してはならない。 いくつかのアーキテクチャでは、システムコールの引き数の順序は上記とは異なっている。 microblaze, ARM, ARM 64, PA-RISC, arc, Power PC, xtensa, MIPS アーキテクチャでは、 4 番目 と 5 番目の引き数の順番が逆である。 cris と s390 アーキテクチャでは、最初と 2 番目の引き数 の順番が逆である。 blackfin, m68k, sparc blackfin, m68k, sparc では引き数渡しの規約が上記の説明とは異なる。 詳細は、カーネル (と glibc) のソースを参照のこと。 ia64 ia64 では、別のインターフェースが使用される: int __clone2(int (*fn)(void *), void *child_stack_base, size_t stack_size, int flags, void *arg, ... /* pid_t *ptid, struct user_desc *tls, pid_t *ctid */ ); 上記のプロトタイプは glibc ラッパー関数用のものである。 素のシステムコールのインターフェー スには引き数 fn と arg がない。 また、引き数の順序が変わり、 flags が最初の引き数で、 tls が最後の引き数である。 __clone2() は clone() と同じように動作するが、以下の点が異なる: child_stack_base は子プロ セスのスタックエリアの最小のアドレスを指し、 stack_size は child_stack_base が指し示すス タックエリアの大きさを示す。 Linux 2.4 以前 Linux 2.4 以前では、 clone() は引き数 ptid, tls, ctid を取らない。
返り値
成功した場合、呼び出し元の実行スレッドには子プロセスのスレッドID が返される。 失敗した場 合、 呼び出し元のコンテキストには -1 が返され、子プロセスは 作成されず、 errno が適切に設 定される。
エラー
EAGAIN すでに実行中のプロセスが多すぎる。 EINVAL CLONE_SIGHAND が指定されていたが、 CLONE_VM が指定されていなかった。 (Linux 2.6.0-test6 以降) EINVAL CLONE_THREAD が指定されていたが、 CLONE_SIGHAND が指定されていなかった。 (Linux 2.5.35 以降) EINVAL CLONE_FS と CLONE_NEWNS の両方が flags に指定された。 EINVAL CLONE_NEWIPC と CLONE_SYSVSEM の両方が flags に指定された。 EINVAL CLONE_NEWPID と CLONE_THREAD の両方が flags に指定された。 EINVAL child_stack にゼロを指定した場合に clone() が返す。 EINVAL flags に CLONE_NEWIPC が指定されたが、カーネルでオプション CONFIG_SYSVIPC と CONFIG_IPC_NS が有効になっていなかった。 EINVAL flags に CLONE_NEWNET が指定されたが、カーネルでオプション CONFIG_NET_NS が有効に なっていなかった。 EINVAL flags に CLONE_NEWPID が指定されたが、カーネルでオプション CONFIG_PID_NS が有効に なっていなかった。 EINVAL flags に CLONE_NEWUTS が指定されたが、カーネルでオプション CONFIG_UTS が有効になっ ていなかった。 ENOMEM 子プロセスのために確保すべきタスク構造体や、呼び出し元のコンテキストの 一部をコピー するのに必要なメモリを十分に割り当てることができない。 EPERM 非特権プロセス (CAP_SYS_ADMIN を持たないプロセス) が CLONE_NEWIPC, CLONE_NEWNET, CLONE_NEWNS, CLONE_NEWPID, CLONE_NEWUTS を指定した。 EPERM PID が 0 以外のプロセスによって CLONE_PID が指定された。
バージョン
libc5 には clone() はない。glibc2 では clone() が提供されており、このマニュアルページに 記載の通りである。
準拠
clone() は Linux 特有であり、移植を考慮したプログラムでは使用すべき ではない。
注意
カーネル 2.4.x 系列では、一般的には CLONE_THREAD フラグを指定しても新しいスレッドの親を 呼 び出し元プロセスの親と同じにはしない。 しかし、バージョン 2.4.7〜2.4.18 のカーネルでは、 (カーネル 2.6 と同じように) CLONE_THREAD フラグを指定すると、 暗黙のうちに CLONE_PARENT フ ラグを指定したことになる。 CLONE_DETACHED というフラグが、2.5.32 で導入されて以来しばらくの間存在した。 このフラグは 親プロセスが子プロセス終了のシグナルを必要としないことを 表すものである。 2.6.2 で、 CLONE_DETATCHED を CLONE_THREAD と一緒に指定する必要はなくなった。 このフラグはまだ定義さ れているが、何の効果もない。 i386 上では、 clone() は vsyscall 経由ではなく、直接 int $0x80 経由で呼び出すべきである。
バグ
NPTL スレッド・ライブラリを含んでいる GNU C ライブラリのいくつかのバージョン には、 getpid(2) のラッパー関数が含まれており、このラッパー関数は PID をキャッシュする。 この キャッシュ処理が正しく動作するためには glibc の clone() のラッパー関数での助けが必要だ が、現状の実装では、 ある状況下においてキャッシュが最新とならない可能性がある。 特に、 clone() の呼び出し直後にシグナルが子プロセスに配送された場合に、 そのシグナルに対するハン ドラ内で getpid(2) を呼び出すと、それまでに clone のラッパー関数が子プロセスの PID キャッ シュを 更新する機会が得られていなければ、呼び出し元プロセス ("親プロセス") の PID が 返さ れる可能性がある。 (この議論では、子プロセスが CLONE_THREAD を使って作成された場合のことは 無視している。 子プロセスが CLONE_THREAD を作って作成された場合には、 呼び出し元と子プロセ スは同じスレッド・グループに属すので、 getpid(2) は子プロセスと clone() を呼び出したプロ セスで同じ値を返すのが「正しい」。 キャッシュが最新とならない問題 (stale-cache problem) は、 flags に CLONE_VM が含まれている場合にも発生しない。) 本当の値を得るためには、次のよ うなコードを使う必要があるかもしれない。 #include <syscall.h> pid_t mypid; mypid = syscall(SYS_getpid);
例
以下のプログラムは、 別の UTS 名前空間で動作する子プロセスを clone() を使って作成する例で ある。 子プロセスは、自分の UTS 名前空間においてホスト名を変更する。 それから、親プロセス と子プロセスの両方でシステムのホスト名を表示し、 親プロセスと子プロセスの UTS 名前空間でホ スト名が異なることを確認する。 このプログラムの使用方法については setns(2) を参照。 プログラムのソース #define _GNU_SOURCE #include <sys/wait.h> #include <sys/utsname.h> #include <sched.h> #include <string.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); \ } while (0) static int /* clone された子プロセスの開始関数 */ childFunc(void *arg) { struct utsname uts; /* 子プロセスの UTS 名前空間でホスト名を変更する */ if (sethostname(arg, strlen(arg)) == -1) errExit("sethostname"); /* ホスト名を取得し表示する */ if (uname(&uts) == -1) errExit("uname"); printf("uts.nodename in child: %s\n", uts.nodename); /* sleep を使ってしばらく名前空間をオープンされたままにする。 これにより実験を行うことができる -- 例えば、 別のプロセスがこの名前空間に参加するなど。 */ sleep(200); return 0; /* 子プロセスを終了する */ } #define STACK_SIZE (1024 * 1024) /* clone される子プロセスのスタックサイズ */ int main(int argc, char *argv[]) { char *stack; /* スタックバッファの先頭 */ char *stackTop; /* スタックバッファの末尾 */ pid_t pid; struct utsname uts; if (argc < 2) { fprintf(stderr, "Usage: %s <child-hostname>\n", argv[0]); exit(EXIT_SUCCESS); } /* 子プロセス用のスタックを割り当てる */ stack = malloc(STACK_SIZE); if (stack == NULL) errExit("malloc"); stackTop = stack + STACK_SIZE; /* スタックは下方向に伸びるものとする */ /* 自分専用の UTS 名前空間を持つ子プロセスを作成する; 子プロセスは childFunc() の実行を開始する */ pid = clone(childFunc, stackTop, CLONE_NEWUTS | SIGCHLD, argv[1]); if (pid == -1) errExit("clone"); printf("clone() returned %ld\n", (long) pid); /* 親プロセスの実行はここに来る */ sleep(1); /* 子プロセスがホスト名を変更する時間を与える */ /* 親プロセスの UTS 名前空間でのホスト名を表示する; これは子プロセスの UTS 名前空間でのホスト名とは異なる */ if (uname(&uts) == -1) errExit("uname"); printf("uts.nodename in parent: %s\n", uts.nodename); if (waitpid(pid, NULL, 0) == -1) /* 子プロセスを待つ */ errExit("waitpid"); printf("child has terminated\n"); exit(EXIT_SUCCESS); }
関連項目
fork(2), futex(2), getpid(2), gettid(2), kcmp(2), set_thread_area(2), set_tid_address(2), setns(2), tkill(2), unshare(2), wait(2), capabilities(7), pthreads(7)
この文書について
この man ページは Linux man-pages プロジェクトのリリース 3.65 の一部 である。プロジェクト の説明とバグ報告に関する情報は http://www.kernel.org/doc/man-pages/ に書かれている。