ゾンビプロセスを作成しない


Rev.2を表示中。最新版はこちら

親プロセスがwaitで子の終了ステータスを取得しない間、子プロセスはゾンビ状態となります。しかし処理によっては、いつ終了するか分からない子プロセスのために、親プロセスは毎回wait状態で待つわけにいきません。そこで子の終了をシグナルで親プロセスに知らせるという手法があります。struct sigaction saに子プロセスからの終了シグナルをハンドルすることで実現しています。なお親プロセスが子プロセスのそのシグナルを無視するか、ハンドラーにSIG_IGNを設定することで、子プロセスをゾンビ状態にしないことができ、子プロセスが呼び出したexit関数内からタスク構造体を解放するようです。
・補足
waitで待つ場合、親が呼び出したwait内から解放されます。

ゾンビ作成サンプル

#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char** argv)
{
   pid_t pid;
/* ゾンビを作成しない
   struct sigaction sa;
   sa.sa_handler = SIG_IGN;
   sa.sa_flags = SA_NOCLDWAIT;
   if (sigaction(SIGCHLD, &sa, NULL) == -1) {
       exit(1);
   }
*/
   pid = fork();
   if (pid == 0 )
   {
       /* 子プロセス */
       printf("This is child process.\n");
       exit(0);
   }
   /* 親プロセス */
   sleep(10);
   return 0;
}
実行結果
[root@localhost test]# ps
  PID TTY          TIME CMD
 2056 pts/0    00:00:02 bash
 2400 pts/0    00:00:00 a.out
 2401 pts/0    00:00:00 a.out <defunct>   <- ゾンビ
 2403 pts/0    00:00:00 ps
先のプログラムのゾンビを作成しないのコメントを削除した結果
[root@localhost test]# ps
  PID TTY          TIME CMD
 2056 pts/0    00:00:02 bash
 2410 pts/0    00:00:00 a.out
 2413 pts/0    00:00:00 ps
これを踏まえて実装を見てみます。do_exit関数からは、exit_notify関数で親プロセスへ知らせます。tracehook_notify_deathk関数は親プロセスにシグナルで待ち受けているかのチェックをしています。待ち受けているならdo_notify_parent関数が呼ばれ、その結果がDEATH_REAP(-1)なら子プロセスをEXIT_DEAD状態にし、タスク構造体を解放していました。
static void exit_notify(struct task_struct *tsk, int group_dead)
{
       int signal;
・・・・
       signal = tracehook_notify_death(tsk, &cookie, group_dead);
       if (signal >= 0)
               signal = do_notify_parent(tsk, signal);

       tsk->exit_state = signal == DEATH_REAP ? EXIT_DEAD : EXIT_ZOMBIE;
・・・・
        if (signal == DEATH_REAP)
               release_task(tsk);
}
psigは親のsighand_structです。子プロセスがトレースされてなく親のプロセスがsa_handler == SIG_IGN または、sa_flags & SA_NOCLDWAITの時、ret=-1(DEATH_REAP)となります。なおsig=-1は、__group_send_sig_info関数で親プロセスに送信するための有効なシグナルかどうかの判断のようです。
int do_notify_parent(struct task_struct *tsk, int sig)
{
       struct sighand_struct *psig;
・・・
       psig = tsk->parent->sighand;
       spin_lock_irqsave(&psig->siglock, flags);
       if (!tsk->ptrace && sig == SIGCHLD &&
           (psig->action[SIGCHLD-1].sa.sa_handler == SIG_IGN ||
            (psig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDWAIT))) {
              ret = tsk->exit_signal = -1;
               if (psig->action[SIGCHLD-1].sa.sa_handler == SIG_IGN)
                       sig = -1;
       }
       if (valid_signal(sig) && sig > 0)
               __group_send_sig_info(sig, &info, tsk->parent);
・・・
       return ret;
}



最終更新 2010/01/22 02:00:26 - north
(2010/01/22 01:57:06 作成)


検索

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