/*** Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved. File: IPCMemory.Unix.cpp Date: 2022-4-14 Author: Reece ***/ #include #include "IPC.hpp" #include "IPCHandle.hpp" #include "IPCMemory.Unix.hpp" #include #include #include #include /* For mode constants */ #include /* For O_* constants */ namespace Aurora::IO::IPC { ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Shared memory ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// struct IPCSharedMemoryImpl : IPCSharedMemory { IPCSharedMemoryImpl(int fd, void *ptr, const IPC::IPCHandle &handle, bool owns); ~IPCSharedMemoryImpl(); virtual Memory::MemoryViewWrite GetMemory() override; virtual AuUInt GetLength() override; virtual AuString ExportToString() override; private: IPC::IPCHandle handle_; bool owns_; int fd_{}; void *base_{}; AuUInt len_ {}; }; static AuString GetServerPath(const IPC::IPCHandle &handle) { AuString path; path += "/AURORA_"; path += AuToString(AuUInt32(handle.cookie)); path += "_"; path += AuToString(AuUInt32(handle.pid)); return path; } IPCSharedMemoryImpl::IPCSharedMemoryImpl(int fd, void *ptr, const IPC::IPCHandle &handle, bool owns) : fd_(fd), base_(ptr), len_(handle.word), owns_(owns), handle_(handle) { } IPCSharedMemoryImpl::~IPCSharedMemoryImpl() { if (this->base_) { ::munmap(this->base_, this->len_); } int fd {-1}; if ((fd = AuExchange(this->fd_, -1)) != -1) { ::close(fd); } } Memory::MemoryViewWrite IPCSharedMemoryImpl::GetMemory() { return AuMemoryViewWrite(this->base_, this->len_); } AuUInt IPCSharedMemoryImpl::GetLength() { return this->len_; } AuString IPCSharedMemoryImpl::ExportToString() { return this->handle_.ToString(); } AUKN_SYM AuSPtr NewSharedMemory(AuUInt length) { IPC::IPCHandle handle; handle.NewId(length); auto path = GetServerPath(handle); int fd = ::shm_open(path.c_str(), O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); if (fd == -1) { SysPushErrorIO(); return {}; } if (::ftruncate(fd, length) == -1) { SysPushErrorMem(); ::close(fd); return {}; } auto map = ::mmap(nullptr, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (map == MAP_FAILED) { SysPushErrorIO(); ::close(fd); return {}; } auto object = AuMakeShared(fd, map, handle, true); if (!object) { SysPushErrorMem(); ::munmap(map, length); ::close(fd); return {}; } return object; } AUKN_SYM AuSPtr ImportSharedMemory(const AuString &handleString) { IPC::IPCHandle handle; if (!handle.FromString(handleString)) { SysPushErrorParseError(); return {}; } auto path = GetServerPath(handle); int fd = ::shm_open(path.c_str(), O_RDWR, S_IRUSR | S_IWUSR); if (fd == -1) { SysPushErrorIO(); return {}; } auto map = ::mmap(nullptr, handle.word, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (map == MAP_FAILED) { SysPushErrorIO(); ::close(fd); return {}; } auto object = AuMakeShared(fd, map, handle, false); if (!object) { SysPushErrorMem(); ::munmap(map, handle.word); ::close(fd); return {}; } return object; } }