Skip to content

Instantly share code, notes, and snippets.

@AHilyard
Last active May 23, 2021 21:33
Show Gist options
  • Save AHilyard/005f7d9257ccd089c739 to your computer and use it in GitHub Desktop.
Save AHilyard/005f7d9257ccd089c739 to your computer and use it in GitHub Desktop.
SignalManager class to handle Unix signals safely in Qt Applications.
/**
* @file signalmanager.cpp
*
* @date 6/24/2015
* @author Anthony Hilyard
* @brief
*/
#include "signalmanager.h"
/**
* @brief SignalManager constructor
* @param parent Parent QObject
*/
SignalManager::SignalManager(QObject *parent) :
QObject(parent)
{
}
/**
* @brief SignalManager destructor.
*/
SignalManager::~SignalManager()
{
}
/**
* @brief Grabs the shared singleton SignalManager instance.
* @return The shared SignalManager.
*/
SignalManager *SignalManager::manager()
{
static SignalManager *_manager = NULL;
if (!_manager)
{
_manager = new SignalManager();
}
return _manager;
}
/**
* @brief Adds a signal handler for the given signal.
* @param signal The signal to add a handler for.
* @param callback The callback function that will be executed when this signal is received.
* @return True on success, false on failure.
*
* This function will execute the given callback function when the given signal is
* received. This callback function can safely contain any Qt functions.
* Example usage:
* SignalManager::addSignalHandler(SIGINT, sigIntHandler);
* SignalManager::addSignalHandler(SIGTERM, sigTermHandler);
*/
bool SignalManager::addSignalHandler(int signal, __sighandler_t callback)
{
SignalManager *signalManager = manager();
struct sigaction sigstruct;
sigstruct.sa_handler = signalHandler;
sigemptyset(&sigstruct.sa_mask);
sigstruct.sa_flags = 0;
sigstruct.sa_flags |= SA_RESTART;
if (sigaction(signal, &sigstruct, 0) > 0)
{
return false;
}
int *sigFd = new int[2];
if (::socketpair(AF_UNIX, SOCK_STREAM, 0, sigFd))
{
qFatal("Couldn't create socketpair!");
}
// Store the signal and socket/callback pair.
signalManager->_sigFd.insert(signal, QPair<int *, __sighandler_t>(sigFd, callback));
// Store the socket and signal/notifier pair.
signalManager->_socketSignalMapping.insert(sigFd[1], QPair<int, QSocketNotifier *>(signal, new QSocketNotifier(sigFd[1], QSocketNotifier::Read, signalManager)));
connect(signalManager->_socketSignalMapping[sigFd[1]].second, SIGNAL(activated(int)), signalManager, SLOT(handleSignal(int)));
return true;
}
/**
* @brief Unix signal handler.
* @param signal The signal to handle.
*/
void SignalManager::signalHandler(int signal)
{
char a = 1;
::write(manager()->_sigFd[signal].first[0], &a, sizeof(a));
}
/**
* @brief Qt signal handler.
* @param socketId The ID of the activated socket.
*/
void SignalManager::handleSignal(int socketId)
{
_socketSignalMapping[socketId].second->setEnabled(false);
char tmp;
::read(socketId, &tmp, sizeof(tmp));
// Execute the callback for this signal.
_sigFd[_socketSignalMapping[socketId].first].second(_socketSignalMapping[socketId].first);
_socketSignalMapping[socketId].second->setEnabled(true);
}
/**
* @file signalmanager.h
*
* @date 6/24/2015
* @author Anthony Hilyard
* @brief
*/
#ifndef SIGNALMANAGER_H
#define SIGNALMANAGER_H
#include <signal.h>
#include <sys/socket.h>
#include <unistd.h>
#include <QObject>
#include <QSocketNotifier>
#include <QMap>
#include <QPair>
class SignalManager : public QObject
{
Q_OBJECT
public:
static bool addSignalHandler(int, __sighandler_t);
private:
explicit SignalManager(QObject *parent = 0);
~SignalManager();
SignalManager(SignalManager const &);
SignalManager &operator=(SignalManager const &);
static SignalManager *manager();
static void signalHandler(int signal);
QMap<int, QPair<int *, __sighandler_t> > _sigFd; //< Maps signals to socket file descriptors and callback functions.
QMap<int, QPair<int, QSocketNotifier *> > _socketSignalMapping; //< Maps socket IDs to signals and QSocketNotifiers.
private slots:
void handleSignal(int);
};
#endif // SIGNALMANAGER_H
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment