This repository has been archived on 2023-11-05. You can view files and clone it, but cannot push or open issues or pull requests.
signal-wrangler/include/sgnl/SignalHandler.h

99 lines
2.3 KiB
C
Raw Normal View History

2019-09-15 04:41:56 +08:00
// Author: Thomas Trapp - https://thomastrapp.com/
// License: MIT
#pragma once
#include <csignal>
#include <cstring>
#include <functional>
#include <future>
#include <initializer_list>
2019-09-15 04:41:56 +08:00
#include <stdexcept>
#include <string>
#include <utility>
2019-09-15 04:41:56 +08:00
namespace sgnl {
class SignalHandlerException : public std::runtime_error
{
using std::runtime_error::runtime_error;
};
/// When constructed, SignalHandler blocks the given `signals` in the calling
/// thread.
///
/// Signals can be polled by calling `SignalHandler::sigwait()` or
/// `SignalHandler::sigwait_handler(handler)`.
/// `handler` is a callable that accepts a signal number as its first and only
/// argument. `handler` returns false if the waiting should be continued.
///
/// When destructed, SignalHandler unblocks the `signals`.
2019-09-15 04:41:56 +08:00
class SignalHandler
{
public:
explicit SignalHandler(const std::initializer_list<int>& signals)
: set_()
2019-09-15 04:41:56 +08:00
{
if( sigemptyset(&this->set_) != 0 )
throw SignalHandlerException("sigemptyset error");
for( int signum : signals )
if( sigaddset(&this->set_, signum) != 0 )
2019-09-15 04:41:56 +08:00
throw SignalHandlerException("sigaddset error");
int s = pthread_sigmask(SIG_BLOCK, &this->set_, nullptr);
if( s != 0 )
throw SignalHandlerException(
std::string("pthread_sigmask: ") + std::strerror(s));
}
~SignalHandler() noexcept
{
pthread_sigmask(SIG_UNBLOCK, &this->set_, nullptr);
}
SignalHandler(const SignalHandler& other) = delete;
SignalHandler(SignalHandler&& other) = delete;
SignalHandler& operator=(const SignalHandler& other) = delete;
SignalHandler& operator=(SignalHandler&& other) = delete;
2020-07-17 21:46:06 +08:00
int sigwait() const
{
int signum = 0;
int ret = ::sigwait(&this->set_, &signum);
if( ret != 0 )
throw SignalHandlerException(
std::string("sigwait: ") + std::strerror(ret));
return signum;
}
2020-07-17 21:46:06 +08:00
int sigwait_handler(std::function<bool (int)> handler) const
2019-09-15 04:41:56 +08:00
{
while( true )
{
int signum = this->sigwait();
if( handler(signum) )
return signum;
2019-09-15 04:41:56 +08:00
}
}
auto async_sigwait_handler(std::function<bool (int)> handler) const
{
return std::async(
std::launch::async,
&SignalHandler::sigwait_handler,
this,
std::move(handler));
}
2019-09-15 04:41:56 +08:00
private:
sigset_t set_;
};
} // namespace sgnl