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 38 #include <atf-c++.hpp> 39 40 #include "utils/format/macros.hpp" 41 #include "utils/process/child.ipp" 42 #include "utils/process/status.hpp" 43 #include "utils/signals/exceptions.hpp" 44 #include "utils/signals/programmer.hpp" 45 46 namespace process = utils::process; 47 namespace signals = utils::signals; 48 49 50 namespace { 51 52 53 /// Set to the signal that fired; -1 if none. 54 static volatile int fired_signal = -1; 55 56 57 /// Test handler for signals. 58 /// 59 /// \post fired_signal is set to the signal that triggered the handler. 60 /// 61 /// \param signo The signal that triggered the handler. 62 static void 63 signal_handler(const int signo) 64 { 65 fired_signal = signo; 66 } 67 68 69 /// Child process that pauses waiting to be killed. 70 static void 71 pause_child(void) 72 { 73 sigset_t mask; 74 sigemptyset(&mask); 75 if (sigsuspend(&mask) == -1) 76 ::exit(EXIT_FAILURE); 77 else { 78 // If this happens, it is because we received a non-deadly signal and 79 // the execution resumed. This is not what we expect, so exit with an 80 // arbitrary code. 81 ::exit(45); 82 } 83 } 84 85 86 /// Checks that interrupts_handler() handles a particular signal. 87 /// 88 /// This indirectly checks the check_interrupt() function, which is not part of 89 /// the class but is tightly related. 90 /// 91 /// \param signo The signal to check. 92 static void 93 check_interrupts_handler(const int signo) 94 { 95 signals::programmer test_handler(signo, signal_handler); 96 97 { 98 signals::interrupts_handler interrupts; 99 100 signals::check_interrupt(); 101 ::kill(getpid(), signo); 102 ATF_REQUIRE_THROW_RE(signals::interrupted_error, 103 F("Interrupted by signal %s") % signo, 104 signals::check_interrupt()); 105 } 106 107 ATF_REQUIRE_EQ(-1, fired_signal); 108 ::kill(getpid(), signo); 109 ATF_REQUIRE_EQ(signo, fired_signal); 110 111 test_handler.unprogram(); 112 } 113 114 115 /// Checks that interrupts_inhibiter() handles a particular signal. 116 /// 117 /// \param signo The signal to check. 118 static void 119 check_interrupts_inhibiter(const int signo) 120 { 121 signals::programmer test_handler(signo, signal_handler); 122 123 { 124 signals::interrupts_inhibiter inhibiter; 125 ::kill(::getpid(), signo); 126 ATF_REQUIRE_EQ(-1, fired_signal); 127 } 128 ATF_REQUIRE_EQ(signo, fired_signal); 129 130 test_handler.unprogram(); 131 } 132 133 134 } // anonymous namespace 135 136 137 ATF_TEST_CASE_WITHOUT_HEAD(interrupts_handler__sighup); 138 ATF_TEST_CASE_BODY(interrupts_handler__sighup) 139 { 140 check_interrupts_handler(SIGHUP); 141 } 142 143 144 ATF_TEST_CASE_WITHOUT_HEAD(interrupts_handler__sigint); 145 ATF_TEST_CASE_BODY(interrupts_handler__sigint) 146 { 147 check_interrupts_handler(SIGINT); 148 } 149 150 151 ATF_TEST_CASE_WITHOUT_HEAD(interrupts_handler__sigterm); 152 ATF_TEST_CASE_BODY(interrupts_handler__sigterm) 153 { 154 check_interrupts_handler(SIGTERM); 155 } 156 157 158 ATF_TEST_CASE_WITHOUT_HEAD(interrupts_handler__kill_children); 159 ATF_TEST_CASE_BODY(interrupts_handler__kill_children) 160 { 161 std::unique_ptr< process::child > child1(process::child::fork_capture( 162 pause_child)); 163 std::unique_ptr< process::child > child2(process::child::fork_capture( 164 pause_child)); 165 166 signals::interrupts_handler interrupts; 167 168 // Our children pause until the reception of a signal. Interrupting 169 // ourselves will cause the signal to be re-delivered to our children due to 170 // the interrupts_handler semantics. If this does not happen, the wait 171 // calls below would block indefinitely and cause our test to time out. 172 ::kill(::getpid(), SIGHUP); 173 174 const process::status status1 = child1->wait(); 175 ATF_REQUIRE(status1.signaled()); 176 ATF_REQUIRE_EQ(SIGHUP, status1.termsig()); 177 const process::status status2 = child2->wait(); 178 ATF_REQUIRE(status2.signaled()); 179 ATF_REQUIRE_EQ(SIGHUP, status2.termsig()); 180 } 181 182 183 ATF_TEST_CASE_WITHOUT_HEAD(interrupts_inhibiter__sighup); 184 ATF_TEST_CASE_BODY(interrupts_inhibiter__sighup) 185 { 186 check_interrupts_inhibiter(SIGHUP); 187 } 188 189 190 ATF_TEST_CASE_WITHOUT_HEAD(interrupts_inhibiter__sigint); 191 ATF_TEST_CASE_BODY(interrupts_inhibiter__sigint) 192 { 193 check_interrupts_inhibiter(SIGINT); 194 } 195 196 197 ATF_TEST_CASE_WITHOUT_HEAD(interrupts_inhibiter__sigterm); 198 ATF_TEST_CASE_BODY(interrupts_inhibiter__sigterm) 199 { 200 check_interrupts_inhibiter(SIGTERM); 201 } 202 203 204 ATF_INIT_TEST_CASES(tcs) 205 { 206 ATF_ADD_TEST_CASE(tcs, interrupts_handler__sighup); 207 ATF_ADD_TEST_CASE(tcs, interrupts_handler__sigint); 208 ATF_ADD_TEST_CASE(tcs, interrupts_handler__sigterm); 209 ATF_ADD_TEST_CASE(tcs, interrupts_handler__kill_children); 210 211 ATF_ADD_TEST_CASE(tcs, interrupts_inhibiter__sighup); 212 ATF_ADD_TEST_CASE(tcs, interrupts_inhibiter__sigint); 213 ATF_ADD_TEST_CASE(tcs, interrupts_inhibiter__sigterm); 214 } 215