プロセスグループ


パイプで複数のプロセスを連結して動作させると、プロセスグループというものが作られます。ジョブと言いますが、カーネルではどのように管理されているのでしょうか?と以前スレッドグループをプロセスグループと勘違いしていました。そこで改めて調べてみました。

しかし、tasku_structにプロセスグループにかかるメンバーがないのです。bashそのものを調べた分けでないのですが、以下の理由で、たぶんプロセスグループはbashでの処理じゃないかと思うに至りました。

理由1:tasku_structにプロセスグループにかかるメンバーがない。
理由2:jobsコマンドはbash内部コマンド。
理由3:あるシェルでジョブとして起動したものは、他のシェルでjobsとしても表示しない。

bashではプロセス起動毎にそのプロセスIDとともにbash内の認識番号(ジョブID)を割り当てているようで、これはパイプ等で連結しない1プロセス起動の通常の立ち上げでも同じようです。そうすることで、ジョブ単位で処理したほうがいいもの(セッションの割り当て。画面、キー入力をどのプロセスに送ればいいか。)なんかは、シェルがそのジョブIDのプロセス群にかかる処理を、逐一しているんじゃないかと思われます。従ってパイプで連結されたプロセス群の入力は最初のプロセスで、出力は最後のプロセスとすればいいわけで、セッションの割付はジョブ単位としたほうが言い訳で、シェルとしてプロセスグループというものを実装していると思います。

・以下スレッドグループについて
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/httpd
PPIDは親のプロセスIDをPGIDはスレッドグループ番号です。通常の場合スレッドグループ番号はプロセスIDと同じです。下から5つ目のhttpdのPID=1520,PGID=1520で、これがプロセスリーダだと分かります。下の4つのPGIDは1520,また親プロセスも1520ですから、プロセスグループを形成していて、しかもスレッドとして起動されたな。というのが分かります。

tasku_structとしてのプロセス識別子としては、pidとtgidだけのようです。pidはプロセス/スレッドに割り当てられたユニークな識別子です。カーネル内のスケジューリングではプロセスであろうとスレッドであろうと関係ありません。同じものとして処理されます。ただし終了処理においてシグナルをそのスレッドグループの全プロセスに送る場合があります。そのような場合はカーネルの処理というわけです。

プロセス/スレッドが作成されると、p->pid = pid_nr(pid)でユニークなプロセスIDが割り当てら、p->tgid = current->tgidでスレッドグループIDにはそのプロセスIDが割り当てられます。もしCLONE_THREAD(スレッドとして作成)なら、p->tgid = current->tgidでスレッドを作成したプロセスの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(&current->signal->count);
               atomic_inc(&current->signal->live);
               p->group_leader = current->group_leader;
               list_add_tail_rcu(&p->thread_group, &p->group_leader->thread_group);
・・・・・
p->group_leader = current->group_leaderスレッドグループリーダをスレッドのtasku_structの>group_leaderにセットし、list_add_tail_rcu(&p->thread_group, &p->group_leader->thread_group)で、スレッドグループのtasku_struct→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;
・・・・・
      }



最終更新 2010/10/05 19:12:34 - north
(2010/01/21 14:45:06 作成)


検索

アクセス数
3576061
最近のコメント
コアダンプファイル - sakaia
list_head構造体 - yocto_no_yomikata
勧告ロックと強制ロック - wataash
LKMからのファイル出力 - 重松 宏昌
kprobe - ななし
ksetの実装 - スーパーコピー
カーネルスレッドとは - ノース
カーネルスレッドとは - nbyst
asmlinkageってなに? - ノース
asmlinkageってなに? - よろしく
Adsense
広告情報が設定されていません。