プロセスグループ
Rev.3を表示中。最新版はこちら。
これは大うそです。改めて書き直します。複数のプロセスをまとめてプロセスグループというものが作られます。プロセスグループを作ると親となるプロセスグループにシグナルを送ると、そのグループのプロセスへもシグナルが送られます。httpdはpreforkで前もって複数のプロセス(スレッド)が立ち上がります。親のhttpdを削除すると、すべてのhttpdが削除されます。これは、これらのhttpdがプロセスグループを形成しているからです。
[root@localhost ~]# ps -fje | more UID PID PPID PGID SID C STIME TTY TIME CMD root 1 0 1 1 0 19:29 ? 00:00:04 init [3] root 72 7 1 1 0 19:29 ? 00:00:00 [kseriod] root 129 7 1 1 0 19:29 ? 00:00:00 [pdflush] root 130 7 1 1 0 19:29 ? 00:00:01 [pdflush] root 131 7 1 1 0 19:29 ? 00:00:00 [kswapd0] root 132 7 1 1 0 19:29 ? 00:00:00 [aio/0] root 290 7 1 1 0 19:29 ? 00:00:00 [kpsmoused] root 1511 1 1511 1511 0 19:31 ? 00:00:00 /usr/sbin/sshd root 1520 1 1520 1520 0 19:31 ? 00:00:00 /usr/sbin/httpd apache 1557 1520 1520 1520 0 19:31 ? 00:00:00 /usr/sbin/httpd apache 1558 1520 1520 1520 0 19:31 ? 00:00:00 /usr/sbin/httpd apache 1559 1520 1520 1520 0 19:31 ? 00:00:00 /usr/sbin/httpd apache 1560 1520 1520 1520 0 19:31 ? 00:00:00 /usr/sbin/httpdPPIDは親のプロセスIDをPGIDはプロセスグループ番号です。プロセスグループ番号は親プロセスのIDとなります。下から5つ目のhttpdのPID=1529,PGID=1529で、これがプロセスリーダだと分かります。下の4つのPGIDは1520,また親プロセスも1520ですから、プロセスグループを形成していて、しかもスレッドとして起動されたな。というのが分かります。
プロセスグループのカーネル実装は、do_forkからよばれるcopy_processでtask_struct構造体のpid_t tgidメンバーに設定し、struct list_head thread_groupでリスト化することで実現しています。なお、スレッドでない場合自プロセスIDを設定します。自分が親でグループなし。という感じです。
static struct task_struct *copy_process(unsigned long clone_flags, ・・・・・ p->pid = pid_nr(pid); p->tgid = p->pid; if (clone_flags & CLONE_THREAD) p->tgid = current->tgid; ・・・・・ if (clone_flags & CLONE_THREAD) { atomic_inc(¤t->signal->count); atomic_inc(¤t->signal->live); p->group_leader = current->group_leader; list_add_tail_rcu(&p->thread_group, &p->group_leader->thread_group); ・・・・・シグナル発生時、send_signal経由してよばれるcomplete_signal関数内で、スレッドグループに発生した致命的な(マスクできないってこと?)シグナルを、struct list_head thread_groupをたどることにより、全プロセス(スレッド)に配送しています。
static void complete_signal(int sig, struct task_struct *p, int group) { ・・・・・ if (!sig_kernel_coredump(sig)) { signal->flags = SIGNAL_GROUP_EXIT; signal->group_exit_code = sig; signal->group_stop_count = 0; t = p; do { sigaddset(&t->pending.signal, SIGKILL); signal_wake_up(t, 1); } while_each_thread(p, t); return; ・・・・・ }