【问题标题】:Linux C: upon receiving a signal, is it possible to know the PID of the sender?Linux C:收到信号后,是否可以知道发送者的PID?
【发布时间】:2012-07-15 13:03:06
【问题描述】:

假设我的 C 程序处理 SIGUSR1

当它收到这个信号时,有没有可能知道是谁发出的? 即,如何获取发送者进程的pid?

【问题讨论】:

标签: c linux signals system ipc


【解决方案1】:

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

  • 一个int,用于信号编号(就像signal
  • siginfo_t *,这是一个包含有关信号源的各种信息的结构,包括发送者的 pid(如果适用)。 (它还包括一些关于自动信号的信号原因的信息,例如SIGSEGV。)
  • ucontext_t *,与哪个线程收到信号有关。几乎可以忽略不计。

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

      【解决方案3】:

      另一个选项是使用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() 类似,但您可以在同一个调用中传递整数或指针。

      【讨论】:

        【解决方案4】:

        这是 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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-06-03
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多