mirror of
https://github.com/xiaoyifang/goldendict-ng.git
synced 2024-11-23 16:04:06 +00:00
feat: properly handle Unix signals, like SIGTERM
, for graceful exit (#1732)
* feat: handle UNIX shutting down SIGNALS * Convey ksignalhandler from LGPLv2.1+ to GPLv3+ which allowed/required --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
This commit is contained in:
parent
da1c67c35d
commit
3ca7c39e69
|
@ -14,6 +14,7 @@
|
|||
|
||||
#if defined( Q_OS_UNIX )
|
||||
#include <clocale>
|
||||
#include "unix/ksignalhandler.hh"
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_WIN32
|
||||
|
@ -590,6 +591,12 @@ int main( int argc, char ** argv )
|
|||
if ( gdcl.needTranslateWord() )
|
||||
m.wordReceived( gdcl.wordToTranslate() );
|
||||
|
||||
#ifdef Q_OS_UNIX
|
||||
// handle Unix's shutdown signals for graceful exit
|
||||
KSignalHandler::self()->watchSignal( SIGINT );
|
||||
KSignalHandler::self()->watchSignal( SIGTERM );
|
||||
QObject::connect( KSignalHandler::self(), &KSignalHandler::signalReceived, &m, &MainWindow::quitApp );
|
||||
#endif
|
||||
int r = app.exec();
|
||||
|
||||
app.removeDataCommiter( m );
|
||||
|
|
99
src/unix/ksignalhandler.cc
Normal file
99
src/unix/ksignalhandler.cc
Normal file
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2021 Aleix Pol Gonzalez <aleixpol@kde.org>
|
||||
|
||||
SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
Copied from KDE's KCoreAddons with minor modifications
|
||||
*/
|
||||
#include <QtGlobal>
|
||||
#ifdef Q_OS_UNIX
|
||||
|
||||
#include "ksignalhandler.hh"
|
||||
#include <QSocketNotifier>
|
||||
#include <QTimer>
|
||||
#include <QDebug>
|
||||
#include <cerrno>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
|
||||
class KSignalHandlerPrivate: public QObject
|
||||
{
|
||||
public:
|
||||
static void signalHandler( int signal );
|
||||
void handleSignal();
|
||||
|
||||
QSet< int > m_signalsRegistered;
|
||||
static int signalFd[ 2 ];
|
||||
QSocketNotifier * m_handler = nullptr;
|
||||
|
||||
KSignalHandler * q;
|
||||
};
|
||||
|
||||
int KSignalHandlerPrivate::signalFd[ 2 ];
|
||||
|
||||
KSignalHandler::KSignalHandler():
|
||||
d( new KSignalHandlerPrivate )
|
||||
{
|
||||
d->q = this;
|
||||
if ( ::socketpair( AF_UNIX, SOCK_STREAM, 0, KSignalHandlerPrivate::signalFd ) ) {
|
||||
qDebug() << "Couldn't create a socketpair";
|
||||
return;
|
||||
}
|
||||
|
||||
// ensure the sockets are not leaked to child processes, SOCK_CLOEXEC not supported on macOS
|
||||
fcntl( KSignalHandlerPrivate::signalFd[ 0 ], F_SETFD, FD_CLOEXEC );
|
||||
fcntl( KSignalHandlerPrivate::signalFd[ 1 ], F_SETFD, FD_CLOEXEC );
|
||||
|
||||
QTimer::singleShot( 0, [ this ] {
|
||||
d->m_handler = new QSocketNotifier( KSignalHandlerPrivate::signalFd[ 1 ], QSocketNotifier::Read, this );
|
||||
connect( d->m_handler, &QSocketNotifier::activated, d.get(), &KSignalHandlerPrivate::handleSignal );
|
||||
} );
|
||||
}
|
||||
|
||||
KSignalHandler::~KSignalHandler()
|
||||
{
|
||||
for ( int sig : std::as_const( d->m_signalsRegistered ) ) {
|
||||
signal( sig, nullptr );
|
||||
}
|
||||
close( KSignalHandlerPrivate::signalFd[ 0 ] );
|
||||
close( KSignalHandlerPrivate::signalFd[ 1 ] );
|
||||
}
|
||||
|
||||
void KSignalHandler::watchSignal( int signalToTrack )
|
||||
{
|
||||
d->m_signalsRegistered.insert( signalToTrack );
|
||||
signal( signalToTrack, KSignalHandlerPrivate::signalHandler );
|
||||
}
|
||||
|
||||
void KSignalHandlerPrivate::signalHandler( int signal )
|
||||
{
|
||||
const int ret = ::write( signalFd[ 0 ], &signal, sizeof( signal ) );
|
||||
if ( ret != sizeof( signal ) ) {
|
||||
qDebug() << "signalHandler couldn't write for signal" << strsignal( signal ) << " Got error:" << strerror( errno );
|
||||
}
|
||||
}
|
||||
|
||||
void KSignalHandlerPrivate::handleSignal()
|
||||
{
|
||||
m_handler->setEnabled( false );
|
||||
int signal;
|
||||
const int ret = ::read( KSignalHandlerPrivate::signalFd[ 1 ], &signal, sizeof( signal ) );
|
||||
if ( ret != sizeof( signal ) ) {
|
||||
qDebug() << "handleSignal couldn't read signal for fd" << KSignalHandlerPrivate::signalFd[ 1 ]
|
||||
<< " Got error:" << strerror( errno );
|
||||
return;
|
||||
}
|
||||
m_handler->setEnabled( true );
|
||||
|
||||
Q_EMIT q->signalReceived( signal );
|
||||
}
|
||||
|
||||
KSignalHandler * KSignalHandler::self()
|
||||
{
|
||||
static KSignalHandler s_self;
|
||||
return &s_self;
|
||||
}
|
||||
|
||||
#endif
|
68
src/unix/ksignalhandler.hh
Normal file
68
src/unix/ksignalhandler.hh
Normal file
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2021 Aleix Pol Gonzalez <aleixpol@kde.org>
|
||||
|
||||
SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
Copied from KDE's KCoreAddons with minor modifications
|
||||
*/
|
||||
#pragma once
|
||||
#include <QtGlobal>
|
||||
#ifdef Q_OS_UNIX
|
||||
#include <QObject>
|
||||
#include <signal.h>
|
||||
|
||||
class KSignalHandlerPrivate;
|
||||
|
||||
/**
|
||||
* Allows getting ANSI C signals and forward them onto the Qt eventloop.
|
||||
*
|
||||
* It's a singleton as it relies on static data getting defined.
|
||||
*
|
||||
* \code
|
||||
* {
|
||||
* KSignalHandler::self()->watchSignal(SIGTERM);
|
||||
* connect(KSignalHandler::self(), &KSignalHandler::signalReceived,
|
||||
* this, &SomeClass::handleSignal);
|
||||
* job->start();
|
||||
* }
|
||||
* \endcode
|
||||
*
|
||||
* @since 5.92
|
||||
*/
|
||||
class KSignalHandler: public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
~KSignalHandler() override;
|
||||
|
||||
/**
|
||||
* Adds @p signal to be watched for. Once the process is notified about this signal, @m signalReceived will be emitted with the same @p signal as an
|
||||
* argument.
|
||||
*
|
||||
* @see signalReceived
|
||||
*/
|
||||
void watchSignal( int signal );
|
||||
|
||||
/**
|
||||
* Fetches an instance we can use to register our signals.
|
||||
*/
|
||||
static KSignalHandler * self();
|
||||
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* Notifies that @p signal is emitted.
|
||||
*
|
||||
* To catch a signal, we need to make sure it's registered using @m watchSignal.
|
||||
*
|
||||
* @see watchSignal
|
||||
*/
|
||||
void signalReceived( int signal );
|
||||
|
||||
private:
|
||||
KSignalHandler();
|
||||
|
||||
QScopedPointer< KSignalHandlerPrivate > d;
|
||||
};
|
||||
|
||||
#endif
|
Loading…
Reference in a new issue