summaryrefslogtreecommitdiff
path: root/src/processrunner.cpp
diff options
context:
space:
mode:
authorisanae <14251494+isanae@users.noreply.github.com>2019-10-29 12:08:13 -0400
committerisanae <14251494+isanae@users.noreply.github.com>2019-11-06 07:44:55 -0500
commitb05cbeed900fbb3492e3cb5b624f5d9efaa288ea (patch)
tree9f05dbab21c3f81efc54a27cf22ee370170c381b /src/processrunner.cpp
parent4d269c2e1a625e6d50b7e6272b4f474a921c6bfa (diff)
refactored waiting into waitForProcesses()
Diffstat (limited to 'src/processrunner.cpp')
-rw-r--r--src/processrunner.cpp276
1 files changed, 116 insertions, 160 deletions
diff --git a/src/processrunner.cpp b/src/processrunner.cpp
index 81c4b99e..dbcee3ab 100644
--- a/src/processrunner.cpp
+++ b/src/processrunner.cpp
@@ -8,45 +8,62 @@
using namespace MOBase;
-void adjustForVirtualized(
- const IPluginGame* game, spawn::SpawnParameters& sp, const Settings& settings)
+enum class WaitResults
{
- const QString modsPath = settings.paths().mods();
+ Completed = 1,
+ Error,
+ Cancelled
+};
- // Check if this a request with either an executable or a working directory
- // under our mods folder then will start the process in a virtualized
- // "environment" with the appropriate paths fixed:
- // (i.e. mods\FNIS\path\exe => game\data\path\exe)
- QString cwdPath = sp.currentDirectory.absolutePath();
- bool virtualizedCwd = cwdPath.startsWith(modsPath, Qt::CaseInsensitive);
- QString binPath = sp.binary.absoluteFilePath();
- bool virtualizedBin = binPath.startsWith(modsPath, Qt::CaseInsensitive);
- if (virtualizedCwd || virtualizedBin) {
- if (virtualizedCwd) {
- int cwdOffset = cwdPath.indexOf('/', modsPath.length() + 1);
- QString adjustedCwd = cwdPath.mid(cwdOffset, -1);
- cwdPath = game->dataDirectory().absolutePath();
- if (cwdOffset >= 0)
- cwdPath += adjustedCwd;
- }
+WaitResults waitForProcess(
+ HANDLE handle, DWORD* exitCode, std::function<bool ()> progress)
+{
+ if (handle == INVALID_HANDLE_VALUE) {
+ return WaitResults::Error;
+ }
- if (virtualizedBin) {
- int binOffset = binPath.indexOf('/', modsPath.length() + 1);
- QString adjustedBin = binPath.mid(binOffset, -1);
- binPath = game->dataDirectory().absolutePath();
- if (binOffset >= 0)
- binPath += adjustedBin;
+ log::debug("waiting for completion on pid {}", ::GetProcessId(handle));
+
+ std::vector<HANDLE> handles;
+ handles.push_back(handle);
+
+ std::vector<DWORD> exitCodes;
+
+ for (;;) {
+ // Wait for a an event on the handle, a key press, mouse click or timeout
+ const auto res = MsgWaitForMultipleObjects(
+ 1, &handle, FALSE, 50, QS_KEY | QS_MOUSEBUTTON);
+
+ if (res == WAIT_FAILED) {
+ // error
+ const auto e = ::GetLastError();
+
+ log::error(
+ "failed waiting for process completion, {}", formatSystemMessage(e));
+
+ return WaitResults::Error;
+ } else if (res == WAIT_OBJECT_0) {
+ // completed
+ if (exitCode) {
+ if (!::GetExitCodeProcess(handle, exitCode)) {
+ const auto e = ::GetLastError();
+ log::warn(
+ "failed to get exit code of process, {}",
+ formatSystemMessage(e));
+ }
+ }
+
+ return WaitResults::Completed;
}
- QString cmdline
- = QString("launch \"%1\" \"%2\" %3")
- .arg(QDir::toNativeSeparators(cwdPath),
- QDir::toNativeSeparators(binPath), sp.arguments);
+ // keep processing events so the app doesn't appear dead
+ QCoreApplication::sendPostedEvents();
+ QCoreApplication::processEvents();
- sp.binary = QFileInfo(QCoreApplication::applicationFilePath());
- sp.arguments = cmdline;
- sp.currentDirectory.setPath(QCoreApplication::applicationDirPath());
+ if (progress && progress()) {
+ return WaitResults::Cancelled;
+ }
}
}
@@ -84,11 +101,32 @@ env::Process* getInterestingProcess(std::vector<env::Process>& processes)
}
}
-
// everything is hidden, just pick the first one
return &processes[0];
}
+WaitResults waitForProcesses(
+ std::vector<env::Process>& processes,
+ LPDWORD exitCode, ILockedWaitingForProcess* uilock)
+{
+ const auto* interesting = getInterestingProcess(processes);
+ if (!interesting) {
+ return WaitResults::Error;
+ }
+
+ if (uilock) {
+ uilock->setProcessInformation(interesting->pid(), interesting->name());
+ }
+
+ auto interestingHandle = interesting->openHandleForWait();
+ if (!interestingHandle) {
+ return WaitResults::Error;
+ }
+
+ auto progress = [&]{ return uilock->unlockForced(); };
+ return waitForProcess(interestingHandle.get(), exitCode, progress);
+}
+
SpawnedProcess::SpawnedProcess(HANDLE handle, spawn::SpawnParameters sp)
: m_handle(handle), m_parameters(std::move(sp))
@@ -358,6 +396,48 @@ HANDLE ProcessRunner::spawnAndWait(
return handle;
}
+void adjustForVirtualized(
+ const IPluginGame* game, spawn::SpawnParameters& sp, const Settings& settings)
+{
+ const QString modsPath = settings.paths().mods();
+
+ // Check if this a request with either an executable or a working directory
+ // under our mods folder then will start the process in a virtualized
+ // "environment" with the appropriate paths fixed:
+ // (i.e. mods\FNIS\path\exe => game\data\path\exe)
+ QString cwdPath = sp.currentDirectory.absolutePath();
+ bool virtualizedCwd = cwdPath.startsWith(modsPath, Qt::CaseInsensitive);
+ QString binPath = sp.binary.absoluteFilePath();
+ bool virtualizedBin = binPath.startsWith(modsPath, Qt::CaseInsensitive);
+ if (virtualizedCwd || virtualizedBin) {
+ if (virtualizedCwd) {
+ int cwdOffset = cwdPath.indexOf('/', modsPath.length() + 1);
+ QString adjustedCwd = cwdPath.mid(cwdOffset, -1);
+ cwdPath = game->dataDirectory().absolutePath();
+ if (cwdOffset >= 0)
+ cwdPath += adjustedCwd;
+
+ }
+
+ if (virtualizedBin) {
+ int binOffset = binPath.indexOf('/', modsPath.length() + 1);
+ QString adjustedBin = binPath.mid(binOffset, -1);
+ binPath = game->dataDirectory().absolutePath();
+ if (binOffset >= 0)
+ binPath += adjustedBin;
+ }
+
+ QString cmdline
+ = QString("launch \"%1\" \"%2\" %3")
+ .arg(QDir::toNativeSeparators(cwdPath),
+ QDir::toNativeSeparators(binPath), sp.arguments);
+
+ sp.binary = QFileInfo(QCoreApplication::applicationFilePath());
+ sp.arguments = cmdline;
+ sp.currentDirectory.setPath(QCoreApplication::applicationDirPath());
+ }
+}
+
SpawnedProcess ProcessRunner::spawn(spawn::SpawnParameters sp)
{
QWidget* parent = nullptr;
@@ -451,34 +531,8 @@ bool ProcessRunner::waitForProcessCompletion(
const auto tree = env::getProcessTree(handle);
std::vector<env::Process> processes = {tree};
- const auto* interesting = getInterestingProcess(processes);
- if (!interesting) {
- return true;
- }
-
- if (uilock) {
- uilock->setProcessInformation(interesting->pid(), interesting->name());
- }
-
- auto interestingHandle = interesting->openHandleForWait();
- if (!interestingHandle) {
- return true;
- }
-
- auto progress = [&]{ return uilock->unlockForced(); };
- const auto r = waitForProcess(
- interestingHandle.get(), exitCode, progress);
-
- switch (r)
- {
- case WaitResults::Completed: // fall-through
- case WaitResults::Cancelled:
- return true;
-
- case WaitResults::Error: // fall-through
- default:
- return false;
- }
+ const auto r = waitForProcesses(processes, exitCode, uilock);
+ return (r != WaitResults::Error);
}
bool ProcessRunner::waitForAllUSVFSProcessesWithLock()
@@ -511,23 +565,7 @@ bool ProcessRunner::waitForAllUSVFSProcesses(ILockedWaitingForProcess* uilock)
}
}
- const auto* interesting = getInterestingProcess(processes);
- if (!interesting) {
- break;
- }
-
- if (uilock) {
- uilock->setProcessInformation(interesting->pid(), interesting->name());
- }
-
- auto interestingHandle = interesting->openHandleForWait();
- if (!interestingHandle) {
- break;
- }
-
- auto progress = [&]{ return uilock->unlockForced(); };
- const auto r = waitForProcess(
- interestingHandle.get(), nullptr, progress);
+ const auto r = waitForProcesses(processes, nullptr, uilock);
switch (r)
{
@@ -550,85 +588,3 @@ bool ProcessRunner::waitForAllUSVFSProcesses(ILockedWaitingForProcess* uilock)
log::debug("waiting for process completion successful");
return true;
}
-
-
-
-WaitResults waitForProcess(
- HANDLE handle, DWORD* exitCode, std::function<bool ()> progress)
-{
- if (handle == INVALID_HANDLE_VALUE) {
- return WaitResults::Error;
- }
-
- log::debug("waiting for completion on pid {}", ::GetProcessId(handle));
-
- std::vector<HANDLE> handles;
- handles.push_back(handle);
-
- std::vector<DWORD> exitCodes;
-
- const auto r = waitForProcesses(handles, exitCodes, progress);
-
- if (r == WaitResults::Completed) {
- if (exitCode && !exitCodes.empty()) {
- *exitCode = exitCodes[0];
- }
- }
-
- return r;
-}
-
-WaitResults waitForProcesses(
- const std::vector<HANDLE>& handles, std::vector<DWORD>& exitCodes,
- std::function<bool ()> progress)
-{
- if (handles.empty()) {
- return WaitResults::Completed;
- }
-
- const auto WAIT_OBJECT_N = static_cast<DWORD>(WAIT_OBJECT_0 + handles.size());
-
- for (;;) {
- // Wait for a an event on the handle, a key press, mouse click or timeout
- const auto res = MsgWaitForMultipleObjects(
- static_cast<DWORD>(handles.size()), &handles[0],
- TRUE, 50, QS_KEY | QS_MOUSEBUTTON);
-
- if (res == WAIT_FAILED) {
- // error
- const auto e = ::GetLastError();
-
- log::error(
- "failed waiting for process completion, {}", formatSystemMessage(e));
-
- return WaitResults::Error;
- } else if (res >= WAIT_OBJECT_0 && res < WAIT_OBJECT_N) {
- // completed
- exitCodes.resize(handles.size());
- std::fill(exitCodes.begin(), exitCodes.end(), 0);
-
- for (std::size_t i=0; i<handles.size(); ++i) {
- DWORD exitCode = 0;
-
- if (::GetExitCodeProcess(handles[i], &exitCode)) {
- exitCodes[i] = exitCode;
- } else {
- const auto e = ::GetLastError();
- log::warn(
- "failed to get exit code of process, {}",
- formatSystemMessage(e));
- }
- }
-
- return WaitResults::Completed;
- }
-
- // keep processing events so the app doesn't appear dead
- QCoreApplication::sendPostedEvents();
- QCoreApplication::processEvents();
-
- if (progress && progress()) {
- return WaitResults::Cancelled;
- }
- }
-}