当一个应用程序(一个C ++守护进程,在我的情况下)接收到一个SIGTERM或SIGINT时,loggingclosures消息的正确方法是什么?
根据CERT和signal(7)手册页 ,许多函数(包括大多数日志logging库使用的函数)对于来自信号处理程序的调用是不安全的。
弗拉德·拉扎连科 ( Vlad Lazarenko )在今年早些时候就这个话题写了一篇很棒的博客 。 在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来源中借鉴的。