1
1
Fork 0
forked from suyu/suyu

Merge pull request #8592 from devsnek/sig-handlers

exit gracefully on sigint/sigterm
This commit is contained in:
snek 2022-07-27 12:51:26 -07:00 committed by GitHub
parent 1779795d81
commit 9479940a1f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 71 additions and 0 deletions

View file

@ -8,6 +8,10 @@
#ifdef __APPLE__ #ifdef __APPLE__
#include <unistd.h> // for chdir #include <unistd.h> // for chdir
#endif #endif
#ifdef __linux__
#include <csignal>
#include <sys/socket.h>
#endif
// VFS includes must be before glad as they will conflict with Windows file api, which uses defines. // VFS includes must be before glad as they will conflict with Windows file api, which uses defines.
#include "applets/qt_controller.h" #include "applets/qt_controller.h"
@ -259,6 +263,10 @@ GMainWindow::GMainWindow(bool has_broken_vulkan)
config{std::make_unique<Config>(*system)}, config{std::make_unique<Config>(*system)},
vfs{std::make_shared<FileSys::RealVfsFilesystem>()}, vfs{std::make_shared<FileSys::RealVfsFilesystem>()},
provider{std::make_unique<FileSys::ManualContentProvider>()} { provider{std::make_unique<FileSys::ManualContentProvider>()} {
#ifdef __linux__
SetupSigInterrupts();
#endif
Common::Log::Initialize(); Common::Log::Initialize();
LoadTranslation(); LoadTranslation();
@ -462,7 +470,13 @@ GMainWindow::~GMainWindow() {
if (render_window->parent() == nullptr) { if (render_window->parent() == nullptr) {
delete render_window; delete render_window;
} }
system->GetRoomNetwork().Shutdown(); system->GetRoomNetwork().Shutdown();
#ifdef __linux__
::close(sig_interrupt_fds[0]);
::close(sig_interrupt_fds[1]);
#endif
} }
void GMainWindow::RegisterMetaTypes() { void GMainWindow::RegisterMetaTypes() {
@ -1352,6 +1366,52 @@ static void ReleaseWakeLockLinux(QDBusObjectPath lock) {
QString::fromLatin1("org.freedesktop.portal.Request")); QString::fromLatin1("org.freedesktop.portal.Request"));
unlocker.call(QString::fromLatin1("Close")); unlocker.call(QString::fromLatin1("Close"));
} }
std::array<int, 3> GMainWindow::sig_interrupt_fds{0, 0, 0};
void GMainWindow::SetupSigInterrupts() {
if (sig_interrupt_fds[2] == 1) {
return;
}
socketpair(AF_UNIX, SOCK_STREAM, 0, sig_interrupt_fds.data());
sig_interrupt_fds[2] = 1;
struct sigaction sa;
sa.sa_handler = &GMainWindow::HandleSigInterrupt;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESETHAND;
sigaction(SIGINT, &sa, nullptr);
sigaction(SIGTERM, &sa, nullptr);
sig_interrupt_notifier = new QSocketNotifier(sig_interrupt_fds[1], QSocketNotifier::Read, this);
connect(sig_interrupt_notifier, &QSocketNotifier::activated, this,
&GMainWindow::OnSigInterruptNotifierActivated);
connect(this, &GMainWindow::SigInterrupt, this, &GMainWindow::close);
}
void GMainWindow::HandleSigInterrupt(int sig) {
if (sig == SIGINT) {
exit(1);
}
// Calling into Qt directly from a signal handler is not safe,
// so wake up a QSocketNotifier with this hacky write call instead.
char a = 1;
int ret = write(sig_interrupt_fds[0], &a, sizeof(a));
(void)ret;
}
void GMainWindow::OnSigInterruptNotifierActivated() {
sig_interrupt_notifier->setEnabled(false);
char a;
int ret = read(sig_interrupt_fds[1], &a, sizeof(a));
(void)ret;
sig_interrupt_notifier->setEnabled(true);
emit SigInterrupt();
}
#endif // __linux__ #endif // __linux__
void GMainWindow::PreventOSSleep() { void GMainWindow::PreventOSSleep() {

View file

@ -163,6 +163,8 @@ signals:
void WebBrowserExtractOfflineRomFS(); void WebBrowserExtractOfflineRomFS();
void WebBrowserClosed(Service::AM::Applets::WebExitReason exit_reason, std::string last_url); void WebBrowserClosed(Service::AM::Applets::WebExitReason exit_reason, std::string last_url);
void SigInterrupt();
public slots: public slots:
void OnLoadComplete(); void OnLoadComplete();
void OnExecuteProgram(std::size_t program_index); void OnExecuteProgram(std::size_t program_index);
@ -251,6 +253,12 @@ private:
void RequestGameResume(); void RequestGameResume();
void closeEvent(QCloseEvent* event) override; void closeEvent(QCloseEvent* event) override;
#ifdef __linux__
void SetupSigInterrupts();
static void HandleSigInterrupt(int);
void OnSigInterruptNotifierActivated();
#endif
private slots: private slots:
void OnStartGame(); void OnStartGame();
void OnRestartGame(); void OnRestartGame();
@ -419,6 +427,9 @@ private:
bool is_tas_recording_dialog_active{}; bool is_tas_recording_dialog_active{};
#ifdef __linux__ #ifdef __linux__
QSocketNotifier* sig_interrupt_notifier;
static std::array<int, 3> sig_interrupt_fds;
QDBusObjectPath wake_lock{}; QDBusObjectPath wake_lock{};
#endif #endif