プロセスが終了するときにもpid namespaceが関係するので、その辺りのめもです。
流れとしてはこんな感じです。
do_exit()@kernel/exit.c -> exit_notify@kernel/exit.c -> forget_original_parent()@kernel/exit.c -> find_child_reaper()@kernel/exit.c -> zap_pid_ns_processes()@kernel/pid_namespace.c
今回読むのはzap_pid_ns_processes()です。 プロトタイプはこうです。
184 void zap_pid_ns_processes(struct pid_namespace *pid_ns)
この関数はPID Namespace(pid_ns)に属するプロセスに対してSIGKILLを投げていって、プロセスを終了させるのが仕事です。 最初にこの名前空間にこれ以上プロセスが作れないようにPID Namespaceをロックします。次はカレントプロセスに対してSIGCHLDを無視するようにします。そして、名前空間内の各プロセスに対してSIGKILLを投げていきます。このときはpid_task()を使ってpidからpidに該当するtask_struct構造体を取得します。
216 read_lock(&tasklist_lock); 217 nr = next_pidmap(pid_ns, 1); 218 while (nr > 0) { 219 rcu_read_lock(); 220 221 task = pid_task(find_vpid(nr), PIDTYPE_PID); 222 if (task && !__fatal_signal_pending(task)) 223 send_sig_info(SIGKILL, SEND_SIG_FORCED, task); 224 225 rcu_read_unlock(); 226 227 nr = next_pidmap(pid_ns, nr); 228 } 229 read_unlock(&tasklist_lock);
KILLしまくったら次はSIGCHLDを無視している間にゾンビ状態(EXIT_ZOMBIE)になってしまった子プロセスを回収します。使うのはsys_wait4()です。ただし、sys_wait4()だとEXIT_DEADになったプロセスは回収できないとのことですが、コメントによるとEXIT_DEADのプロセスは(゚ε゚)キニシナイ!!とのことです。これはinit_pid_nsのinitプロセスに任せるようです。まあ、名前空間はツリー構造なのでこの名前空間にいるプロセスはツリー構造の上にある名前空間から参照できますしね。 つぎにカレントプロセスをTASK_UNINTERRUPTIBLE状態にして、pid_ns->nr_hashed == init_pidsになるまでshcedule()を呼んで待ちます。
init_pidsは関数の最初のほうで、カレントプロセスがスレッドグループリーダーなら1、そうじゃなければ2と設定しています。
189 int init_pids = thread_group_leader(me) ? 1 : 2;
待ち状態を抜けたらカレントプロセスの状態をTASK_RUNNINGに戻します。そして、pid_ns構造体のreboot変数が0でない場合はcurrent->signal->group_exit_codeにその値を設定します。関数の最後にacct_exit_ns()を呼び、アカウンティング情報の後始末をします。
APIデザインケーススタディ ~Rubyの実例から学ぶ。問題に即したデザインと普遍の考え方 (WEB+DB PRESS plus)
- 作者: 田中哲
- 出版社/メーカー: 技術評論社
- 発売日: 2015/12/16
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (2件) を見る