Path: blob/main/contrib/kyua/utils/signals/programmer.cpp
48196 views
// Copyright 2010 The Kyua Authors.1// All rights reserved.2//3// Redistribution and use in source and binary forms, with or without4// modification, are permitted provided that the following conditions are5// met:6//7// * Redistributions of source code must retain the above copyright8// notice, this list of conditions and the following disclaimer.9// * Redistributions in binary form must reproduce the above copyright10// notice, this list of conditions and the following disclaimer in the11// documentation and/or other materials provided with the distribution.12// * Neither the name of Google Inc. nor the names of its contributors13// may be used to endorse or promote products derived from this software14// without specific prior written permission.15//16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.2728#include "utils/signals/programmer.hpp"2930extern "C" {31#include <signal.h>32}3334#include <cerrno>3536#include "utils/format/macros.hpp"37#include "utils/logging/macros.hpp"38#include "utils/noncopyable.hpp"39#include "utils/sanity.hpp"40#include "utils/signals/exceptions.hpp"414243namespace utils {44namespace signals {454647/// Internal implementation for the signals::programmer class.48struct programmer::impl : utils::noncopyable {49/// The number of the signal managed by this programmer.50int signo;5152/// Whether the signal is currently programmed by us or not.53bool programmed;5455/// The signal handler that we replaced; to be restored on unprogramming.56struct ::sigaction old_sa;5758/// Initializes the internal implementation of the programmer.59///60/// \param signo_ The signal number.61impl(const int signo_) :62signo(signo_),63programmed(false)64{65}66};676869} // namespace signals70} // namespace utils717273namespace signals = utils::signals;747576/// 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{85struct ::sigaction sa;86sa.sa_handler = handler;87sigemptyset(&sa.sa_mask);88sa.sa_flags = SA_RESTART;8990if (::sigaction(_pimpl->signo, &sa, &_pimpl->old_sa) == -1) {91const int original_errno = errno;92throw system_error(F("Could not install handler for signal %s") %93_pimpl->signo, original_errno);94} else95_pimpl->programmed = true;96}979899/// Destructor; unprograms the signal handler if still programmed.100///101/// Given that this is a destructor and it can't report errors back to the102/// caller, the caller must attempt to call unprogram() on its own.103signals::programmer::~programmer(void)104{105if (_pimpl->programmed) {106LW("Destroying still-programmed signals::programmer object");107try {108unprogram();109} catch (const system_error& e) {110UNREACHABLE;111}112}113}114115116/// 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 and122/// therefore there is no way to restore the original handler.123void124signals::programmer::unprogram(void)125{126PRE(_pimpl->programmed);127128// If we fail, we don't want the destructor to attempt to unprogram the129// handler again, as it would result in a crash.130_pimpl->programmed = false;131132if (::sigaction(_pimpl->signo, &_pimpl->old_sa, NULL) == -1) {133const int original_errno = errno;134throw system_error(F("Could not reset handler for signal %s") %135_pimpl->signo, original_errno);136}137}138139140