diff options
| author | Leitwolf11 | 2026-11-13 23:24:10 +0300 |
|---|---|---|
| committer | Leitwolf11 | 2026-11-13 23:24:10 +0300 |
| commit | b26486d68ece48a1dfdb208a9f3f1bd8acab0382 (patch) | |
| tree | af0d8c583c22d61568ae250011b77cba6acc8c34 /src/Progmasoft/Runner/Process.cpp | |
| parent | 454cca9b63991416f4d9bd1ca350f1ae14e278e7 (diff) | |
| download | catch3-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.cpp | 22 |
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()) { |