16b3a42afSjmmv // Copyright 2012 Google Inc.
26b3a42afSjmmv // All rights reserved.
36b3a42afSjmmv //
46b3a42afSjmmv // Redistribution and use in source and binary forms, with or without
56b3a42afSjmmv // modification, are permitted provided that the following conditions are
66b3a42afSjmmv // met:
76b3a42afSjmmv //
86b3a42afSjmmv // * Redistributions of source code must retain the above copyright
96b3a42afSjmmv // notice, this list of conditions and the following disclaimer.
106b3a42afSjmmv // * Redistributions in binary form must reproduce the above copyright
116b3a42afSjmmv // notice, this list of conditions and the following disclaimer in the
126b3a42afSjmmv // documentation and/or other materials provided with the distribution.
136b3a42afSjmmv // * Neither the name of Google Inc. nor the names of its contributors
146b3a42afSjmmv // may be used to endorse or promote products derived from this software
156b3a42afSjmmv // without specific prior written permission.
166b3a42afSjmmv //
176b3a42afSjmmv // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
186b3a42afSjmmv // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
196b3a42afSjmmv // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
206b3a42afSjmmv // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
216b3a42afSjmmv // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
226b3a42afSjmmv // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
236b3a42afSjmmv // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
246b3a42afSjmmv // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
256b3a42afSjmmv // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
266b3a42afSjmmv // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
276b3a42afSjmmv // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
286b3a42afSjmmv
296b3a42afSjmmv #include "utils/signals/interrupts.hpp"
306b3a42afSjmmv
316b3a42afSjmmv extern "C" {
326b3a42afSjmmv #include <signal.h>
336b3a42afSjmmv #include <unistd.h>
346b3a42afSjmmv }
356b3a42afSjmmv
366b3a42afSjmmv #include <cstdlib>
376b3a42afSjmmv #include <cstring>
386b3a42afSjmmv #include <set>
396b3a42afSjmmv
406b3a42afSjmmv #include "utils/sanity.hpp"
416b3a42afSjmmv #include "utils/signals/exceptions.hpp"
426b3a42afSjmmv #include "utils/signals/programmer.hpp"
436b3a42afSjmmv
446b3a42afSjmmv namespace signals = utils::signals;
456b3a42afSjmmv
466b3a42afSjmmv
476b3a42afSjmmv namespace {
486b3a42afSjmmv
496b3a42afSjmmv
506b3a42afSjmmv /// The interrupt signal that fired, or -1 if none.
516b3a42afSjmmv static volatile int fired_signal = -1;
526b3a42afSjmmv
536b3a42afSjmmv
546b3a42afSjmmv /// Collection of PIDs.
556b3a42afSjmmv typedef std::set< pid_t > pids_set;
566b3a42afSjmmv
576b3a42afSjmmv
586b3a42afSjmmv /// List of processes to kill upon reception of a signal.
596b3a42afSjmmv static pids_set pids_to_kill;
606b3a42afSjmmv
616b3a42afSjmmv
626b3a42afSjmmv /// Programmer status for the SIGHUP signal.
63*46b85cbbSlukem static std::unique_ptr< signals::programmer > sighup_handler;
646b3a42afSjmmv /// Programmer status for the SIGINT signal.
65*46b85cbbSlukem static std::unique_ptr< signals::programmer > sigint_handler;
666b3a42afSjmmv /// Programmer status for the SIGTERM signal.
67*46b85cbbSlukem static std::unique_ptr< signals::programmer > sigterm_handler;
686b3a42afSjmmv
696b3a42afSjmmv
706b3a42afSjmmv /// Signal mask to restore after exiting a signal inhibited section.
716b3a42afSjmmv static sigset_t old_sigmask;
726b3a42afSjmmv
736b3a42afSjmmv
746b3a42afSjmmv /// Whether there is an interrupts_handler object in existence or not.
756b3a42afSjmmv bool interrupts_handler_active = false;
766b3a42afSjmmv
776b3a42afSjmmv
786b3a42afSjmmv /// Whether there is an interrupts_inhibiter object in existence or not.
796b3a42afSjmmv bool interrupts_inhibiter_active = false;
806b3a42afSjmmv
816b3a42afSjmmv
826b3a42afSjmmv /// Generic handler to capture interrupt signals.
836b3a42afSjmmv ///
846b3a42afSjmmv /// From this handler, we record that an interrupt has happened so that
856b3a42afSjmmv /// check_interrupt() can know whether there execution has to be stopped or not.
866b3a42afSjmmv /// We also terminate any of our child processes (started by the
876b3a42afSjmmv /// utils::process::children class) so that any ongoing wait(2) system calls
886b3a42afSjmmv /// terminate.
896b3a42afSjmmv ///
906b3a42afSjmmv /// \param signo The signal that caused this handler to be called.
916b3a42afSjmmv static void
signal_handler(const int signo)926b3a42afSjmmv signal_handler(const int signo)
936b3a42afSjmmv {
946b3a42afSjmmv static const char* message = "[-- Signal caught; please wait for "
956b3a42afSjmmv "cleanup --]\n";
966b3a42afSjmmv if (::write(STDERR_FILENO, message, std::strlen(message)) == -1) {
976b3a42afSjmmv // We are exiting: the message printed here is only for informational
986b3a42afSjmmv // purposes. If we fail to print it (which probably means something
996b3a42afSjmmv // is really bad), there is not much we can do within the signal
1006b3a42afSjmmv // handler, so just ignore this.
1016b3a42afSjmmv }
1026b3a42afSjmmv
1036b3a42afSjmmv fired_signal = signo;
1046b3a42afSjmmv
1056b3a42afSjmmv for (pids_set::const_iterator iter = pids_to_kill.begin();
1066b3a42afSjmmv iter != pids_to_kill.end(); ++iter) {
1076b3a42afSjmmv // Redirecting the interrupt signal to our child processes does NOT
1086b3a42afSjmmv // guarantee that they also terminate. For that to happen, we'd need to
1096b3a42afSjmmv // SIGKILL them.
1106b3a42afSjmmv //
1116b3a42afSjmmv // *However*, because we use this code to invoke the kyua-testers only,
1126b3a42afSjmmv // and because we assume that such processes are well-behaved and
1136b3a42afSjmmv // terminate according to our expectations, we do it this way, which
1146b3a42afSjmmv // allows the testers to know which specific signal made them terminate.
1156b3a42afSjmmv (void)::kill(*iter, signo);
1166b3a42afSjmmv }
1176b3a42afSjmmv }
1186b3a42afSjmmv
1196b3a42afSjmmv
1206b3a42afSjmmv /// Installs signal handlers for potential interrupts.
1216b3a42afSjmmv ///
1226b3a42afSjmmv /// \pre Must not have been called before.
1236b3a42afSjmmv /// \post The various sig*_handler global variables are atomically updated.
1246b3a42afSjmmv static void
setup_handlers(void)1256b3a42afSjmmv setup_handlers(void)
1266b3a42afSjmmv {
1276b3a42afSjmmv PRE(sighup_handler.get() == NULL);
1286b3a42afSjmmv PRE(sigint_handler.get() == NULL);
1296b3a42afSjmmv PRE(sigterm_handler.get() == NULL);
1306b3a42afSjmmv
1316b3a42afSjmmv // Create the handlers on the stack first so that, if any of them fails, the
1326b3a42afSjmmv // stack unwinding cleans things up.
133*46b85cbbSlukem std::unique_ptr< signals::programmer > tmp_sighup_handler(
1346b3a42afSjmmv new signals::programmer(SIGHUP, signal_handler));
135*46b85cbbSlukem std::unique_ptr< signals::programmer > tmp_sigint_handler(
1366b3a42afSjmmv new signals::programmer(SIGINT, signal_handler));
137*46b85cbbSlukem std::unique_ptr< signals::programmer > tmp_sigterm_handler(
1386b3a42afSjmmv new signals::programmer(SIGTERM, signal_handler));
1396b3a42afSjmmv
1406b3a42afSjmmv // Now, update the global pointers, which is an operation that cannot fail.
141*46b85cbbSlukem sighup_handler = std::move(tmp_sighup_handler);
142*46b85cbbSlukem sigint_handler = std::move(tmp_sigint_handler);
143*46b85cbbSlukem sigterm_handler = std::move(tmp_sigterm_handler);
1446b3a42afSjmmv }
1456b3a42afSjmmv
1466b3a42afSjmmv
1476b3a42afSjmmv /// Uninstalls the signal handlers installed by setup_handlers().
1486b3a42afSjmmv static void
cleanup_handlers(void)1496b3a42afSjmmv cleanup_handlers(void)
1506b3a42afSjmmv {
1516b3a42afSjmmv sighup_handler->unprogram(); sighup_handler.reset(NULL);
1526b3a42afSjmmv sigint_handler->unprogram(); sigint_handler.reset(NULL);
1536b3a42afSjmmv sigterm_handler->unprogram(); sigterm_handler.reset(NULL);
1546b3a42afSjmmv }
1556b3a42afSjmmv
1566b3a42afSjmmv
1576b3a42afSjmmv
1586b3a42afSjmmv /// Masks the signals installed by setup_handlers().
1596b3a42afSjmmv static void
mask_signals(void)1606b3a42afSjmmv mask_signals(void)
1616b3a42afSjmmv {
1626b3a42afSjmmv sigset_t mask;
1636b3a42afSjmmv sigemptyset(&mask);
1646b3a42afSjmmv sigaddset(&mask, SIGHUP);
1656b3a42afSjmmv sigaddset(&mask, SIGINT);
1666b3a42afSjmmv sigaddset(&mask, SIGTERM);
1676b3a42afSjmmv const int ret = ::sigprocmask(SIG_BLOCK, &mask, &old_sigmask);
1686b3a42afSjmmv INV(ret != -1);
1696b3a42afSjmmv }
1706b3a42afSjmmv
1716b3a42afSjmmv
1726b3a42afSjmmv /// Resets the signal masking put in place by mask_signals().
1736b3a42afSjmmv static void
unmask_signals(void)1746b3a42afSjmmv unmask_signals(void)
1756b3a42afSjmmv {
1766b3a42afSjmmv const int ret = ::sigprocmask(SIG_SETMASK, &old_sigmask, NULL);
1776b3a42afSjmmv INV(ret != -1);
1786b3a42afSjmmv }
1796b3a42afSjmmv
1806b3a42afSjmmv
1816b3a42afSjmmv } // anonymous namespace
1826b3a42afSjmmv
1836b3a42afSjmmv
1846b3a42afSjmmv /// Constructor that sets up the signal handlers.
interrupts_handler(void)1856b3a42afSjmmv signals::interrupts_handler::interrupts_handler(void)
1866b3a42afSjmmv {
1876b3a42afSjmmv PRE(!interrupts_handler_active);
1886b3a42afSjmmv setup_handlers();
1896b3a42afSjmmv interrupts_handler_active = true;
1906b3a42afSjmmv }
1916b3a42afSjmmv
1926b3a42afSjmmv
1936b3a42afSjmmv /// Destructor that removes the signal handlers.
~interrupts_handler(void)1946b3a42afSjmmv signals::interrupts_handler::~interrupts_handler(void)
1956b3a42afSjmmv {
1966b3a42afSjmmv cleanup_handlers();
1976b3a42afSjmmv interrupts_handler_active = false;
1986b3a42afSjmmv }
1996b3a42afSjmmv
2006b3a42afSjmmv
2016b3a42afSjmmv /// Constructor that sets up signal masking.
interrupts_inhibiter(void)2026b3a42afSjmmv signals::interrupts_inhibiter::interrupts_inhibiter(void)
2036b3a42afSjmmv {
2046b3a42afSjmmv PRE(!interrupts_inhibiter_active);
2056b3a42afSjmmv mask_signals();
2066b3a42afSjmmv interrupts_inhibiter_active = true;
2076b3a42afSjmmv }
2086b3a42afSjmmv
2096b3a42afSjmmv
2106b3a42afSjmmv /// Destructor that removes signal masking.
~interrupts_inhibiter(void)2116b3a42afSjmmv signals::interrupts_inhibiter::~interrupts_inhibiter(void)
2126b3a42afSjmmv {
2136b3a42afSjmmv unmask_signals();
2146b3a42afSjmmv interrupts_inhibiter_active = false;
2156b3a42afSjmmv }
2166b3a42afSjmmv
2176b3a42afSjmmv
2186b3a42afSjmmv /// Checks if an interrupt has fired.
2196b3a42afSjmmv ///
2206b3a42afSjmmv /// Calls to this function should be sprinkled in strategic places through the
2216b3a42afSjmmv /// code protected by an interrupts_handler object.
2226b3a42afSjmmv ///
2236b3a42afSjmmv /// \throw interrupted_error If there has been an interrupt.
2246b3a42afSjmmv void
check_interrupt(void)2256b3a42afSjmmv signals::check_interrupt(void)
2266b3a42afSjmmv {
2276b3a42afSjmmv if (fired_signal != -1)
2286b3a42afSjmmv throw interrupted_error(fired_signal);
2296b3a42afSjmmv }
2306b3a42afSjmmv
2316b3a42afSjmmv
2326b3a42afSjmmv /// Registers a child process to be killed upon reception of an interrupt.
2336b3a42afSjmmv ///
2346b3a42afSjmmv /// \pre Must be called with interrupts being inhibited. The caller must ensure
2356b3a42afSjmmv /// that the call call to fork() and the addition of the PID happen atomically.
2366b3a42afSjmmv ///
2376b3a42afSjmmv /// \param pid The PID of the child process. Must not have been yet regsitered.
2386b3a42afSjmmv void
add_pid_to_kill(const pid_t pid)2396b3a42afSjmmv signals::add_pid_to_kill(const pid_t pid)
2406b3a42afSjmmv {
2416b3a42afSjmmv PRE(interrupts_inhibiter_active);
2426b3a42afSjmmv PRE(pids_to_kill.find(pid) == pids_to_kill.end());
2436b3a42afSjmmv pids_to_kill.insert(pid);
2446b3a42afSjmmv }
2456b3a42afSjmmv
2466b3a42afSjmmv
2476b3a42afSjmmv /// Unregisters a child process previously registered via add_pid_to_kill().
2486b3a42afSjmmv ///
2496b3a42afSjmmv /// \pre Must be called with interrupts being inhibited. This is not necessary,
2506b3a42afSjmmv /// but pushing this to the caller simplifies our logic and provides consistency
2516b3a42afSjmmv /// with the add_pid_to_kill() call.
2526b3a42afSjmmv ///
2536b3a42afSjmmv /// \param pid The PID of the child process. Must have been registered
2546b3a42afSjmmv /// previously, and the process must have already been awaited for.
2556b3a42afSjmmv void
remove_pid_to_kill(const pid_t pid)2566b3a42afSjmmv signals::remove_pid_to_kill(const pid_t pid)
2576b3a42afSjmmv {
2586b3a42afSjmmv PRE(interrupts_inhibiter_active);
2596b3a42afSjmmv PRE(pids_to_kill.find(pid) != pids_to_kill.end());
2606b3a42afSjmmv pids_to_kill.erase(pid);
2616b3a42afSjmmv }
262