TASK_INTERRUPTIBLE状態のプロセスは、シグナル伝達によってのみ目覚めさせることができますか?

TASK_INTERRUPTIBLE状態のプロセスは、シグナル伝達によってのみ目覚めさせることができますか?

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()HUPEINTR

TASK_INTERRUPTIBLE状態のプロセスは、シグナル伝達によってのみ目覚めさせることができますか?

シグナル伝達は一方向ですが、唯一の方法ではありません。ただTASK_INTERRUPTIBLEこの状態のプロセスを目覚めさせる方法です。たとえば、入力を待つプロセスをブロックする場合を考えてみましょう。入力が可能になると、プロセスがアクティブになります。この場合、ウェイクアッププロセスにはシグナルは含まれません。

[通話中にプロセスがブロックされましたwait()]ステータスがTASK_INTERRUPTIBLEに変更されましたか?

はい、上記をご覧ください。

wait()/waitpid() 呼び出しが返される原因は何ですか?ただSIGCHLDを送るのですか?子プロセスが終了すると、常にSIGCHLDが生成され、プロセスに渡されますか?

ここでは、(1)カーネルシステムコールインタフェースの動作と(2)Cライブラリ関数の動作という2つのことが起こります。通常、プログラムはCライブラリ関数を呼び出し、Cライブラリ関数はシステムコールを呼び出します。ライブラリ関数はシステムコールの戻り値を確認できます。たとえば、以前の呼び出しが返されたが不明なEINTR場合は、システム呼び出しを再度呼び出すことができます。

おすすめ記事