feat: gracefully shut down on SIGINT/SIGTERM on Linux/mac (#6053)
This commit is contained in:
@@ -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: 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: 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: 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: Highlight checks now use non-capturing groups for the boundaries. (#5784)
|
||||||
- Dev: Removed unused PubSub whisper code. (#5898)
|
- Dev: Removed unused PubSub whisper code. (#5898)
|
||||||
- Dev: Updated Conan dependencies. (#5776)
|
- Dev: Updated Conan dependencies. (#5776)
|
||||||
|
|||||||
@@ -547,6 +547,8 @@ set(SOURCE_FILES
|
|||||||
util/Twitch.cpp
|
util/Twitch.cpp
|
||||||
util/Twitch.hpp
|
util/Twitch.hpp
|
||||||
util/TypeName.hpp
|
util/TypeName.hpp
|
||||||
|
util/UnixSignalHandler.cpp
|
||||||
|
util/UnixSignalHandler.hpp
|
||||||
util/Variant.hpp
|
util/Variant.hpp
|
||||||
util/VectorMessageSink.cpp
|
util/VectorMessageSink.cpp
|
||||||
util/VectorMessageSink.hpp
|
util/VectorMessageSink.hpp
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
#include "singletons/Settings.hpp"
|
#include "singletons/Settings.hpp"
|
||||||
#include "singletons/Updates.hpp"
|
#include "singletons/Updates.hpp"
|
||||||
#include "util/CombinePath.hpp"
|
#include "util/CombinePath.hpp"
|
||||||
|
#include "util/UnixSignalHandler.hpp"
|
||||||
#include "widgets/dialogs/LastRunCrashDialog.hpp"
|
#include "widgets/dialogs/LastRunCrashDialog.hpp"
|
||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
@@ -172,6 +173,21 @@ namespace {
|
|||||||
|
|
||||||
signal(SIGSEGV, handleSignal);
|
signal(SIGSEGV, handleSignal);
|
||||||
#endif
|
#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
|
// We delete cache files that haven't been modified in 14 days. This strategy may be
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -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
|
||||||
Reference in New Issue
Block a user