aboutsummaryrefslogtreecommitdiff
path: root/zencore
diff options
context:
space:
mode:
authorPer Larsson <[email protected]>2021-09-20 08:54:34 +0200
committerPer Larsson <[email protected]>2021-09-20 08:54:34 +0200
commite25b4b20d8a5696aa7055c9c167fa47b3739bc7e (patch)
tree049654b87096a22e1bf696a385db608a75f229fa /zencore
parentProbe upstream Zen server when initializing upstream cache. (diff)
parentFixed unused variable warnings exposed by xmake build (unclear why I do not r... (diff)
downloadzen-e25b4b20d8a5696aa7055c9c167fa47b3739bc7e.tar.xz
zen-e25b4b20d8a5696aa7055c9c167fa47b3739bc7e.zip
Merge branch 'main' of https://github.com/EpicGames/zen
Diffstat (limited to 'zencore')
-rw-r--r--zencore/except.cpp41
-rw-r--r--zencore/include/zencore/except.h53
-rw-r--r--zencore/include/zencore/session.h3
-rw-r--r--zencore/include/zencore/testutils.h31
-rw-r--r--zencore/include/zencore/thread.h8
-rw-r--r--zencore/include/zencore/uid.h1
-rw-r--r--zencore/include/zencore/zencore.h80
-rw-r--r--zencore/session.cpp15
-rw-r--r--zencore/testutils.cpp33
-rw-r--r--zencore/thread.cpp39
-rw-r--r--zencore/uid.cpp8
-rw-r--r--zencore/zencore.cpp25
-rw-r--r--zencore/zencore.vcxproj2
-rw-r--r--zencore/zencore.vcxproj.filters2
14 files changed, 239 insertions, 102 deletions
diff --git a/zencore/except.cpp b/zencore/except.cpp
index 9bf043f4a..44b8edffb 100644
--- a/zencore/except.cpp
+++ b/zencore/except.cpp
@@ -7,6 +7,41 @@ namespace zen {
#if ZEN_PLATFORM_WINDOWS
+class WindowsException : public std::exception
+{
+public:
+ WindowsException(std::string_view Message)
+ {
+ m_hResult = HRESULT_FROM_WIN32(GetLastError());
+ m_Message = Message;
+ }
+
+ WindowsException(HRESULT hRes, std::string_view Message)
+ {
+ m_hResult = hRes;
+ m_Message = Message;
+ }
+
+ WindowsException(HRESULT hRes, const char* Message, const char* Detail)
+ {
+ m_hResult = hRes;
+
+ ExtendableStringBuilder<128> msg;
+ msg.Append(Message);
+ msg.Append(" (detail: '");
+ msg.Append(Detail);
+ msg.Append("')");
+
+ m_Message = msg.c_str();
+ }
+
+ virtual const char* what() const override { return m_Message.c_str(); }
+
+private:
+ std::string m_Message;
+ HRESULT m_hResult;
+};
+
void
ThrowSystemException([[maybe_unused]] HRESULT hRes, [[maybe_unused]] std::string_view Message)
{
@@ -28,6 +63,12 @@ ThrowLastError(std::string_view Message)
throw std::system_error(std::error_code(zen::GetLastError(), std::system_category()), std::string(Message));
}
+void
+ThrowSystemError(uint32_t ErrorCode, std::string_view Message)
+{
+ throw std::system_error(std::error_code(ErrorCode, std::system_category()), std::string(Message));
+}
+
std::string
GetLastErrorAsString()
{
diff --git a/zencore/include/zencore/except.h b/zencore/include/zencore/except.h
index 08330e4bc..5cfefb1e2 100644
--- a/zencore/include/zencore/except.h
+++ b/zencore/include/zencore/except.h
@@ -15,63 +15,20 @@
namespace zen {
#if ZEN_PLATFORM_WINDOWS
-class WindowsException : public std::exception
-{
-public:
- WindowsException(std::string_view Message)
- {
- m_hResult = HRESULT_FROM_WIN32(GetLastError());
- m_Message = Message;
- }
-
- WindowsException(HRESULT hRes, std::string_view Message)
- {
- m_hResult = hRes;
- m_Message = Message;
- }
-
- WindowsException(HRESULT hRes, const char* Message, const char* Detail)
- {
- m_hResult = hRes;
-
- ExtendableStringBuilder<128> msg;
- msg.Append(Message);
- msg.Append(" (detail: '");
- msg.Append(Detail);
- msg.Append("')");
-
- m_Message = msg.c_str();
- }
-
- virtual const char* what() const override { return m_Message.c_str(); }
-
-private:
- std::string m_Message;
- HRESULT m_hResult;
-};
-
-ZENCORE_API void ThrowSystemException(HRESULT hRes, std::string_view Message);
+ZENCORE_API void ThrowSystemException [[noreturn]] (HRESULT hRes, std::string_view Message);
#endif // ZEN_PLATFORM_WINDOWS
-ZENCORE_API void ThrowLastError(std::string_view Message);
+ZENCORE_API void ThrowLastError [[noreturn]] (std::string_view Message);
#if __cpp_lib_source_location
-ZENCORE_API void ThrowLastError(std::string_view Message, const std::source_location& Location);
+ZENCORE_API void ThrowLastError [[noreturn]] (std::string_view Message, const std::source_location& Location);
#endif
+ZENCORE_API void ThrowSystemError [[noreturn]] (uint32_t ErrorCode, std::string_view Message);
+
ZENCORE_API std::string GetLastErrorAsString();
ZENCORE_API std::string GetWindowsErrorAsString(uint32_t Win32ErrorCode);
-inline void
-ThrowSystemException(const char* Message)
-{
-#if ZEN_PLATFORM_WINDOWS
- throw WindowsException(Message);
-#else
- ThrowLastError(Message);
-#endif
-}
-
inline int32_t
GetLastError()
{
diff --git a/zencore/include/zencore/session.h b/zencore/include/zencore/session.h
index 2da41b2c8..dd90197bf 100644
--- a/zencore/include/zencore/session.h
+++ b/zencore/include/zencore/session.h
@@ -8,6 +8,7 @@ namespace zen {
struct Oid;
-ZENCORE_API Oid GetSessionId();
+ZENCORE_API [[nodiscard]] Oid GetSessionId();
+ZENCORE_API [[nodiscard]] std::string_view GetSessionIdString();
} // namespace zen
diff --git a/zencore/include/zencore/testutils.h b/zencore/include/zencore/testutils.h
new file mode 100644
index 000000000..72d985d5c
--- /dev/null
+++ b/zencore/include/zencore/testutils.h
@@ -0,0 +1,31 @@
+// Copyright Epic Games, Inc. All Rights Reserved.
+
+#pragma once
+
+#include <filesystem>
+
+namespace zen {
+
+std::filesystem::path CreateTemporaryDirectory();
+
+class ScopedTemporaryDirectory
+{
+public:
+ ScopedTemporaryDirectory();
+ ~ScopedTemporaryDirectory();
+
+ std::filesystem::path& Path() { return m_RootPath; }
+
+private:
+ std::filesystem::path m_RootPath;
+};
+
+struct ScopedCurrentDirectoryChange
+{
+ std::filesystem::path OldPath{std::filesystem::current_path()};
+
+ ScopedCurrentDirectoryChange() { std::filesystem::current_path(CreateTemporaryDirectory()); }
+ ~ScopedCurrentDirectoryChange() { std::filesystem::current_path(OldPath); }
+};
+
+} // namespace zen
diff --git a/zencore/include/zencore/thread.h b/zencore/include/zencore/thread.h
index e65867ec4..7889682cd 100644
--- a/zencore/include/zencore/thread.h
+++ b/zencore/include/zencore/thread.h
@@ -4,9 +4,7 @@
#include "zencore.h"
-#if !ZEN_PLATFORM_WINDOWS
-# include <shared_mutex>
-#endif
+#include <shared_mutex>
#include <vector>
@@ -66,11 +64,7 @@ public:
};
private:
-#if ZEN_PLATFORM_WINDOWS
- void* m_Srw = nullptr;
-#else
std::shared_mutex m_Mutex;
-#endif
};
/** Basic abstraction of a simple event synchronization mechanism (aka 'binary semaphore')
diff --git a/zencore/include/zencore/uid.h b/zencore/include/zencore/uid.h
index f095c49ef..f4e9ab65a 100644
--- a/zencore/include/zencore/uid.h
+++ b/zencore/include/zencore/uid.h
@@ -60,6 +60,7 @@ struct Oid
const Oid& Generate();
[[nodiscard]] static Oid FromHexString(const std::string_view String);
StringBuilderBase& ToString(StringBuilderBase& OutString) const;
+ void ToString(char OutString[StringLength]);
[[nodiscard]] static Oid FromMemory(const void* Ptr);
auto operator<=>(const Oid& rhs) const = default;
diff --git a/zencore/include/zencore/zencore.h b/zencore/include/zencore/zencore.h
index da17e61e3..310f6c4ed 100644
--- a/zencore/include/zencore/zencore.h
+++ b/zencore/include/zencore/zencore.h
@@ -3,7 +3,7 @@
#pragma once
#include <cinttypes>
-#include <exception>
+#include <stdexcept>
#include <string>
//////////////////////////////////////////////////////////////////////////
@@ -90,37 +90,69 @@
// Assert
//
+#if ZEN_PLATFORM_WINDOWS
+// Tells the compiler to put the decorated function in a certain section (aka. segment) of the executable.
+# define ZEN_CODE_SECTION(Name) __declspec(code_seg(Name))
+# define ZEN_FORCENOINLINE __declspec(noinline) /* Force code to NOT be inline */
+#else
+# define ZEN_CODE_SECTION(Name)
+# define ZEN_FORCENOINLINE
+#endif
+
+#if ZEN_ARCH_ARM64
+// On ARM we can't do this because the executable will require jumps larger
+// than the branch instruction can handle. Clang will only generate
+// the trampolines in the .text segment of the binary. If the uedbg segment
+// is present it will generate code that it cannot link.
+# define ZEN_DEBUG_SECTION
+#else
+// We'll put all assert implementation code into a separate section in the linked
+// executable. This code should never execute so using a separate section keeps
+// it well off the hot path and hopefully out of the instruction cache. It also
+// facilitates reasoning about the makeup of a compiled/linked binary.
+# define ZEN_DEBUG_SECTION ZEN_CODE_SECTION(".zcold")
+#endif // DO_CHECK || DO_GUARD_SLOW
+
namespace zen {
-class AssertException : public std::exception
+class AssertException : public std::logic_error
{
public:
- AssertException(const char* Msg);
- ~AssertException();
-
- [[nodiscard]] virtual char const* what() const noexcept override { return m_Msg.c_str(); }
-
-private:
- std::string m_Msg;
+ AssertException(const char* Msg) : std::logic_error(Msg) {}
};
} // namespace zen
-#define ZEN_ASSERT(x, ...) \
- do \
- { \
- if (x) \
- break; \
- throw ::zen::AssertException{#x}; \
+template<typename RetType = void, class InnerType, typename... ArgTypes>
+RetType ZEN_FORCENOINLINE ZEN_DEBUG_SECTION
+DispatchAssert(InnerType&& Inner, ArgTypes const&... Args)
+{
+ return Inner(Args...);
+}
+
+#define ZEN_ASSERT(x, ...) \
+ do \
+ { \
+ if (x) [[unlikely]] \
+ break; \
+ struct Impl \
+ { \
+ static void ZEN_FORCENOINLINE ZEN_DEBUG_SECTION ExecThrow [[noreturn]] () { throw ::zen::AssertException{#x}; } \
+ }; \
+ Impl::ExecThrow(); \
} while (false)
#ifndef NDEBUG
-# define ZEN_ASSERT_SLOW(x, ...) \
- do \
- { \
- if (x) \
- break; \
- throw ::zen::AssertException{#x}; \
+# define ZEN_ASSERT_SLOW(x, ...) \
+ do \
+ { \
+ if (x) [[unlikely]] \
+ break; \
+ struct Impl \
+ { \
+ static void ZEN_FORCENOINLINE ZEN_DEBUG_SECTION ExecThrow [[noreturn]] () { throw ::zen::AssertException{#x}; } \
+ }; \
+ Impl::ExecThrow(); \
} while (false)
#else
# define ZEN_ASSERT_SLOW(x, ...)
@@ -148,17 +180,19 @@ char (&ZenArrayCountHelper(const T (&)[N]))[N + 1];
#define ZEN_UNUSED(...) ((void)__VA_ARGS__)
#define ZEN_NOT_IMPLEMENTED(...) ZEN_ASSERT(false, __VA_ARGS__)
-#define ZENCORE_API // Placeholder to allow DLL configs in the future
+#define ZENCORE_API // Placeholder to allow DLL configs in the future (maybe)
namespace zen {
ZENCORE_API bool IsPointerToStack(const void* ptr); // Query if pointer is within the stack of the currently executing thread
ZENCORE_API bool IsApplicationExitRequested();
ZENCORE_API void RequestApplicationExit(int ExitCode);
+ZENCORE_API bool IsDebuggerPresent();
+ZENCORE_API bool IsInteractiveSession();
ZENCORE_API void zencore_forcelinktests();
-}
+} // namespace zen
//////////////////////////////////////////////////////////////////////////
diff --git a/zencore/session.cpp b/zencore/session.cpp
index d57d3685b..ce4bfae1b 100644
--- a/zencore/session.cpp
+++ b/zencore/session.cpp
@@ -9,14 +9,27 @@
namespace zen {
static Oid GlobalSessionId;
+static char GlobalSessionString[Oid::StringLength];
static std::once_flag SessionInitFlag;
Oid
GetSessionId()
{
- std::call_once(SessionInitFlag, [&] { GlobalSessionId.Generate(); });
+ std::call_once(SessionInitFlag, [&] {
+ GlobalSessionId.Generate();
+ GlobalSessionId.ToString(GlobalSessionString);
+ });
return GlobalSessionId;
}
+std::string_view
+GetSessionIdString()
+{
+ // Ensure we actually have a generated session identifier
+ std::ignore = GetSessionId();
+
+ return std::string_view(GlobalSessionString, Oid::StringLength);
+}
+
} // namespace zen \ No newline at end of file
diff --git a/zencore/testutils.cpp b/zencore/testutils.cpp
new file mode 100644
index 000000000..116491950
--- /dev/null
+++ b/zencore/testutils.cpp
@@ -0,0 +1,33 @@
+// Copyright Epic Games, Inc. All Rights Reserved.
+
+#include "zencore/testutils.h"
+#include <zencore/session.h>
+#include "zencore/string.h"
+
+namespace zen {
+
+static std::atomic<int> Sequence{0};
+
+std::filesystem::path
+CreateTemporaryDirectory()
+{
+ std::error_code Ec;
+
+ std::filesystem::path DirPath = std::filesystem::temp_directory_path() / GetSessionIdString() / IntNum(++Sequence).c_str();
+ std::filesystem::remove_all(DirPath, Ec);
+ std::filesystem::create_directories(DirPath);
+
+ return DirPath;
+}
+
+ScopedTemporaryDirectory::ScopedTemporaryDirectory() : m_RootPath(CreateTemporaryDirectory())
+{
+}
+
+ScopedTemporaryDirectory::~ScopedTemporaryDirectory()
+{
+ std::error_code Ec;
+ std::filesystem::remove_all(m_RootPath, Ec);
+}
+
+} // namespace zen \ No newline at end of file
diff --git a/zencore/thread.cpp b/zencore/thread.cpp
index 1c7e4b3ab..d4f101454 100644
--- a/zencore/thread.cpp
+++ b/zencore/thread.cpp
@@ -17,41 +17,25 @@ namespace zen {
void
RwLock::AcquireShared()
{
-#if ZEN_PLATFORM_WINDOWS
- AcquireSRWLockShared((PSRWLOCK)&m_Srw);
-#else
m_Mutex.lock_shared();
-#endif
}
void
RwLock::ReleaseShared()
{
-#if ZEN_PLATFORM_WINDOWS
- ReleaseSRWLockShared((PSRWLOCK)&m_Srw);
-#else
m_Mutex.unlock_shared();
-#endif
}
void
RwLock::AcquireExclusive()
{
-#if ZEN_PLATFORM_WINDOWS
- AcquireSRWLockExclusive((PSRWLOCK)&m_Srw);
-#else
m_Mutex.lock();
-#endif
}
void
RwLock::ReleaseExclusive()
{
-#if ZEN_PLATFORM_WINDOWS
- ReleaseSRWLockExclusive((PSRWLOCK)&m_Srw);
-#else
m_Mutex.unlock();
-#endif
}
Event::Event()
@@ -257,7 +241,8 @@ ProcessHandle::Wait(int TimeoutMs)
case WAIT_FAILED:
// What might go wrong here, and what is meaningful to act on?
- throw WindowsException("Process::Wait failed");
+ using namespace std::literals;
+ ThrowLastError("Process::Wait failed"sv);
}
return false;
@@ -333,16 +318,32 @@ ProcessMonitor::IsActive() const
bool
IsProcessRunning(int pid)
{
+ // This function is arguably not super useful, a pid can be re-used
+ // by the OS so holding on to a pid and polling it over some time
+ // period will not necessarily tell you what you probably want to know.
+
+#if ZEN_PLATFORM_WINDOWS
HANDLE hProc = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid);
- if (hProc == NULL)
+ if (!hProc)
{
- return false;
+ DWORD Error = zen::GetLastError();
+
+ if (Error == ERROR_INVALID_PARAMETER)
+ {
+ return false;
+ }
+
+ using namespace fmt::literals;
+ ThrowSystemError(Error, "failed to open process with pid {}"_format(pid));
}
CloseHandle(hProc);
return true;
+#else
+ ZEN_NOT_IMPLEMENTED();
+#endif
}
int
diff --git a/zencore/uid.cpp b/zencore/uid.cpp
index d946638ec..ed00b1814 100644
--- a/zencore/uid.cpp
+++ b/zencore/uid.cpp
@@ -91,10 +91,16 @@ Oid::FromMemory(const void* Ptr)
return Id;
}
+void
+Oid::ToString(char OutString[StringLength])
+{
+ ToHexBytes(reinterpret_cast<const uint8_t*>(OidBits), sizeof(Oid::OidBits), OutString);
+}
+
StringBuilderBase&
Oid::ToString(StringBuilderBase& OutString) const
{
- char str[25];
+ char str[StringLength + 1];
ToHexBytes(reinterpret_cast<const uint8_t*>(OidBits), sizeof(Oid::OidBits), str);
str[2 * sizeof(Oid)] = '\0';
diff --git a/zencore/zencore.cpp b/zencore/zencore.cpp
index 5899f014d..122719d90 100644
--- a/zencore/zencore.cpp
+++ b/zencore/zencore.cpp
@@ -30,6 +30,8 @@
namespace zen {
+//////////////////////////////////////////////////////////////////////////
+
bool
IsPointerToStack(const void* ptr)
{
@@ -55,12 +57,31 @@ IsPointerToStack(const void* ptr)
#endif
}
-AssertException::AssertException(const char* Msg) : m_Msg(Msg)
+bool
+IsDebuggerPresent()
{
+#if ZEN_PLATFORM_WINDOWS
+ return ::IsDebuggerPresent();
+#else
+ return false;
+#endif
}
-AssertException::~AssertException()
+bool
+IsInteractiveSession()
{
+#if ZEN_PLATFORM_WINDOWS
+ DWORD dwSessionId = 0;
+ if (ProcessIdToSessionId(GetCurrentProcessId(), &dwSessionId))
+ {
+ return (dwSessionId != 0);
+ }
+
+ return false;
+#else
+ // TODO: figure out what makes sense here
+ return true;
+#endif
}
//////////////////////////////////////////////////////////////////////////
diff --git a/zencore/zencore.vcxproj b/zencore/zencore.vcxproj
index 150c42cd6..59b0bafcc 100644
--- a/zencore/zencore.vcxproj
+++ b/zencore/zencore.vcxproj
@@ -142,6 +142,7 @@
<ClInclude Include="include\zencore\streamutil.h" />
<ClInclude Include="include\zencore\string.h" />
<ClInclude Include="include\zencore\targetver.h" />
+ <ClInclude Include="include\zencore\testutils.h" />
<ClInclude Include="include\zencore\thread.h" />
<ClInclude Include="include\zencore\timer.h" />
<ClInclude Include="include\zencore\uid.h" />
@@ -181,6 +182,7 @@
<ClCompile Include="stream.cpp" />
<ClCompile Include="streamutil.cpp" />
<ClCompile Include="string.cpp" />
+ <ClCompile Include="testutils.cpp" />
<ClCompile Include="thread.cpp" />
<ClCompile Include="timer.cpp" />
<ClCompile Include="uid.cpp" />
diff --git a/zencore/zencore.vcxproj.filters b/zencore/zencore.vcxproj.filters
index ea0f8a912..6c6b308f8 100644
--- a/zencore/zencore.vcxproj.filters
+++ b/zencore/zencore.vcxproj.filters
@@ -42,6 +42,7 @@
<ClInclude Include="include\zencore\postwindows.h" />
<ClInclude Include="include\zencore\logging.h" />
<ClInclude Include="include\zencore\session.h" />
+ <ClInclude Include="include\zencore\testutils.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="snapshot_manifest.cpp" />
@@ -74,6 +75,7 @@
<ClCompile Include="logging.cpp" />
<ClCompile Include="intmath.cpp" />
<ClCompile Include="session.cpp" />
+ <ClCompile Include="testutils.cpp" />
</ItemGroup>
<ItemGroup>
<Filter Include="CAS">