-
Notifications
You must be signed in to change notification settings - Fork 98
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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>
- Loading branch information
1 parent
da1c67c
commit 3ca7c39
Showing
3 changed files
with
174 additions
and
0 deletions.
There are no files selected for viewing
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
/* | ||
SPDX-FileCopyrightText: 2021 Aleix Pol Gonzalez <[email protected]> | ||
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 |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
/* | ||
SPDX-FileCopyrightText: 2021 Aleix Pol Gonzalez <[email protected]> | ||
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 |