1 // Copyright (C) 2020 Joel Rosdahl and other contributors
3 // See doc/AUTHORS.adoc for a complete list of contributors.
5 // This program is free software; you can redistribute it and/or modify it
6 // under the terms of the GNU General Public License as published by the Free
7 // Software Foundation; either version 3 of the License, or (at your option)
10 // This program is distributed in the hope that it will be useful, but WITHOUT
11 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 // You should have received a copy of the GNU General Public License along with
16 // this program; if not, write to the Free Software Foundation, Inc., 51
17 // Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 #include "SignalHandler.hpp"
21 #include "assertions.hpp"
25 # include "Context.hpp"
29 SignalHandler* g_the_signal_handler = nullptr;
30 sigset_t g_fatal_signal_set;
33 register_signal_handler(int signum)
36 memset(&act, 0, sizeof(act));
37 act.sa_handler = SignalHandler::on_signal;
38 act.sa_mask = g_fatal_signal_set;
40 act.sa_flags = SA_RESTART;
42 sigaction(signum, &act, nullptr);
47 SignalHandler::SignalHandler(Context& ctx) : m_ctx(ctx)
49 ASSERT(!g_the_signal_handler);
50 g_the_signal_handler = this;
52 sigemptyset(&g_fatal_signal_set);
53 sigaddset(&g_fatal_signal_set, SIGINT);
54 sigaddset(&g_fatal_signal_set, SIGTERM);
56 sigaddset(&g_fatal_signal_set, SIGHUP);
59 sigaddset(&g_fatal_signal_set, SIGQUIT);
62 register_signal_handler(SIGINT);
63 register_signal_handler(SIGTERM);
65 register_signal_handler(SIGHUP);
68 register_signal_handler(SIGQUIT);
72 SignalHandler::~SignalHandler()
74 ASSERT(g_the_signal_handler);
75 g_the_signal_handler = nullptr;
79 SignalHandler::on_signal(int signum)
81 ASSERT(g_the_signal_handler);
82 Context& ctx = g_the_signal_handler->m_ctx;
84 // Unregister handler for this signal so that we can send the signal to
85 // ourselves at the end of the handler.
86 signal(signum, SIG_DFL);
88 // If ccache was killed explicitly, then bring the compiler subprocess (if
89 // any) with us as well.
90 if (signum == SIGTERM && ctx.compiler_pid != 0
91 && waitpid(ctx.compiler_pid, nullptr, WNOHANG) == 0) {
92 kill(ctx.compiler_pid, signum);
95 ctx.unlink_pending_tmp_files_signal_safe();
97 if (ctx.compiler_pid != 0) {
98 // Wait for compiler subprocess to exit before we snuff it.
99 waitpid(ctx.compiler_pid, nullptr, 0);
102 // Resend signal to ourselves to exit properly after returning from the
104 kill(getpid(), signum);
109 SignalHandler::SignalHandler(Context& ctx) : m_ctx(ctx)
113 SignalHandler::~SignalHandler()
120 SignalHandler::block_signals()
123 sigprocmask(SIG_BLOCK, &g_fatal_signal_set, nullptr);
128 SignalHandler::unblock_signals()
133 sigprocmask(SIG_SETMASK, &empty, nullptr);
137 SignalHandlerBlocker::SignalHandlerBlocker()
139 SignalHandler::block_signals();
142 SignalHandlerBlocker::~SignalHandlerBlocker()
144 SignalHandler::unblock_signals();