1 // Copyright 2012 The Kyua Authors. 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 <sys/types.h> 33 34 #include <signal.h> 35 #include <unistd.h> 36 } 37 38 #include <cstdlib> 39 #include <cstring> 40 #include <set> 41 42 #include "utils/logging/macros.hpp" 43 #include "utils/process/operations.hpp" 44 #include "utils/sanity.hpp" 45 #include "utils/signals/exceptions.hpp" 46 #include "utils/signals/programmer.hpp" 47 48 namespace signals = utils::signals; 49 namespace process = utils::process; 50 51 52 namespace { 53 54 55 /// The interrupt signal that fired, or -1 if none. 56 static volatile int fired_signal = -1; 57 58 59 /// Collection of PIDs. 60 typedef std::set< pid_t > pids_set; 61 62 63 /// List of processes to kill upon reception of a signal. 64 static pids_set pids_to_kill; 65 66 67 /// Programmer status for the SIGHUP signal. 68 static std::auto_ptr< signals::programmer > sighup_handler; 69 /// Programmer status for the SIGINT signal. 70 static std::auto_ptr< signals::programmer > sigint_handler; 71 /// Programmer status for the SIGTERM signal. 72 static std::auto_ptr< signals::programmer > sigterm_handler; 73 74 75 /// Signal mask to restore after exiting a signal inhibited section. 76 static sigset_t global_old_sigmask; 77 78 79 /// Whether there is an interrupts_handler object in existence or not. 80 static bool interrupts_handler_active = false; 81 82 83 /// Whether there is an interrupts_inhibiter object in existence or not. 84 static std::size_t interrupts_inhibiter_active = 0; 85 86 87 /// Generic handler to capture interrupt signals. 88 /// 89 /// From this handler, we record that an interrupt has happened so that 90 /// check_interrupt() can know whether there execution has to be stopped or not. 91 /// We also terminate any of our child processes (started by the 92 /// utils::process::children class) so that any ongoing wait(2) system calls 93 /// terminate. 94 /// 95 /// \param signo The signal that caused this handler to be called. 96 static void 97 signal_handler(const int signo) 98 { 99 static const char* message = "[-- Signal caught; please wait for " 100 "cleanup --]\n"; 101 if (::write(STDERR_FILENO, message, std::strlen(message)) == -1) { 102 // We are exiting: the message printed here is only for informational 103 // purposes. If we fail to print it (which probably means something 104 // is really bad), there is not much we can do within the signal 105 // handler, so just ignore this. 106 } 107 108 fired_signal = signo; 109 110 for (pids_set::const_iterator iter = pids_to_kill.begin(); 111 iter != pids_to_kill.end(); ++iter) { 112 process::terminate_group(*iter); 113 } 114 } 115 116 117 /// Installs signal handlers for potential interrupts. 118 /// 119 /// \pre Must not have been called before. 120 /// \post The various sig*_handler global variables are atomically updated. 121 static void 122 setup_handlers(void) 123 { 124 PRE(sighup_handler.get() == NULL); 125 PRE(sigint_handler.get() == NULL); 126 PRE(sigterm_handler.get() == NULL); 127 128 // Create the handlers on the stack first so that, if any of them fails, the 129 // stack unwinding cleans things up. 130 std::auto_ptr< signals::programmer > tmp_sighup_handler( 131 new signals::programmer(SIGHUP, signal_handler)); 132 std::auto_ptr< signals::programmer > tmp_sigint_handler( 133 new signals::programmer(SIGINT, signal_handler)); 134 std::auto_ptr< signals::programmer > tmp_sigterm_handler( 135 new signals::programmer(SIGTERM, signal_handler)); 136 137 // Now, update the global pointers, which is an operation that cannot fail. 138 sighup_handler = tmp_sighup_handler; 139 sigint_handler = tmp_sigint_handler; 140 sigterm_handler = tmp_sigterm_handler; 141 } 142 143 144 /// Uninstalls the signal handlers installed by setup_handlers(). 145 static void 146 cleanup_handlers(void) 147 { 148 sighup_handler->unprogram(); sighup_handler.reset(NULL); 149 sigint_handler->unprogram(); sigint_handler.reset(NULL); 150 sigterm_handler->unprogram(); sigterm_handler.reset(NULL); 151 } 152 153 154 155 /// Masks the signals installed by setup_handlers(). 156 /// 157 /// \param[out] old_sigmask The old signal mask to save via the 158 /// \code oset \endcode argument with sigprocmask(2). 159 static void 160 mask_signals(sigset_t* old_sigmask) 161 { 162 sigset_t mask; 163 sigemptyset(&mask); 164 sigaddset(&mask, SIGALRM); 165 sigaddset(&mask, SIGHUP); 166 sigaddset(&mask, SIGINT); 167 sigaddset(&mask, SIGTERM); 168 const int ret = ::sigprocmask(SIG_BLOCK, &mask, old_sigmask); 169 INV(ret != -1); 170 } 171 172 173 /// Resets the signal masking put in place by mask_signals(). 174 /// 175 /// \param[in] old_sigmask The old signal mask to restore via the 176 /// \code set \endcode argument with sigprocmask(2). 177 static void 178 unmask_signals(sigset_t* old_sigmask) 179 { 180 const int ret = ::sigprocmask(SIG_SETMASK, old_sigmask, NULL); 181 INV(ret != -1); 182 } 183 184 185 } // anonymous namespace 186 187 188 /// Constructor that sets up the signal handlers. 189 signals::interrupts_handler::interrupts_handler(void) : 190 _programmed(false) 191 { 192 PRE(!interrupts_handler_active); 193 setup_handlers(); 194 _programmed = true; 195 interrupts_handler_active = true; 196 } 197 198 199 /// Destructor that removes the signal handlers. 200 /// 201 /// Given that this is a destructor and it can't report errors back to the 202 /// caller, the caller must attempt to call unprogram() on its own. 203 signals::interrupts_handler::~interrupts_handler(void) 204 { 205 if (_programmed) { 206 LW("Destroying still-programmed signals::interrupts_handler object"); 207 try { 208 unprogram(); 209 } catch (const error& e) { 210 UNREACHABLE; 211 } 212 } 213 } 214 215 216 /// Unprograms all signals captured by the interrupts handler. 217 /// 218 /// \throw system_error If the unprogramming of any signal fails. 219 void 220 signals::interrupts_handler::unprogram(void) 221 { 222 PRE(_programmed); 223 224 // Modify the control variables first before unprogramming the handlers. If 225 // we fail to do the latter, we do not want to try again because we will not 226 // succeed (and we'll cause a crash due to failed preconditions). 227 _programmed = false; 228 interrupts_handler_active = false; 229 230 cleanup_handlers(); 231 fired_signal = -1; 232 } 233 234 235 /// Constructor that sets up signal masking. 236 signals::interrupts_inhibiter::interrupts_inhibiter(void) 237 { 238 sigset_t old_sigmask; 239 mask_signals(&old_sigmask); 240 if (interrupts_inhibiter_active == 0) { 241 global_old_sigmask = old_sigmask; 242 } 243 ++interrupts_inhibiter_active; 244 } 245 246 247 /// Destructor that removes signal masking. 248 signals::interrupts_inhibiter::~interrupts_inhibiter(void) 249 { 250 if (interrupts_inhibiter_active > 1) { 251 --interrupts_inhibiter_active; 252 } else { 253 interrupts_inhibiter_active = false; 254 unmask_signals(&global_old_sigmask); 255 } 256 } 257 258 259 /// Checks if an interrupt has fired. 260 /// 261 /// Calls to this function should be sprinkled in strategic places through the 262 /// code protected by an interrupts_handler object. 263 /// 264 /// Only one call to this function will raise an exception per signal received. 265 /// This is to allow executing cleanup actions without reraising interrupt 266 /// exceptions unless the user has fired another interrupt. 267 /// 268 /// \throw interrupted_error If there has been an interrupt. 269 void 270 signals::check_interrupt(void) 271 { 272 if (fired_signal != -1) { 273 const int original_fired_signal = fired_signal; 274 fired_signal = -1; 275 throw interrupted_error(original_fired_signal); 276 } 277 } 278 279 280 /// Registers a child process to be killed upon reception of an interrupt. 281 /// 282 /// \pre Must be called with interrupts being inhibited. The caller must ensure 283 /// that the call call to fork() and the addition of the PID happen atomically. 284 /// 285 /// \param pid The PID of the child process. Must not have been yet regsitered. 286 void 287 signals::add_pid_to_kill(const pid_t pid) 288 { 289 PRE(interrupts_inhibiter_active); 290 PRE(pids_to_kill.find(pid) == pids_to_kill.end()); 291 pids_to_kill.insert(pid); 292 } 293 294 295 /// Unregisters a child process previously registered via add_pid_to_kill(). 296 /// 297 /// \pre Must be called with interrupts being inhibited. This is not necessary, 298 /// but pushing this to the caller simplifies our logic and provides consistency 299 /// with the add_pid_to_kill() call. 300 /// 301 /// \param pid The PID of the child process. Must have been registered 302 /// previously, and the process must have already been awaited for. 303 void 304 signals::remove_pid_to_kill(const pid_t pid) 305 { 306 PRE(interrupts_inhibiter_active); 307 PRE(pids_to_kill.find(pid) != pids_to_kill.end()); 308 pids_to_kill.erase(pid); 309 } 310