Регистрация сообщения от SIGTERM

Как правильно регистрировать сообщение о завершении работы, когда приложение (в моем случае демон C++) получает SIGTERM или SIGINT?

Согласно CERT и man-странице signal(7), многие функции (в том числе, предположительно, используемые большинством библиотек журналов) небезопасны для вызова из обработчиков сигналов.

2 ответа

Влад Лазаренко написал отличный пост в начале этого года на эту тему. В Linux это сводится к созданию дескриптора сигнала с signalfd(2) и использовать цикл событий, такой как poll(2) или же epoll_wait(2), Вот пример чтения Влада из дескриптора

#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");
        }
    }
}

Этот пример может быть легко расширен для интеграции в цикл обработки событий.

Ведение журнала может быть сделано не из обработчика, а после него:

int received_sigterm = 0;

void
sigterm_handler(int sig)
{
  received_sigterm = 1;
}

void
loop(void)
{
  for(;;) {
    sleep(1);
    if (received_sigterm)
      log("finish\n");
  }
}

int
main()
{
  log("start\n");
  signal(SIGTERM, sigterm_handler);
  loop();
}

Концепция заимствована из источников openssh-6.1.

Другие вопросы по тегам