/*** Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved. File: AuIPCMemory.Unix.cpp Date: 2022-4-14 Author: Reece ***/ #include #include "IPC.hpp" #include "AuIPCHandle.hpp" #include "AuIPCMemory.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 *pBase, const IPC::IPCHandle &handle, bool bOwns) : fd_(fd), pBase_(ptr), uLen_(handle.values[0].token.word), bOwns_(bOwns), handle_(handle) { } IPCSharedMemoryImpl::~IPCSharedMemoryImpl() { if (this->pBase_) { ::munmap(this->pBase_, this->uLen_); } int fd {-1}; if ((fd = AuExchange(this->fd_, -1)) != -1) { ::close(fd); } } Memory::MemoryViewWrite IPCSharedMemoryImpl::GetMemory() { return AuMemoryViewWrite(this->pBase_, this->uLen_); } AuUInt IPCSharedMemoryImpl::GetLength() { return this->uLen_; } AuString IPCSharedMemoryImpl::ExportToString() { return this->handle_.ToString(); } AUKN_SYM AuSPtr NewSharedMemory(AuUInt uLength) { IPC::IPCHandle handle; IPC::IPCToken token; token.pid = handle.pid; token.word = uLength; 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, uLength) == -1) { SysPushErrorMem(); ::close(fd); return {}; } auto map = ::mmap(nullptr, uLength, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (map == MAP_FAILED) { SysPushErrorIO(); ::close(fd); return {}; } auto pObject = AuMakeShared(fd, map, handle, true); if (!pObject) { SysPushErrorMem(); ::munmap(map, uLength); ::close(fd); return {}; } return pObject; } 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 pObject = AuMakeShared(fd, map, handle, false); if (!pObject) { SysPushErrorMem(); ::munmap(map, token.word); ::close(fd); return {}; } return pObject; } 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); } }