/*** 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 /* For mode constants */ #include /* For O_* constants */ #if defined(AURORA_IS_LINUX_DERIVED) #include "IPCMutexFutex.Linux.hpp" /* For import */ #endif namespace Aurora::IO::IPC { ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Shared memory ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// AuString GetServerPath(const IPC::IPCToken &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.values[0].token.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; IPC::IPCToken token; token.pid = handle.pid; token.word = length; token.NewId(); handle.PushId(EIPCHandleType::eIPCMemory, token); auto path = GetServerPath(token); 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; } AuSPtr ImportSharedMemoryEx(const IPCToken &token) { auto path = GetServerPath(token); int fd = ::shm_open(path.c_str(), O_RDWR, S_IRUSR | S_IWUSR); if (fd == -1) { SysPushErrorIO(); return {}; } auto map = ::mmap(nullptr, token.word, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (map == MAP_FAILED) { SysPushErrorIO(); ::close(fd); return {}; } IPC::IPCHandle handle; handle.PushId(EIPCHandleType::eIPCMemory, token); auto object = AuMakeShared(fd, map, handle, false); if (!object) { SysPushErrorMem(); ::munmap(map, token.word); ::close(fd); return {}; } return object; } AUKN_SYM AuSPtr ImportSharedMemory(const AuString &handleString) { IPC::IPCHandle handle; if (!handle.FromString(handleString)) { SysPushErrorParseError("Invalid handle: {}", handleString); return {}; } auto val = handle.GetToken(IPC::EIPCHandleType::eIPCMemory, 0); if (!val) { SysPushErrorParseError("Invalid handle: {}", handleString); return {}; } return ImportSharedMemoryEx(val->token); } }