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 31extern "C" { 32#include <signal.h> 33#include <unistd.h> 34} 35 36#include <cstdlib> 37#include <iostream> 38 39#include <atf-c++.hpp> 40 41#include "utils/format/macros.hpp" 42#include "utils/fs/path.hpp" 43#include "utils/process/child.ipp" 44#include "utils/process/status.hpp" 45#include "utils/signals/exceptions.hpp" 46#include "utils/signals/programmer.hpp" 47 48namespace fs = utils::fs; 49namespace process = utils::process; 50namespace signals = utils::signals; 51 52 53namespace { 54 55 56/// Set to the signal that fired; -1 if none. 57static volatile int fired_signal = -1; 58 59 60/// Test handler for signals. 61/// 62/// \post fired_signal is set to the signal that triggered the handler. 63/// 64/// \param signo The signal that triggered the handler. 65static void 66signal_handler(const int signo) 67{ 68 PRE(fired_signal == -1 || fired_signal == signo); 69 fired_signal = signo; 70} 71 72 73/// Child process that pauses waiting to be killed. 74static void 75pause_child(void) 76{ 77 sigset_t mask; 78 sigemptyset(&mask); 79 // We loop waiting for signals because we want the parent process to send us 80 // a SIGKILL that we cannot handle, not just any non-deadly signal. 81 for (;;) { 82 std::cerr << F("Waiting for any signal; pid=%s\n") % ::getpid(); 83 ::sigsuspend(&mask); 84 std::cerr << F("Signal received; pid=%s\n") % ::getpid(); 85 } 86} 87 88 89/// Checks that interrupts_handler() handles a particular signal. 90/// 91/// This indirectly checks the check_interrupt() function, which is not part of 92/// the class but is tightly related. 93/// 94/// \param signo The signal to check. 95/// \param explicit_unprogram Whether to call interrupts_handler::unprogram() 96/// explicitly before letting the object go out of scope. 97static void 98check_interrupts_handler(const int signo, const bool explicit_unprogram) 99{ 100 fired_signal = -1; 101 102 signals::programmer test_handler(signo, signal_handler); 103 104 { 105 signals::interrupts_handler interrupts; 106 107 // No pending interrupts at first. 108 signals::check_interrupt(); 109 110 // Send us an interrupt and check for it. 111 ::kill(getpid(), signo); 112 ATF_REQUIRE_THROW_RE(signals::interrupted_error, 113 F("Interrupted by signal %s") % signo, 114 signals::check_interrupt()); 115 116 // Interrupts should have been cleared now, so this should not throw. 117 signals::check_interrupt(); 118 119 // Check to see if a second interrupt is detected. 120 ::kill(getpid(), signo); 121 ATF_REQUIRE_THROW_RE(signals::interrupted_error, 122 F("Interrupted by signal %s") % signo, 123 signals::check_interrupt()); 124 125 // And ensure the interrupt was cleared again. 126 signals::check_interrupt(); 127 128 if (explicit_unprogram) { 129 interrupts.unprogram(); 130 } 131 } 132 133 ATF_REQUIRE_EQ(-1, fired_signal); 134 ::kill(getpid(), signo); 135 ATF_REQUIRE_EQ(signo, fired_signal); 136 137 test_handler.unprogram(); 138} 139 140 141/// Checks that interrupts_inhibiter() handles a particular signal. 142/// 143/// \param signo The signal to check. 144static void 145check_interrupts_inhibiter(const int signo) 146{ 147 signals::programmer test_handler(signo, signal_handler); 148 149 { 150 signals::interrupts_inhibiter inhibiter; 151 { 152 signals::interrupts_inhibiter nested_inhibiter; 153 ::kill(::getpid(), signo); 154 ATF_REQUIRE_EQ(-1, fired_signal); 155 } 156 ::kill(::getpid(), signo); 157 ATF_REQUIRE_EQ(-1, fired_signal); 158 } 159 ATF_REQUIRE_EQ(signo, fired_signal); 160 161 test_handler.unprogram(); 162} 163 164 165} // anonymous namespace 166 167 168ATF_TEST_CASE_WITHOUT_HEAD(interrupts_handler__sighup); 169ATF_TEST_CASE_BODY(interrupts_handler__sighup) 170{ 171 // We run this twice in sequence to ensure that we can actually program two 172 // interrupts handlers in a row. 173 check_interrupts_handler(SIGHUP, true); 174 check_interrupts_handler(SIGHUP, false); 175} 176 177 178ATF_TEST_CASE_WITHOUT_HEAD(interrupts_handler__sigint); 179ATF_TEST_CASE_BODY(interrupts_handler__sigint) 180{ 181 // We run this twice in sequence to ensure that we can actually program two 182 // interrupts handlers in a row. 183 check_interrupts_handler(SIGINT, true); 184 check_interrupts_handler(SIGINT, false); 185} 186 187 188ATF_TEST_CASE_WITHOUT_HEAD(interrupts_handler__sigterm); 189ATF_TEST_CASE_BODY(interrupts_handler__sigterm) 190{ 191 // We run this twice in sequence to ensure that we can actually program two 192 // interrupts handlers in a row. 193 check_interrupts_handler(SIGTERM, true); 194 check_interrupts_handler(SIGTERM, false); 195} 196 197 198ATF_TEST_CASE(interrupts_handler__kill_children); 199ATF_TEST_CASE_HEAD(interrupts_handler__kill_children) 200{ 201 set_md_var("timeout", "10"); 202} 203ATF_TEST_CASE_BODY(interrupts_handler__kill_children) 204{ 205 std::auto_ptr< process::child > child1(process::child::fork_files( 206 pause_child, fs::path("/dev/stdout"), fs::path("/dev/stderr"))); 207 std::auto_ptr< process::child > child2(process::child::fork_files( 208 pause_child, fs::path("/dev/stdout"), fs::path("/dev/stderr"))); 209 210 signals::interrupts_handler interrupts; 211 212 // Our children pause until the reception of a signal. Interrupting 213 // ourselves will cause the signal to be re-delivered to our children due to 214 // the interrupts_handler semantics. If this does not happen, the wait 215 // calls below would block indefinitely and cause our test to time out. 216 ::kill(::getpid(), SIGHUP); 217 218 const process::status status1 = child1->wait(); 219 ATF_REQUIRE(status1.signaled()); 220 ATF_REQUIRE_EQ(SIGKILL, status1.termsig()); 221 const process::status status2 = child2->wait(); 222 ATF_REQUIRE(status2.signaled()); 223 ATF_REQUIRE_EQ(SIGKILL, status2.termsig()); 224} 225 226 227ATF_TEST_CASE_WITHOUT_HEAD(interrupts_inhibiter__sigalrm); 228ATF_TEST_CASE_BODY(interrupts_inhibiter__sigalrm) 229{ 230 check_interrupts_inhibiter(SIGALRM); 231} 232 233 234ATF_TEST_CASE_WITHOUT_HEAD(interrupts_inhibiter__sighup); 235ATF_TEST_CASE_BODY(interrupts_inhibiter__sighup) 236{ 237 check_interrupts_inhibiter(SIGHUP); 238} 239 240 241ATF_TEST_CASE_WITHOUT_HEAD(interrupts_inhibiter__sigint); 242ATF_TEST_CASE_BODY(interrupts_inhibiter__sigint) 243{ 244 check_interrupts_inhibiter(SIGINT); 245} 246 247 248ATF_TEST_CASE_WITHOUT_HEAD(interrupts_inhibiter__sigterm); 249ATF_TEST_CASE_BODY(interrupts_inhibiter__sigterm) 250{ 251 check_interrupts_inhibiter(SIGTERM); 252} 253 254 255ATF_INIT_TEST_CASES(tcs) 256{ 257 ATF_ADD_TEST_CASE(tcs, interrupts_handler__sighup); 258 ATF_ADD_TEST_CASE(tcs, interrupts_handler__sigint); 259 ATF_ADD_TEST_CASE(tcs, interrupts_handler__sigterm); 260 ATF_ADD_TEST_CASE(tcs, interrupts_handler__kill_children); 261 262 ATF_ADD_TEST_CASE(tcs, interrupts_inhibiter__sigalrm); 263 ATF_ADD_TEST_CASE(tcs, interrupts_inhibiter__sighup); 264 ATF_ADD_TEST_CASE(tcs, interrupts_inhibiter__sigint); 265 ATF_ADD_TEST_CASE(tcs, interrupts_inhibiter__sigterm); 266} 267