1 // Copyright 2010 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/programmer.hpp" 30 31 extern "C" { 32 #include <signal.h> 33 } 34 35 #include <cerrno> 36 37 #include "utils/format/macros.hpp" 38 #include "utils/logging/macros.hpp" 39 #include "utils/noncopyable.hpp" 40 #include "utils/sanity.hpp" 41 #include "utils/signals/exceptions.hpp" 42 43 44 namespace utils { 45 namespace signals { 46 47 48 /// Internal implementation for the signals::programmer class. 49 struct programmer::impl : utils::noncopyable { 50 /// The number of the signal managed by this programmer. 51 int signo; 52 53 /// Whether the signal is currently programmed by us or not. 54 bool programmed; 55 56 /// The signal handler that we replaced; to be restored on unprogramming. 57 struct ::sigaction old_sa; 58 59 /// Initializes the internal implementation of the programmer. 60 /// 61 /// \param signo_ The signal number. 62 impl(const int signo_) : 63 signo(signo_), 64 programmed(false) 65 { 66 } 67 }; 68 69 70 } // namespace signals 71 } // namespace utils 72 73 74 namespace signals = utils::signals; 75 76 77 /// Programs a signal handler. 78 /// 79 /// \param signo The signal for which to install the handler. 80 /// \param handler The handler to install. 81 /// 82 /// \throw signals::system_error If there is an error programming the signal. 83 signals::programmer::programmer(const int signo, const handler_type handler) : 84 _pimpl(new impl(signo)) 85 { 86 struct ::sigaction sa; 87 sa.sa_handler = handler; 88 sigemptyset(&sa.sa_mask); 89 sa.sa_flags = SA_RESTART; 90 91 if (::sigaction(_pimpl->signo, &sa, &_pimpl->old_sa) == -1) { 92 const int original_errno = errno; 93 throw system_error(F("Could not install handler for signal %s") % 94 _pimpl->signo, original_errno); 95 } else 96 _pimpl->programmed = true; 97 } 98 99 100 /// Destructor; unprograms the signal handler if still programmed. 101 /// 102 /// Given that this is a destructor and it can't report errors back to the 103 /// caller, the caller must attempt to call unprogram() on its own. 104 signals::programmer::~programmer(void) 105 { 106 if (_pimpl->programmed) { 107 LW("Destroying still-programmed signals::programmer object"); 108 try { 109 unprogram(); 110 } catch (const system_error& e) { 111 UNREACHABLE; 112 } 113 } 114 } 115 116 117 /// Unprograms the signal handler. 118 /// 119 /// \pre The signal handler is programmed (i.e. this can only be called once). 120 /// 121 /// \throw system_error If unprogramming the signal failed. If this happens, 122 /// the signal is left programmed, this object forgets about the signal and 123 /// therefore there is no way to restore the original handler. 124 void 125 signals::programmer::unprogram(void) 126 { 127 PRE(_pimpl->programmed); 128 129 // If we fail, we don't want the destructor to attempt to unprogram the 130 // handler again, as it would result in a crash. 131 _pimpl->programmed = false; 132 133 if (::sigaction(_pimpl->signo, &_pimpl->old_sa, NULL) == -1) { 134 const int original_errno = errno; 135 throw system_error(F("Could not reset handler for signal %s") % 136 _pimpl->signo, original_errno); 137 } 138 } 139