aboutsummaryrefslogtreecommitdiff
path: root/src/zencore/include
diff options
context:
space:
mode:
authorStefan Boberg <[email protected]>2026-01-19 13:14:42 +0100
committerGitHub Enterprise <[email protected]>2026-01-19 13:14:42 +0100
commit5081a33dcd19c5d6f9d9cdae9f8745ba786374d4 (patch)
tree6733e6f69137afc690a8c6dcdf618e69ce8029c5 /src/zencore/include
parentMerge pull request #701 from ue-foundation/lm/mac-daemon-mode (diff)
downloadzen-5081a33dcd19c5d6f9d9cdae9f8745ba786374d4.tar.xz
zen-5081a33dcd19c5d6f9d9cdae9f8745ba786374d4.zip
consul package and basic client added (#716)
* this adds a consul package which can be used to fetch a consul binary * it also adds a `ConsulProcess` helper which can be used to spawn and manage a consul service instance * zencore dependencies brought across: - `except_fmt.h` for easer generation of formatted exception messages - `process.h/cpp` changes (adds `Kill` operation and process group support on Windows) - `string.h` changes to allow generic use of `WideToUtf8()`
Diffstat (limited to 'src/zencore/include')
-rw-r--r--src/zencore/include/zencore/except_fmt.h36
-rw-r--r--src/zencore/include/zencore/filesystem.h2
-rw-r--r--src/zencore/include/zencore/process.h61
-rw-r--r--src/zencore/include/zencore/string.h16
4 files changed, 98 insertions, 17 deletions
diff --git a/src/zencore/include/zencore/except_fmt.h b/src/zencore/include/zencore/except_fmt.h
new file mode 100644
index 000000000..095a78da7
--- /dev/null
+++ b/src/zencore/include/zencore/except_fmt.h
@@ -0,0 +1,36 @@
+// Copyright Epic Games, Inc. All Rights Reserved.
+
+#pragma once
+
+#include <fmt/args.h>
+#include <fmt/format.h>
+#include "except.h"
+
+namespace zen {
+
+/**
+ * Exception helper class to make formatted exception messages slightly easier by
+ * avoiding the need to explicitly call fmt::format(), making for less visual noise.
+ *
+ * Usage:
+ *
+ * throw zen::runtime_error("Failed to open file '{}'", FileName);
+ *
+ */
+template<typename BaseT>
+class format_exception : public BaseT
+{
+public:
+ format_exception(std::string_view Message) : BaseT(std::string(Message)) {}
+
+ template<typename... T>
+ format_exception(fmt::format_string<T...> fmt, T&&... args) : BaseT(fmt::format(fmt, std::forward<T>(args)...))
+ {
+ }
+};
+
+using runtime_error = format_exception<std::runtime_error>;
+using invalid_argument = format_exception<std::invalid_argument>;
+using out_of_range = format_exception<std::out_of_range>;
+
+} // namespace zen
diff --git a/src/zencore/include/zencore/filesystem.h b/src/zencore/include/zencore/filesystem.h
index 938a05b59..53cb550c1 100644
--- a/src/zencore/include/zencore/filesystem.h
+++ b/src/zencore/include/zencore/filesystem.h
@@ -159,7 +159,7 @@ ZENCORE_API FileContents ReadStdIn();
IoBuffer referencing the file contents so that it may be read at a later time. This is
leveraged to allow sending of data straight from disk cache and other optimizations.
*/
-ZENCORE_API FileContents ReadFile(std::filesystem::path Path);
+ZENCORE_API FileContents ReadFile(const std::filesystem::path& Path);
ZENCORE_API bool ScanFile(std::filesystem::path Path, uint64_t ChunkSize, std::function<void(const void* Data, size_t Size)>&& ProcessFunc);
ZENCORE_API void WriteFile(std::filesystem::path Path, const IoBuffer* const* Data, size_t BufferCount);
diff --git a/src/zencore/include/zencore/process.h b/src/zencore/include/zencore/process.h
index 04b79a1e0..d8d2a2b6b 100644
--- a/src/zencore/include/zencore/process.h
+++ b/src/zencore/include/zencore/process.h
@@ -14,26 +14,27 @@ namespace zen {
class ProcessHandle
{
public:
- ZENCORE_API ProcessHandle();
+ ProcessHandle();
ProcessHandle(const ProcessHandle&) = delete;
ProcessHandle& operator=(const ProcessHandle&) = delete;
- ZENCORE_API ~ProcessHandle();
-
- ZENCORE_API void Initialize(int Pid);
- ZENCORE_API void Initialize(int Pid, std::error_code& OutEc);
- ZENCORE_API void Initialize(void* ProcessHandle); /// Initialize with an existing handle - takes ownership of the handle
- ZENCORE_API [[nodiscard]] bool IsRunning() const;
- ZENCORE_API [[nodiscard]] bool IsValid() const;
- ZENCORE_API bool Wait(int TimeoutMs = -1);
- ZENCORE_API bool Wait(int TimeoutMs, std::error_code& OutEc);
- ZENCORE_API int WaitExitCode();
- ZENCORE_API int GetExitCode();
- ZENCORE_API bool Terminate(int ExitCode);
- ZENCORE_API void Reset();
- [[nodiscard]] inline int Pid() const { return m_Pid; }
- [[nodiscard]] inline void* Handle() const { return m_ProcessHandle; }
+ ~ProcessHandle();
+
+ void Initialize(int Pid);
+ void Initialize(int Pid, std::error_code& OutEc);
+ void Initialize(void* ProcessHandle); /// Initialize with an existing handle - takes ownership of the handle
+ [[nodiscard]] bool IsRunning() const;
+ [[nodiscard]] bool IsValid() const;
+ bool Wait(int TimeoutMs = -1);
+ bool Wait(int TimeoutMs, std::error_code& OutEc);
+ int WaitExitCode();
+ int GetExitCode();
+ bool Kill();
+ bool Terminate(int ExitCode);
+ void Reset();
+ [[nodiscard]] inline int Pid() const { return m_Pid; }
+ [[nodiscard]] inline void* Handle() const { return m_ProcessHandle; }
private:
void* m_ProcessHandle = nullptr;
@@ -53,6 +54,10 @@ struct CreateProcOptions
Flag_Elevated = 1 << 1,
Flag_Unelevated = 1 << 2,
Flag_NoConsole = 1 << 3,
+ // This flag creates the new process in a new process group. This is relevant only on Windows, and
+ // allows sending ctrl-break events to the new process group without also sending it to the current
+ // process.
+ Flag_Windows_NewProcessGroup = 1 << 4,
};
const std::filesystem::path* WorkingDirectory = nullptr;
@@ -102,10 +107,34 @@ int GetProcessId(CreateProcResult ProcId);
std::filesystem::path GetProcessExecutablePath(int Pid, std::error_code& OutEc);
std::error_code FindProcess(const std::filesystem::path& ExecutableImage, ProcessHandle& OutHandle, bool IncludeSelf = true);
+/** Wait for all threads in the current process to exit (except the calling thread)
+ *
+ * This is only implemented on Windows currently. The use-case for this is to try
+ * and ensure that all threads have exited before exiting main() in order to
+ * avoid some issues which can occur if threads are still running during process
+ * shutdown especially when the CRT is statically linked into the executable.
+ *
+ * This is a best-effort function and may return before all threads have exited.
+ */
+void WaitForThreads(uint64_t WaitTimeMs);
+
#if ZEN_PLATFORM_LINUX
void IgnoreChildSignals();
#endif
+struct ProcessMetrics
+{
+ uint64_t MemoryBytes = 0;
+ uint64_t KernelTimeMs = 0;
+ uint64_t UserTimeMs = 0;
+ uint64_t WorkingSetSize = 0;
+ uint64_t PeakWorkingSetSize = 0;
+ uint64_t PagefileUsage = 0;
+ uint64_t PeakPagefileUsage = 0;
+};
+
+void GetProcessMetrics(ProcessHandle& Handle, ProcessMetrics& OutMetrics);
+
void process_forcelink(); // internal
} // namespace zen
diff --git a/src/zencore/include/zencore/string.h b/src/zencore/include/zencore/string.h
index 4379f2f80..5abdaf413 100644
--- a/src/zencore/include/zencore/string.h
+++ b/src/zencore/include/zencore/string.h
@@ -535,6 +535,22 @@ std::string WideToUtf8(const wchar_t* wstr);
void WideToUtf8(const std::wstring_view& wstr, StringBuilderBase& out);
std::string WideToUtf8(const std::wstring_view Wstr);
+// This is a no-op helper to make it easier to write code that works with both
+// narrow and wide strings
+inline std::string
+WideToUtf8(const char* str8)
+{
+ return str8;
+}
+
+inline std::string
+WideToUtf8(const std::string_view str8)
+{
+ return std::string(str8);
+}
+
+//////////////////////////////////////////////////////////////////////////
+
inline uint8_t
Char2Nibble(char c)
{