aboutsummaryrefslogtreecommitdiff
path: root/src/zencore/include
diff options
context:
space:
mode:
authorStefan Boberg <[email protected]>2023-05-15 18:07:45 +0200
committerStefan Boberg <[email protected]>2023-05-15 18:07:45 +0200
commit06aaf561fed3db1eed2a044180895957de87ed20 (patch)
treec80ef0d23b77ea251904c9f05a0626ef6fdc3a78 /src/zencore/include
parentimplemented string conversion for CbValidateError enum (diff)
parentRemove ATL header usage (#306) (diff)
downloadzen-06aaf561fed3db1eed2a044180895957de87ed20.tar.xz
zen-06aaf561fed3db1eed2a044180895957de87ed20.zip
Merge branch 'main' of https://github.com/EpicGames/zen
Diffstat (limited to 'src/zencore/include')
-rw-r--r--src/zencore/include/zencore/except.h1
-rw-r--r--src/zencore/include/zencore/windows.h417
-rw-r--r--src/zencore/include/zencore/workthreadpool.h46
3 files changed, 441 insertions, 23 deletions
diff --git a/src/zencore/include/zencore/except.h b/src/zencore/include/zencore/except.h
index d3269f33a..114f98d77 100644
--- a/src/zencore/include/zencore/except.h
+++ b/src/zencore/include/zencore/except.h
@@ -3,6 +3,7 @@
#pragma once
#include <zencore/string.h>
+#include <zencore/zencore.h>
#if ZEN_PLATFORM_WINDOWS
# include <zencore/windows.h>
#else
diff --git a/src/zencore/include/zencore/windows.h b/src/zencore/include/zencore/windows.h
index 91828f0ec..333188cb3 100644
--- a/src/zencore/include/zencore/windows.h
+++ b/src/zencore/include/zencore/windows.h
@@ -4,22 +4,411 @@
#include <zencore/zencore.h>
+#if ZEN_PLATFORM_WINDOWS
+
ZEN_THIRD_PARTY_INCLUDES_START
struct IUnknown; // Workaround for "combaseapi.h(229): error C2187: syntax error: 'identifier' was unexpected here" when using /permissive-
-#ifndef NOMINMAX
-# define NOMINMAX // We don't want your min/max macros
-#endif
-#ifndef NOGDI
-# define NOGDI // We don't want your GetObject define
-#endif
-#ifndef WIN32_LEAN_AND_MEAN
-# define WIN32_LEAN_AND_MEAN
-#endif
-#ifndef _WIN32_WINNT
-# define _WIN32_WINNT 0x0A00
-#endif
-#include <windows.h>
-#undef GetObject
+# ifndef NOMINMAX
+# define NOMINMAX // We don't want your min/max macros
+# endif
+# ifndef NOGDI
+# define NOGDI // We don't want your GetObject define
+# endif
+# ifndef WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+# endif
+# ifndef _WIN32_WINNT
+# define _WIN32_WINNT 0x0A00
+# endif
+# include <windows.h>
+# undef GetObject
ZEN_THIRD_PARTY_INCLUDES_END
+
+//////////////////////////////////////////////////////////////////////////
+
+namespace zen::windows {
+
+class Handle
+{
+public:
+ Handle() noexcept = default;
+ inline Handle(Handle& h) noexcept { Attach(h.Detach()); }
+ explicit Handle(HANDLE h) noexcept : m_Handle(h) {}
+ inline ~Handle() noexcept
+ {
+ if (m_Handle)
+ {
+ Close();
+ }
+ }
+
+ Handle& operator=(Handle& InHandle) noexcept
+ {
+ if (this != &InHandle)
+ {
+ if (m_Handle != NULL)
+ {
+ Close();
+ }
+ Attach(InHandle.Detach());
+ }
+
+ return *this;
+ }
+
+ inline operator HANDLE() const noexcept { return m_Handle; }
+ inline void Attach(HANDLE h) noexcept
+ {
+ ZEN_ASSERT(m_Handle == NULL);
+ m_Handle = h;
+ }
+ inline HANDLE Detach() noexcept
+ {
+ HANDLE h;
+
+ h = m_Handle;
+ m_Handle = NULL;
+
+ return h;
+ }
+ void Close() noexcept
+ {
+ if (m_Handle != NULL)
+ {
+ ::CloseHandle(m_Handle);
+ m_Handle = NULL;
+ }
+ }
+
+public:
+ HANDLE m_Handle{0};
+};
+
+/////////////////////////////////////////////////////////////////////////////
+// Error to HRESULT helpers
+
+inline HRESULT
+MapHresultFromLastError() noexcept
+{
+ DWORD ErrorCode = ::GetLastError();
+ return HRESULT_FROM_WIN32(ErrorCode);
+}
+
+inline HRESULT
+MapHresultFromWin32(DWORD ErrorCode) noexcept
+{
+ return HRESULT_FROM_WIN32(ErrorCode);
+}
+
+//////////////////////////////////////////////////////////////////////////
+
+class FileHandle : public Handle
+{
+public:
+ FileHandle() noexcept = default;
+ FileHandle(FileHandle& InFile) noexcept : Handle(InFile) {}
+ explicit FileHandle(HANDLE InFileHandle) noexcept : Handle(InFileHandle) {}
+
+ HRESULT Create(LPCTSTR szFilename,
+ DWORD dwDesiredAccess,
+ DWORD dwShareMode,
+ DWORD dwCreationDisposition,
+ DWORD dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL)
+ {
+ ZEN_ASSERT(m_Handle == NULL);
+
+ HANDLE hFile = ::CreateFile(szFilename, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, dwFlagsAndAttributes, NULL);
+
+ if (hFile == INVALID_HANDLE_VALUE)
+ return MapHresultFromLastError();
+
+ Attach(hFile);
+
+ return S_OK;
+ }
+
+ HRESULT Read(LPVOID pBuffer, DWORD nBufSize)
+ {
+ ZEN_ASSERT(m_Handle != NULL);
+
+ DWORD nBytesRead = 0;
+ BOOL Success = ::ReadFile(m_Handle, pBuffer, nBufSize, &nBytesRead, NULL);
+
+ if (!Success)
+ return MapHresultFromLastError();
+
+ if (nBytesRead != nBufSize)
+ return HRESULT_FROM_WIN32(ERROR_HANDLE_EOF);
+
+ return S_OK;
+ }
+
+ HRESULT Read(LPVOID pBuffer, DWORD nBufSize, LPOVERLAPPED pOverlapped)
+ {
+ ZEN_ASSERT(m_Handle != NULL);
+
+ BOOL Success = ::ReadFile(m_Handle, pBuffer, nBufSize, NULL, pOverlapped);
+ if (!Success)
+ return MapHresultFromLastError();
+
+ return S_OK;
+ }
+
+ HRESULT Write(LPCVOID pBuffer, DWORD nBufSize, DWORD* pnBytesWritten = NULL)
+ {
+ ZEN_ASSERT(m_Handle != NULL);
+
+ DWORD nBytesWritten;
+ if (pnBytesWritten == NULL)
+ pnBytesWritten = &nBytesWritten;
+
+ BOOL Success = ::WriteFile(m_Handle, pBuffer, nBufSize, pnBytesWritten, NULL);
+ if (!Success)
+ return MapHresultFromLastError();
+
+ return S_OK;
+ }
+
+ HRESULT Write(LPCVOID pBuffer, DWORD nBufSize, LPOVERLAPPED pOverlapped)
+ {
+ ZEN_ASSERT(m_Handle != NULL);
+
+ BOOL Success = ::WriteFile(m_Handle, pBuffer, nBufSize, NULL, pOverlapped);
+ if (!Success)
+ return MapHresultFromLastError();
+
+ return S_OK;
+ }
+
+ HRESULT Seek(LONGLONG nOffset, DWORD dwFrom = FILE_CURRENT)
+ {
+ ZEN_ASSERT(m_Handle != NULL);
+ ZEN_ASSERT(dwFrom == FILE_BEGIN || dwFrom == FILE_END || dwFrom == FILE_CURRENT);
+
+ LARGE_INTEGER liOffset;
+ liOffset.QuadPart = nOffset;
+ DWORD nNewPos = ::SetFilePointer(m_Handle, liOffset.LowPart, &liOffset.HighPart, dwFrom);
+
+ if (nNewPos == INVALID_SET_FILE_POINTER)
+ {
+ HRESULT hr = MapHresultFromLastError();
+
+ if (FAILED(hr))
+ return hr;
+ }
+
+ return S_OK;
+ }
+
+ HRESULT GetPosition(ULONGLONG& OutPos) const
+ {
+ ZEN_ASSERT(m_Handle != NULL);
+
+ LARGE_INTEGER liOffset;
+ liOffset.QuadPart = 0;
+ liOffset.LowPart = ::SetFilePointer(m_Handle, 0, &liOffset.HighPart, FILE_CURRENT);
+ if (liOffset.LowPart == INVALID_SET_FILE_POINTER)
+ {
+ HRESULT hr = MapHresultFromLastError();
+
+ if (FAILED(hr))
+ return hr;
+ }
+ OutPos = liOffset.QuadPart;
+
+ return S_OK;
+ }
+
+ HRESULT GetSize(ULONGLONG& OutLen) const
+ {
+ ZEN_ASSERT(m_Handle != NULL);
+
+ ULARGE_INTEGER liFileSize;
+ liFileSize.LowPart = ::GetFileSize(m_Handle, &liFileSize.HighPart);
+
+ if (liFileSize.LowPart == INVALID_FILE_SIZE)
+ {
+ HRESULT hr = MapHresultFromLastError();
+ if (FAILED(hr))
+ return hr;
+ }
+
+ OutLen = liFileSize.QuadPart;
+
+ return S_OK;
+ }
+};
+
+//////////////////////////////////////////////////////////////////////////
+
+class FileMapping
+{
+public:
+ FileMapping() throw()
+ {
+ m_pData = NULL;
+ m_hMapping = NULL;
+ }
+
+ ~FileMapping() throw() { Unmap(); }
+
+ HRESULT MapFile(_In_ HANDLE hFile,
+ _In_ SIZE_T nMappingSize = 0,
+ _In_ ULONGLONG nOffset = 0,
+ _In_ DWORD dwMappingProtection = PAGE_READONLY,
+ _In_ DWORD dwViewDesiredAccess = FILE_MAP_READ) throw()
+ {
+ ZEN_ASSERT(m_pData == NULL);
+ ZEN_ASSERT(m_hMapping == NULL);
+ ZEN_ASSERT(hFile != INVALID_HANDLE_VALUE && hFile != NULL);
+
+ ULARGE_INTEGER liFileSize;
+ liFileSize.LowPart = ::GetFileSize(hFile, &liFileSize.HighPart);
+ if (liFileSize.QuadPart < nMappingSize)
+ liFileSize.QuadPart = nMappingSize;
+
+ m_hMapping = ::CreateFileMapping(hFile, NULL, dwMappingProtection, liFileSize.HighPart, liFileSize.LowPart, 0);
+ if (m_hMapping == NULL)
+ return MapHresultFromLastError();
+
+ if (nMappingSize == 0)
+ m_nMappingSize = (SIZE_T)(liFileSize.QuadPart - nOffset);
+ else
+ m_nMappingSize = nMappingSize;
+
+ m_dwViewDesiredAccess = dwViewDesiredAccess;
+ m_nOffset.QuadPart = nOffset;
+
+ m_pData = ::MapViewOfFileEx(m_hMapping, m_dwViewDesiredAccess, m_nOffset.HighPart, m_nOffset.LowPart, m_nMappingSize, NULL);
+ if (m_pData == NULL)
+ {
+ HRESULT hr;
+
+ hr = MapHresultFromLastError();
+ ::CloseHandle(m_hMapping);
+ m_hMapping = NULL;
+ return hr;
+ }
+
+ return S_OK;
+ }
+
+ HRESULT MapSharedMem(_In_ SIZE_T nMappingSize,
+ _In_z_ LPCTSTR szName,
+ _Out_opt_ BOOL* pbAlreadyExisted = NULL,
+ _In_opt_ LPSECURITY_ATTRIBUTES lpsa = NULL,
+ _In_ DWORD dwMappingProtection = PAGE_READWRITE,
+ _In_ DWORD dwViewDesiredAccess = FILE_MAP_ALL_ACCESS) throw()
+ {
+ ZEN_ASSERT(m_pData == NULL);
+ ZEN_ASSERT(m_hMapping == NULL);
+ ZEN_ASSERT(nMappingSize > 0);
+ ZEN_ASSERT(szName != NULL); // if you just want a regular chunk of memory, use a heap allocator
+
+ m_nMappingSize = nMappingSize;
+
+ ULARGE_INTEGER nSize;
+ nSize.QuadPart = nMappingSize;
+ m_hMapping = ::CreateFileMapping(INVALID_HANDLE_VALUE, lpsa, dwMappingProtection, nSize.HighPart, nSize.LowPart, szName);
+ if (m_hMapping == NULL)
+ {
+ HRESULT hr = MapHresultFromLastError();
+ _Analysis_assume_(FAILED(hr));
+ return hr;
+ }
+
+ if (pbAlreadyExisted != NULL)
+ *pbAlreadyExisted = (GetLastError() == ERROR_ALREADY_EXISTS);
+
+ m_dwViewDesiredAccess = dwViewDesiredAccess;
+ m_nOffset.QuadPart = 0;
+
+ m_pData = ::MapViewOfFileEx(m_hMapping, m_dwViewDesiredAccess, m_nOffset.HighPart, m_nOffset.LowPart, m_nMappingSize, NULL);
+ if (m_pData == NULL)
+ {
+ HRESULT hr;
+
+ hr = MapHresultFromLastError();
+ ::CloseHandle(m_hMapping);
+ m_hMapping = NULL;
+ return hr;
+ }
+
+ return S_OK;
+ }
+
+ HRESULT OpenMapping(_In_z_ LPCTSTR szName,
+ _In_ SIZE_T nMappingSize,
+ _In_ ULONGLONG nOffset = 0,
+ _In_ DWORD dwViewDesiredAccess = FILE_MAP_ALL_ACCESS) throw()
+ {
+ ZEN_ASSERT(m_pData == NULL);
+ ZEN_ASSERT(m_hMapping == NULL);
+ ZEN_ASSERT(szName != NULL); // if you just want a regular chunk of memory, use a heap allocator
+
+ m_nMappingSize = nMappingSize;
+ m_dwViewDesiredAccess = dwViewDesiredAccess;
+
+ m_hMapping = ::OpenFileMapping(m_dwViewDesiredAccess, FALSE, szName);
+ if (m_hMapping == NULL)
+ return MapHresultFromLastError();
+
+ m_dwViewDesiredAccess = dwViewDesiredAccess;
+ m_nOffset.QuadPart = nOffset;
+
+ m_pData = ::MapViewOfFileEx(m_hMapping, m_dwViewDesiredAccess, m_nOffset.HighPart, m_nOffset.LowPart, m_nMappingSize, NULL);
+ if (m_pData == NULL)
+ {
+ HRESULT hr;
+
+ hr = MapHresultFromLastError();
+ ::CloseHandle(m_hMapping);
+ m_hMapping = NULL;
+ return hr;
+ }
+
+ return S_OK;
+ }
+
+ HRESULT Unmap() throw()
+ {
+ HRESULT hr = S_OK;
+
+ if (m_pData != NULL)
+ {
+ if (!::UnmapViewOfFile(m_pData))
+ hr = MapHresultFromLastError();
+ m_pData = NULL;
+ }
+ if (m_hMapping != NULL)
+ {
+ if (!::CloseHandle(m_hMapping) && SUCCEEDED(hr))
+ hr = MapHresultFromLastError();
+ m_hMapping = NULL;
+ }
+ return hr;
+ }
+
+ void* GetData() const throw() { return m_pData; }
+
+ HANDLE GetHandle() const throw() { return m_hMapping; }
+
+ SIZE_T GetMappingSize() throw() { return m_nMappingSize; }
+
+ HRESULT CopyFrom(_In_ FileMapping& orig) throw();
+
+ FileMapping(_In_ FileMapping& orig);
+ FileMapping& operator=(_In_ FileMapping& orig);
+
+private:
+ void* m_pData;
+ SIZE_T m_nMappingSize;
+ HANDLE m_hMapping;
+ ULARGE_INTEGER m_nOffset;
+ DWORD m_dwViewDesiredAccess;
+};
+
+} // namespace zen::windows
+#endif
diff --git a/src/zencore/include/zencore/workthreadpool.h b/src/zencore/include/zencore/workthreadpool.h
index 0ddc65298..c10c6ed12 100644
--- a/src/zencore/include/zencore/workthreadpool.h
+++ b/src/zencore/include/zencore/workthreadpool.h
@@ -4,17 +4,16 @@
#include <zencore/zencore.h>
-#include <zencore/blockingqueue.h>
#include <zencore/refcount.h>
#include <exception>
#include <functional>
-#include <system_error>
-#include <thread>
-#include <vector>
+#include <future>
namespace zen {
+//////////////////////////////////////////////////////////////////////////
+
struct IWork : public RefCounted
{
virtual void Execute() = 0;
@@ -27,22 +26,51 @@ private:
friend class WorkerThreadPool;
};
+//////////////////////////////////////////////////////////////////////////
+
class WorkerThreadPool
{
public:
- WorkerThreadPool(int InThreadCount);
+ explicit WorkerThreadPool(int InThreadCount);
+ WorkerThreadPool(int InThreadCount, std::string_view WorkerThreadBaseName);
~WorkerThreadPool();
void ScheduleWork(Ref<IWork> Work);
void ScheduleWork(std::function<void()>&& Work);
- [[nodiscard]] size_t PendingWork() const;
+ template<typename Func>
+ auto EnqueueTask(std::packaged_task<Func> Task);
+
+ [[nodiscard]] size_t PendingWorkItemCount() const;
private:
- void WorkerThreadFunction();
+ struct Impl;
+ struct ThreadStartInfo;
- std::vector<std::thread> m_WorkerThreads;
- BlockingQueue<Ref<IWork>> m_WorkQueue;
+ std::unique_ptr<Impl> m_Impl;
};
+//////////////////////////////////////////////////////////////////////////
+
+template<typename Func>
+auto
+WorkerThreadPool::EnqueueTask(std::packaged_task<Func> Task)
+{
+ struct FutureWork : IWork
+ {
+ FutureWork(std::packaged_task<Func> Task) : m_Task{std::move(Task)} {}
+ virtual void Execute() override { m_Task(); }
+
+ std::packaged_task<Func> m_Task;
+ };
+
+ Ref<FutureWork> Work{new FutureWork(std::move(Task))};
+
+ auto Future = Work->m_Task.get_future();
+ ScheduleWork(std::move(Work));
+ return Future;
+}
+
+void workthreadpool_forcelink(); // internal
+
} // namespace zen