2020-06-27 07:04:56 +00:00
|
|
|
#ifndef MYX_QT_POSIX_SIGNAL_WATCHER_CPP_
|
|
|
|
#define MYX_QT_POSIX_SIGNAL_WATCHER_CPP_
|
|
|
|
|
2020-07-02 12:58:28 +00:00
|
|
|
#include <myx/backports/cpp/helpers.hpp>
|
2020-07-10 12:29:51 +00:00
|
|
|
#include <myx/core/config.hpp>
|
2020-06-27 07:04:56 +00:00
|
|
|
|
|
|
|
#include <myx/qt/posix_signal_watcher.hpp>
|
2020-06-28 06:52:03 +00:00
|
|
|
#include <myx/qt/posix_signal_watcher_p.hpp>
|
2020-06-27 07:04:56 +00:00
|
|
|
|
|
|
|
namespace myx {
|
|
|
|
|
|
|
|
namespace qt {
|
|
|
|
|
2020-06-29 19:24:15 +00:00
|
|
|
std::array< int, 2 > PosixSignalWatcherPrivate::mSockpair { { 0, 0 } };
|
2020-06-27 07:04:56 +00:00
|
|
|
|
|
|
|
PosixSignalWatcherPrivate::~PosixSignalWatcherPrivate() = default;
|
|
|
|
|
|
|
|
PosixSignalWatcherPrivate::PosixSignalWatcherPrivate( PosixSignalWatcher* q ) :
|
|
|
|
q_ptr( q )
|
|
|
|
{
|
|
|
|
#if MYX_QT_HAS_POSIX_SIGNALS
|
|
|
|
// Create socket pair
|
2020-06-28 06:52:03 +00:00
|
|
|
if ( ::socketpair( AF_UNIX, SOCK_STREAM, 0, mSockpair.data() ) != 0 )
|
2020-06-27 07:04:56 +00:00
|
|
|
{
|
|
|
|
qDebug() << "PosixSignalWatcher: socketpair: " << ::strerror( errno );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// Create a notifier for the read end of the pair
|
2020-06-30 17:04:26 +00:00
|
|
|
// m_notifier.reset( new QSocketNotifier( mSockpair[1], QSocketNotifier::Read ) );
|
|
|
|
m_notifier = std::make_unique< QSocketNotifier >( mSockpair[1], QSocketNotifier::Read );
|
2020-06-27 07:04:56 +00:00
|
|
|
|
|
|
|
// Called when the signal handler has written to the socket pair.
|
|
|
|
// Emits the Posix signal as a Qt signal.
|
|
|
|
connect( m_notifier.get(), &QSocketNotifier::activated, q, [this]( int sockfd ) {
|
|
|
|
Q_Q( PosixSignalWatcher );
|
|
|
|
|
|
|
|
int signal = 0;
|
|
|
|
(void)::read( sockfd, &signal, sizeof( signal ) );
|
|
|
|
qDebug() << "Caught signal: " << ::strsignal( signal );
|
|
|
|
Q_EMIT q->posixSignal( signal );
|
|
|
|
} );
|
|
|
|
|
|
|
|
|
|
|
|
m_notifier->setEnabled( true );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* Registers a handler for the given Posix \a signal. The handler will write to
|
|
|
|
* a socket pair, the other end of which is connected to a QSocketNotifier.
|
|
|
|
* This provides a way to break out of the asynchronous context from which the
|
|
|
|
* signal handler is called and back into the Qt event loop.
|
|
|
|
*/
|
2020-06-28 06:52:03 +00:00
|
|
|
MYXLIB_INLINE void PosixSignalWatcherPrivate::watchForSignal( int signal )
|
2020-06-27 07:04:56 +00:00
|
|
|
{
|
|
|
|
if ( m_watchedSignals.contains( signal ) )
|
|
|
|
{
|
|
|
|
qDebug() << "Already watching for signal " << signal;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if MYX_QT_HAS_POSIX_SIGNALS
|
|
|
|
// Register a sigaction which will write to the socket pair
|
2020-07-09 12:46:02 +00:00
|
|
|
struct sigaction sigact;
|
2020-06-30 17:04:26 +00:00
|
|
|
sigact.sa_handler = PosixSignalWatcherPrivate::signalHandler; //NOLINT
|
2020-06-27 07:04:56 +00:00
|
|
|
sigact.sa_flags = 0;
|
|
|
|
sigemptyset( &sigact.sa_mask );
|
2020-07-10 12:29:51 +00:00
|
|
|
sigact.sa_flags |= SA_RESTART;
|
|
|
|
sigact.sa_restorer = nullptr;
|
2020-06-28 06:52:03 +00:00
|
|
|
if ( ::sigaction( signal, &sigact, nullptr ) != 0 )
|
2020-06-27 07:04:56 +00:00
|
|
|
{
|
|
|
|
qDebug() << "PosixSignalWatcher: sigaction: " << ::strerror( errno );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
m_watchedSignals.append( signal );
|
|
|
|
} // PosixSignalWatcherPrivate::watchForSignal
|
|
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* Called when a Posix \a signal is received. Write to the socket to wake up the
|
|
|
|
* QSocketNotifier.
|
|
|
|
*/
|
|
|
|
MYXLIB_INLINE void PosixSignalWatcherPrivate::signalHandler( int signal )
|
|
|
|
{
|
2020-06-28 06:52:03 +00:00
|
|
|
(void)::write( mSockpair[0], &signal, sizeof( signal ) );
|
2020-06-27 07:04:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* Create a new PosixSignalWatcher as a child of the given \a parent.
|
|
|
|
*/
|
|
|
|
MYXLIB_INLINE PosixSignalWatcher::PosixSignalWatcher( QObject* parent ) :
|
|
|
|
QObject( parent ),
|
|
|
|
d_ptr ( new PosixSignalWatcherPrivate( this ) )
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* Register a signal handler for the given \a signal.
|
|
|
|
*
|
|
|
|
* After calling this method you can \c connect() to the POSIXSignal() Qt signal
|
|
|
|
* to be notified when the Posix signal is received.
|
|
|
|
*/
|
|
|
|
MYXLIB_INLINE void PosixSignalWatcher::watchForSignal( int signal )
|
|
|
|
{
|
|
|
|
Q_D( PosixSignalWatcher );
|
|
|
|
d->watchForSignal( signal );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \fn void PosixSignalWatcher::posixSignal(int signal)
|
|
|
|
* Emitted when the given Posix \a signal is received.
|
|
|
|
*
|
|
|
|
* watchForSignal() must be called for each Posix signal that you want to receive
|
|
|
|
* via the POSIXSignal() Qt signal. If a watcher is watching multiple signals,
|
|
|
|
* POSIXSignal() will be emitted whenever *any* of the watched Posix signals are
|
|
|
|
* received, and the \a signal argument can be inspected to find out which one
|
|
|
|
* was actually received.
|
|
|
|
*/
|
|
|
|
|
|
|
|
} // namespace qt
|
|
|
|
|
|
|
|
} // namespace myx
|
|
|
|
|
|
|
|
#endif // ifndef MYX_QT_POSIX_SIGNAL_WATCHER_CPP_
|