Linux C: после получения сигнала можно ли узнать идентификатор отправителя?

Предположим, что моя программа C обрабатывает SIGUSR1. Когда он получает сигнал, можно ли узнать, кто его отправил? То есть,. получить pid этого процесса?

Ответ 1

Да, если вы используете вызов sigaction для настройки вашего обработчика сигнала вместо signal. Это позволит вам настроить обработчик сигнала, который принимает три параметра:

  • An int, для номера сигнала (точно так же, как signal)
  • A siginfo_t *, который представляет собой структуру, содержащую все виды информации об источнике сигнала, включая pid отправителя, если применимо. (Он также содержит некоторую информацию о причине сигнала для автоматических сигналов типа SIGSEGV.)
  • A ucontext_t *, который связан с тем, какой поток получил сигнал. В основном игнорируется.

Ответ 2

Да. Зарегистрируйте обработчик сигнала, используя sigaction с флагом SA_SIGINFO, заполняя поле sa_sigaction. Теперь ваша функция обработчика принимает параметр siginfo_t*, который включает в себя поле si_pid.

Обратите внимание, что si_pid устанавливается только при некоторых обстоятельствах. В вашем случае вам нужно проверить, что для параметра si_code установлено значение SI_USER или SI_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(), но вы можете передать целое число или указатель в том же вызове.