Linuxプログラミングインターフェース説明する
22.3 割り込み可能および無停電プロセススリープ状態
SIGKILLとSIGSTOPは、常にプロセスに対して即座に対処するという手がかりを前のステートメントに追加する必要があります。異なる時点で、カーネルはプロセスをスリープモードに切り替えることができ、次の2つのスリープ状態があります。
ジョブ_割り込み可能: プロセスがイベントを待っています。。たとえば、端末入力を待っている間、現在空のパイプにデータを書き込んでいる間、System Vセマフォの値を増やしています。プロセスはこの状態で時間を費やすことができます。この状態のプロセスに対してシグナルが発生すると、タスクは中断され、シグナル伝達によってプロセスが目覚めます。ps(1)を介してリストされている場合、TASK_INTERRUPTIBLE状態のプロセスはSTAT(プロセス状態)フィールドに文字Sとして表示されます。
TASK_UNINTERRUPTIBLE:プロセスがディスクI / O完了などの特別なカテゴリのイベントを待っています。この状態のプロセスに対してシグナルが生成されると、プロセスがこの状態を終了するまでシグナルは転送されません。 TASK_UNINTERRUPTIBLE状態のプロセスは、ps(1)によってSTATフィールドにDが含まれてリストされます。
したがって、TASK_INTERRUPTIBLE状態のプロセスはイベントを待っており、そのプロセスに対して生成された信号の転送によって目覚めます。
プロセスが待機するイベントとプロセスを起こす信号との間にはどのような関係がありますか?シグナルはイベントの発生を示すべきですか?それとも、シグナルはイベントから独立していますか?
TASK_INTERRUPTIBLE状態のプロセスは、シグナル伝達によってのみ目覚めさせることができますか?
たとえば、プロセスが子プロセスを呼び出すwait()
かwaitpid()
、終了を待っている場合、
- ステータスがTASK_INTERRUPTIBLEに変更されましたか?
- 電話が
wait()/waitpid()
戻ってくるようにするにはどうすればよいですか? SIGCHLDの通過ですか?子プロセスが終了すると、常にSIGCHLDが生成され、プロセスに渡されますか?
ありがとうございます。
ベストアンサー1
プロセスが待機するイベントとプロセスを起こす信号との間にはどのような関係がありますか?シグナルはイベントの発生を示すべきですか?それとも、シグナルはイベントから独立していますか?
シグナルとプロセスが待っているイベントとの間には関係がある必要はありません。あなたの例では、プロセスは中断可能なスリープ状態にあり、子プロセスが終了するのを待って信号に応答して目を覚ます可能性があります。
次のプログラム例を考えてみましょう。
#include <stdio.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
static void signal_handler(int signo)
{
#define msg "received signal\n"
write(STDOUT_FILENO, msg, sizeof(msg));
#undef msg
}
int main(void)
{
const struct sigaction act = {
.sa_handler = signal_handler,
// Not including SA_RESTART in sa_flags
};
if (sigaction(SIGHUP, &act, NULL) < 0) {
perror("sigaction");
return 1;
}
const int pid = fork();
if (pid < 0) {
perror("fork");
return 1;
}
if (pid == 0) {
// Child -- hang out a while
sleep(60);
} else {
// parent
if (syscall(SYS_wait4, pid, NULL, 0, NULL) < 0) {
perror("wait");
}
}
return 0;
}
プログラムは、まずSIGHUP
信号に応答するために信号ハンドラを設定します。はいいいえSA_RESTART
特定のライブラリ機能が中断されたシステムコールを自動的に再起動するようにするこのフラグが含まれています。
その後、プログラムはfork()
新しいプロセスを生成するために使用されます。子はしばらく寝て、親は子が完了するのを待ちます。
syscall(SYS_wait4,...
ここではなぜ代わりに使用しますかwaitpid()
? Cライブラリ関数に実装されているすべての動作を削除したいと思いますwaitpid()
。 Cライブラリ関数をスキップしてすぐにカーネルに移動します。
これで、次のプログラムを実行できます。
$ ./a.out
その後、他の端末で次のものを見ることができます。
$ ps aux | grep a.out
username 7839 0.0 0.0 2128 692 pts/0 S+ 22:28 0:00 ./a.out
username 7840 0.0 0.0 2128 76 pts/0 S+ 22:28 0:00 ./a.out
これはS
中断可能なスリープモードを意味するため、通話でブロックされたプロセスはwait()
中断可能なスリープモードになります。 (通話中にブロックされたプロセスsleep()
もInterruptible Sleep状態にあることに注意してください。)
プロセスに信号を送信すると、次のようになりますSIGHUP
。
$ kill -HUP 7839
プログラムの出力が表示されます。
received signal
wait: Interrupted system call
received signal
関数signal_handler()
呼び出しでペア呼び出しに応答してエラー(true)Interrupted system call
が返されました。シグナリングはスリープモードを中断し、シグナルハンドラを実行し、呼び出しが返されるのを待ちます(中断されたシステムコール)。perror()
waitpid()
wait4()
HUP
EINTR
TASK_INTERRUPTIBLE状態のプロセスは、シグナル伝達によってのみ目覚めさせることができますか?
シグナル伝達は一方向ですが、唯一の方法ではありません。ただTASK_INTERRUPTIBLE
この状態のプロセスを目覚めさせる方法です。たとえば、入力を待つプロセスをブロックする場合を考えてみましょう。入力が可能になると、プロセスがアクティブになります。この場合、ウェイクアッププロセスにはシグナルは含まれません。
[通話中にプロセスがブロックされました
wait()
]ステータスがTASK_INTERRUPTIBLEに変更されましたか?
はい、上記をご覧ください。
wait()/waitpid() 呼び出しが返される原因は何ですか?ただSIGCHLDを送るのですか?子プロセスが終了すると、常にSIGCHLDが生成され、プロセスに渡されますか?
ここでは、(1)カーネルシステムコールインタフェースの動作と(2)Cライブラリ関数の動作という2つのことが起こります。通常、プログラムはCライブラリ関数を呼び出し、Cライブラリ関数はシステムコールを呼び出します。ライブラリ関数はシステムコールの戻り値を確認できます。たとえば、以前の呼び出しが返されたが不明なEINTR
場合は、システム呼び出しを再度呼び出すことができます。