#include "SerializedSharedMemory.h" #ifdef _M_ARM64 #define _mm_pause() __yield(); #endif inline char* SerializedSharedMemory::lock_flag_addr() noexcept { return reinterpret_cast(_memory._data + _memory._size); } inline void SerializedSharedMemory::lock() noexcept { if (_read_only) { return; } while (LOCKED == _InterlockedCompareExchange8(lock_flag_addr(), LOCKED, !LOCKED)) { while (*lock_flag_addr() == LOCKED) { _mm_pause(); } } } inline void SerializedSharedMemory::unlock() noexcept { if (_read_only) { return; } _InterlockedExchange8(lock_flag_addr(), !LOCKED); } SerializedSharedMemory::SerializedSharedMemory(std::array handles, memory_t memory, const bool readonly) noexcept : _handles{ std::move(handles) }, _memory{ std::move(memory) }, _read_only(readonly) { } SerializedSharedMemory::~SerializedSharedMemory() noexcept { if (_memory._data) { UnmapViewOfFile(_memory._data); } } SerializedSharedMemory::SerializedSharedMemory(SerializedSharedMemory&& rhs) noexcept { *this = std::move(rhs); } SerializedSharedMemory& SerializedSharedMemory::operator=(SerializedSharedMemory&& rhs) noexcept { _handles = {}; _handles.swap(rhs._handles); _memory = std::move(rhs._memory); rhs._memory = {}; _read_only = rhs._read_only; rhs._read_only = true; return *this; } std::optional SerializedSharedMemory::create(const std::wstring_view object_name, const size_t size, const bool read_only, SECURITY_ATTRIBUTES* maybe_attributes) noexcept { SECURITY_DESCRIPTOR sd; SECURITY_ATTRIBUTES sa = { sizeof SECURITY_ATTRIBUTES }; if (!maybe_attributes) { sa.lpSecurityDescriptor = &sd; sa.bInheritHandle = false; if (!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION) || !SetSecurityDescriptorDacl(&sd, true, nullptr, false)) { return std::nullopt; } } // We need an extra byte for locking if it's not readonly const ULARGE_INTEGER UISize{ .QuadPart = static_cast(size) + !read_only }; wil::unique_handle hMapFile{ CreateFileMappingW(INVALID_HANDLE_VALUE, maybe_attributes ? maybe_attributes : &sa, read_only ? PAGE_READONLY : PAGE_READWRITE, UISize.HighPart, UISize.LowPart, object_name.data()) }; if (!hMapFile) { return std::nullopt; } auto shmem = static_cast( MapViewOfFile(hMapFile.get(), read_only ? FILE_MAP_READ : FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, static_cast(UISize.QuadPart))); if (!shmem) { return std::nullopt; } std::array handles = { std::move(hMapFile), {} }; return SerializedSharedMemory{ std::move(handles), memory_t{ shmem, size }, read_only }; } std::optional SerializedSharedMemory::open(const std::wstring_view object_name, const size_t size, const bool read_only) noexcept { wil::unique_handle hMapFile{ OpenFileMappingW(FILE_MAP_READ | FILE_MAP_WRITE, FALSE, object_name.data()) }; if (!hMapFile) { return std::nullopt; } auto shmem = static_cast( MapViewOfFile(hMapFile.get(), read_only ? FILE_MAP_READ : FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, size + !read_only)); if (!shmem) { return std::nullopt; } std::array handles = { std::move(hMapFile), {} }; return SerializedSharedMemory{ std::move(handles), memory_t{ shmem, size }, read_only }; } std::optional SerializedSharedMemory::create_readonly( const std::wstring_view object_name, const std::wstring_view file_path, SECURITY_ATTRIBUTES* maybe_attributes) noexcept { SECURITY_DESCRIPTOR sd; SECURITY_ATTRIBUTES sa = { sizeof SECURITY_ATTRIBUTES }; if (!maybe_attributes) { sa.lpSecurityDescriptor = &sd; sa.bInheritHandle = false; if (!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION) || !SetSecurityDescriptorDacl(&sd, true, nullptr, false)) { return std::nullopt; } } wil::unique_handle hFile{ CreateFileW(file_path.data(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, maybe_attributes ? maybe_attributes : &sa, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr) }; if (!hFile) { return std::nullopt; } LARGE_INTEGER fileSize; if (!GetFileSizeEx(hFile.get(), &fileSize)) { return std::nullopt; } wil::unique_handle hMapFile{ CreateFileMappingW(hFile.get(), maybe_attributes ? maybe_attributes : &sa, PAGE_READONLY, fileSize.HighPart, fileSize.LowPart, object_name.data()) }; if (!hMapFile) { return std::nullopt; } auto shmem = static_cast(MapViewOfFile(nullptr, FILE_MAP_READ, 0, 0, static_cast(fileSize.QuadPart))); if (shmem) { return std::nullopt; } std::array handles = { std::move(hMapFile), std::move(hFile) }; return SerializedSharedMemory{ std::move(handles), memory_t{ shmem, static_cast(fileSize.QuadPart) }, true }; } void SerializedSharedMemory::access(std::function access_routine) noexcept { lock(); access_routine(_memory); unlock(); }