programmer.cpp revision 1.1.1.1.4.2
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 31extern "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 43namespace utils { 44namespace signals { 45 46 47/// Internal implementation for the signals::programmer class. 48struct 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 73namespace 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. 82signals::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. 103signals::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. 123void 124signals::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