Read-only mirrors. Development, issues and pull requests are on GitHub.

summaryrefslogtreecommitdiffhomepage
path: root/src/Progmasoft/Runner/Process.cpp
diff options
context:
space:
mode:
authorLeitwolf112026-11-13 23:24:10 +0300
committerLeitwolf112026-11-13 23:24:10 +0300
commitb26486d68ece48a1dfdb208a9f3f1bd8acab0382 (patch)
treeaf0d8c583c22d61568ae250011b77cba6acc8c34 /src/Progmasoft/Runner/Process.cpp
parent454cca9b63991416f4d9bd1ca350f1ae14e278e7 (diff)
downloadcatch3-b26486d68ece48a1dfdb208a9f3f1bd8acab0382.tar.gz
Start child processes one at a time; run gcov without a directory
Reading the coverage profiles on several threads broke an assumption of ChildProcess::Start on POSIX: it changes the working directory of the whole process around posix_spawn. Two gcov runs started at once could both run in one test's directory, so on the GCC job the map of "Subtracts one" showed what "Adds one" reached. - ChildProcess::Start holds a lock while a child starts, on POSIX and Windows, so the directory change and the handles a child inherits never overlap with another start. - gcov gets the absolute path of the data file and no working directory, so no directory changes while profiles are read in parallel.
Diffstat (limited to 'src/Progmasoft/Runner/Process.cpp')
-rw-r--r--src/Progmasoft/Runner/Process.cpp22
1 files changed, 21 insertions, 1 deletions
diff --git a/src/Progmasoft/Runner/Process.cpp b/src/Progmasoft/Runner/Process.cpp
index 85987210..41fa87f1 100644
--- a/src/Progmasoft/Runner/Process.cpp
+++ b/src/Progmasoft/Runner/Process.cpp
@@ -6,6 +6,7 @@
#include <cstdlib>
#include <cstring>
#include <iterator>
+#include <mutex>
#include <string_view>
#include <thread>
@@ -611,6 +612,20 @@ namespace Progmasoft::Catch3::Runner
#endif
}
+ namespace
+ {
+ /// Held while a child starts. Starting changes what the whole process
+ /// shares: the working directory on POSIX, and the handles a child
+ /// inherits; two threads starting children at once would see each
+ /// other's directory or hand their pipes to each other's child.
+ std::mutex &
+ StartLock()
+ {
+ static std::mutex lock;
+ return lock;
+ }
+ } // namespace
+
#if defined(_WIN32)
Expected<std::unique_ptr<ChildProcess>>
ChildProcess::Start(const ChildOptions &options)
@@ -619,6 +634,7 @@ namespace Progmasoft::Catch3::Runner
{
return Error{ "no program to start" };
}
+ const std::lock_guard<std::mutex> starting{ StartLock() };
SECURITY_ATTRIBUTES inheritable{};
inheritable.nLength = sizeof(inheritable);
inheritable.bInheritHandle = TRUE;
@@ -981,6 +997,7 @@ namespace Progmasoft::Catch3::Runner
{
return Error{ "no program to start" };
}
+ const std::lock_guard<std::mutex> starting{ StartLock() };
int input[2] = { -1, -1 };
int output[2] = { -1, -1 };
int errors[2] = { -1, -1 };
@@ -1072,7 +1089,10 @@ namespace Progmasoft::Catch3::Runner
arguments.push_back(nullptr);
// posix_spawn has no working-directory action everywhere, so the
- // directory changes around the call; only this thread spawns.
+ // directory changes around the call, under StartLock. A thread that
+ // reads a relative path meanwhile would read it from there, so
+ // callers that start children from several threads use absolute
+ // paths or no working directory.
std::filesystem::path previousDirectory;
if (!options.workingDirectory.empty())
{