xref: /minix3/external/bsd/kyua-cli/dist/utils/signals/interrupts.cpp (revision 3260d16f34636651fb9ef891a1ffe03fd23b513d)
111be35a1SLionel Sambuc // Copyright 2012 Google Inc.
211be35a1SLionel Sambuc // All rights reserved.
311be35a1SLionel Sambuc //
411be35a1SLionel Sambuc // Redistribution and use in source and binary forms, with or without
511be35a1SLionel Sambuc // modification, are permitted provided that the following conditions are
611be35a1SLionel Sambuc // met:
711be35a1SLionel Sambuc //
811be35a1SLionel Sambuc // * Redistributions of source code must retain the above copyright
911be35a1SLionel Sambuc //   notice, this list of conditions and the following disclaimer.
1011be35a1SLionel Sambuc // * Redistributions in binary form must reproduce the above copyright
1111be35a1SLionel Sambuc //   notice, this list of conditions and the following disclaimer in the
1211be35a1SLionel Sambuc //   documentation and/or other materials provided with the distribution.
1311be35a1SLionel Sambuc // * Neither the name of Google Inc. nor the names of its contributors
1411be35a1SLionel Sambuc //   may be used to endorse or promote products derived from this software
1511be35a1SLionel Sambuc //   without specific prior written permission.
1611be35a1SLionel Sambuc //
1711be35a1SLionel Sambuc // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1811be35a1SLionel Sambuc // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1911be35a1SLionel Sambuc // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2011be35a1SLionel Sambuc // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2111be35a1SLionel Sambuc // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2211be35a1SLionel Sambuc // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2311be35a1SLionel Sambuc // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2411be35a1SLionel Sambuc // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2511be35a1SLionel Sambuc // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2611be35a1SLionel Sambuc // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2711be35a1SLionel Sambuc // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2811be35a1SLionel Sambuc 
2911be35a1SLionel Sambuc #include "utils/signals/interrupts.hpp"
3011be35a1SLionel Sambuc 
3111be35a1SLionel Sambuc extern "C" {
3211be35a1SLionel Sambuc #include <signal.h>
3311be35a1SLionel Sambuc #include <unistd.h>
3411be35a1SLionel Sambuc }
3511be35a1SLionel Sambuc 
3611be35a1SLionel Sambuc #include <cstdlib>
3711be35a1SLionel Sambuc #include <cstring>
3811be35a1SLionel Sambuc #include <set>
3911be35a1SLionel Sambuc 
4011be35a1SLionel Sambuc #include "utils/sanity.hpp"
4111be35a1SLionel Sambuc #include "utils/signals/exceptions.hpp"
4211be35a1SLionel Sambuc #include "utils/signals/programmer.hpp"
4311be35a1SLionel Sambuc 
4411be35a1SLionel Sambuc namespace signals = utils::signals;
4511be35a1SLionel Sambuc 
4611be35a1SLionel Sambuc 
4711be35a1SLionel Sambuc namespace {
4811be35a1SLionel Sambuc 
4911be35a1SLionel Sambuc 
5011be35a1SLionel Sambuc /// The interrupt signal that fired, or -1 if none.
5111be35a1SLionel Sambuc static volatile int fired_signal = -1;
5211be35a1SLionel Sambuc 
5311be35a1SLionel Sambuc 
5411be35a1SLionel Sambuc /// Collection of PIDs.
5511be35a1SLionel Sambuc typedef std::set< pid_t > pids_set;
5611be35a1SLionel Sambuc 
5711be35a1SLionel Sambuc 
5811be35a1SLionel Sambuc /// List of processes to kill upon reception of a signal.
5911be35a1SLionel Sambuc static pids_set pids_to_kill;
6011be35a1SLionel Sambuc 
6111be35a1SLionel Sambuc 
6211be35a1SLionel Sambuc /// Programmer status for the SIGHUP signal.
6311be35a1SLionel Sambuc static std::auto_ptr< signals::programmer > sighup_handler;
6411be35a1SLionel Sambuc /// Programmer status for the SIGINT signal.
6511be35a1SLionel Sambuc static std::auto_ptr< signals::programmer > sigint_handler;
6611be35a1SLionel Sambuc /// Programmer status for the SIGTERM signal.
6711be35a1SLionel Sambuc static std::auto_ptr< signals::programmer > sigterm_handler;
6811be35a1SLionel Sambuc 
6911be35a1SLionel Sambuc 
7011be35a1SLionel Sambuc /// Signal mask to restore after exiting a signal inhibited section.
7111be35a1SLionel Sambuc static sigset_t old_sigmask;
7211be35a1SLionel Sambuc 
7311be35a1SLionel Sambuc 
7411be35a1SLionel Sambuc /// Whether there is an interrupts_handler object in existence or not.
7511be35a1SLionel Sambuc bool interrupts_handler_active = false;
7611be35a1SLionel Sambuc 
7711be35a1SLionel Sambuc 
7811be35a1SLionel Sambuc /// Whether there is an interrupts_inhibiter object in existence or not.
7911be35a1SLionel Sambuc bool interrupts_inhibiter_active = false;
8011be35a1SLionel Sambuc 
8111be35a1SLionel Sambuc 
8211be35a1SLionel Sambuc /// Generic handler to capture interrupt signals.
8311be35a1SLionel Sambuc ///
8411be35a1SLionel Sambuc /// From this handler, we record that an interrupt has happened so that
8511be35a1SLionel Sambuc /// check_interrupt() can know whether there execution has to be stopped or not.
8611be35a1SLionel Sambuc /// We also terminate any of our child processes (started by the
8711be35a1SLionel Sambuc /// utils::process::children class) so that any ongoing wait(2) system calls
8811be35a1SLionel Sambuc /// terminate.
8911be35a1SLionel Sambuc ///
9011be35a1SLionel Sambuc /// \param signo The signal that caused this handler to be called.
9111be35a1SLionel Sambuc static void
signal_handler(const int signo)9211be35a1SLionel Sambuc signal_handler(const int signo)
9311be35a1SLionel Sambuc {
9411be35a1SLionel Sambuc     static const char* message = "[-- Signal caught; please wait for "
9511be35a1SLionel Sambuc         "cleanup --]\n";
9611be35a1SLionel Sambuc     if (::write(STDERR_FILENO, message, std::strlen(message)) == -1) {
9711be35a1SLionel Sambuc         // We are exiting: the message printed here is only for informational
9811be35a1SLionel Sambuc         // purposes.  If we fail to print it (which probably means something
9911be35a1SLionel Sambuc         // is really bad), there is not much we can do within the signal
10011be35a1SLionel Sambuc         // handler, so just ignore this.
10111be35a1SLionel Sambuc     }
10211be35a1SLionel Sambuc 
10311be35a1SLionel Sambuc     fired_signal = signo;
10411be35a1SLionel Sambuc 
10511be35a1SLionel Sambuc     for (pids_set::const_iterator iter = pids_to_kill.begin();
10611be35a1SLionel Sambuc         iter != pids_to_kill.end(); ++iter) {
10711be35a1SLionel Sambuc         // Redirecting the interrupt signal to our child processes does NOT
10811be35a1SLionel Sambuc         // guarantee that they also terminate.  For that to happen, we'd need to
10911be35a1SLionel Sambuc         // SIGKILL them.
11011be35a1SLionel Sambuc         //
11111be35a1SLionel Sambuc         // *However*, because we use this code to invoke the kyua-testers only,
11211be35a1SLionel Sambuc         // and because we assume that such processes are well-behaved and
11311be35a1SLionel Sambuc         // terminate according to our expectations, we do it this way, which
11411be35a1SLionel Sambuc         // allows the testers to know which specific signal made them terminate.
11511be35a1SLionel Sambuc         (void)::kill(*iter, signo);
11611be35a1SLionel Sambuc     }
11711be35a1SLionel Sambuc }
11811be35a1SLionel Sambuc 
11911be35a1SLionel Sambuc 
12011be35a1SLionel Sambuc /// Installs signal handlers for potential interrupts.
12111be35a1SLionel Sambuc ///
12211be35a1SLionel Sambuc /// \pre Must not have been called before.
12311be35a1SLionel Sambuc /// \post The various sig*_handler global variables are atomically updated.
12411be35a1SLionel Sambuc static void
setup_handlers(void)12511be35a1SLionel Sambuc setup_handlers(void)
12611be35a1SLionel Sambuc {
12711be35a1SLionel Sambuc     PRE(sighup_handler.get() == NULL);
12811be35a1SLionel Sambuc     PRE(sigint_handler.get() == NULL);
12911be35a1SLionel Sambuc     PRE(sigterm_handler.get() == NULL);
13011be35a1SLionel Sambuc 
13111be35a1SLionel Sambuc     // Create the handlers on the stack first so that, if any of them fails, the
13211be35a1SLionel Sambuc     // stack unwinding cleans things up.
13311be35a1SLionel Sambuc     std::auto_ptr< signals::programmer > tmp_sighup_handler(
13411be35a1SLionel Sambuc         new signals::programmer(SIGHUP, signal_handler));
13511be35a1SLionel Sambuc     std::auto_ptr< signals::programmer > tmp_sigint_handler(
13611be35a1SLionel Sambuc         new signals::programmer(SIGINT, signal_handler));
13711be35a1SLionel Sambuc     std::auto_ptr< signals::programmer > tmp_sigterm_handler(
13811be35a1SLionel Sambuc         new signals::programmer(SIGTERM, signal_handler));
13911be35a1SLionel Sambuc 
14011be35a1SLionel Sambuc     // Now, update the global pointers, which is an operation that cannot fail.
14111be35a1SLionel Sambuc     sighup_handler = tmp_sighup_handler;
14211be35a1SLionel Sambuc     sigint_handler = tmp_sigint_handler;
14311be35a1SLionel Sambuc     sigterm_handler = tmp_sigterm_handler;
14411be35a1SLionel Sambuc }
14511be35a1SLionel Sambuc 
14611be35a1SLionel Sambuc 
14711be35a1SLionel Sambuc /// Uninstalls the signal handlers installed by setup_handlers().
14811be35a1SLionel Sambuc static void
cleanup_handlers(void)14911be35a1SLionel Sambuc cleanup_handlers(void)
15011be35a1SLionel Sambuc {
15111be35a1SLionel Sambuc     sighup_handler->unprogram(); sighup_handler.reset(NULL);
15211be35a1SLionel Sambuc     sigint_handler->unprogram(); sigint_handler.reset(NULL);
15311be35a1SLionel Sambuc     sigterm_handler->unprogram(); sigterm_handler.reset(NULL);
15411be35a1SLionel Sambuc }
15511be35a1SLionel Sambuc 
15611be35a1SLionel Sambuc 
15711be35a1SLionel Sambuc 
15811be35a1SLionel Sambuc /// Masks the signals installed by setup_handlers().
15911be35a1SLionel Sambuc static void
mask_signals(void)16011be35a1SLionel Sambuc mask_signals(void)
16111be35a1SLionel Sambuc {
16211be35a1SLionel Sambuc     sigset_t mask;
16311be35a1SLionel Sambuc     sigemptyset(&mask);
16411be35a1SLionel Sambuc     sigaddset(&mask, SIGHUP);
16511be35a1SLionel Sambuc     sigaddset(&mask, SIGINT);
16611be35a1SLionel Sambuc     sigaddset(&mask, SIGTERM);
167*3260d16fSLionel Sambuc #if defined(__minix) && !defined(NDEBUG)
168*3260d16fSLionel Sambuc     const int ret =
169*3260d16fSLionel Sambuc #endif /* defined(__minix) && !defined(NDEBUG) */
170*3260d16fSLionel Sambuc     ::sigprocmask(SIG_BLOCK, &mask, &old_sigmask);
17111be35a1SLionel Sambuc     INV(ret != -1);
17211be35a1SLionel Sambuc }
17311be35a1SLionel Sambuc 
17411be35a1SLionel Sambuc 
17511be35a1SLionel Sambuc /// Resets the signal masking put in place by mask_signals().
17611be35a1SLionel Sambuc static void
unmask_signals(void)17711be35a1SLionel Sambuc unmask_signals(void)
17811be35a1SLionel Sambuc {
179*3260d16fSLionel Sambuc #if defined(__minix) && !defined(NDEBUG)
180*3260d16fSLionel Sambuc     const int ret =
181*3260d16fSLionel Sambuc #endif /* defined(__minix) && !defined(NDEBUG) */
182*3260d16fSLionel Sambuc     ::sigprocmask(SIG_SETMASK, &old_sigmask, NULL);
18311be35a1SLionel Sambuc     INV(ret != -1);
18411be35a1SLionel Sambuc }
18511be35a1SLionel Sambuc 
18611be35a1SLionel Sambuc 
18711be35a1SLionel Sambuc }  // anonymous namespace
18811be35a1SLionel Sambuc 
18911be35a1SLionel Sambuc 
19011be35a1SLionel Sambuc /// Constructor that sets up the signal handlers.
interrupts_handler(void)19111be35a1SLionel Sambuc signals::interrupts_handler::interrupts_handler(void)
19211be35a1SLionel Sambuc {
19311be35a1SLionel Sambuc     PRE(!interrupts_handler_active);
19411be35a1SLionel Sambuc     setup_handlers();
19511be35a1SLionel Sambuc     interrupts_handler_active = true;
19611be35a1SLionel Sambuc }
19711be35a1SLionel Sambuc 
19811be35a1SLionel Sambuc 
19911be35a1SLionel Sambuc /// Destructor that removes the signal handlers.
~interrupts_handler(void)20011be35a1SLionel Sambuc signals::interrupts_handler::~interrupts_handler(void)
20111be35a1SLionel Sambuc {
20211be35a1SLionel Sambuc     cleanup_handlers();
20311be35a1SLionel Sambuc     interrupts_handler_active = false;
20411be35a1SLionel Sambuc }
20511be35a1SLionel Sambuc 
20611be35a1SLionel Sambuc 
20711be35a1SLionel Sambuc /// Constructor that sets up signal masking.
interrupts_inhibiter(void)20811be35a1SLionel Sambuc signals::interrupts_inhibiter::interrupts_inhibiter(void)
20911be35a1SLionel Sambuc {
21011be35a1SLionel Sambuc     PRE(!interrupts_inhibiter_active);
21111be35a1SLionel Sambuc     mask_signals();
21211be35a1SLionel Sambuc     interrupts_inhibiter_active = true;
21311be35a1SLionel Sambuc }
21411be35a1SLionel Sambuc 
21511be35a1SLionel Sambuc 
21611be35a1SLionel Sambuc /// Destructor that removes signal masking.
~interrupts_inhibiter(void)21711be35a1SLionel Sambuc signals::interrupts_inhibiter::~interrupts_inhibiter(void)
21811be35a1SLionel Sambuc {
21911be35a1SLionel Sambuc     unmask_signals();
22011be35a1SLionel Sambuc     interrupts_inhibiter_active = false;
22111be35a1SLionel Sambuc }
22211be35a1SLionel Sambuc 
22311be35a1SLionel Sambuc 
22411be35a1SLionel Sambuc /// Checks if an interrupt has fired.
22511be35a1SLionel Sambuc ///
22611be35a1SLionel Sambuc /// Calls to this function should be sprinkled in strategic places through the
22711be35a1SLionel Sambuc /// code protected by an interrupts_handler object.
22811be35a1SLionel Sambuc ///
22911be35a1SLionel Sambuc /// \throw interrupted_error If there has been an interrupt.
23011be35a1SLionel Sambuc void
check_interrupt(void)23111be35a1SLionel Sambuc signals::check_interrupt(void)
23211be35a1SLionel Sambuc {
23311be35a1SLionel Sambuc     if (fired_signal != -1)
23411be35a1SLionel Sambuc         throw interrupted_error(fired_signal);
23511be35a1SLionel Sambuc }
23611be35a1SLionel Sambuc 
23711be35a1SLionel Sambuc 
23811be35a1SLionel Sambuc /// Registers a child process to be killed upon reception of an interrupt.
23911be35a1SLionel Sambuc ///
24011be35a1SLionel Sambuc /// \pre Must be called with interrupts being inhibited.  The caller must ensure
24111be35a1SLionel Sambuc /// that the call call to fork() and the addition of the PID happen atomically.
24211be35a1SLionel Sambuc ///
24311be35a1SLionel Sambuc /// \param pid The PID of the child process.  Must not have been yet regsitered.
24411be35a1SLionel Sambuc void
add_pid_to_kill(const pid_t pid)24511be35a1SLionel Sambuc signals::add_pid_to_kill(const pid_t pid)
24611be35a1SLionel Sambuc {
24711be35a1SLionel Sambuc     PRE(interrupts_inhibiter_active);
24811be35a1SLionel Sambuc     PRE(pids_to_kill.find(pid) == pids_to_kill.end());
24911be35a1SLionel Sambuc     pids_to_kill.insert(pid);
25011be35a1SLionel Sambuc }
25111be35a1SLionel Sambuc 
25211be35a1SLionel Sambuc 
25311be35a1SLionel Sambuc /// Unregisters a child process previously registered via add_pid_to_kill().
25411be35a1SLionel Sambuc ///
25511be35a1SLionel Sambuc /// \pre Must be called with interrupts being inhibited.  This is not necessary,
25611be35a1SLionel Sambuc /// but pushing this to the caller simplifies our logic and provides consistency
25711be35a1SLionel Sambuc /// with the add_pid_to_kill() call.
25811be35a1SLionel Sambuc ///
25911be35a1SLionel Sambuc /// \param pid The PID of the child process.  Must have been registered
26011be35a1SLionel Sambuc ///     previously, and the process must have already been awaited for.
26111be35a1SLionel Sambuc void
remove_pid_to_kill(const pid_t pid)26211be35a1SLionel Sambuc signals::remove_pid_to_kill(const pid_t pid)
26311be35a1SLionel Sambuc {
26411be35a1SLionel Sambuc     PRE(interrupts_inhibiter_active);
26511be35a1SLionel Sambuc     PRE(pids_to_kill.find(pid) != pids_to_kill.end());
26611be35a1SLionel Sambuc     pids_to_kill.erase(pid);
26711be35a1SLionel Sambuc }
268