feat: gracefully shut down on SIGINT/SIGTERM on Linux/mac (#6053)

This commit is contained in:
pajlada
2025-03-09 16:38:05 +01:00
committed by GitHub
parent ffe28b88a4
commit 6b80321083
5 changed files with 136 additions and 0 deletions
+1
View File
@@ -44,6 +44,7 @@
- Dev: Subscriptions to PubSub channel points redemption topics now use no auth token, making it continue to work during PubSub shutdown. (#5947)
- Dev: Add initial experimental EventSub support. (#5837, #5895, #5897, #5904, #5910, #5903, #5915, #5916, #5930, #5935, #5932, #5943, #5952, #5953, #5968, #5973, #5974, #5980, #5981, #5985, #5990, #5992, #5993, #5996, #5995, #6000, #6001, #6002, #6003, #6005, #6007, #6010, #6008, #6012, #6013, #6015, #6017, #6027, #6028, #6035, #6036, #6040, #6041, #6048)
- Dev: Remove unneeded platform specifier for toasts. (#5914)
- Dev: Cleanly shutdown on `SIGINT`/`SIGTERM` on Linux & macOS. (#6053)
- Dev: Highlight checks now use non-capturing groups for the boundaries. (#5784)
- Dev: Removed unused PubSub whisper code. (#5898)
- Dev: Updated Conan dependencies. (#5776)
+2
View File
@@ -547,6 +547,8 @@ set(SOURCE_FILES
util/Twitch.cpp
util/Twitch.hpp
util/TypeName.hpp
util/UnixSignalHandler.cpp
util/UnixSignalHandler.hpp
util/Variant.hpp
util/VectorMessageSink.cpp
util/VectorMessageSink.hpp
+16
View File
@@ -11,6 +11,7 @@
#include "singletons/Settings.hpp"
#include "singletons/Updates.hpp"
#include "util/CombinePath.hpp"
#include "util/UnixSignalHandler.hpp"
#include "widgets/dialogs/LastRunCrashDialog.hpp"
#include <QApplication>
@@ -172,6 +173,21 @@ namespace {
signal(SIGSEGV, handleSignal);
#endif
#if defined(Q_OS_UNIX)
auto *sigintHandler = new UnixSignalHandler(SIGINT);
QObject::connect(sigintHandler, &UnixSignalHandler::signalFired, [] {
qCInfo(chatterinoApp)
<< "Received SIGINT, request application quit";
QApplication::quit();
});
auto *sigtermHandler = new UnixSignalHandler(SIGTERM);
QObject::connect(sigtermHandler, &UnixSignalHandler::signalFired, [] {
qCInfo(chatterinoApp)
<< "Received SIGTERM, request application quit";
QApplication::quit();
});
#endif
}
// We delete cache files that haven't been modified in 14 days. This strategy may be
+83
View File
@@ -0,0 +1,83 @@
#include <QtGlobal>
#if defined(Q_OS_UNIX)
# include "common/QLogging.hpp"
# include "util/UnixSignalHandler.hpp"
# include <QPointer>
# include <sys/socket.h>
# include <unistd.h>
# include <csignal>
# include <unordered_map>
namespace {
using namespace chatterino;
std::unordered_map<int, QPointer<UnixSignalHandler>> HANDLERS{};
} // namespace
namespace chatterino {
UnixSignalHandler::UnixSignalHandler(int signal)
{
if (::socketpair(AF_UNIX, SOCK_STREAM, 0, this->fd.data()) != 0)
{
qCWarning(chatterinoApp)
<< "Failed to create UnixSignalHandler for" << signal;
return;
}
this->socketNotifier =
new QSocketNotifier(this->fd[1], QSocketNotifier::Read, this);
QObject::connect(this->socketNotifier, &QSocketNotifier::activated, this,
&UnixSignalHandler::handleSignal);
struct sigaction action;
action.sa_handler = UnixSignalHandler::fired;
sigemptyset(&action.sa_mask);
action.sa_flags = 0;
action.sa_flags |= SA_RESTART;
if (sigaction(signal, &action, nullptr) != 0)
{
qCWarning(chatterinoApp) << "Failed to listen to signal for" << signal;
return;
}
HANDLERS[signal] = QPointer(this);
}
void UnixSignalHandler::fired(int signal)
{
const auto &cls = HANDLERS[signal];
assert(!cls.isNull());
if (cls.isNull())
{
qCWarning(chatterinoApp)
<< "unix signal fired without a registered handler";
return;
}
char a = 1;
::write(cls->fd[0], &a, sizeof(a));
}
void UnixSignalHandler::handleSignal()
{
this->socketNotifier->setEnabled(false);
char tmp{};
::read(this->fd[1], &tmp, sizeof(tmp));
this->socketNotifier->setEnabled(true);
this->signalFired();
}
} // namespace chatterino
#endif
+34
View File
@@ -0,0 +1,34 @@
#pragma once
#include <QtGlobal>
#if defined(Q_OS_UNIX)
# include <QObject>
# include <QSocketNotifier>
# include <array>
namespace chatterino {
class UnixSignalHandler : public QObject
{
Q_OBJECT
public:
UnixSignalHandler(int signal);
static void fired(int signal);
Q_SIGNALS:
void signalFired();
private:
void handleSignal();
std::array<int, 2> fd{};
QSocketNotifier *socketNotifier;
};
} // namespace chatterino
#endif