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