1#include <Foundation/FoundationPCH.h>
2PL_FOUNDATION_INTERNAL_HEADER
4#include <Foundation/IO/MemoryMappedFile.h>
5#include <Foundation/Logging/Log.h>
6#include <Foundation/Strings/PathUtils.h>
13#if PL_ENABLED(PL_PLATFORM_LINUX)
14# include <linux/version.h>
17#if PL_ENABLED(PL_PLATFORM_OSX)
24 void* m_pMappedFilePtr =
nullptr;
25 plUInt64 m_uiFileSize = 0;
31#if PL_ENABLED(PL_SUPPORTS_MEMORY_MAPPED_FILE)
32 if (m_pMappedFilePtr !=
nullptr)
34 munmap(m_pMappedFilePtr, m_uiFileSize);
35 m_pMappedFilePtr =
nullptr;
42# if PL_ENABLED(PL_PLATFORM_ANDROID)
47 if (!m_sSharedMemoryName.
IsEmpty())
49 shm_unlink(m_sSharedMemoryName);
50 m_sSharedMemoryName.
Clear();
58plMemoryMappedFile::plMemoryMappedFile()
63plMemoryMappedFile::~plMemoryMappedFile()
68#if PL_ENABLED(PL_SUPPORTS_MEMORY_MAPPED_FILE)
71 PL_ASSERT_DEV(mode !=
Mode::None,
"Invalid mode to open the memory mapped file");
74 PL_LOG_BLOCK(
"MemoryMapFile", sAbsolutePath);
80 m_pImpl->m_Mode = mode;
82 int access = O_RDONLY;
84 int flags = MAP_PRIVATE;
91# if PL_ENABLED(PL_PLATFORM_LINUX)
92# if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22)
93 flags |= MAP_POPULATE;
96 m_pImpl->m_hFile = open(sPath, access | O_CLOEXEC, 0);
97 if (m_pImpl->m_hFile == -1)
99 plLog::Error(
"Could not open file for memory mapping - {}", strerror(errno));
104 if (stat(sPath, &sb) == -1 || sb.st_size == 0)
106 plLog::Error(
"File for memory mapping is empty - {}", strerror(errno));
110 m_pImpl->m_uiFileSize = sb.st_size;
112 m_pImpl->m_pMappedFilePtr = mmap(
nullptr, m_pImpl->m_uiFileSize, prot, flags, m_pImpl->m_hFile, 0);
113 if (m_pImpl->m_pMappedFilePtr ==
nullptr)
115 plLog::Error(
"Could not create memory mapping of file - {}", strerror(errno));
124#if PL_ENABLED(PL_SUPPORTS_SHARED_MEMORY)
127 PL_ASSERT_DEV(mode !=
Mode::None,
"Invalid mode to open the memory mapped file");
128 PL_ASSERT_DEV(uiSize > 0,
"plMemoryMappedFile::OpenShared() needs a valid file size to map");
132 PL_LOG_BLOCK(
"MemoryMapFile", sName);
136 m_pImpl->m_Mode = mode;
138 int prot = PROT_READ;
139 int oflag = O_RDONLY;
140 int flags = MAP_SHARED;
141# if PL_ENABLED(PL_PLATFORM_LINUX)
142# if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22)
143 flags |= MAP_POPULATE;
154 m_pImpl->m_hFile = shm_open(sName, oflag, 0666);
155 if (m_pImpl->m_hFile == -1)
157 plLog::Error(
"Could not open shared memory mapping - {}", strerror(errno));
161 m_pImpl->m_sSharedMemoryName = sName;
163 if (ftruncate(m_pImpl->m_hFile, uiSize) == -1)
165 plLog::Error(
"Could not open shared memory mapping - {}", strerror(errno));
169 m_pImpl->m_uiFileSize = uiSize;
171 m_pImpl->m_pMappedFilePtr = mmap(
nullptr, m_pImpl->m_uiFileSize, prot, flags, m_pImpl->m_hFile, 0);
172 if (m_pImpl->m_pMappedFilePtr ==
nullptr)
174 plLog::Error(
"Could not create memory mapping of file - {}", strerror(errno));
189 return m_pImpl->m_Mode;
194 PL_ASSERT_DEBUG(m_pImpl->m_Mode >=
Mode::ReadOnly,
"File must be opened with read access before accessing it for reading.");
195 PL_ASSERT_DEBUG(uiOffset <= m_pImpl->m_uiFileSize,
"Read offset must be smaller than mapped file size");
209 PL_ASSERT_DEBUG(m_pImpl->m_Mode >=
Mode::ReadWrite,
"File must be opened with read/write access before accessing it for writing.");
210 PL_ASSERT_DEBUG(uiOffset <= m_pImpl->m_uiFileSize,
"Read offset must be smaller than mapped file size");
224 return m_pImpl->m_uiFileSize;
static void Error(plLogInterface *pInterface, const plFormatString &string)
An error that needs to be fixed as soon as possible.
Definition Log.cpp:375
@ Start
Byte offsets are relative to the start of the mapped memory.
void Close()
Removes the memory mapping. Outstanding modifications will be written back to disk at this point.
Definition MemoryMappedFile_NoImpl.h:27
const void * GetReadPointer(plUInt64 uiOffset=0, OffsetBase base=OffsetBase::Start) const
Returns a pointer for reading the mapped file. Asserts that the memory mapping was done successfully.
Definition MemoryMappedFile_NoImpl.h:37
Mode
Definition MemoryMappedFile.h:17
@ ReadOnly
File is mapped for read-only access.
@ None
Currently no file is mapped.
@ ReadWrite
File is mapped for read/write access.
plResult Open(plStringView sAbsolutePath, Mode mode)
Attempts to open the given file and map it into memory.
plResult OpenShared(plStringView sSharedName, plUInt64 uiSize, Mode mode)
Attempts to open or create the given shared memory block addressed by szSharedName.
void * GetWritePointer(plUInt64 uiOffset=0, OffsetBase base=OffsetBase::Start)
Returns a pointer for writing the mapped file. Asserts that the memory mapping was successful and the...
Definition MemoryMappedFile_NoImpl.h:43
Mode GetMode() const
Returns the mode with which the file was opened or None, if is currently not in use.
Definition MemoryMappedFile_NoImpl.h:32
plUInt64 GetFileSize() const
Returns the size (in bytes) of the memory mapping. Zero if no file is mapped at the moment.
Definition MemoryMappedFile_NoImpl.h:49
static T * AddByteOffset(T *pPtr, std::ptrdiff_t offset)
Returns the address stored in ptr plus the given byte offset iOffset, cast to type T.
static bool IsAbsolutePath(plStringView sPath)
Returns true, if the given path represents an absolute path on the current OS.
Definition PathUtils.cpp:136
plStringBuilder is a class that is meant for creating and modifying strings.
Definition StringBuilder.h:35
plStringView represent a read-only sub-string of a larger string, as it can store a dedicated string ...
Definition StringView.h:34
void Clear()
Resets this string to an empty string.
Definition String_inl.h:49
Definition MemoryMappedFile_NoImpl.h:9
Default enum for returning failure or success, instead of using a bool.
Definition Types.h:54
bool IsEmpty() const
Returns whether the string is an empty string.
Definition StringBase_inl.h:25