如何在 Linux 中判断哪个进程向我的进程发送了信号

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/8400530/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 03:31:26  来源:igfitidea点击:

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

linuxsignals

提问by oshai

I have a java application that got SIG TERM. I want to know the pid of the process that sent this signal.
Is that possible?

我有一个 Java 应用程序,它得到了SIG TERM. 我想知道发送这个信号的进程的pid。
那可能吗?

采纳答案by user1686

Two Linux-specific methods are SA_SIGINFOand signalfd(), which allows programs to receive verydetailed information about signals sent, including the sender's PID.

两个特定于 Linux 的方法是SA_SIGINFOsignalfd(),它允许程序接收有关发送信号的非常详细的信息,包括发送者的 PID。

  • Call sigaction()and pass to it a struct sigactionwhich has the desired signal handler in sa_sigactionand the SA_SIGINFOflag in sa_flagsset. With this flag, your signal handler will receive threearguments, one of which is a siginfo_tstructure containing the sender's PID and UID.

  • Call signalfd()and read signalfd_siginfostructures from it (usually in some kind of a select/poll loop). The contents will be similar to siginfo_t.

  • 调用sigaction()并传递给它 a struct sigaction,其中包含所需的信号处理程序sa_sigaction和设置的SA_SIGINFO标志sa_flags。使用此标志,您的信号处理程序将接收三个参数,其中一个是siginfo_t包含发送方 PID 和 UID 的结构。

  • 从中调用signalfd()和读取signalfd_siginfo结构(通常在某种选择/轮询循环中)。内容将类似于siginfo_t.

Which one to use depends on how your application is written; they probably won't work well outside plain C, and I wouldn't have any hope of getting them work in Java. They are also unportable outside Linux. They also likely are the Very Wrong Way of doing what you are trying to achieve.

使用哪一个取决于你的应用程序是如何编写的;在纯 C 之外,它们可能不会很好地工作,而且我也不希望让它们在 Java 中工作。它们在 Linux 之外也是不可移植的。他们也很可能是做你想要实现的事情的非常错误的方式。

回答by BillThor

No, Signals are not intended as an interprocess communication channel. As far as I am aware, there is no PID passed. The sending PID is irrelevant for all of the uses I have seen for signals. You can be relatively sure that the processes sending the signal either had root privileges, or belonged to the the same UID as your process.

不,信号不打算作为进程间通信通道。据我所知,没有通过 PID。发送 PID 与我见过的所有信号用途无关。您可以相对确定发送信号的进程要么具有 root 权限,要么属于与您的进程相同的 UID。

It is possible that the process that sent the signal does not exist anymore. If the kill command was used rather than the shell built-in, it is almost certain the process no longer exists.

发送信号的进程可能不再存在。如果使用 kill 命令而不是内置的 shell,则几乎可以肯定该进程不再存在。

From the Java side this is even more difficult. The process runs in a Java Virtual Machine, which is abstracted from the Operating System. Not all Operating System concepts exist with this machine.

从 Java 方面来看,这更加困难。该进程在 Java 虚拟机中运行,该虚拟机是从操作系统中抽象出来的。并非所有操作系统概念都存在于这台机器上。

回答by Eric Wang

I also needed to identify the signal sender in a program, so I took grawity's answer, and used it in my program, it works well.

我还需要在程序中识别信号发送者,所以我采用了grawity的答案,并在我的程序中使用它,效果很好。

Here's the sample code:

这是示例代码:

send_signal_raise.c

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;
}

Compile:

编译:

gcc -pthread -Wall send_signal_raise.c

gcc -pthread -Wall send_signal_raise.c

Execute:

执行:

./a.out

./a.out

What it does:

它能做什么:

The program sends SIGINTto itself 10 times, before sending SIGQUITto terminate itself.

程序向SIGINT自身发送10 次,然后发送SIGQUIT以终止自身。

Also, during its execution, press CTRL+Cto send SIGINT, or CTRL+\to send SIGQUITwhich would terminate the program by hand.

此外,它的执行过程中,按CTRL+CSIGINT,或CTRL+\SIGQUIT这将手工终止程序。

The program could successfully identify who sent the signal(s).

该程序可以成功识别谁发送了信号。