// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include #include #include #include #include #include class ZenServerEnvironment { public: ZenServerEnvironment(); ~ZenServerEnvironment(); void Initialize(std::filesystem::path ProgramBaseDir); void InitializeForTest(std::filesystem::path ProgramBaseDir, std::filesystem::path TestBaseDir); std::filesystem::path CreateNewTestDir(); std::filesystem::path ProgramBaseDir() const { return m_ProgramBaseDir; } std::filesystem::path GetTestRootDir(std::string_view Path); inline bool IsInitialized() const { return m_IsInitialized; } inline bool IsTestEnvironment() const { return m_IsTestInstance; } private: std::filesystem::path m_ProgramBaseDir; std::filesystem::path m_TestBaseDir; bool m_IsInitialized = false; bool m_IsTestInstance = false; }; struct ZenServerInstance { ZenServerInstance(ZenServerEnvironment& TestEnvironment); ~ZenServerInstance(); void Shutdown(); void SignalShutdown(); void WaitUntilReady(); [[nodiscard]] bool WaitUntilReady(int Timeout); void EnableTermination() { m_Terminate = true; } void EnableMesh() { m_MeshEnabled = true; } void SetTestDir(std::filesystem::path TestDir) { ZEN_ASSERT(!m_Process.IsValid()); m_TestDir = TestDir; } void SpawnServer(int BasePort = 0); void AttachToRunningServer(int BasePort = 0); private: ZenServerEnvironment& m_Env; zen::ProcessHandle m_Process; zen::Event m_ReadyEvent; zen::Event m_ShutdownEvent; bool m_Terminate = false; std::filesystem::path m_TestDir; bool m_MeshEnabled = false; void CreateShutdownEvent(int BasePort); }; /** Shared system state * * Used as a scratchpad to identify running instances etc * * The state lives in a memory-mapped file backed by the swapfile * */ class ZenServerState { public: ZenServerState(); ~ZenServerState(); struct ZenServerEntry { std::atomic Pid; std::atomic ListenPort; std::atomic Flags; uint8_t SessionId[12]; uint8_t Padding[12]; enum class FlagsEnum : uint16_t { kShutdownPlease = 1 << 0 }; FRIEND_ENUM_CLASS_FLAGS(FlagsEnum); void Reset(); void SignalShutdownRequest(); }; static_assert(sizeof(ZenServerEntry) == 32); void Initialize(); [[nodiscard]] bool InitializeReadOnly(); [[nodiscard]] ZenServerEntry* Lookup(int ListenPort); ZenServerEntry* Register(int ListenPort); void Sweep(); void Snapshot(std::function&& Callback); private: void* m_hMapFile = nullptr; ZenServerEntry* m_Data; int m_MaxEntryCount = 4096 / sizeof(ZenServerEntry); ZenServerEntry* m_OurEntry = nullptr; };