Linux C:接收信号时,是否可以知道发送者的PID?

19

假设我的C程序处理 SIGUSR1 信号。

当接收到此信号时,是否可能知道是谁发送的? 也就是说,如何获取发送进程的pid?


1
这个回答解决了你的问题吗?如何在Linux中确定是哪个进程向我的进程发送了信号 - maksadbek
4个回答

17

如果你使用sigaction()调用来设置信号处理程序而不是signal,那么是的。这样做可以让您设置一个接受三个参数的信号处理程序:

  • int类型,代表信号数量(就像signal一样)
  • siginfo_t *是一个结构体,其中包含有关信号源的所有信息,包括发送者的pid(如果适用)。 (它还包括关于诸如SIGSEGV之类的自动信号引起的信号原因的一些信息。)
  • ucontext_t *与哪个线程收到信号有关,但大多数情况下可以忽略。

11

是的。使用 sigaction 注册您的信号处理器,并使用 SA_SIGINFO 标志填充 sa_sigaction 字段。现在,您的处理器函数将接受一个 siginfo_t* 参数,其中包括一个 si_pid 字段。

请注意,在某些情况下才会设置 si_pid。在您的情况下,您需要检查 si_code 是否设置为 SI_USERSI_QUEUE。阅读 man 2 sigaction 获取更多信息。


4

另一种选择是使用signalfd()。如果您使用信号在进程之间发送信息,则比信号处理程序更有结构的信号处理可能是您想要的。 struct signalfd_siginfo :: ssi_pid 是发件人。

来自手册页面的示例:

#include <sys/signalfd.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>

#define handle_error(msg) \
    do { perror(msg); exit(EXIT_FAILURE); } while (0)

int main(int argc, char *argv[]) {
    sigset_t mask;
    int sfd;
    struct signalfd_siginfo fdsi;
    ssize_t s;

    sigemptyset(&mask);
    sigaddset(&mask, SIGINT);
    sigaddset(&mask, SIGQUIT);

    /* Block signals so that they aren't handled
       according to their default dispositions */

    if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1)
        handle_error("sigprocmask");

    sfd = signalfd(-1, &mask, 0);
    if (sfd == -1)
        handle_error("signalfd");

    for (;;) {
        s = read(sfd, &fdsi, sizeof(struct signalfd_siginfo));
        if (s != sizeof(struct signalfd_siginfo))
            handle_error("read");

        if (fdsi.ssi_signo == SIGINT) {
            printf("Got SIGINT\n");
        } else if (fdsi.ssi_signo == SIGQUIT) {
            printf("Got SIGQUIT\n");
            exit(EXIT_SUCCESS);
        } else {
            printf("Read unexpected signal\n");
        }
    }
}

参见:sigqueue()。与kill()类似,但您可以在同一调用中传递整数或指针。


2
这是一个完整的POSIX标准sigaction() API示例:
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

void sigusr1(int signo, siginfo_t *si, void *data) {
  (void)signo;
  (void)data;
  printf("Signal %d from pid %lu\n", (int)si->si_signo,
         (unsigned long)si->si_pid);
  exit(0);
}

int main(void) {
  struct sigaction sa;
  memset(&sa, 0, sizeof(sa));
  sa.sa_flags = SA_SIGINFO;
  sa.sa_sigaction = sigusr1;
  if (sigaction(SIGUSR1, &sa, 0) == -1) {
    fprintf(stderr, "%s: %s\n", "sigaction", strerror(errno));
  }
  printf("Pid %lu waiting for SIGUSR1\n", (unsigned long)getpid());
  for (;;) {
    sleep(10);
  }
  return 0;
}

尝试运行它,然后发送SIGUSR1信号(例如,在shell中使用kill -SIGUSR1 that-pid命令)。 sigaction函数: http://pubs.opengroup.org/onlinepubs/009604499/functions/sigaction.html siginfo结构体: http://pubs.opengroup.org/onlinepubs/009604499/basedefs/signal.h.html

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接