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 <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 48 namespace fs = utils::fs; 49 namespace process = utils::process; 50 namespace signals = utils::signals; 51 52 53 namespace { 54 55 56 /// Set to the signal that fired; -1 if none. 57 static 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. 65 static void 66 signal_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. 74 static void 75 pause_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. 97 static void 98 check_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. 144 static void 145 check_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 168 ATF_TEST_CASE_WITHOUT_HEAD(interrupts_handler__sighup); 169 ATF_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 178 ATF_TEST_CASE_WITHOUT_HEAD(interrupts_handler__sigint); 179 ATF_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 188 ATF_TEST_CASE_WITHOUT_HEAD(interrupts_handler__sigterm); 189 ATF_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 198 ATF_TEST_CASE(interrupts_handler__kill_children); 199 ATF_TEST_CASE_HEAD(interrupts_handler__kill_children) 200 { 201 set_md_var("timeout", "10"); 202 } 203 ATF_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 227 ATF_TEST_CASE_WITHOUT_HEAD(interrupts_inhibiter__sigalrm); 228 ATF_TEST_CASE_BODY(interrupts_inhibiter__sigalrm) 229 { 230 check_interrupts_inhibiter(SIGALRM); 231 } 232 233 234 ATF_TEST_CASE_WITHOUT_HEAD(interrupts_inhibiter__sighup); 235 ATF_TEST_CASE_BODY(interrupts_inhibiter__sighup) 236 { 237 check_interrupts_inhibiter(SIGHUP); 238 } 239 240 241 ATF_TEST_CASE_WITHOUT_HEAD(interrupts_inhibiter__sigint); 242 ATF_TEST_CASE_BODY(interrupts_inhibiter__sigint) 243 { 244 check_interrupts_inhibiter(SIGINT); 245 } 246 247 248 ATF_TEST_CASE_WITHOUT_HEAD(interrupts_inhibiter__sigterm); 249 ATF_TEST_CASE_BODY(interrupts_inhibiter__sigterm) 250 { 251 check_interrupts_inhibiter(SIGTERM); 252 } 253 254 255 ATF_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