#include "shm.h" #include #include #include #include #include #include #include #include #include #include #include "def.h" #include "log.h" #include "memory/resource.h" namespace { struct info_t { std::atomic_size_t acc_; char name_[ipc::name_length]; }; constexpr std::size_t calc_size(std::size_t size) { return ((((size - 1) / alignof(info_t)) + 1) * alignof(info_t)) + sizeof(info_t); } inline auto& acc_of(void* mem, std::size_t size) { return reinterpret_cast(static_cast(mem) + size - sizeof(info_t))->acc_; } inline auto& str_of(void* mem, std::size_t size) { return reinterpret_cast(static_cast(mem) + size - sizeof(info_t))->name_; } } // internal-linkage namespace ipc { namespace shm { id_t acquire(char const * name, std::size_t size, unsigned mode) { if (name == nullptr || name[0] == '\0' || size == 0) { return nullptr; } std::string op_name = std::string{"__IPC_SHM__"} + name; if (op_name.size() >= ipc::name_length) { ipc::error("name is too long!: [%d]%s\n", static_cast(op_name.size()), op_name.c_str()); return nullptr; } // Open the object for read-write access. int flag = O_RDWR; switch (mode) { case open: break; // The check for the existence of the object, // and its creation if it does not exist, are performed atomically. case create: flag |= O_CREAT | O_EXCL; break; // Create the shared memory object if it does not exist. default: flag |= O_CREAT; break; } int fd = ::shm_open(op_name.c_str(), flag, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); if (fd == -1) { ipc::error("fail shm_open[%d]: %s\n", errno, name); return nullptr; } size = calc_size(size); if (::ftruncate(fd, static_cast(size)) != 0) { ipc::error("fail ftruncate[%d]: %s\n", errno, name); ::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) { ipc::error("fail mmap[%d]: %s\n", errno, name); ::shm_unlink(op_name.c_str()); return nullptr; } if (acc_of(mem, size).fetch_add(1, std::memory_order_release) == 0) { std::memcpy(&str_of(mem, size), op_name.c_str(), op_name.size()); } return static_cast(mem); } void * to_mem(id_t id) { return static_cast(id); } void release(id_t id, void * mem, std::size_t size) { if (mem == nullptr) { return; } if (mem != to_mem(id)) { return; } size = calc_size(size); if (acc_of(mem, size).fetch_sub(1, std::memory_order_acquire) == 1) { char name[ipc::name_length] = {}; std::memcpy(name, &str_of(mem, size), sizeof(name)); ::munmap(mem, size); ::shm_unlink(name); } else ::munmap(mem, size); } void remove(char const * name) { if (name == nullptr || name[0] == '\0') { return; } std::string op_name = std::string{"__IPC_SHM__"} + name; if (op_name.size() >= ipc::name_length) { ipc::error("name is too long!: [%d]%s\n", static_cast(op_name.size()), op_name.c_str()); return; } ::shm_unlink(op_name.c_str()); } } // namespace shm } // namespace ipc