簡體   English   中英

如何在 Linux 中判斷哪個進程向我的進程發送了信號

[英]How can I tell in Linux which process sent my process a signal

我有一個獲得SIG TERM的 java 應用程序。 我想知道發送這個信號的進程的pid。
那可能嗎?

兩個特定於 Linux 的方法是SA_SIGINFOsignalfd() ,它們允許程序接收有關發送信號的非常詳細的信息,包括發送者的 PID。

  • 調用sigaction()並將struct sigaction傳遞給它,該struct sigactionsa_sigaction具有所需的信號處理程序,並在sa_flags設置了SA_SIGINFO標志。 使用此標志,您的信號處理程序將接收三個參數,其中一個是包含發送方 PID 和 UID 的siginfo_t結構。

  • 調用signalfd()signalfd_siginfo讀取signalfd_siginfo結構(通常在某種選擇/輪詢循環中)。 內容將類似於siginfo_t

使用哪一個取決於你的應用程序是如何編寫的; 在純 C 之外,它們可能不會很好地工作,而且我也不希望讓它們在 Java 中工作。 它們在 Linux 之外也是不可移植的。 他們也很可能是做你想要實現的事情的非常錯誤的方式。

我還需要在程序中識別信號發送者,所以我采用了grawity的答案,並在我的程序中使用它,效果很好。

這是示例代碼:

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 + C發送SIGINT ,或按CTRL + \\發送SIGQUIT ,這將手動終止程序。

該程序可以成功識別誰發送了信號。

BCC包括killsnoop實用程序。 它需要一個支持 BPF 的內核。

摘自killsnoop (8) 手冊頁

       killsnoop  traces  the  kill()  syscall, to show signals sent via this method. This may be
       useful to troubleshoot  failing  applications,  where  an  unknown  mechanism  is  sending
       signals.

       This  works by tracing the kernel sys_kill() function using dynamic tracing, and will need
       updating to match any changes to this function.

       This makes use of a Linux 4.5 feature (bpf_perf_event_output()); for  kernels  older  than
       4.5, see the version under tools/old, which uses an older mechanism.

       Since this uses BPF, only the root user can use this tool.

不,信號不打算作為進程間通信通道。 據我所知,沒有通過 PID。 發送 PID 與我見過的所有信號用途無關。 您可以相對確定發送信號的進程要么具有 root 權限,要么屬於與您的進程相同的 UID。

發送信號的進程可能不再存在。 如果使用 kill 命令而不是內置的 shell,則幾乎可以肯定該進程不再存在。

從 Java 方面來看,這更加困難。 該進程在 Java 虛擬機中運行,該虛擬機是從操作系統中抽象出來的。 並非所有操作系統概念都存在於這台機器上。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM