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