diff options
| author | Stefan Boberg <[email protected]> | 2023-05-15 18:07:45 +0200 |
|---|---|---|
| committer | Stefan Boberg <[email protected]> | 2023-05-15 18:07:45 +0200 |
| commit | 06aaf561fed3db1eed2a044180895957de87ed20 (patch) | |
| tree | c80ef0d23b77ea251904c9f05a0626ef6fdc3a78 /src/zencore/include | |
| parent | implemented string conversion for CbValidateError enum (diff) | |
| parent | Remove ATL header usage (#306) (diff) | |
| download | zen-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.h | 1 | ||||
| -rw-r--r-- | src/zencore/include/zencore/windows.h | 417 | ||||
| -rw-r--r-- | src/zencore/include/zencore/workthreadpool.h | 46 |
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 |