记录来自SIGTERM的消息
问题描述:
当应用程序(C++守护进程,在我的情况下)接收到SIGTERM或SIGINT时,记录关闭消息的正确方法是什么?记录来自SIGTERM的消息
根据CERT和signal(7) manpage,许多函数(大概包括大多数日志记录库使用的函数)对于从信号处理程序调用不安全。
答
记录无法从处理器来完成,但之后:
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源借来的。
答
Vlad Lazarenko在今年早些时候写了一个很棒的blog post关于这个话题。在Linux上,它归结为使用signalfd(2)
创建信号描述符并使用事件循环,如poll(2)
或epoll_wait(2)
。这里是从描述符中读取的Vlad的示例
#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");
}
}
}
该示例可以很容易地扩展到集成到事件循环中。
什么是环境:一个shell脚本,C程序,Perl脚本,由HTTP服务器执行的PHP脚本等? – aqn
@aqn - C++守护进程。我会更新我的问题。谢谢。 –
使用管道或(UDP)套接字将消息发送到主程序循环或单独的记录过程。 – wildplasser