diff options
| author | Stefan Boberg <[email protected]> | 2023-11-21 14:52:56 +0100 |
|---|---|---|
| committer | GitHub <[email protected]> | 2023-11-21 14:52:56 +0100 |
| commit | 8e1cb139d817880c557d407c363eb838c0893f5a (patch) | |
| tree | 69da94b1df3f2fd1d19e623084c88543c0ce85f6 /src/zencore | |
| parent | basic ZEN_ASSERT_FORMAT implementation (#556) (diff) | |
| download | zen-8e1cb139d817880c557d407c363eb838c0893f5a.tar.xz zen-8e1cb139d817880c557d407c363eb838c0893f5a.zip | |
zen run command (#552)
initial version -- this is primarily intended to be used for running stress tests and/or benchmarks
example usage:
`zen run -n 10 -- zenserver-test`
`zen run -n 10 -- zenserver-test --ts=core.assert` run zenserver-test 10 times (testing only the `core.assert` test suite)
`zen run --time 600 --basepath=d:\test_dir\test1 -- zenserver-test` keeps spawning new instances for 10 minutes (600 seconds)
Diffstat (limited to 'src/zencore')
| -rw-r--r-- | src/zencore/filesystem.cpp | 119 | ||||
| -rw-r--r-- | src/zencore/include/zencore/filesystem.h | 3 | ||||
| -rw-r--r-- | src/zencore/include/zencore/process.h | 4 | ||||
| -rw-r--r-- | src/zencore/process.cpp | 61 |
4 files changed, 185 insertions, 2 deletions
diff --git a/src/zencore/filesystem.cpp b/src/zencore/filesystem.cpp index b941613ec..f117001b5 100644 --- a/src/zencore/filesystem.cpp +++ b/src/zencore/filesystem.cpp @@ -1558,6 +1558,76 @@ RotateFiles(const std::filesystem::path& Filename, std::size_t MaxFiles) return Result; } +std::error_code +RotateDirectories(const std::filesystem::path& DirectoryName, std::size_t MaxDirectories) +{ + const std::filesystem::path BasePath(DirectoryName.parent_path()); + const std::string Stem(DirectoryName.stem().string()); + + auto GetPathForIndex = [&](size_t Index) -> std::filesystem::path { + if (Index == 0) + { + return BasePath / Stem; + } + return BasePath / fmt::format("{}.{}", Stem, Index); + }; + + auto IsEmpty = [](const std::filesystem::path& Path, std::error_code& Ec) -> bool { return std::filesystem::is_empty(Path, Ec); }; + + std::error_code Result; + const bool BaseIsEmpty = IsEmpty(GetPathForIndex(0), Result); + if (Result) + { + return Result; + } + + if (BaseIsEmpty) + return Result; + + for (std::size_t i = MaxDirectories; i > 0; i--) + { + const std::filesystem::path SourcePath = GetPathForIndex(i - 1); + + if (std::filesystem::exists(SourcePath)) + { + std::filesystem::path TargetPath = GetPathForIndex(i); + + std::error_code DummyEc; + if (std::filesystem::exists(TargetPath, DummyEc)) + { + std::filesystem::remove_all(TargetPath, DummyEc); + } + std::filesystem::rename(SourcePath, TargetPath, DummyEc); + } + } + + return Result; +} + +std::filesystem::path +SearchPathForExecutable(std::string_view ExecutableName) +{ +#if ZEN_PLATFORM_WINDOWS + std::wstring Executable(Utf8ToWide(ExecutableName)); + + DWORD Result = SearchPathW(nullptr, Executable.c_str(), L".exe", 0, nullptr, nullptr); + + if (!Result) + return ExecutableName; + + auto PathBuffer = std::make_unique_for_overwrite<WCHAR[]>(Result); + + Result = SearchPathW(nullptr, Executable.c_str(), L".exe", Result, PathBuffer.get(), nullptr); + + if (!Result) + return ExecutableName; + + return PathBuffer.get(); +#else + return ExecutableName; +#endif +} + ////////////////////////////////////////////////////////////////////////// // // Testing related code follows... @@ -1717,6 +1787,55 @@ TEST_CASE("PathBuilder") # endif } +TEST_CASE("RotateDirectories") +{ + std::filesystem::path TestBaseDir = GetRunningExecutablePath().parent_path() / ".test"; + CleanDirectory(TestBaseDir); + std::filesystem::path RotateDir = TestBaseDir / "rotate_dir" / "dir_to_rotate"; + IoBuffer DummyFileData = IoBufferBuilder::MakeCloneFromMemory("blubb", 5); + + auto NewDir = [&] { + CreateDirectories(RotateDir); + WriteFile(RotateDir / ".placeholder", DummyFileData); + }; + + auto DirWithSuffix = [&](int Index) -> std::filesystem::path { return RotateDir.generic_string().append(fmt::format(".{}", Index)); }; + + const int RotateMax = 10; + + NewDir(); + CHECK(std::filesystem::exists(RotateDir)); + RotateDirectories(RotateDir, RotateMax); + CHECK(!std::filesystem::exists(RotateDir)); + CHECK(std::filesystem::exists(DirWithSuffix(1))); + NewDir(); + CHECK(std::filesystem::exists(RotateDir)); + RotateDirectories(RotateDir, RotateMax); + CHECK(!std::filesystem::exists(RotateDir)); + CHECK(std::filesystem::exists(DirWithSuffix(1))); + CHECK(std::filesystem::exists(DirWithSuffix(2))); + + for (int i = 0; i < RotateMax; ++i) + { + NewDir(); + std::error_code Ec = RotateDirectories(RotateDir, 10); + const bool IsError = !!Ec; + CHECK_EQ(IsError, false); + } + + CHECK(!std::filesystem::exists(RotateDir)); + + for (int i = 0; i < RotateMax; ++i) + { + CHECK(std::filesystem::exists(DirWithSuffix(i + 1))); + } + + for (int i = RotateMax; i < RotateMax + 5; ++i) + { + CHECK(!std::filesystem::exists(DirWithSuffix(RotateMax + i + 1))); + } +} + #endif } // namespace zen diff --git a/src/zencore/include/zencore/filesystem.h b/src/zencore/include/zencore/filesystem.h index 963890fb9..07eb72879 100644 --- a/src/zencore/include/zencore/filesystem.h +++ b/src/zencore/include/zencore/filesystem.h @@ -211,7 +211,10 @@ void GetDirectoryContent(const std::filesystem::path& RootDir, uint8_t Flags, Di std::string GetEnvVariable(std::string_view VariableName); +std::filesystem::path SearchPathForExecutable(std::string_view ExecutableName); + std::error_code RotateFiles(const std::filesystem::path& Filename, std::size_t MaxFiles); +std::error_code RotateDirectories(const std::filesystem::path& DirectoryName, std::size_t MaxDirectories); ////////////////////////////////////////////////////////////////////////// diff --git a/src/zencore/include/zencore/process.h b/src/zencore/include/zencore/process.h index ec598b929..d90a32301 100644 --- a/src/zencore/include/zencore/process.h +++ b/src/zencore/include/zencore/process.h @@ -34,6 +34,9 @@ public: private: void* m_ProcessHandle = nullptr; int m_Pid = 0; +#if ZEN_PLATFORM_LINUX || ZEN_PLATFORM_MAC + int m_ExitCode = -1; +#endif }; /** Basic process creation @@ -49,6 +52,7 @@ struct CreateProcOptions const std::filesystem::path* WorkingDirectory = nullptr; uint32_t Flags = 0; + std::filesystem::path StdoutFile; }; #if ZEN_PLATFORM_WINDOWS diff --git a/src/zencore/process.cpp b/src/zencore/process.cpp index 1c208701c..2d0ec2de6 100644 --- a/src/zencore/process.cpp +++ b/src/zencore/process.cpp @@ -185,6 +185,11 @@ ProcessHandle::Wait(int TimeoutMs) int WaitState = 0; waitpid(m_Pid, &WaitState, WNOHANG | WCONTINUED | WUNTRACED); + if (WIFEXITED(WaitState)) + { + m_ExitCode = WEXITSTATUS(WaitState); + } + if (kill(m_Pid, 0) < 0) { int32_t LastError = zen::GetLastError(); @@ -220,6 +225,8 @@ ProcessHandle::WaitExitCode() ZEN_ASSERT(ExitCode != STILL_ACTIVE); return ExitCode; +#elif ZEN_PLATFORM_LINUX || ZEN_PLATFORM_MAC + return m_ExitCode; #else ZEN_NOT_IMPLEMENTED(); @@ -278,7 +285,7 @@ CreateProcNormal(const std::filesystem::path& Executable, std::string_view Comma PROCESS_INFORMATION ProcessInfo{}; STARTUPINFO StartupInfo{.cb = sizeof(STARTUPINFO)}; - const bool InheritHandles = false; + bool InheritHandles = false; void* Environment = nullptr; LPSECURITY_ATTRIBUTES ProcessAttributes = nullptr; LPSECURITY_ATTRIBUTES ThreadAttributes = nullptr; @@ -298,6 +305,42 @@ CreateProcNormal(const std::filesystem::path& Executable, std::string_view Comma ExtendableWideStringBuilder<256> CommandLineZ; CommandLineZ << CommandLine; + if (!Options.StdoutFile.empty()) + { + SECURITY_ATTRIBUTES sa; + sa.nLength = sizeof sa; + sa.lpSecurityDescriptor = nullptr; + sa.bInheritHandle = TRUE; + + StartupInfo.hStdInput = nullptr; + StartupInfo.hStdOutput = CreateFileW(Options.StdoutFile.c_str(), + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ, + &sa, + CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, + nullptr); + + const BOOL Success = DuplicateHandle(GetCurrentProcess(), + StartupInfo.hStdOutput, + GetCurrentProcess(), + &StartupInfo.hStdError, + 0, + TRUE, + DUPLICATE_SAME_ACCESS); + + if (Success) + { + StartupInfo.dwFlags |= STARTF_USESTDHANDLES; + InheritHandles = true; + } + else + { + CloseHandle(StartupInfo.hStdOutput); + StartupInfo.hStdOutput = 0; + } + } + BOOL Success = CreateProcessW(Executable.c_str(), CommandLineZ.Data(), ProcessAttributes, @@ -309,6 +352,12 @@ CreateProcNormal(const std::filesystem::path& Executable, std::string_view Comma &StartupInfo, &ProcessInfo); + if (StartupInfo.dwFlags & STARTF_USESTDHANDLES) + { + CloseHandle(StartupInfo.hStdError); + CloseHandle(StartupInfo.hStdOutput); + } + if (!Success) { return nullptr; @@ -395,6 +444,14 @@ CreateProcUnelevated(const std::filesystem::path& Executable, std::string_view C ExtendableWideStringBuilder<256> CommandLineZ; CommandLineZ << CommandLine; + ExtendableWideStringBuilder<256> CurrentDirZ; + LPCWSTR WorkingDirectoryPtr = nullptr; + if (Options.WorkingDirectory) + { + CurrentDirZ << Options.WorkingDirectory->native(); + WorkingDirectoryPtr = CurrentDirZ.c_str(); + } + bOk = CreateProcessW(Executable.c_str(), CommandLineZ.Data(), nullptr, @@ -402,7 +459,7 @@ CreateProcUnelevated(const std::filesystem::path& Executable, std::string_view C FALSE, CreateProcFlags, nullptr, - nullptr, + WorkingDirectoryPtr, &StartupInfo.StartupInfo, &ProcessInfo); if (bOk == FALSE) |