clone - システムコールの説明 - Linux コマンド集 一覧表
名前
clone - 子プロセスを作成する
書式
#include <sched.h> int clone(int (*fn)(void *), void *child_stack", int " flags ", void *" "arg" ); _syscall2(int, clone, int, flags, void *, child_stack) _syscall5(int, clone, int, flags, void *, child_stack, int *, parent_tidptr, struct user_desc *, newtls, int *, child_tidptr) /* Using syscall(2) may be preferable; see intro(2) */
説明
clone
()は
fork
(2) と同じような方法で新しいプロセスを作成する。
clone
()には、ライブラリ関数とその下層にあたる
clone
()システムコールが存在する。以下の説明では、システムコールの方を
sys_clone
と表すこととする。
sys_clone
に関する説明はこのマニュアルの最後の方にある。
fork
(2) とは異なり、これらのコールでは、子プロセス (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_PARENT (Linux 2.3.12 以降)
-
CLONE_PARENT
が設定された場合、新しい子供の
(
getppid
(2)で返される) 親プロセスは呼び出し元のプロセスの親プロセスと同じになる。
CLONE_PARENT が設定されていない場合、 ( fork (2)と同様に) 呼び出し元のプロセスがその子供の親になる。
子供が終了した時にシグナルが送られるのは getppid (2)が返す親プロセスである点に注意すること。このため CLONE_PARENT が設定された場合、呼び出し元のプロセスではなく呼び出し元のプロセスの 親プロセスにシグナルが送られる。 - CLONE_FS
-
CLONE_FS
が設定された場合、呼び出し元のプロセスと子プロセスが同じファイル・システム
情報を共有する。ファイル・システム情報は、ファイル・システムのルート (root)、
カレント・ワーキング・ディレクトリ (current working directory)
や umask などである。
呼び出し元のプロセスや子プロセスのどちらか一方によって
chroot
(2),
chdir
(2),
umask
(2) が呼び出されると、もう一方のプロセスにも影響が及ぶ。
CLONE_FS が設定されていない場合、子プロセスは、 clone ()が実行された時点での、呼び出し元のプロセスのファイル・システム情報のコピーを 使用する。 これ以降は、呼び出し元のプロセスと子プロセスの一方が chroot (2), chdir (2), umask (2) を呼び出しても、もう一方のプロセスには影響を与えない。 - CLONE_FILES
-
CLONE_FILES
が設定された場合、呼び出し元のプロセスと子プロセスはファイルディスクリプタの
テーブルを共有する。
呼び出し元プロセスとその子プロセスの一方が作成した
ファイルディスクリプタは、もう一方においても有効である。
同じように、一方のプロセスがファイルディスクリプタを閉じたり、
(
fcntl
(2)
F_SETFD
操作を使って) ディスクリプタに関連するフラグを変更したりすると、
もう一方のプロセスにも影響する。
CLONE_FILES が設定されていない場合、子プロセスは、 clone ()が実行された時点で、呼び出し元のプロセスがオープンしている全ての ファイルディスクリプタのコピーを継承する (子プロセスの複製されたファイルディスクリプタは、 対応する呼び出し元のプロセスのファイルディスクリプタと 同じファイル記述 ( open (2)参照) を参照する)。 これ以降に、呼び出し元のプロセスと子プロセスの一方が ファイルディスクリプタの操作 (ファイルディスクリプタの オープン・クローズや、ファイルディスクリプタ・フラグの変更) を行っても、もう一方のプロセスには影響を与えない。 - CLONE_NEWNS (Linux 2.4.19 以降)
-
子プロセスを新しい名前空間 (namespace) で開始する。
各々のプロセスは一つの名前空間中に存在する。プロセスの "名前空間 (namespace)" は、そのプロセスから見えるファイル階層を表すデータ (mount の集合) である。 CLONE_NEWNS フラグがセットされずに fork (2) か clone (2) が呼ばれると、子プロセスは親プロセスと同じ名前空間に作成される。 システムコール mount (2)、 umount (2)が呼ばれると呼び出し元のプロセスの名前空間が変更され、この結果 呼び出し元のプロセスと同じ名前空間にいるプロセスはすべて影響を受けるが、 異なる名前空間にいるプロセスは影響を受けない。
CLONE_NEWNS フラグがセットされて clone (2) が呼ばれると、clone で作成された子プロセスは新しい名前空間で開始される。 新しい名前空間は親プロセスの名前空間のコピーで初期化される。
特権プロセス (CAP_SYS_ADMIN ケーパビリティを持つプロセス) のみが CLONE_NEWNS フラグを指定することができる。 一つの clone ()呼び出しで、 CLONE_NEWNS と CLONE_FS の両方を指定することはできない。 - CLONE_SIGHAND
-
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_PTRACE
- CLONE_PTRACE が指定され、かつ呼び出し元のプロセスが追跡 (trace) されていた場合、子プロセスも 同様に追跡される。 ( ptrace (2)を参照のこと)
- CLONE_UNTRACED (Linux 2.5.46 以降)
- CLONE_UNTRACED が指定されると、 trace を行っているプロセスは この子プロセスに CLONE_PTRACE を適用することができない。
- CLONE_STOPPED (Linux 2.6.0-test2 以降)
- CLONE_STOPPED が設定されると、子プロセスは最初 ( SIGSTOP シグナルを送られたかのように) 停止した状態となる。 子プロセスを再開させるには SIGCONT シグナルを送信しなければならない。
- CLONE_VFORK
-
CLONE_VFORK
が設定された場合、
(
vfork
(2)と同様に) 子プロセスが
execve
(2) または
_exit
(2) によって仮想メモリを解放するまで、呼び出し元のプロセスの実行は停止される。
CLONE_VFORK が設定されていない場合、 clone ()呼び出し後は、呼び出し元のプロセスと子プロセスの 両方がスケジュール対象となり、アプリケーションはこれらのプロセスの 実行順序に依存しないようにすべきである。 - CLONE_VM
-
CLONE_VM
が設定された場合、呼び出し元のプロセスと子プロセスは同じメモリ空間で
実行される。特に、呼び出し元のプロセスや子プロセスの一方がメモリに
書き込んだ内容はもう一方のプロセスからも見ることができる。さらに、
子プロセスや呼び出し元のプロセスの一方が
mmap
(2) や
munmap
(2)を使ってメモリをマップしたりアンマップした場合、
もう一方のプロセスにも影響が及ぶ。
CLONE_VM が設定されていない場合、子プロセスは clone ()が実行された時点での、親プロセスのメモリ空間をコピーした 別のメモリ空間で実行される。 一方のプロセスが行ったメモリへの書き込みや ファイルのマップ/アンマップは、 fork (2) の場合と同様、もう一方のプロセスには影響しない。 - CLONE_PID (廃止)
- CLONE_PID が設定された場合、子プロセスは呼び出し元のプロセスと同じプロセス ID で作成される。これはシステムをハッキングするのには便利だが、 それ以外にはあまり使われない。 Linux 2.3.21 以降では、 システムのブートプロセス (PID 0) だけがこのフラグを指定できる。 Linux 2.5.16 で削除された。
- 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 (2) を使って生成したスレッドには SIGCHLD (もしくは他の終了シグナル) は送信されない。 また、 wait (2) を使って終了したスレッドの状態を取得することもできない (そのようなスレッドは detached (分離された) といわれる)。
スレッド・グループに属す全てのスレッドが終了した後、 そのスレッド・グループの親プロセスに SIGCHLD (もしくは他の終了シグナル) が送られる。
スレッド・グループに属すいずれかのスレッドが execve (2) を実行すると、スレッド・グループ・リーダー以外の全てのスレッドは 終了され、新しいプロセスがそのスレッド・グループ・リーダーの下で 実行される。
スレッド・グループに属すスレッドの一つが fork (2) を使って子プロセスを作成した場合、 スレッド・グループのどのスレッドであっても その子供を wait (2) できる。
Linux 2.5.35 以降では、 CLONE_THREAD を指定する場合、 flags に CLONE_SIGHAND も含まれていなければならない。
kill (2) を使ってスレッド・グループ全体 (つまり TGID) にシグナルを送ることもできれば、 tgkill (2)を使って特定のスレッド (つまり TID) にシグナルを送ることもできる。
シグナルの配送と処理はプロセス全体に影響する: ハンドラを設定していないシグナルがあるスレッドに配送されると、 そのシグナルはスレッド・グループの全メンバーに影響を及ぼす (終了したり、停止したり、動作を継続したり、無視されたりする)。
各々のスレッドは独自のシグナルマスクを持っており、 sigprocmask (2) で設定できる。 だが、処理待ちのシグナルには、 kill (2) で送信されるプロセス全体に対するもの (つまり、スレッド・グループの どのメンバーにも配送できるもの) と、 tgkill (2)で送信される個々のスレッドに対するものがありえる。 sigpending (2) を呼び出すと、プロセス全体に対する処理待ちシグナルと呼び出し元の スレッドに対する処理待ちシグナルを結合したシグナル集合が返される。
kill (2) を使ってスレッド・グループにシグナルが送られた場合で、 そのスレッド・グループがそのシグナルに対するシグナル・ハンドラが 登録されていたときには、シグナル・ハンドラはスレッド・グループの メンバーのうち、ただ一つのスレッドでだけ起動される。ハンドラが 起動されるスレッドは、そのシグナルを禁止 (block) していない メンバーの中から一つだけが勝手に (arbitrarily) 選ばれる。 スレッド・グループに属す複数のスレッドが sigwaitinfo (2) を使って同じシグナルを待っている場合、 これらのスレッドの中から一つをカーネルが勝手に選択し、 そのスレッドが kill (2) を使って送信されたシグナルを受信する。 - CLONE_SYSVSEM (Linux 2.5.10 以降)
- CLONE_SYSVSEM がセットされると、子プロセスと呼び出し元プロセスは一つの System V セマフォのアンドゥ値リスト ( semop (2)参照) を共有する。このフラグがセットされていなければ、 子プロセスは独自のアンドゥリストを持つ (リストの初期値は空である)。
- CLONE_SETTLS (Linux 2.5.32 以降)
- newtls 引き数は、新しい TLS (Thread Local Storage) ディスクリプタである。 ( set_thread_area (2)を参照のこと)
- CLONE_PARENT_SETTID (Linux 2.5.49 以降)
- 親プロセスと子プロセスのメモリ内の parent_tidptr が指す領域に子プロセスのスレッド ID を格納する。 (Linux 2.5.32-2.5.48 では、 同じことをする CLONE_SETTID というフラグが存在した。)
- CLONE_CHILD_SETTID (Linux 2.5.49 以降)
- 子プロセスのメモリ内の child_tidptr が指す場所に子プロセスのスレッド ID を格納する。
- CLONE_CHILD_CLEARTID (Linux 2.5.49 以降)
-
子プロセスが終了したときに子プロセスのメモリ内の
child_tidptr
が指す場所にある子プロセスのスレッド ID を消去し、
そのアドレスで futex を wake (起床) させる。
このアドレスは
set_tid_address
(2) システムコールで変更することができる。
この機能はスレッドライブラリで使用される。
sys_clone
sys_clone
システムコールは、より
fork
(2) に近いかたちになっており、子プロセスの実行が呼び出しが行われた場所から
続けられる。
そのため、
sys_clone
が必要とする引き数は
flags
と
child_stack
だけであり、それらは
clone
()と同じ意味を持つ
(これらの引き数の順番は
clone
()とは異なることに注意せよ)。
sys_clone
のもう一つの違いは、
child_stack
引き数がゼロでも良いことである。この場合には、どちらかのプロセスが
スタックを変更した時に、書き込み時コピー (copy-on-write) 方式により
子プロセスがスタック・ページの独立したコピーを得られることが保証される。
この場合、正常に動作させるためには、
CLONE_VM
オプションを指定してはならない。
Linux 2.5.49 以降では、
sys_clone
システムコールは 5つの引き数をとる。
新たに追加された 2つの引き数は、
parent_tidptr
と
child_tidptr
である。
parent_tidptr
は、CLONE_PARENT_SETTID が指定された場合に、子プロセスのスレッドIDが
書き込まれる (親プロセスと子プロセスのメモリ内の) 場所を指す。
child_tidptr
は、CLONE_CHILD_SETTID が指定された場合に、子プロセスのスレッドIDが
書き込まれる (子プロセスのメモリ内の) 場所を指す。
返り値
成功した場合、呼び出し元の実行スレッドには子プロセスのスレッド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
- child_stack にゼロを指定した場合に clone ()が返す。
- ENOMEM
- 子プロセスのために確保すべきタスク構造体や、呼び出し元のコンテキストの 一部をコピーするのに必要なメモリを十分に割り当てることができない。
- EPERM
- root 以外のプロセス (CAP_SYS_ADMIN がないプロセス) により CLONE_NEWNS が指定された。
- EPERM
- PID が 0 以外のプロセスによって CLONE_PID が指定された。
可用性
libc5 には clone ()はない。glibc2 では clone ()が提供されており、このマニュアルページに記載の通りである。
注意
カーネル 2.4.x 系列では、一般的には
CLONE_THREAD
フラグを指定しても新しいスレッドの親を
呼び出し元プロセスの親と同じにはしない。
しかし、バージョン 2.4.7〜2.4.18 のカーネルでは、
(カーネル 2.6 と同じように) CLONE_THREAD フラグを指定すると、
暗黙のうちに CLONE_PARENT フラグを指定したことになる。
x86 上では、
clone
()は vsyscall 経由ではなく、直接
"int $0x80"
経由で呼び出すべきである。
準拠
clone ()と sys_clone コールは Linux 特有であり、移植を考慮したプログラムでは使用すべき ではない。
バグ
NPTL スレッド・ライブラリを含んでいる GNU C ライブラリのいくつかのバージョン には、 getpid ()のラッパー関数が含まれており、このラッパー関数は PID をキャッシュする。 このようなライブラリをリンクしたプログラムでは、 getpid ()を呼び出すと同じ値が返ることがある。 たとえ、そのスレッドが CLONE_THREAD を用いて作成されたものでなくても (したがって、同じスレッド・グループに 属していなくても) である。 本当の値を得るには、以下のようなコードを使う必要があるだろう。
#include <syscall.h>
pid_t mypid;
mypid = syscall(SYS_getpid);