diff options
| author | Stefan Boberg <[email protected]> | 2023-05-02 10:01:47 +0200 |
|---|---|---|
| committer | GitHub <[email protected]> | 2023-05-02 10:01:47 +0200 |
| commit | 075d17f8ada47e990fe94606c3d21df409223465 (patch) | |
| tree | e50549b766a2f3c354798a54ff73404217b4c9af /zencore/iobuffer.cpp | |
| parent | fix: bundle shouldn't append content zip to zen (diff) | |
| download | zen-075d17f8ada47e990fe94606c3d21df409223465.tar.xz zen-075d17f8ada47e990fe94606c3d21df409223465.zip | |
moved source directories into `/src` (#264)
* moved source directories into `/src`
* updated bundle.lua for new `src` path
* moved some docs, icon
* removed old test trees
Diffstat (limited to 'zencore/iobuffer.cpp')
| -rw-r--r-- | zencore/iobuffer.cpp | 653 |
1 files changed, 0 insertions, 653 deletions
diff --git a/zencore/iobuffer.cpp b/zencore/iobuffer.cpp deleted file mode 100644 index 1d7d47695..000000000 --- a/zencore/iobuffer.cpp +++ /dev/null @@ -1,653 +0,0 @@ -// Copyright Epic Games, Inc. All Rights Reserved. - -#include <zencore/iobuffer.h> - -#include <zencore/except.h> -#include <zencore/filesystem.h> -#include <zencore/fmtutils.h> -#include <zencore/iohash.h> -#include <zencore/logging.h> -#include <zencore/memory.h> -#include <zencore/testing.h> -#include <zencore/thread.h> - -#include <memory.h> -#include <system_error> - -#if ZEN_USE_MIMALLOC -ZEN_THIRD_PARTY_INCLUDES_START -# include <mimalloc.h> -ZEN_THIRD_PARTY_INCLUDES_END -#endif - -#if ZEN_PLATFORM_WINDOWS -# include <atlfile.h> -#else -# include <sys/stat.h> -# include <sys/mman.h> -#endif - -#include <gsl/gsl-lite.hpp> - -namespace zen { - -////////////////////////////////////////////////////////////////////////// - -void -IoBufferCore::AllocateBuffer(size_t InSize, size_t Alignment) const -{ -#if ZEN_PLATFORM_WINDOWS - if (((InSize & 0xffFF) == 0) && (Alignment == 0x10000)) - { - m_Flags.fetch_or(kLowLevelAlloc, std::memory_order_relaxed); - m_DataPtr = VirtualAlloc(nullptr, InSize, MEM_COMMIT, PAGE_READWRITE); - - return; - } -#endif // ZEN_PLATFORM_WINDOWS - -#if ZEN_USE_MIMALLOC - void* Ptr = mi_aligned_alloc(Alignment, RoundUp(InSize, Alignment)); - m_Flags.fetch_or(kIoBufferAlloc, std::memory_order_relaxed); -#else - void* Ptr = Memory::Alloc(InSize, Alignment); -#endif - - ZEN_ASSERT(Ptr); - - m_DataPtr = Ptr; -} - -void -IoBufferCore::FreeBuffer() -{ - if (!m_DataPtr) - { - return; - } - - const uint32_t LocalFlags = m_Flags.load(std::memory_order_relaxed); -#if ZEN_PLATFORM_WINDOWS - if (LocalFlags & kLowLevelAlloc) - { - VirtualFree(const_cast<void*>(m_DataPtr), 0, MEM_DECOMMIT); - - return; - } -#endif // ZEN_PLATFORM_WINDOWS - -#if ZEN_USE_MIMALLOC - if (LocalFlags & kIoBufferAlloc) - { - return mi_free(const_cast<void*>(m_DataPtr)); - } -#endif - - ZEN_UNUSED(LocalFlags); - return Memory::Free(const_cast<void*>(m_DataPtr)); -} - -////////////////////////////////////////////////////////////////////////// - -static_assert(sizeof(IoBufferCore) == 32); - -IoBufferCore::IoBufferCore(size_t InSize) -{ - ZEN_ASSERT(InSize); - - AllocateBuffer(InSize, sizeof(void*)); - m_DataBytes = InSize; - - SetIsOwnedByThis(true); -} - -IoBufferCore::IoBufferCore(size_t InSize, size_t Alignment) -{ - ZEN_ASSERT(InSize); - - AllocateBuffer(InSize, Alignment); - m_DataBytes = InSize; - - SetIsOwnedByThis(true); -} - -IoBufferCore::~IoBufferCore() -{ - if (IsOwnedByThis() && m_DataPtr) - { - FreeBuffer(); - m_DataPtr = nullptr; - } -} - -void -IoBufferCore::DeleteThis() const -{ - // We do this just to avoid paying for the cost of a vtable - if (const IoBufferExtendedCore* _ = ExtendedCore()) - { - delete _; - } - else - { - delete this; - } -} - -void -IoBufferCore::Materialize() const -{ - if (const IoBufferExtendedCore* _ = ExtendedCore()) - { - _->Materialize(); - } -} - -void -IoBufferCore::MakeOwned(bool Immutable) -{ - if (!IsOwned()) - { - const void* OldDataPtr = m_DataPtr; - AllocateBuffer(m_DataBytes, sizeof(void*)); - memcpy(const_cast<void*>(m_DataPtr), OldDataPtr, m_DataBytes); - SetIsOwnedByThis(true); - } - - SetIsImmutable(Immutable); -} - -void* -IoBufferCore::MutableDataPointer() const -{ - EnsureDataValid(); - ZEN_ASSERT(!IsImmutable()); - return const_cast<void*>(m_DataPtr); -} - -////////////////////////////////////////////////////////////////////////// - -IoBufferExtendedCore::IoBufferExtendedCore(void* FileHandle, uint64_t Offset, uint64_t Size, bool TransferHandleOwnership) -: IoBufferCore(nullptr, Size) -, m_FileHandle(FileHandle) -, m_FileOffset(Offset) -{ - uint32_t NewFlags = kIsOwnedByThis | kIsExtended; - - if (TransferHandleOwnership) - { - NewFlags |= kOwnsFile; - } - m_Flags.fetch_or(NewFlags, std::memory_order_relaxed); -} - -IoBufferExtendedCore::IoBufferExtendedCore(const IoBufferExtendedCore* Outer, uint64_t Offset, uint64_t Size) -: IoBufferCore(Outer, nullptr, Size) -, m_FileHandle(Outer->m_FileHandle) -, m_FileOffset(Outer->m_FileOffset + Offset) -{ - m_Flags.fetch_or(kIsExtended, std::memory_order_relaxed); -} - -IoBufferExtendedCore::~IoBufferExtendedCore() -{ - if (m_MappedPointer) - { -#if ZEN_PLATFORM_WINDOWS - UnmapViewOfFile(m_MappedPointer); -#else - uint64_t MapSize = ~uint64_t(uintptr_t(m_MmapHandle)); - munmap(m_MappedPointer, MapSize); -#endif - } - - const uint32_t LocalFlags = m_Flags.load(std::memory_order_relaxed); -#if ZEN_PLATFORM_WINDOWS - if (LocalFlags & kOwnsMmap) - { - CloseHandle(m_MmapHandle); - } -#endif - - if (LocalFlags & kOwnsFile) - { - if (m_DeleteOnClose) - { -#if ZEN_PLATFORM_WINDOWS - // Mark file for deletion when final handle is closed - FILE_DISPOSITION_INFO Fdi{.DeleteFile = TRUE}; - - SetFileInformationByHandle(m_FileHandle, FileDispositionInfo, &Fdi, sizeof Fdi); -#else - std::filesystem::path FilePath = zen::PathFromHandle(m_FileHandle); - unlink(FilePath.c_str()); -#endif - } -#if ZEN_PLATFORM_WINDOWS - BOOL Success = CloseHandle(m_FileHandle); -#else - int Fd = int(uintptr_t(m_FileHandle)); - bool Success = (close(Fd) == 0); -#endif - if (!Success) - { - ZEN_WARN("Error reported on file handle close, reason '{}'", GetLastErrorAsString()); - } - } - - m_DataPtr = nullptr; -} - -static constexpr size_t MappingLockCount = 128; -static_assert(IsPow2(MappingLockCount), "MappingLockCount must be power of two"); - -static RwLock g_MappingLocks[MappingLockCount]; - -static RwLock& -MappingLockForInstance(const IoBufferExtendedCore* instance) -{ - intptr_t base = (intptr_t)instance; - size_t lock_index = ((base >> 5) ^ (base >> 13)) & (MappingLockCount - 1u); - return g_MappingLocks[lock_index]; -} - -void -IoBufferExtendedCore::Materialize() const -{ - // The synchronization scheme here is very primitive, if we end up with - // a lot of contention we can make it more fine-grained - - if (m_Flags.load(std::memory_order_acquire) & kIsMaterialized) - return; - - RwLock::ExclusiveLockScope _(MappingLockForInstance(this)); - - // Someone could have gotten here first - // We can use memory_order_relaxed on this load because the mutex has already provided the fence - if (m_Flags.load(std::memory_order_relaxed) & kIsMaterialized) - return; - - uint32_t NewFlags = kIsMaterialized; - - if (m_DataBytes == 0) - { - // Fake a "valid" pointer, nobody should read this as size is zero - m_DataPtr = reinterpret_cast<uint8_t*>(&m_MmapHandle); - m_Flags.fetch_or(NewFlags, std::memory_order_release); - return; - } - - const size_t DisableMMapSizeLimit = 0x1000ull; - - if (m_DataBytes < DisableMMapSizeLimit) - { - AllocateBuffer(m_DataBytes, sizeof(void*)); - NewFlags |= kIsOwnedByThis; - -#if ZEN_PLATFORM_WINDOWS - OVERLAPPED Ovl{}; - - Ovl.Offset = DWORD(m_FileOffset & 0xffff'ffffu); - Ovl.OffsetHigh = DWORD(m_FileOffset >> 32); - - DWORD dwNumberOfBytesRead = 0; - BOOL Success = ::ReadFile(m_FileHandle, (void*)m_DataPtr, DWORD(m_DataBytes), &dwNumberOfBytesRead, &Ovl); - - ZEN_ASSERT(Success); - ZEN_ASSERT(dwNumberOfBytesRead == m_DataBytes); -#else - static_assert(sizeof(off_t) >= sizeof(uint64_t), "sizeof(off_t) does not support large files"); - int Fd = int(uintptr_t(m_FileHandle)); - int BytesRead = pread(Fd, (void*)m_DataPtr, m_DataBytes, m_FileOffset); - bool Success = (BytesRead > 0); -#endif // ZEN_PLATFORM_WINDOWS - - m_Flags.fetch_or(NewFlags, std::memory_order_release); - return; - } - - void* NewMmapHandle; - - const uint64_t MapOffset = m_FileOffset & ~0xffffull; - const uint64_t MappedOffsetDisplacement = m_FileOffset - MapOffset; - const uint64_t MapSize = m_DataBytes + MappedOffsetDisplacement; - - ZEN_ASSERT(MapSize > 0); - -#if ZEN_PLATFORM_WINDOWS - NewMmapHandle = CreateFileMapping(m_FileHandle, - /* lpFileMappingAttributes */ nullptr, - /* flProtect */ PAGE_READONLY, - /* dwMaximumSizeLow */ 0, - /* dwMaximumSizeHigh */ 0, - /* lpName */ nullptr); - - if (NewMmapHandle == nullptr) - { - int32_t Error = zen::GetLastError(); - ZEN_ERROR("CreateFileMapping failed on file '{}', {}", zen::PathFromHandle(m_FileHandle), GetSystemErrorAsString(Error)); - throw std::system_error(std::error_code(Error, std::system_category()), - fmt::format("CreateFileMapping failed on file '{}'", zen::PathFromHandle(m_FileHandle))); - } - - NewFlags |= kOwnsMmap; - - void* MappedBase = MapViewOfFile(NewMmapHandle, - /* dwDesiredAccess */ FILE_MAP_READ, - /* FileOffsetHigh */ uint32_t(MapOffset >> 32), - /* FileOffsetLow */ uint32_t(MapOffset & 0xffFFffFFu), - /* dwNumberOfBytesToMap */ MapSize); -#else - NewMmapHandle = (void*)uintptr_t(~MapSize); // ~ so it's never null (assuming MapSize >= 0) - NewFlags |= kOwnsMmap; - - void* MappedBase = mmap( - /* addr */ nullptr, - /* length */ MapSize, - /* prot */ PROT_READ, - /* flags */ MAP_SHARED | MAP_NORESERVE, - /* fd */ int(uintptr_t(m_FileHandle)), - /* offset */ MapOffset); -#endif // ZEN_PLATFORM_WINDOWS - - if (MappedBase == nullptr) - { - int32_t Error = zen::GetLastError(); -#if ZEN_PLATFORM_WINDOWS - CloseHandle(NewMmapHandle); -#endif // ZEN_PLATFORM_WINDOWS - ZEN_ERROR("MapViewOfFile failed (offset {:#x}, size {:#x}) file: '{}', {}", - MapOffset, - MapSize, - zen::PathFromHandle(m_FileHandle), - GetSystemErrorAsString(Error)); - throw std::system_error(std::error_code(Error, std::system_category()), - fmt::format("MapViewOfFile failed (offset {:#x}, size {:#x}) file: '{}'", - MapOffset, - MapSize, - zen::PathFromHandle(m_FileHandle))); - } - - m_MappedPointer = MappedBase; - m_DataPtr = reinterpret_cast<uint8_t*>(MappedBase) + MappedOffsetDisplacement; - m_MmapHandle = NewMmapHandle; - - m_Flags.fetch_or(NewFlags, std::memory_order_release); -} - -bool -IoBufferExtendedCore::GetFileReference(IoBufferFileReference& OutRef) const -{ - if (m_FileHandle == nullptr) - { - return false; - } - - OutRef.FileHandle = m_FileHandle; - OutRef.FileChunkOffset = m_FileOffset; - OutRef.FileChunkSize = m_DataBytes; - - return true; -} - -void -IoBufferExtendedCore::MarkAsDeleteOnClose() -{ - m_DeleteOnClose = true; -} - -////////////////////////////////////////////////////////////////////////// - -IoBuffer::IoBuffer(size_t InSize) : m_Core(new IoBufferCore(InSize)) -{ - m_Core->SetIsImmutable(false); -} - -IoBuffer::IoBuffer(size_t InSize, uint64_t InAlignment) : m_Core(new IoBufferCore(InSize, InAlignment)) -{ - m_Core->SetIsImmutable(false); -} - -IoBuffer::IoBuffer(const IoBuffer& OuterBuffer, size_t Offset, size_t Size) -{ - if (Size == ~(0ull)) - { - Size = std::clamp<size_t>(Size, 0, OuterBuffer.Size() - Offset); - } - - ZEN_ASSERT(Offset <= OuterBuffer.Size()); - ZEN_ASSERT((Offset + Size) <= OuterBuffer.Size()); - - if (IoBufferExtendedCore* Extended = OuterBuffer.m_Core->ExtendedCore()) - { - m_Core = new IoBufferExtendedCore(Extended, Offset, Size); - } - else - { - m_Core = new IoBufferCore(OuterBuffer.m_Core, reinterpret_cast<const uint8_t*>(OuterBuffer.Data()) + Offset, Size); - } -} - -IoBuffer::IoBuffer(EFileTag, void* FileHandle, uint64_t ChunkFileOffset, uint64_t ChunkSize) -: m_Core(new IoBufferExtendedCore(FileHandle, ChunkFileOffset, ChunkSize, /* owned */ true)) -{ -} - -IoBuffer::IoBuffer(EBorrowedFileTag, void* FileHandle, uint64_t ChunkFileOffset, uint64_t ChunkSize) -: m_Core(new IoBufferExtendedCore(FileHandle, ChunkFileOffset, ChunkSize, /* owned */ false)) -{ -} - -bool -IoBuffer::GetFileReference(IoBufferFileReference& OutRef) const -{ - if (IoBufferExtendedCore* ExtCore = m_Core->ExtendedCore()) - { - if (ExtCore->GetFileReference(OutRef)) - { - return true; - } - } - - // Not a file reference - - OutRef.FileHandle = 0; - OutRef.FileChunkOffset = ~0ull; - OutRef.FileChunkSize = 0; - - return false; -} - -void -IoBuffer::MarkAsDeleteOnClose() -{ - if (IoBufferExtendedCore* ExtCore = m_Core->ExtendedCore()) - { - ExtCore->MarkAsDeleteOnClose(); - } -} - -////////////////////////////////////////////////////////////////////////// - -IoBuffer -IoBufferBuilder::ReadFromFileMaybe(IoBuffer& InBuffer) -{ - IoBufferFileReference FileRef; - if (InBuffer.GetFileReference(/* out */ FileRef)) - { - IoBuffer OutBuffer(FileRef.FileChunkSize); - -#if ZEN_PLATFORM_WINDOWS - OVERLAPPED Ovl{}; - - const uint64_t NumberOfBytesToRead = FileRef.FileChunkSize; - const uint64_t& FileOffset = FileRef.FileChunkOffset; - - Ovl.Offset = DWORD(FileOffset & 0xffff'ffffu); - Ovl.OffsetHigh = DWORD(FileOffset >> 32); - - DWORD dwNumberOfBytesRead = 0; - BOOL Success = ::ReadFile(FileRef.FileHandle, OutBuffer.MutableData(), DWORD(NumberOfBytesToRead), &dwNumberOfBytesRead, &Ovl); -#else - int Fd = int(intptr_t(FileRef.FileHandle)); - int Result = pread(Fd, OutBuffer.MutableData(), size_t(FileRef.FileChunkSize), off_t(FileRef.FileChunkOffset)); - bool Success = (Result < 0); - - uint32_t dwNumberOfBytesRead = uint32_t(Result); -#endif - - if (!Success) - { - ThrowLastError("ReadFile failed in IoBufferBuilder::ReadFromFileMaybe"); - } - - ZEN_ASSERT(dwNumberOfBytesRead == FileRef.FileChunkSize); - - return OutBuffer; - } - else - { - return InBuffer; - } -} - -IoBuffer -IoBufferBuilder::MakeFromFileHandle(void* FileHandle, uint64_t Offset, uint64_t Size) -{ - return IoBuffer(IoBuffer::BorrowedFile, FileHandle, Offset, Size); -} - -IoBuffer -IoBufferBuilder::MakeFromFile(const std::filesystem::path& FileName, uint64_t Offset, uint64_t Size) -{ - uint64_t FileSize; - -#if ZEN_PLATFORM_WINDOWS - CAtlFile DataFile; - - DWORD ShareOptions = FILE_SHARE_DELETE | FILE_SHARE_WRITE | FILE_SHARE_DELETE | FILE_SHARE_READ; - HRESULT hRes = DataFile.Create(FileName.c_str(), GENERIC_READ, ShareOptions, OPEN_EXISTING); - - if (FAILED(hRes)) - { - return {}; - } - - DataFile.GetSize((ULONGLONG&)FileSize); -#else - int Flags = O_RDONLY | O_CLOEXEC; - int Fd = open(FileName.c_str(), Flags); - if (Fd < 0) - { - return {}; - } - - static_assert(sizeof(decltype(stat::st_size)) == sizeof(uint64_t), "fstat() doesn't support large files"); - struct stat Stat; - fstat(Fd, &Stat); - FileSize = Stat.st_size; -#endif // ZEN_PLATFORM_WINDOWS - - // TODO: should validate that offset is in range - - if (Size == ~0ull) - { - Size = FileSize - Offset; - } - else - { - // Clamp size - if ((Offset + Size) > FileSize) - { - Size = FileSize - Offset; - } - } - - if (Size) - { -#if ZEN_PLATFORM_WINDOWS - void* Fd = DataFile.Detach(); -#endif - IoBuffer Iob(IoBuffer::File, (void*)uintptr_t(Fd), Offset, Size); - Iob.m_Core->SetIsWholeFile(Offset == 0 && Size == FileSize); - return Iob; - } - -#if !ZEN_PLATFORM_WINDOWS - close(Fd); -#endif - - // For an empty file, we may as well just return an empty memory IoBuffer - return IoBuffer(IoBuffer::Wrap, "", 0); -} - -IoBuffer -IoBufferBuilder::MakeFromTemporaryFile(const std::filesystem::path& FileName) -{ - uint64_t FileSize; - void* Handle; - -#if ZEN_PLATFORM_WINDOWS - CAtlFile DataFile; - - // We need to open with DELETE since this is used for the case - // when a file has been written to a staging directory, and is going - // to be moved in place - - HRESULT hRes = DataFile.Create(FileName.native().c_str(), GENERIC_READ | DELETE, FILE_SHARE_READ | FILE_SHARE_DELETE, OPEN_EXISTING); - - if (FAILED(hRes)) - { - return {}; - } - - DataFile.GetSize((ULONGLONG&)FileSize); - - Handle = DataFile.Detach(); -#else - int Fd = open(FileName.native().c_str(), O_RDONLY); - if (Fd < 0) - { - return {}; - } - - static_assert(sizeof(decltype(stat::st_size)) == sizeof(uint64_t), "fstat() doesn't support large files"); - struct stat Stat; - fstat(Fd, &Stat); - FileSize = Stat.st_size; - - Handle = (void*)uintptr_t(Fd); -#endif // ZEN_PLATFORM_WINDOWS - - IoBuffer Iob(IoBuffer::File, Handle, 0, FileSize); - Iob.m_Core->SetIsWholeFile(true); - - return Iob; -} - -IoHash -HashBuffer(IoBuffer& Buffer) -{ - // TODO: handle disk buffers with special path - return IoHash::HashBuffer(Buffer.Data(), Buffer.Size()); -} - -////////////////////////////////////////////////////////////////////////// - -#if ZEN_WITH_TESTS - -void -iobuffer_forcelink() -{ -} - -TEST_CASE("IoBuffer") -{ - zen::IoBuffer buffer1; - zen::IoBuffer buffer2(16384); - zen::IoBuffer buffer3(buffer2, 0, buffer2.Size()); -} - -#endif - -} // namespace zen |