繁体   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