Introduction
Following is a short simple hack implementing an RAII based signal handling guard passing signals as template parameters.
The guard constructor sets a signal handler for a list of signals and the destructor resets the original signal handlers. The code makes use of variadic templates in a way I find pretty cool.
There is not much to this blog entry except for the code showing how to apply a function to each element in a list of template parameters.
Using the code
A small example using standard RAII style shows how the signal guard can be used:
// test program
int main(){
{
// install a signal handler for some signals
sigguard<SIGINT,SIGHUP>([](int sig){});
// code, code, code ...
// ...
}
// old signal handler re-installed when 'sigguard' destructor runs
// ...
}
The code
#include <stack>
#include <iostream>
#include <utility>
#include <csignal>
#include <cstring>
template<int...SIGS>
class sigguard{
public:
// ctor
sigguard(sighandler_t fsig):fsig_(fsig){
setsigs(std::integer_sequence<int,SIGS...>());
}
// dtor
~sigguard(){
while(!oldhandlers_.empty()){
auto const[sig,fsig]=oldhandlers_.top();
oldhandlers_.pop();
signal(sig,fsig);
}
}
private:
// install signal handler for list of signals
template<int...sigs>
void setsigs(std::integer_sequence<int,sigs...>){
using xxx=int[];
(void)xxx{(setsig(sigs),0)...};
}
// set a single signal handler and save the old one so it can be set in the dtor
void setsig(int sig){
auto oldhandler=signal(sig,fsig_);
if(oldhandler==SIG_ERR){
throw std::runtime_error(std::string("could not set signal handler: ")+strsignal(sig));
}
oldhandlers_.push(std::make_pair(sig,oldhandler));
}
// old signal handlers
std::stack<std::pair<int,sighandler_t>>oldhandlers_;
// signal handler function
sighandler_t fsig_;
};