アプリケーション (私の場合は C++ デーモン) が SIGTERM または SIGINT を受け取ったときに、シャットダウン メッセージをログに記録する適切な方法は何ですか?
CERTとsignal(7) manpageによると、多くの関数 (おそらく、ほとんどのロギング ライブラリで使用されている関数を含む) は、シグナル ハンドラから呼び出すのは安全ではありません。
アプリケーション (私の場合は C++ デーモン) が SIGTERM または SIGINT を受け取ったときに、シャットダウン メッセージをログに記録する適切な方法は何ですか?
CERTとsignal(7) manpageによると、多くの関数 (おそらく、ほとんどのロギング ライブラリで使用されている関数を含む) は、シグナル ハンドラから呼び出すのは安全ではありません。
Vlad Lazarenkoは、今年の初めにこのトピックについて素晴らしいブログ投稿を書きました。Linux では、シグナル記述子を作成し、またはsignalfd(2)
などのイベント ループを使用することになります。記述子から読み取った Vlad の例を次に示します。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");
}
}
}
この例は、イベント ループに統合するように簡単に拡張できます。