diff options
| author | tristan-iu <tristan.iung@hotmail.com> | 2026-06-21 17:56:42 +0200 |
|---|---|---|
| committer | tristan-iu <tristan.iung@hotmail.com> | 2026-06-23 23:56:08 +0200 |
| commit | 0990b4dae74ffca4c033bc9a691981d52439b3c1 (patch) | |
| tree | 972300b289fa5b079a8a2a7137aee6fdd077968a | |
| parent | ce2ae9f4769f6181fe36a87056775af23faaeb59 (diff) | |
Don't kill launcher-spawned engine on force-unlock for non-VFS games
| -rw-r--r-- | src/src/processrunner.cpp | 50 |
1 files changed, 44 insertions, 6 deletions
diff --git a/src/src/processrunner.cpp b/src/src/processrunner.cpp index 36108b8..01ed905 100644 --- a/src/src/processrunner.cpp +++ b/src/src/processrunner.cpp @@ -595,8 +595,16 @@ DWORD exitCodeFromWaitStatus(int status) return 0; } +// killTreeOnUnlock: when the user force-unlocks/cancels the lock dialog, SIGKILL +// the launched process tree (and the wineserver) so the wineprefix/FUSE VFS can +// be torn down cleanly. This is correct for Proton games and for native games +// that still rely on the FUSE VFS (e.g. Stardew Valley). It must be FALSE for +// native, non-VFS games like OpenMW (usesVFS()==false): there is nothing to tear +// down, and killing the tree would take down a launcher-spawned engine the user +// is actively using. See OrganizerCore::managedGame()->usesVFS() at the caller. ProcessRunner::Results waitForPid(pid_t pid, LPDWORD exitCode, - UILocker::Session* ls, const QStringList& expected) + UILocker::Session* ls, const QStringList& expected, + bool killTreeOnUnlock) { if (pid <= 0) { return ProcessRunner::Error; @@ -777,6 +785,23 @@ ProcessRunner::Results waitForPid(pid_t pid, LPDWORD exitCode, case UILocker::ForceUnlocked: case UILocker::Cancelled: { const bool cancelled = (UILocker::Session::result() == UILocker::Cancelled); + + // The teardown below exists only to clean up the wineprefix and let the + // FUSE VFS unmount. A native, non-VFS game (OpenMW, usesVFS()==false) + // has neither, and its launcher spawns the real engine as a child the + // user is still playing — so force-unlock here must release the lock + // without killing the process tree. + if (!killTreeOnUnlock) { + log::debug("waiting for {} {} by user; non-VFS game, releasing lock " + "but leaving the process tree running", + displayPid, cancelled ? "cancelled" : "force unlocked"); + if (exitCode != nullptr) { + *exitCode = 0; + } + return cancelled ? ProcessRunner::Cancelled + : ProcessRunner::ForceUnlocked; + } + log::debug("waiting for {} {} by user, terminating", displayPid, cancelled ? "cancelled" : "force unlocked"); @@ -825,14 +850,17 @@ ProcessRunner::Results waitForPid(pid_t pid, LPDWORD exitCode, ProcessRunner::Results waitForProcess(HANDLE initialProcess, LPDWORD exitCode, UILocker::Session* ls, - const QStringList& expected) + const QStringList& expected, + bool killTreeOnUnlock) { - return waitForPid(handleToPid(initialProcess), exitCode, ls, expected); + return waitForPid(handleToPid(initialProcess), exitCode, ls, expected, + killTreeOnUnlock); } ProcessRunner::Results waitForProcesses(const std::vector<HANDLE>& initialProcesses, UILocker::Session* ls, - const QStringList& expected) + const QStringList& expected, + bool killTreeOnUnlock) { if (initialProcesses.empty()) { return ProcessRunner::Completed; @@ -840,7 +868,8 @@ ProcessRunner::Results waitForProcesses(const std::vector<HANDLE>& initialProces for (HANDLE h : initialProcesses) { DWORD ignored = 0; - const auto r = waitForPid(handleToPid(h), &ignored, ls, expected); + const auto r = waitForPid(handleToPid(h), &ignored, ls, expected, + killTreeOnUnlock); if (r != ProcessRunner::Completed) { return r; } @@ -1324,9 +1353,18 @@ ProcessRunner::Results ProcessRunner::postRun() } } + // Only tear down the launched process tree on force-unlock for games that + // have a wineprefix/FUSE VFS to clean up. Native, non-VFS games (OpenMW) + // must keep running when the user releases the lock — same usesVFS() gate as + // the FUSE mount in OrganizerCore (default true = unchanged for every other + // game). + const auto* game = m_core.managedGame(); + const bool killTreeOnUnlock = (game == nullptr) || game->usesVFS(); + auto r = Error; withLock([&](auto& ls) { - r = waitForProcess(m_handle.get(), &m_exitCode, &ls, expectedExecutables); + r = waitForProcess(m_handle.get(), &m_exitCode, &ls, expectedExecutables, + killTreeOnUnlock); }); if (shouldRefresh(r)) { |
