简体   繁体   English

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

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

I have a java application that got SIG TERM .我有一个获得SIG TERM的 java 应用程序。 I want to know the pid of the process that sent this signal.我想知道发送这个信号的进程的pid。
Is that possible?那可能吗?

Two Linux-specific methods are SA_SIGINFO and signalfd() , which allows programs to receive very detailed information about signals sent, including the sender's PID.两个特定于 Linux 的方法是SA_SIGINFOsignalfd() ,它们允许程序接收有关发送信号的非常详细的信息,包括发送者的 PID。

  • Call sigaction() and pass to it a struct sigaction which has the desired signal handler in sa_sigaction and the SA_SIGINFO flag in sa_flags set.调用sigaction()并将struct sigaction传递给它,该struct sigactionsa_sigaction具有所需的信号处理程序,并在sa_flags设置了SA_SIGINFO标志。 With this flag, your signal handler will receive three arguments, one of which is a siginfo_t structure containing the sender's PID and UID.使用此标志,您的信号处理程序将接收三个参数,其中一个是包含发送方 PID 和 UID 的siginfo_t结构。

  • Call signalfd() and read signalfd_siginfo structures from it (usually in some kind of a select/poll loop).调用signalfd()signalfd_siginfo读取signalfd_siginfo结构(通常在某种选择/轮询循环中)。 The contents will be similar to siginfo_t .内容将类似于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.在纯 C 之外,它们可能不会很好地工作,而且我也不希望让它们在 Java 中工作。 They are also unportable outside Linux.它们在 Linux 之外也是不可移植的。 They also likely are the Very Wrong Way of doing what you are trying to achieve.他们也很可能是做你想要实现的事情的非常错误的方式。

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

Execute:执行:

./a.out

What it does:它能做什么:

The program sends SIGINT to itself 10 times, before sending SIGQUIT to terminate itself.程序向自身发送SIGINT 10 次,然后发送SIGQUIT以终止自身。

Also, during its execution, press CTRL + C to send SIGINT , or CTRL + \\ to send SIGQUIT which would terminate the program by hand.此外,在执行过程中,按CTRL + C发送SIGINT ,或按CTRL + \\发送SIGQUIT ,这将手动终止程序。

The program could successfully identify who sent the signal(s).该程序可以成功识别谁发送了信号。

BCC includes the killsnoop utility. BCC包括killsnoop实用程序。 It requires a kernel with BPF support.它需要一个支持 BPF 的内核。

Excerpt from killsnoop (8) man-page :摘自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.

No, Signals are not intended as an interprocess communication channel.不,信号不打算作为进程间通信通道。 As far as I am aware, there is no PID passed.据我所知,没有通过 PID。 The sending PID is irrelevant for all of the uses I have seen for signals.发送 PID 与我见过的所有信号用途无关。 You can be relatively sure that the processes sending the signal either had root privileges, or belonged to the same UID as your process.您可以相对确定发送信号的进程要么具有 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.从 Java 方面来看,这更加困难。 The process runs in a Java Virtual Machine, which is abstracted from the Operating System.该进程在 Java 虚拟机中运行,该虚拟机是从操作系统中抽象出来的。 Not all Operating System concepts exist with this machine.并非所有操作系统概念都存在于这台机器上。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM