diff options
| author | Stefan Boberg <[email protected]> | 2026-01-19 13:14:42 +0100 |
|---|---|---|
| committer | GitHub Enterprise <[email protected]> | 2026-01-19 13:14:42 +0100 |
| commit | 5081a33dcd19c5d6f9d9cdae9f8745ba786374d4 (patch) | |
| tree | 6733e6f69137afc690a8c6dcdf618e69ce8029c5 /src/zencore/include | |
| parent | Merge pull request #701 from ue-foundation/lm/mac-daemon-mode (diff) | |
| download | zen-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.h | 36 | ||||
| -rw-r--r-- | src/zencore/include/zencore/filesystem.h | 2 | ||||
| -rw-r--r-- | src/zencore/include/zencore/process.h | 61 | ||||
| -rw-r--r-- | src/zencore/include/zencore/string.h | 16 |
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) { |