aboutsummaryrefslogtreecommitdiff
path: root/src/zencore
diff options
context:
space:
mode:
authorStefan Boberg <[email protected]>2023-11-21 14:52:56 +0100
committerGitHub <[email protected]>2023-11-21 14:52:56 +0100
commit8e1cb139d817880c557d407c363eb838c0893f5a (patch)
tree69da94b1df3f2fd1d19e623084c88543c0ce85f6 /src/zencore
parentbasic ZEN_ASSERT_FORMAT implementation (#556) (diff)
downloadzen-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.cpp119
-rw-r--r--src/zencore/include/zencore/filesystem.h3
-rw-r--r--src/zencore/include/zencore/process.h4
-rw-r--r--src/zencore/process.cpp61
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)