76 lines
1.6 KiB
C++
76 lines
1.6 KiB
C++
// Author: Thomas Trapp - https://thomastrapp.com/
|
|
// License: MIT
|
|
|
|
#pragma once
|
|
|
|
#include <sgnl/AtomicCondition.h>
|
|
|
|
#include <csignal>
|
|
#include <cstring>
|
|
#include <map>
|
|
#include <stdexcept>
|
|
#include <utility>
|
|
|
|
|
|
namespace sgnl {
|
|
|
|
|
|
class SignalHandlerException : public std::runtime_error
|
|
{
|
|
using std::runtime_error::runtime_error;
|
|
};
|
|
|
|
|
|
template<typename ValueType>
|
|
class SignalHandler
|
|
{
|
|
public:
|
|
SignalHandler(std::map<int, ValueType> signal_map,
|
|
AtomicCondition<ValueType>& condition)
|
|
: signal_map_(std::move(signal_map))
|
|
, set_()
|
|
, condition_(condition)
|
|
{
|
|
if( sigemptyset(&this->set_) != 0 )
|
|
throw SignalHandlerException("sigemptyset error");
|
|
|
|
for( const auto& p : this->signal_map_ )
|
|
if( sigaddset(&this->set_, p.first) != 0 )
|
|
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));
|
|
}
|
|
|
|
int operator()()
|
|
{
|
|
while( true )
|
|
{
|
|
int signum = 0;
|
|
int ret = sigwait(&this->set_, &signum);
|
|
if( ret != 0 )
|
|
throw SignalHandlerException(
|
|
std::string("sigwait: ") + std::strerror(ret));
|
|
|
|
if( auto it = this->signal_map_.find(signum);
|
|
it != this->signal_map_.end() )
|
|
{
|
|
this->condition_.set(it->second);
|
|
this->condition_.notify_all();
|
|
return it->first;
|
|
}
|
|
}
|
|
}
|
|
|
|
private:
|
|
std::map<int, ValueType> signal_map_;
|
|
sigset_t set_;
|
|
AtomicCondition<ValueType>& condition_;
|
|
};
|
|
|
|
|
|
} // namespace sgnl
|
|
|