From 112a174ae1c4ea3bc7d1592e3f6fc0be7e963f34 Mon Sep 17 00:00:00 2001 From: spycrab Date: Tue, 22 May 2018 21:30:54 +0200 Subject: [PATCH] Qt/Unix: Implement signal handler --- Source/Core/DolphinQt2/CMakeLists.txt | 1 + Source/Core/DolphinQt2/MainWindow.cpp | 32 ++++++++++- Source/Core/DolphinQt2/MainWindow.h | 1 + .../Core/DolphinQt2/QtUtils/SignalDaemon.cpp | 55 +++++++++++++++++++ Source/Core/DolphinQt2/QtUtils/SignalDaemon.h | 31 +++++++++++ 5 files changed, 119 insertions(+), 1 deletion(-) create mode 100644 Source/Core/DolphinQt2/QtUtils/SignalDaemon.cpp create mode 100644 Source/Core/DolphinQt2/QtUtils/SignalDaemon.h diff --git a/Source/Core/DolphinQt2/CMakeLists.txt b/Source/Core/DolphinQt2/CMakeLists.txt index 3d205741b3..d605a2b1a0 100644 --- a/Source/Core/DolphinQt2/CMakeLists.txt +++ b/Source/Core/DolphinQt2/CMakeLists.txt @@ -95,6 +95,7 @@ add_executable(dolphin-emu QtUtils/DoubleClickEventFilter.cpp QtUtils/ElidedButton.cpp QtUtils/ImageConverter.cpp + QtUtils/SignalDaemon.cpp QtUtils/WindowActivationEventFilter.cpp QtUtils/WinIconHelper.cpp QtUtils/WrapInScrollArea.cpp diff --git a/Source/Core/DolphinQt2/MainWindow.cpp b/Source/Core/DolphinQt2/MainWindow.cpp index 90bf1b2d20..3cf69295ae 100644 --- a/Source/Core/DolphinQt2/MainWindow.cpp +++ b/Source/Core/DolphinQt2/MainWindow.cpp @@ -1,4 +1,3 @@ - // Copyright 2015 Dolphin Emulator Project // Licensed under GPLv2+ // Refer to the license.txt file included. @@ -20,6 +19,12 @@ #include #include +#if defined(__unix__) || defined(__unix) || defined(__APPLE__) +#include + +#include "QtUtils/SignalDaemon.h" +#endif + #include "Common/Version.h" #include "Core/Boot/Boot.h" @@ -86,6 +91,23 @@ #include "UICommon/X11Utils.h" #endif +#if defined(__unix__) || defined(__unix) || defined(__APPLE__) +void MainWindow::OnSignal() +{ + close(); +} + +static void InstallSignalHandler() +{ + struct sigaction sa; + sa.sa_handler = &SignalDaemon::HandleInterrupt; + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_RESETHAND; + sigaction(SIGINT, &sa, nullptr); + sigaction(SIGTERM, &sa, nullptr); +} +#endif + MainWindow::MainWindow(std::unique_ptr boot_parameters) : QMainWindow(nullptr) { setWindowTitle(QString::fromStdString(Common::scm_rev_str)); @@ -109,6 +131,14 @@ MainWindow::MainWindow(std::unique_ptr boot_parameters) : QMainW NetPlayInit(); +#if defined(__unix__) || defined(__unix) || defined(__APPLE__) + auto* daemon = new SignalDaemon(this); + + connect(daemon, &SignalDaemon::InterruptReceived, this, &MainWindow::OnSignal); + + InstallSignalHandler(); +#endif + if (boot_parameters) m_pending_boot = std::move(boot_parameters); diff --git a/Source/Core/DolphinQt2/MainWindow.h b/Source/Core/DolphinQt2/MainWindow.h index cb0c26e772..741a9b46c3 100644 --- a/Source/Core/DolphinQt2/MainWindow.h +++ b/Source/Core/DolphinQt2/MainWindow.h @@ -138,6 +138,7 @@ private: void OnBootGameCubeIPL(DiscIO::Region region); void OnImportNANDBackup(); void OnConnectWiiRemote(int id); + void OnSignal(); void OnUpdateProgressDialog(QString label, int progress, int total); diff --git a/Source/Core/DolphinQt2/QtUtils/SignalDaemon.cpp b/Source/Core/DolphinQt2/QtUtils/SignalDaemon.cpp new file mode 100644 index 0000000000..546b03a252 --- /dev/null +++ b/Source/Core/DolphinQt2/QtUtils/SignalDaemon.cpp @@ -0,0 +1,55 @@ +// Copyright 2018 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#include "DolphinQt2/QtUtils/SignalDaemon.h" + +#include +#include +#include + +#include + +int SignalDaemon::s_sigterm_fd[2]; + +static constexpr char message[] = + "\nA signal was received. A second signal will force Dolphin to stop.\n"; + +SignalDaemon::SignalDaemon(QObject* parent) : QObject(parent) +{ + if (socketpair(AF_UNIX, SOCK_STREAM, 0, s_sigterm_fd)) + qFatal("Couldn't create TERM socketpair"); + + m_term = new QSocketNotifier(s_sigterm_fd[1], QSocketNotifier::Read, this); + connect(m_term, &QSocketNotifier::activated, this, &SignalDaemon::OnNotifierActivated); +} + +SignalDaemon::~SignalDaemon() +{ + close(s_sigterm_fd[0]); + close(s_sigterm_fd[1]); +} + +void SignalDaemon::OnNotifierActivated() +{ + m_term->setEnabled(false); + + char tmp; + if (read(s_sigterm_fd[1], &tmp, sizeof(char))) + { + } + + m_term->setEnabled(true); + + emit InterruptReceived(); +} + +void SignalDaemon::HandleInterrupt(int) +{ + write(STDERR_FILENO, message, sizeof(message)); + + char a = 1; + if (write(s_sigterm_fd[0], &a, sizeof(a))) + { + } +} diff --git a/Source/Core/DolphinQt2/QtUtils/SignalDaemon.h b/Source/Core/DolphinQt2/QtUtils/SignalDaemon.h new file mode 100644 index 0000000000..1c17f07e07 --- /dev/null +++ b/Source/Core/DolphinQt2/QtUtils/SignalDaemon.h @@ -0,0 +1,31 @@ +// Copyright 2018 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#pragma once + +#include + +class QSocketNotifier; + +// Loosely based on https://doc.qt.io/qt-5.9/unix-signals.html +class SignalDaemon : public QObject +{ + Q_OBJECT + +public: + explicit SignalDaemon(QObject* parent); + ~SignalDaemon(); + + static void HandleInterrupt(int); + +signals: + void InterruptReceived(); + +private: + void OnNotifierActivated(); + + static int s_sigterm_fd[2]; + + QSocketNotifier* m_term; +};