Last active
May 23, 2021 21:33
-
-
Save AHilyard/005f7d9257ccd089c739 to your computer and use it in GitHub Desktop.
SignalManager class to handle Unix signals safely in Qt Applications.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* @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); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* @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