refactor: Implement Windows event loop in AppUtilWindows for graceful shutdown handling
This commit is contained in:
@ -41,3 +41,11 @@ enum
|
||||
kExitArgs = 3, // bad arguments
|
||||
kExitConfig = 4, // cannot read configuration
|
||||
};
|
||||
|
||||
#if WINAPI_MSWINDOWS
|
||||
namespace deskflow::common {
|
||||
|
||||
const auto kCloseEventName = "Global\\DeskflowCloseEvent";
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -23,6 +23,7 @@
|
||||
#include "deskflow/protocol_types.h"
|
||||
#include "ipc/IpcMessage.h"
|
||||
#include "ipc/IpcServerProxy.h"
|
||||
#include <thread>
|
||||
|
||||
#if SYSAPI_WIN32
|
||||
#include "arch/win32/ArchMiscWindows.h"
|
||||
@ -165,7 +166,6 @@ void App::loggingFilterWarning()
|
||||
|
||||
void App::initApp(int argc, const char **argv)
|
||||
{
|
||||
|
||||
std::string configFilename;
|
||||
CLI::App cliApp{kAppDescription};
|
||||
cliApp.add_option("--config-toml", configFilename, "Use TOML configuration file");
|
||||
|
||||
@ -20,6 +20,7 @@
|
||||
#endif
|
||||
|
||||
#include <stdexcept>
|
||||
#include <thread>
|
||||
|
||||
namespace deskflow {
|
||||
class Screen;
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Deskflow -- mouse and keyboard sharing utility
|
||||
* SPDX-FileCopyrightText: (C) 2012 Symless Ltd.
|
||||
* SPDX-FileCopyrightText: (C) 2012 - 2025 Symless Ltd.
|
||||
* SPDX-FileCopyrightText: (C) 2002 Chris Schoeneman
|
||||
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
||||
*/
|
||||
@ -10,11 +10,10 @@
|
||||
#include "arch/win32/ArchMiscWindows.h"
|
||||
#include "arch/win32/XArchWindows.h"
|
||||
#include "base/Event.h"
|
||||
#include "base/EventQueue.h"
|
||||
#include "base/IEventQueue.h"
|
||||
#include "base/Log.h"
|
||||
#include "base/log_outputters.h"
|
||||
#include "common/constants.h"
|
||||
#include "common/common.h"
|
||||
#include "deskflow/App.h"
|
||||
#include "deskflow/ArgsBase.h"
|
||||
#include "deskflow/Screen.h"
|
||||
@ -24,9 +23,7 @@
|
||||
#include <VersionHelpers.h>
|
||||
#include <Windows.h>
|
||||
#include <conio.h>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
|
||||
#if HAVE_WINTOAST
|
||||
#include "wintoastlib.h"
|
||||
@ -37,10 +34,21 @@ AppUtilWindows::AppUtilWindows(IEventQueue *events) : m_events(events), m_exitMo
|
||||
if (SetConsoleCtrlHandler((PHANDLER_ROUTINE)consoleHandler, TRUE) == FALSE) {
|
||||
throw XArch(new XArchEvalWindows());
|
||||
}
|
||||
|
||||
m_eventThread = std::thread(&AppUtilWindows::eventLoop, this); // NOSONAR - No jthread on Windows
|
||||
|
||||
// Waiting for the event loop start prevents race condition in fast fail scenario,
|
||||
// where the dtor is called just before the event loop starts.
|
||||
LOG_DEBUG("waiting for event thread to start");
|
||||
std::unique_lock<std::mutex> lock(m_eventThreadStartedMutex);
|
||||
m_eventThreadStartedCond.wait(lock, [this] { return m_eventThreadRunning; });
|
||||
LOG_DEBUG("event thread started");
|
||||
}
|
||||
|
||||
AppUtilWindows::~AppUtilWindows()
|
||||
{
|
||||
m_eventThreadRunning = false;
|
||||
m_eventThread.join();
|
||||
}
|
||||
|
||||
BOOL WINAPI AppUtilWindows::consoleHandler(DWORD)
|
||||
@ -263,3 +271,39 @@ void AppUtilWindows::showNotification(const std::string &title, const std::strin
|
||||
LOG((CLOG_INFO "toast notifications are not supported"));
|
||||
#endif
|
||||
}
|
||||
|
||||
void AppUtilWindows::eventLoop()
|
||||
{
|
||||
HANDLE hCloseEvent = CreateEventA(nullptr, TRUE, FALSE, deskflow::common::kCloseEventName);
|
||||
if (!hCloseEvent) {
|
||||
LOG_CRIT("failed to create event for windows event loop");
|
||||
throw XArch(new XArchEvalWindows());
|
||||
}
|
||||
|
||||
LOG_DEBUG("windows event loop running");
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_eventThreadStartedMutex);
|
||||
m_eventThreadRunning = true;
|
||||
}
|
||||
m_eventThreadStartedCond.notify_one();
|
||||
|
||||
while (m_eventThreadRunning) {
|
||||
// Wait for 100ms at most so that we can stop the loop when the app is closing, if not already stopped.
|
||||
DWORD closeEventResult = MsgWaitForMultipleObjects(1, &hCloseEvent, FALSE, 100, QS_ALLINPUT);
|
||||
|
||||
if (closeEventResult == WAIT_OBJECT_0) {
|
||||
LOG_DEBUG("windows event loop received close event");
|
||||
m_events->addEvent(Event(Event::kQuit));
|
||||
m_eventThreadRunning = false;
|
||||
} else if (closeEventResult == WAIT_OBJECT_0 + 1) {
|
||||
MSG msg;
|
||||
while (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE)) {
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CloseHandle(hCloseEvent);
|
||||
LOG_DEBUG("windows event loop finished");
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Deskflow -- mouse and keyboard sharing utility
|
||||
* SPDX-FileCopyrightText: (C) 2012 - 2016 Symless Ltd.
|
||||
* SPDX-FileCopyrightText: (C) 2012 - 2025 Symless Ltd.
|
||||
* SPDX-FileCopyrightText: (C) 2002 Chris Schoeneman
|
||||
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
||||
*/
|
||||
@ -10,7 +10,11 @@
|
||||
#include "deskflow/AppUtil.h"
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include "Windows.h"
|
||||
#include "Windows.h" // IWYU pragma: keep
|
||||
|
||||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
|
||||
#define ARCH_APP_UTIL AppUtilWindows
|
||||
|
||||
@ -44,6 +48,12 @@ public:
|
||||
private:
|
||||
AppExitMode m_exitMode;
|
||||
IEventQueue *m_events;
|
||||
std::thread m_eventThread; // NOSONAR - No jthread on Windows
|
||||
bool m_eventThreadRunning = false;
|
||||
std::condition_variable m_eventThreadStartedCond;
|
||||
std::mutex m_eventThreadStartedMutex;
|
||||
|
||||
void eventLoop();
|
||||
|
||||
static BOOL WINAPI consoleHandler(DWORD Event);
|
||||
};
|
||||
|
||||
@ -122,6 +122,16 @@ void MSWindowsProcess::shutdown(HANDLE handle, DWORD pid, int timeout)
|
||||
{
|
||||
LOG_DEBUG("shutting down process %d", pid);
|
||||
|
||||
LOG_DEBUG("sending close event to close process gracefully");
|
||||
HANDLE hCloseEvent = OpenEvent(EVENT_MODIFY_STATE, FALSE, deskflow::common::kCloseEventName);
|
||||
if (hCloseEvent) { // NOSONAR -- Readability
|
||||
SetEvent(hCloseEvent);
|
||||
CloseHandle(hCloseEvent);
|
||||
} else {
|
||||
LOG((CLOG_WARN "could not send close event to process"));
|
||||
throw XArch(new XArchEvalWindows);
|
||||
}
|
||||
|
||||
DWORD exitCode;
|
||||
GetExitCodeProcess(handle, &exitCode);
|
||||
if (exitCode != STILL_ACTIVE) {
|
||||
|
||||
@ -167,6 +167,7 @@ MSWindowsWatchdog::getUserToken(LPSECURITY_ATTRIBUTES security, bool elevatedTok
|
||||
void MSWindowsWatchdog::mainLoop(void *)
|
||||
{
|
||||
LOG_DEBUG("starting main loop");
|
||||
|
||||
shutdownExistingProcesses();
|
||||
|
||||
// the SendSAS function is used to send a sas (secure attention sequence) to the
|
||||
|
||||
Reference in New Issue
Block a user