1b0d29bc4SBrooks Davis // Copyright 2012 The Kyua Authors.
2b0d29bc4SBrooks Davis // All rights reserved.
3b0d29bc4SBrooks Davis //
4b0d29bc4SBrooks Davis // Redistribution and use in source and binary forms, with or without
5b0d29bc4SBrooks Davis // modification, are permitted provided that the following conditions are
6b0d29bc4SBrooks Davis // met:
7b0d29bc4SBrooks Davis //
8b0d29bc4SBrooks Davis // * Redistributions of source code must retain the above copyright
9b0d29bc4SBrooks Davis // notice, this list of conditions and the following disclaimer.
10b0d29bc4SBrooks Davis // * Redistributions in binary form must reproduce the above copyright
11b0d29bc4SBrooks Davis // notice, this list of conditions and the following disclaimer in the
12b0d29bc4SBrooks Davis // documentation and/or other materials provided with the distribution.
13b0d29bc4SBrooks Davis // * Neither the name of Google Inc. nor the names of its contributors
14b0d29bc4SBrooks Davis // may be used to endorse or promote products derived from this software
15b0d29bc4SBrooks Davis // without specific prior written permission.
16b0d29bc4SBrooks Davis //
17b0d29bc4SBrooks Davis // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18b0d29bc4SBrooks Davis // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19b0d29bc4SBrooks Davis // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20b0d29bc4SBrooks Davis // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21b0d29bc4SBrooks Davis // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22b0d29bc4SBrooks Davis // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23b0d29bc4SBrooks Davis // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24b0d29bc4SBrooks Davis // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25b0d29bc4SBrooks Davis // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26b0d29bc4SBrooks Davis // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27b0d29bc4SBrooks Davis // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28b0d29bc4SBrooks Davis
29b0d29bc4SBrooks Davis #include "utils/signals/interrupts.hpp"
30b0d29bc4SBrooks Davis
31b0d29bc4SBrooks Davis extern "C" {
32b0d29bc4SBrooks Davis #include <sys/types.h>
33b0d29bc4SBrooks Davis
34b0d29bc4SBrooks Davis #include <signal.h>
35b0d29bc4SBrooks Davis #include <unistd.h>
36b0d29bc4SBrooks Davis }
37b0d29bc4SBrooks Davis
38b0d29bc4SBrooks Davis #include <cstdlib>
39b0d29bc4SBrooks Davis #include <cstring>
40b0d29bc4SBrooks Davis #include <set>
41b0d29bc4SBrooks Davis
42b0d29bc4SBrooks Davis #include "utils/logging/macros.hpp"
43b0d29bc4SBrooks Davis #include "utils/process/operations.hpp"
44b0d29bc4SBrooks Davis #include "utils/sanity.hpp"
45b0d29bc4SBrooks Davis #include "utils/signals/exceptions.hpp"
46b0d29bc4SBrooks Davis #include "utils/signals/programmer.hpp"
47b0d29bc4SBrooks Davis
48b0d29bc4SBrooks Davis namespace signals = utils::signals;
49b0d29bc4SBrooks Davis namespace process = utils::process;
50b0d29bc4SBrooks Davis
51b0d29bc4SBrooks Davis
52b0d29bc4SBrooks Davis namespace {
53b0d29bc4SBrooks Davis
54b0d29bc4SBrooks Davis
55b0d29bc4SBrooks Davis /// The interrupt signal that fired, or -1 if none.
56b0d29bc4SBrooks Davis static volatile int fired_signal = -1;
57b0d29bc4SBrooks Davis
58b0d29bc4SBrooks Davis
59b0d29bc4SBrooks Davis /// Collection of PIDs.
60b0d29bc4SBrooks Davis typedef std::set< pid_t > pids_set;
61b0d29bc4SBrooks Davis
62b0d29bc4SBrooks Davis
63b0d29bc4SBrooks Davis /// List of processes to kill upon reception of a signal.
64b0d29bc4SBrooks Davis static pids_set pids_to_kill;
65b0d29bc4SBrooks Davis
66b0d29bc4SBrooks Davis
67b0d29bc4SBrooks Davis /// Programmer status for the SIGHUP signal.
68b392a90bSJohn Baldwin static std::unique_ptr< signals::programmer > sighup_handler;
69b0d29bc4SBrooks Davis /// Programmer status for the SIGINT signal.
70b392a90bSJohn Baldwin static std::unique_ptr< signals::programmer > sigint_handler;
71b0d29bc4SBrooks Davis /// Programmer status for the SIGTERM signal.
72b392a90bSJohn Baldwin static std::unique_ptr< signals::programmer > sigterm_handler;
73b0d29bc4SBrooks Davis
74b0d29bc4SBrooks Davis
75b0d29bc4SBrooks Davis /// Signal mask to restore after exiting a signal inhibited section.
76b0d29bc4SBrooks Davis static sigset_t global_old_sigmask;
77b0d29bc4SBrooks Davis
78b0d29bc4SBrooks Davis
79b0d29bc4SBrooks Davis /// Whether there is an interrupts_handler object in existence or not.
80b0d29bc4SBrooks Davis static bool interrupts_handler_active = false;
81b0d29bc4SBrooks Davis
82b0d29bc4SBrooks Davis
83b0d29bc4SBrooks Davis /// Whether there is an interrupts_inhibiter object in existence or not.
84b0d29bc4SBrooks Davis static std::size_t interrupts_inhibiter_active = 0;
85b0d29bc4SBrooks Davis
86b0d29bc4SBrooks Davis
87b0d29bc4SBrooks Davis /// Generic handler to capture interrupt signals.
88b0d29bc4SBrooks Davis ///
89b0d29bc4SBrooks Davis /// From this handler, we record that an interrupt has happened so that
90b0d29bc4SBrooks Davis /// check_interrupt() can know whether there execution has to be stopped or not.
91b0d29bc4SBrooks Davis /// We also terminate any of our child processes (started by the
92b0d29bc4SBrooks Davis /// utils::process::children class) so that any ongoing wait(2) system calls
93b0d29bc4SBrooks Davis /// terminate.
94b0d29bc4SBrooks Davis ///
95b0d29bc4SBrooks Davis /// \param signo The signal that caused this handler to be called.
96b0d29bc4SBrooks Davis static void
signal_handler(const int signo)97b0d29bc4SBrooks Davis signal_handler(const int signo)
98b0d29bc4SBrooks Davis {
99b0d29bc4SBrooks Davis static const char* message = "[-- Signal caught; please wait for "
100b0d29bc4SBrooks Davis "cleanup --]\n";
101b0d29bc4SBrooks Davis if (::write(STDERR_FILENO, message, std::strlen(message)) == -1) {
102b0d29bc4SBrooks Davis // We are exiting: the message printed here is only for informational
103b0d29bc4SBrooks Davis // purposes. If we fail to print it (which probably means something
104b0d29bc4SBrooks Davis // is really bad), there is not much we can do within the signal
105b0d29bc4SBrooks Davis // handler, so just ignore this.
106b0d29bc4SBrooks Davis }
107b0d29bc4SBrooks Davis
108b0d29bc4SBrooks Davis fired_signal = signo;
109b0d29bc4SBrooks Davis
110b0d29bc4SBrooks Davis for (pids_set::const_iterator iter = pids_to_kill.begin();
111b0d29bc4SBrooks Davis iter != pids_to_kill.end(); ++iter) {
112b0d29bc4SBrooks Davis process::terminate_group(*iter);
113b0d29bc4SBrooks Davis }
114b0d29bc4SBrooks Davis }
115b0d29bc4SBrooks Davis
116b0d29bc4SBrooks Davis
117b0d29bc4SBrooks Davis /// Installs signal handlers for potential interrupts.
118b0d29bc4SBrooks Davis ///
119b0d29bc4SBrooks Davis /// \pre Must not have been called before.
120b0d29bc4SBrooks Davis /// \post The various sig*_handler global variables are atomically updated.
121b0d29bc4SBrooks Davis static void
setup_handlers(void)122b0d29bc4SBrooks Davis setup_handlers(void)
123b0d29bc4SBrooks Davis {
124b0d29bc4SBrooks Davis PRE(sighup_handler.get() == NULL);
125b0d29bc4SBrooks Davis PRE(sigint_handler.get() == NULL);
126b0d29bc4SBrooks Davis PRE(sigterm_handler.get() == NULL);
127b0d29bc4SBrooks Davis
128b0d29bc4SBrooks Davis // Create the handlers on the stack first so that, if any of them fails, the
129b0d29bc4SBrooks Davis // stack unwinding cleans things up.
130b392a90bSJohn Baldwin std::unique_ptr< signals::programmer > tmp_sighup_handler(
131b0d29bc4SBrooks Davis new signals::programmer(SIGHUP, signal_handler));
132b392a90bSJohn Baldwin std::unique_ptr< signals::programmer > tmp_sigint_handler(
133b0d29bc4SBrooks Davis new signals::programmer(SIGINT, signal_handler));
134b392a90bSJohn Baldwin std::unique_ptr< signals::programmer > tmp_sigterm_handler(
135b0d29bc4SBrooks Davis new signals::programmer(SIGTERM, signal_handler));
136b0d29bc4SBrooks Davis
137b0d29bc4SBrooks Davis // Now, update the global pointers, which is an operation that cannot fail.
138b392a90bSJohn Baldwin sighup_handler = std::move(tmp_sighup_handler);
139b392a90bSJohn Baldwin sigint_handler = std::move(tmp_sigint_handler);
140b392a90bSJohn Baldwin sigterm_handler = std::move(tmp_sigterm_handler);
141b0d29bc4SBrooks Davis }
142b0d29bc4SBrooks Davis
143b0d29bc4SBrooks Davis
144b0d29bc4SBrooks Davis /// Uninstalls the signal handlers installed by setup_handlers().
145b0d29bc4SBrooks Davis static void
cleanup_handlers(void)146b0d29bc4SBrooks Davis cleanup_handlers(void)
147b0d29bc4SBrooks Davis {
148*d61c8bcaSJohn Baldwin sighup_handler->unprogram(); sighup_handler.reset();
149*d61c8bcaSJohn Baldwin sigint_handler->unprogram(); sigint_handler.reset();
150*d61c8bcaSJohn Baldwin sigterm_handler->unprogram(); sigterm_handler.reset();
151b0d29bc4SBrooks Davis }
152b0d29bc4SBrooks Davis
153b0d29bc4SBrooks Davis
154b0d29bc4SBrooks Davis
155b0d29bc4SBrooks Davis /// Masks the signals installed by setup_handlers().
156b0d29bc4SBrooks Davis ///
157b0d29bc4SBrooks Davis /// \param[out] old_sigmask The old signal mask to save via the
158b0d29bc4SBrooks Davis /// \code oset \endcode argument with sigprocmask(2).
159b0d29bc4SBrooks Davis static void
mask_signals(sigset_t * old_sigmask)160b0d29bc4SBrooks Davis mask_signals(sigset_t* old_sigmask)
161b0d29bc4SBrooks Davis {
162b0d29bc4SBrooks Davis sigset_t mask;
163b0d29bc4SBrooks Davis sigemptyset(&mask);
164b0d29bc4SBrooks Davis sigaddset(&mask, SIGALRM);
165b0d29bc4SBrooks Davis sigaddset(&mask, SIGHUP);
166b0d29bc4SBrooks Davis sigaddset(&mask, SIGINT);
167b0d29bc4SBrooks Davis sigaddset(&mask, SIGTERM);
168b0d29bc4SBrooks Davis const int ret = ::sigprocmask(SIG_BLOCK, &mask, old_sigmask);
169b0d29bc4SBrooks Davis INV(ret != -1);
170b0d29bc4SBrooks Davis }
171b0d29bc4SBrooks Davis
172b0d29bc4SBrooks Davis
173b0d29bc4SBrooks Davis /// Resets the signal masking put in place by mask_signals().
174b0d29bc4SBrooks Davis ///
175b0d29bc4SBrooks Davis /// \param[in] old_sigmask The old signal mask to restore via the
176b0d29bc4SBrooks Davis /// \code set \endcode argument with sigprocmask(2).
177b0d29bc4SBrooks Davis static void
unmask_signals(sigset_t * old_sigmask)178b0d29bc4SBrooks Davis unmask_signals(sigset_t* old_sigmask)
179b0d29bc4SBrooks Davis {
180b0d29bc4SBrooks Davis const int ret = ::sigprocmask(SIG_SETMASK, old_sigmask, NULL);
181b0d29bc4SBrooks Davis INV(ret != -1);
182b0d29bc4SBrooks Davis }
183b0d29bc4SBrooks Davis
184b0d29bc4SBrooks Davis
185b0d29bc4SBrooks Davis } // anonymous namespace
186b0d29bc4SBrooks Davis
187b0d29bc4SBrooks Davis
188b0d29bc4SBrooks Davis /// Constructor that sets up the signal handlers.
interrupts_handler(void)189b0d29bc4SBrooks Davis signals::interrupts_handler::interrupts_handler(void) :
190b0d29bc4SBrooks Davis _programmed(false)
191b0d29bc4SBrooks Davis {
192b0d29bc4SBrooks Davis PRE(!interrupts_handler_active);
193b0d29bc4SBrooks Davis setup_handlers();
194b0d29bc4SBrooks Davis _programmed = true;
195b0d29bc4SBrooks Davis interrupts_handler_active = true;
196b0d29bc4SBrooks Davis }
197b0d29bc4SBrooks Davis
198b0d29bc4SBrooks Davis
199b0d29bc4SBrooks Davis /// Destructor that removes the signal handlers.
200b0d29bc4SBrooks Davis ///
201b0d29bc4SBrooks Davis /// Given that this is a destructor and it can't report errors back to the
202b0d29bc4SBrooks Davis /// caller, the caller must attempt to call unprogram() on its own.
~interrupts_handler(void)203b0d29bc4SBrooks Davis signals::interrupts_handler::~interrupts_handler(void)
204b0d29bc4SBrooks Davis {
205b0d29bc4SBrooks Davis if (_programmed) {
206b0d29bc4SBrooks Davis LW("Destroying still-programmed signals::interrupts_handler object");
207b0d29bc4SBrooks Davis try {
208b0d29bc4SBrooks Davis unprogram();
209b0d29bc4SBrooks Davis } catch (const error& e) {
210b0d29bc4SBrooks Davis UNREACHABLE;
211b0d29bc4SBrooks Davis }
212b0d29bc4SBrooks Davis }
213b0d29bc4SBrooks Davis }
214b0d29bc4SBrooks Davis
215b0d29bc4SBrooks Davis
216b0d29bc4SBrooks Davis /// Unprograms all signals captured by the interrupts handler.
217b0d29bc4SBrooks Davis ///
218b0d29bc4SBrooks Davis /// \throw system_error If the unprogramming of any signal fails.
219b0d29bc4SBrooks Davis void
unprogram(void)220b0d29bc4SBrooks Davis signals::interrupts_handler::unprogram(void)
221b0d29bc4SBrooks Davis {
222b0d29bc4SBrooks Davis PRE(_programmed);
223b0d29bc4SBrooks Davis
224b0d29bc4SBrooks Davis // Modify the control variables first before unprogramming the handlers. If
225b0d29bc4SBrooks Davis // we fail to do the latter, we do not want to try again because we will not
226b0d29bc4SBrooks Davis // succeed (and we'll cause a crash due to failed preconditions).
227b0d29bc4SBrooks Davis _programmed = false;
228b0d29bc4SBrooks Davis interrupts_handler_active = false;
229b0d29bc4SBrooks Davis
230b0d29bc4SBrooks Davis cleanup_handlers();
231b0d29bc4SBrooks Davis fired_signal = -1;
232b0d29bc4SBrooks Davis }
233b0d29bc4SBrooks Davis
234b0d29bc4SBrooks Davis
235b0d29bc4SBrooks Davis /// Constructor that sets up signal masking.
interrupts_inhibiter(void)236b0d29bc4SBrooks Davis signals::interrupts_inhibiter::interrupts_inhibiter(void)
237b0d29bc4SBrooks Davis {
238b0d29bc4SBrooks Davis sigset_t old_sigmask;
239b0d29bc4SBrooks Davis mask_signals(&old_sigmask);
240b0d29bc4SBrooks Davis if (interrupts_inhibiter_active == 0) {
241b0d29bc4SBrooks Davis global_old_sigmask = old_sigmask;
242b0d29bc4SBrooks Davis }
243b0d29bc4SBrooks Davis ++interrupts_inhibiter_active;
244b0d29bc4SBrooks Davis }
245b0d29bc4SBrooks Davis
246b0d29bc4SBrooks Davis
247b0d29bc4SBrooks Davis /// Destructor that removes signal masking.
~interrupts_inhibiter(void)248b0d29bc4SBrooks Davis signals::interrupts_inhibiter::~interrupts_inhibiter(void)
249b0d29bc4SBrooks Davis {
250b0d29bc4SBrooks Davis if (interrupts_inhibiter_active > 1) {
251b0d29bc4SBrooks Davis --interrupts_inhibiter_active;
252b0d29bc4SBrooks Davis } else {
253b0d29bc4SBrooks Davis interrupts_inhibiter_active = false;
254b0d29bc4SBrooks Davis unmask_signals(&global_old_sigmask);
255b0d29bc4SBrooks Davis }
256b0d29bc4SBrooks Davis }
257b0d29bc4SBrooks Davis
258b0d29bc4SBrooks Davis
259b0d29bc4SBrooks Davis /// Checks if an interrupt has fired.
260b0d29bc4SBrooks Davis ///
261b0d29bc4SBrooks Davis /// Calls to this function should be sprinkled in strategic places through the
262b0d29bc4SBrooks Davis /// code protected by an interrupts_handler object.
263b0d29bc4SBrooks Davis ///
264b0d29bc4SBrooks Davis /// Only one call to this function will raise an exception per signal received.
265b0d29bc4SBrooks Davis /// This is to allow executing cleanup actions without reraising interrupt
266b0d29bc4SBrooks Davis /// exceptions unless the user has fired another interrupt.
267b0d29bc4SBrooks Davis ///
268b0d29bc4SBrooks Davis /// \throw interrupted_error If there has been an interrupt.
269b0d29bc4SBrooks Davis void
check_interrupt(void)270b0d29bc4SBrooks Davis signals::check_interrupt(void)
271b0d29bc4SBrooks Davis {
272b0d29bc4SBrooks Davis if (fired_signal != -1) {
273b0d29bc4SBrooks Davis const int original_fired_signal = fired_signal;
274b0d29bc4SBrooks Davis fired_signal = -1;
275b0d29bc4SBrooks Davis throw interrupted_error(original_fired_signal);
276b0d29bc4SBrooks Davis }
277b0d29bc4SBrooks Davis }
278b0d29bc4SBrooks Davis
279b0d29bc4SBrooks Davis
280b0d29bc4SBrooks Davis /// Registers a child process to be killed upon reception of an interrupt.
281b0d29bc4SBrooks Davis ///
282b0d29bc4SBrooks Davis /// \pre Must be called with interrupts being inhibited. The caller must ensure
283b0d29bc4SBrooks Davis /// that the call call to fork() and the addition of the PID happen atomically.
284b0d29bc4SBrooks Davis ///
285b0d29bc4SBrooks Davis /// \param pid The PID of the child process. Must not have been yet regsitered.
286b0d29bc4SBrooks Davis void
add_pid_to_kill(const pid_t pid)287b0d29bc4SBrooks Davis signals::add_pid_to_kill(const pid_t pid)
288b0d29bc4SBrooks Davis {
289b0d29bc4SBrooks Davis PRE(interrupts_inhibiter_active);
290b0d29bc4SBrooks Davis PRE(pids_to_kill.find(pid) == pids_to_kill.end());
291b0d29bc4SBrooks Davis pids_to_kill.insert(pid);
292b0d29bc4SBrooks Davis }
293b0d29bc4SBrooks Davis
294b0d29bc4SBrooks Davis
295b0d29bc4SBrooks Davis /// Unregisters a child process previously registered via add_pid_to_kill().
296b0d29bc4SBrooks Davis ///
297b0d29bc4SBrooks Davis /// \pre Must be called with interrupts being inhibited. This is not necessary,
298b0d29bc4SBrooks Davis /// but pushing this to the caller simplifies our logic and provides consistency
299b0d29bc4SBrooks Davis /// with the add_pid_to_kill() call.
300b0d29bc4SBrooks Davis ///
301b0d29bc4SBrooks Davis /// \param pid The PID of the child process. Must have been registered
302b0d29bc4SBrooks Davis /// previously, and the process must have already been awaited for.
303b0d29bc4SBrooks Davis void
remove_pid_to_kill(const pid_t pid)304b0d29bc4SBrooks Davis signals::remove_pid_to_kill(const pid_t pid)
305b0d29bc4SBrooks Davis {
306b0d29bc4SBrooks Davis PRE(interrupts_inhibiter_active);
307b0d29bc4SBrooks Davis PRE(pids_to_kill.find(pid) != pids_to_kill.end());
308b0d29bc4SBrooks Davis pids_to_kill.erase(pid);
309b0d29bc4SBrooks Davis }
310