Linuxでは、子プロセスが終了し、その親がまだその上で待機していない場合、ゾンビプロセスになります。子の終了コードはpid記述子に格納されます。
a SIGKILL
が子に送信された場合、何の影響もありません。
これは、終了コードがによって変更されない、SIGKILL
または終了コードが変更されて、子がSIGKILL
?
Linuxでは、子プロセスが終了し、その親がまだその上で待機していない場合、ゾンビプロセスになります。子の終了コードはpid記述子に格納されます。
a SIGKILL
が子に送信された場合、何の影響もありません。
これは、終了コードがによって変更されない、SIGKILL
または終了コードが変更されて、子がSIGKILL
?
回答:
その質問に答えるには、シグナルがプロセスに送信される方法と、プロセスがカーネルにどのように存在するかを理解する必要があります。
各プロセスはtask_struct
カーネル内で表されます(定義はsched.h
ヘッダーファイルにあり、ここから始まります)。その構造体はプロセスに関する情報を保持します。たとえば、pid。重要な情報は、関連する信号が格納される行1566にあります。これは、シグナルがプロセスに送信された場合にのみ設定されます。
デッドプロセスまたはゾンビプロセスには、まだがありtask_struct
ます。構造体は、親プロセス(自然または養子縁組による)が子プロセスをwait()
取得SIGCHLD
するために受け取った後に呼び出されるまで残ります。シグナルが送信されると、signal_struct
が設定されます。この場合、シグナルがキャッチ可能かどうかは関係ありません。
シグナルは、プロセスが実行されるたびに評価されます。または正確には、プロセスが実行される前に。その後、プロセスはそのTASK_RUNNING
状態になります。カーネルは、schedule()
そのスケジューリングアルゴリズムに従って次の実行中のプロセスを決定するルーチンを実行します。このプロセスが次の実行プロセスであると仮定すると、処理signal_struct
される待機シグナルがあるかどうかに関係なく、の値が評価されます。シグナルハンドラが手動で(signal()
またはを介してsigaction()
)定義されている場合、登録された関数が実行されます。そうでない場合は、シグナルのデフォルトアクションが実行されます。デフォルトのアクションは、送信される信号によって異なります。
たとえば、SIGSTOP
シグナルのデフォルトハンドラーは、現在のプロセスの状態をに変更してからTASK_STOPPED
実行schedule()
し、実行する新しいプロセスを選択します。通知は、SIGSTOP
(のような捕捉可能ではないSIGKILL
ので、手動シグナルハンドラを登録する可能性はありません)。キャッチできないシグナルの場合、デフォルトのアクションが常に実行されます。
あなたの質問に:
機能しないプロセスまたはデッドプロセスは、スケジューラーによってTASK_RUNNING
再びその状態にあると決定されることはありません。したがって、カーネルは、対応するシグナルのシグナルハンドラー(デフォルトまたは定義済み)を実行しません。したがって、exit_signal
が再び設定されることはありません。シグナルは、プロセスのsignal_struct
in task_struct
を設定することによってプロセスに「配信」されますが、プロセスが再度実行されることはないため、他に何も起こりません。実行するコードはなく、プロセスに残っているのはそのプロセス構造体だけです。
ただし、親プロセスがその子をwait()
で刈り取る場合、プロセスが受け取る「終了コード」は、プロセスが「最初に」停止したときのものです。処理されるのを待っているシグナルがあってもかまいません。
ゾンビプロセスは基本的にすでに死んでいます。唯一のことは、誰もその死を認めていないため、プロセステーブルのエントリと制御ブロック(Linuxカーネルがアクティビティ内のすべてのスレッドに対して維持する構造)を占有し続けていることです。ファイルの強制ロック、共有メモリセグメント、セマフォなどのその他のリソースは再利用されます。
誰もこのシグナルに応じることができないので、あなたはそれらにシグナルを送ることができません。プロセスはすでにその実行を終了しているため、KILLのような致命的なシグナルでさえ役に立たない。あなたは自分で試すことができます:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
int main(void)
{
pid_t pid = fork();
if (pid == -1)
exit(-1);
if (pid > 0) {
//parent
printf("[parent]: I'm the parent, the pid of my child is %i\n"
"I'll start waiting for it in 10 seconds.\n", pid);
sleep(10);
int status;
wait(&status);
if (WIFSIGNALED(status)) {
printf("[parent]: My child has died from a signal: %i\n", WTERMSIG(status));
} else if (WIFEXITED(status)) {
printf("[parent]: My child has died from natural death\n");
} else {
printf("[parent]: I don't know what happened to my child\n");
}
} else {
//child
printf("[child]: I'm dying soon, try to kill me.\n");
sleep(5);
printf("[child]: Dying now!\n");
}
return 0;
}
ここでは、子を待つ前にフォークしてスリープするプロセスを開始します。子供は少し寝るだけです。眠っているとき、または退出した直後に子供を殺して、違いを確認できます。
$ make zombie
cc zombie.c -o zombie
$ ./zombie
[parent]: I'm the parent, the pid of my child is 16693
I'll start waiting for it in 10 seconds.
[child]: I'm dying soon, try to kill me.
# Here, I did "kill -15 16693" in another console
[parent]: My child has died from a signal: 15
$ ./zombie
[parent]: I'm the parent, the pid of my child is 16717
I'll start waiting for it in 10 seconds.
[child]: I'm dying soon, try to kill me.
[child]: Dying now!
# Here, I did "kill -15 16717" in another console
[parent]: My child has died from natural death
ruby -e "loop while fork { exit! }"
... imgur.com/SoRXErm
kill
自体は0または1を返しますか?