Merge pull request #8592 from devsnek/sig-handlers
exit gracefully on sigint/sigterm
This commit is contained in:
		@@ -8,6 +8,10 @@
 | 
			
		||||
#ifdef __APPLE__
 | 
			
		||||
#include <unistd.h> // for chdir
 | 
			
		||||
#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.
 | 
			
		||||
#include "applets/qt_controller.h"
 | 
			
		||||
@@ -259,6 +263,10 @@ GMainWindow::GMainWindow(bool has_broken_vulkan)
 | 
			
		||||
      config{std::make_unique<Config>(*system)},
 | 
			
		||||
      vfs{std::make_shared<FileSys::RealVfsFilesystem>()},
 | 
			
		||||
      provider{std::make_unique<FileSys::ManualContentProvider>()} {
 | 
			
		||||
#ifdef __linux__
 | 
			
		||||
    SetupSigInterrupts();
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    Common::Log::Initialize();
 | 
			
		||||
    LoadTranslation();
 | 
			
		||||
 | 
			
		||||
@@ -462,7 +470,13 @@ GMainWindow::~GMainWindow() {
 | 
			
		||||
    if (render_window->parent() == nullptr) {
 | 
			
		||||
        delete render_window;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    system->GetRoomNetwork().Shutdown();
 | 
			
		||||
 | 
			
		||||
#ifdef __linux__
 | 
			
		||||
    ::close(sig_interrupt_fds[0]);
 | 
			
		||||
    ::close(sig_interrupt_fds[1]);
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GMainWindow::RegisterMetaTypes() {
 | 
			
		||||
@@ -1352,6 +1366,52 @@ static void ReleaseWakeLockLinux(QDBusObjectPath lock) {
 | 
			
		||||
                            QString::fromLatin1("org.freedesktop.portal.Request"));
 | 
			
		||||
    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__
 | 
			
		||||
 | 
			
		||||
void GMainWindow::PreventOSSleep() {
 | 
			
		||||
 
 | 
			
		||||
@@ -163,6 +163,8 @@ signals:
 | 
			
		||||
    void WebBrowserExtractOfflineRomFS();
 | 
			
		||||
    void WebBrowserClosed(Service::AM::Applets::WebExitReason exit_reason, std::string last_url);
 | 
			
		||||
 | 
			
		||||
    void SigInterrupt();
 | 
			
		||||
 | 
			
		||||
public slots:
 | 
			
		||||
    void OnLoadComplete();
 | 
			
		||||
    void OnExecuteProgram(std::size_t program_index);
 | 
			
		||||
@@ -251,6 +253,12 @@ private:
 | 
			
		||||
    void RequestGameResume();
 | 
			
		||||
    void closeEvent(QCloseEvent* event) override;
 | 
			
		||||
 | 
			
		||||
#ifdef __linux__
 | 
			
		||||
    void SetupSigInterrupts();
 | 
			
		||||
    static void HandleSigInterrupt(int);
 | 
			
		||||
    void OnSigInterruptNotifierActivated();
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
private slots:
 | 
			
		||||
    void OnStartGame();
 | 
			
		||||
    void OnRestartGame();
 | 
			
		||||
@@ -419,6 +427,9 @@ private:
 | 
			
		||||
    bool is_tas_recording_dialog_active{};
 | 
			
		||||
 | 
			
		||||
#ifdef __linux__
 | 
			
		||||
    QSocketNotifier* sig_interrupt_notifier;
 | 
			
		||||
    static std::array<int, 3> sig_interrupt_fds;
 | 
			
		||||
 | 
			
		||||
    QDBusObjectPath wake_lock{};
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user