#include "shm.h" #include #include #include #include #include #include #include #include #include #include "memory/resource.hpp" namespace { using acc_t = std::atomic_size_t; constexpr acc_t* acc_of(void* mem) { return static_cast(mem); } constexpr void* mem_of(void* mem) { return static_cast(mem) - 1; } inline auto* m2h() { static struct { std::mutex lc_; ipc::mem::unordered_map cache_; } m2h_; return &m2h_; } } // internal-linkage namespace ipc { namespace shm { void* acquire(char const * name, std::size_t size) { if (name == nullptr || name[0] == '\0' || size == 0) { return nullptr; } std::string op_name = std::string{"__IPC_SHM__"} + name; int fd = ::shm_open(op_name.c_str(), O_CREAT | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); if (fd == -1) { return nullptr; } size += sizeof(acc_t); if (::ftruncate(fd, static_cast(size)) != 0) { ::close(fd); ::shm_unlink(op_name.c_str()); return nullptr; } void* mem = ::mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); ::close(fd); if (mem == MAP_FAILED) { ::shm_unlink(op_name.c_str()); return nullptr; } auto acc = acc_of(mem); acc->fetch_add(1, std::memory_order_release); { [[maybe_unused]] auto guard = std::unique_lock { m2h()->lc_ }; m2h()->cache_.emplace(++acc, std::move(op_name)); } return acc; } void release(void* mem, std::size_t size) { if (mem == nullptr) { return; } [[maybe_unused]] auto guard = std::unique_lock { m2h()->lc_ }; auto& cc = m2h()->cache_; auto it = cc.find(mem); if (it == cc.end()) { return; } mem = mem_of(mem); size += sizeof(acc_t); if (acc_of(mem)->fetch_sub(1, std::memory_order_acquire) == 1) { ::munmap(mem, size); ::shm_unlink(it->second.c_str()); } else ::munmap(mem, size); cc.erase(it); } } // namespace shm } // namespace ipc