web-dev-qa-db-ja.com

Linuxで、どのプロセスがプロセスにシグナルを送信したかを知るにはどうすればよいですか

SIG TERMを取得したJavaアプリケーションがあります。このシグナルを送信したプロセスのpidを知りたいです。
それは可能ですか?

28
oshai

Linux固有の2つのメソッドは SA_SIGINFOsignalfd() で、プログラムがvery詳細情報を受信できるようにします。送信者のPIDを含む、送信された信号について。

  • sigaction() を呼び出し、struct sigactionに目的のシグナルハンドラーがあり、sa_sigactionSA_SIGINFOフラグが設定されているsa_flagsを渡します。このフラグを使用すると、シグナルハンドラーは3つの引数を受け取ります。そのうちの1つは、送信者のPIDとUIDを含むsiginfo_t構造体です。

  • signalfd() を呼び出し、そこからsignalfd_siginfo構造を読み取ります(通常、ある種の選択/ポーリングループで)。内容はsiginfo_tのようになります。

どちらを使用するかは、アプリケーションの作成方法によって異なります。それらはおそらくプレーンCの外ではうまく機能しないでしょうし、Javaでそれらを機能させることは期待できません。また、Linux以外では移植できません。彼らはまた、あなたが達成しようとしていることを行うための非常に間違った方法である可能性があります。

31
grawity

また、プログラムでシグナルの送信者を特定する必要があったので、grawityの answer を取得して、プログラムで使用しました。これはうまく機能します。

サンプルコードは次のとおりです。

send_signal_raise.c

// send signal to self test - raise()

#include <stdio.h>
#include <signal.h>
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>

static int int_count = 0, max_int = 5;
static struct sigaction siga;

static void multi_handler(int sig, siginfo_t *siginfo, void *context) {
    // get pid of sender,
    pid_t sender_pid = siginfo->si_pid;

    if(sig == SIGINT) {
        int_count++;
        printf("INT(%d), from [%d]\n", int_count, (int)sender_pid);
        return;
    } else if(sig == SIGQUIT) {
        printf("Quit, bye, from [%d]\n", (int)sender_pid);
        exit(0);
    }

    return;
}

int raise_test() {
    // print pid
    printf("process [%d] started.\n", (int)getpid());

    // prepare sigaction
    siga.sa_sigaction = *multi_handler;
    siga.sa_flags |= SA_SIGINFO; // get detail info

    // change signal action,
    if(sigaction(SIGINT, &siga, NULL) != 0) {
        printf("error sigaction()");
        return errno;
    }
    if(sigaction(SIGQUIT, &siga, NULL) != 0) {
        printf("error sigaction()");
        return errno;
    }

    // use "ctrl + c" to send SIGINT, and "ctrl + \" to send SIGQUIT,
    int sig;
    while(1) {
        if(int_count < max_int) {
            sig = SIGINT;
        } else {
            sig  = SIGQUIT;
        }
        raise(sig); // send signal to itself,

        sleep(1); // sleep a while, note that: SIGINT will interrupt this, and make program wake up,
    }

    return 0;
}

int main(int argc, char *argv[]) {
    raise_test();
    return 0;
}

コンパイル:

gcc -pthread -Wall send_signal_raise.c

実行:

./a.out

機能:

プログラムはSIGINTを自分自身に10回送信してから、SIGQUITを送信して自分自身を終了します。

また、実行中にを押します CTRL+CSIGINTを送信する、または CTRL+\SIGQUITを送信すると、プログラムが手動で終了します。

プログラムは、誰が信号を送信したかを正常に識別できました。

9
Eric Wang

いいえ、シグナルはプロセス間通信チャネルとして意図されていません。私の知る限り、PIDは渡されていません。送信PIDは、私がシグナルについて見たすべての用途とは無関係です。シグナルを送信するプロセスがroot権限を持っているか、プロセスと同じUIDに属していることを比較的確信できます。

信号を送信したプロセスが存在しない可能性があります。 Shell組み込みではなくkillコマンドが使用された場合、プロセスが存在しなくなったことはほぼ確実です。

Java側から見ると、これはさらに困難です。プロセスは、オペレーティングシステムから抽象化されたJava仮想マシンで実行されます。すべてのオペレーティングシステムの概念ではありません。このマシンに存在します。

1
BillThor