diff --git a/include/def.h b/include/def.h index 3f99855..47fc9bf 100644 --- a/include/def.h +++ b/include/def.h @@ -29,7 +29,6 @@ using uint_t = typename uint::type; enum : std::size_t { invalid_value = (std::numeric_limits::max)(), data_length = 64, - name_length = 64, default_timeut = 100 // ms }; diff --git a/include/shm.h b/include/shm.h index a7a0886..8430469 100644 --- a/include/shm.h +++ b/include/shm.h @@ -15,8 +15,8 @@ enum : unsigned { }; IPC_EXPORT id_t acquire(char const * name, std::size_t size, unsigned mode = create | open); -IPC_EXPORT void * to_mem (id_t id); -IPC_EXPORT void release(id_t id, void * mem, std::size_t size); +IPC_EXPORT void * get_mem(id_t id, std::size_t * size); +IPC_EXPORT void release(id_t id); IPC_EXPORT void remove (char const * name); class IPC_EXPORT handle { diff --git a/src/platform/shm_linux.cpp b/src/platform/shm_linux.cpp index bd89215..e15e459 100644 --- a/src/platform/shm_linux.cpp +++ b/src/platform/shm_linux.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -14,13 +15,19 @@ #include "def.h" #include "log.h" -#include "memory/resource.h" +#include "pool_alloc.h" namespace { struct info_t { std::atomic_size_t acc_; - char name_[ipc::name_length]; +}; + +struct id_info_t { + int fd_ = -1; + void* mem_ = nullptr; + std::size_t size_ = 0; + std::string name_; }; constexpr std::size_t calc_size(std::size_t size) { @@ -31,24 +38,17 @@ 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) { + if (name == nullptr || name[0] == '\0') { + ipc::error("fail acquire: name is empty\n"); 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) { @@ -71,57 +71,84 @@ id_t acquire(char const * name, std::size_t size, unsigned mode) { 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()); + auto ii = mem::alloc(); + ii->fd_ = fd; + ii->size_ = size; + ii->name_ = std::move(op_name); + return ii; +} + +void * get_mem(id_t id, std::size_t * size) { + if (id == nullptr) { + ipc::error("fail get_mem: invalid id (null)\n"); return nullptr; } - void* mem = ::mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); - ::close(fd); + auto ii = static_cast(id); + if (ii->mem_ != nullptr) { + if (size != nullptr) *size = ii->size_; + return ii->mem_; + } + int fd = ii->fd_; + if (fd == -1) { + ipc::error("fail to_mem: invalid id (fd = -1)\n"); + return nullptr; + } + if (ii->size_ == 0) { + struct stat st; + if (::fstat(fd, &st) != 0) { + ipc::error("fail fstat[%d]: %s, size = %zd\n", errno, ii->name_.c_str(), ii->size_); + return nullptr; + } + ii->size_ = static_cast(st.st_size); + if ((ii->size_ <= sizeof(info_t)) || (ii->size_ % sizeof(info_t))) { + ipc::error("fail to_mem: %s, invalid size = %zd\n", ii->name_.c_str(), ii->size_); + return nullptr; + } + } + else { + ii->size_ = calc_size(ii->size_); + if (::ftruncate(fd, static_cast(ii->size_)) != 0) { + ipc::error("fail ftruncate[%d]: %s, size = %zd\n", errno, ii->name_.c_str(), ii->size_); + return nullptr; + } + } + void* mem = ::mmap(nullptr, ii->size_, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (mem == MAP_FAILED) { - ipc::error("fail mmap[%d]: %s\n", errno, name); - ::shm_unlink(op_name.c_str()); + ipc::error("fail mmap[%d]: %s, size = %zd\n", errno, ii->name_.c_str(), ii->size_); 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); + ::close(fd); + ii->fd_ = -1; + ii->mem_ = mem; + if (size != nullptr) *size = ii->size_; + acc_of(mem, ii->size_).fetch_add(1, std::memory_order_release); + return 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) { +void release(id_t id) { + if (id == nullptr) { + ipc::error("fail release: invalid id (null)\n"); return; } - if (mem != to_mem(id)) { + auto ii = static_cast(id); + if (ii->mem_ == nullptr || ii->size_ == 0) { + ipc::error("fail release: invalid id (mem = %p, size = %zd)\n", ii->mem_, ii->size_); 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); + if (acc_of(ii->mem_, ii->size_).fetch_sub(1, std::memory_order_acquire) == 1) { + ::munmap(ii->mem_, ii->size_); + ::shm_unlink(ii->name_.c_str()); } - else ::munmap(mem, size); + else ::munmap(ii->mem_, ii->size_); + mem::free(ii); } void remove(char const * name) { if (name == nullptr || name[0] == '\0') { + ipc::error("fail remove: name is empty\n"); 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()); + ::shm_unlink((std::string{"__IPC_SHM__"} + name).c_str()); } } // namespace shm diff --git a/src/platform/shm_win.cpp b/src/platform/shm_win.cpp index 3b3cb08..175f307 100644 --- a/src/platform/shm_win.cpp +++ b/src/platform/shm_win.cpp @@ -7,14 +7,26 @@ #include "def.h" #include "log.h" -#include "memory/resource.h" +#include "pool_alloc.h" + #include "platform/to_tchar.h" +namespace { + +struct id_info_t { + HANDLE h_ = NULL; + void* mem_ = nullptr; + std::size_t size_ = 0; +}; + +} // 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) { + if (name == nullptr || name[0] == '\0') { + ipc::error("fail acquire: name is empty\n"); return nullptr; } HANDLE h; @@ -38,28 +50,67 @@ id_t acquire(char const * name, std::size_t size, unsigned mode) { ipc::error("fail CreateFileMapping/OpenFileMapping[%d]: %s\n", static_cast(::GetLastError()), name); return nullptr; } - return static_cast(h); + auto ii = mem::alloc(); + ii->h_ = h; + ii->size_ = size; + return ii; } -void * to_mem(id_t id) { - if (id == nullptr) return nullptr; - HANDLE h = static_cast(id); - LPVOID mem = ::MapViewOfFile(h, FILE_MAP_ALL_ACCESS, 0, 0, 0); +void * get_mem(id_t id, std::size_t * size) { + if (id == nullptr) { + ipc::error("fail get_mem: invalid id (null)\n"); + return nullptr; + } + auto ii = static_cast(id); + if (ii->mem_ != nullptr) { + if (size != nullptr) *size = ii->size_; + return ii->mem_; + } + if (ii->h_ == NULL) { + ipc::error("fail to_mem: invalid id (h = null)\n"); + return nullptr; + } + LPVOID mem = ::MapViewOfFile(ii->h_, FILE_MAP_ALL_ACCESS, 0, 0, 0); if (mem == NULL) { ipc::error("fail MapViewOfFile[%d]\n", static_cast(::GetLastError())); return nullptr; } + PMEMORY_BASIC_INFORMATION mem_info; + if (::VirtualQuery(mem, &mem_info, sizeof(mem_info)) == 0) { + ipc::error("fail VirtualQuery[%d]\n", static_cast(::GetLastError())); + return nullptr; + } + ii->mem_ = mem; + ii->size_ = static_cast(mem_info.RegionSize); + if (size != nullptr) *size = ii->size_; return static_cast(mem); } -void release(id_t id, void * mem, std::size_t /*size*/) { - if (id == nullptr) return; - if (mem == nullptr) return; - ::UnmapViewOfFile(static_cast(mem)); - ::CloseHandle(static_cast(id)); +void release(id_t id) { + if (id == nullptr) { + ipc::error("fail release: invalid id (null)\n"); + return; + } + auto ii = static_cast(id); + if (ii->mem_ == nullptr || ii->size_ == 0) { + ipc::error("fail release: invalid id (mem = %p, size = %zd)\n", ii->mem_, ii->size_); + return; + } + if (ii->h_ == NULL) { + ipc::error("fail release: invalid id (h = null)\n"); + return; + } + ::UnmapViewOfFile(static_cast(ii->mem_)); + ::CloseHandle(ii->h_); + mem::free(ii); } -void remove(char const * /*name*/) { +void remove(char const * name) { + if (name == nullptr || name[0] == '\0') { + ipc::error("fail remove: name is empty\n"); + return; + } + // Do Nothing. } } // namespace shm diff --git a/src/shm.cpp b/src/shm.cpp index efeaba6..37227c1 100644 --- a/src/shm.cpp +++ b/src/shm.cpp @@ -59,15 +59,14 @@ char const * handle::name() const { bool handle::acquire(char const * name, std::size_t size, unsigned mode) { release(); - impl(p_)->id_ = shm::acquire((impl(p_)->n_ = name).c_str(), - impl(p_)->s_ = size, mode); - impl(p_)->m_ = shm::to_mem (impl(p_)->id_); + impl(p_)->id_ = shm::acquire((impl(p_)->n_ = name).c_str(), size, mode); + impl(p_)->m_ = shm::get_mem(impl(p_)->id_, &(impl(p_)->s_)); return valid(); } void handle::release() { if (!valid()) return; - shm::release(impl(p_)->id_, impl(p_)->m_, impl(p_)->s_); + shm::release(impl(p_)->id_); impl(p_)->id_ = nullptr; impl(p_)->m_ = nullptr; impl(p_)->s_ = 0; diff --git a/test/test_ipc.cpp b/test/test_ipc.cpp index 91e8a62..8e103e0 100644 --- a/test/test_ipc.cpp +++ b/test/test_ipc.cpp @@ -347,6 +347,8 @@ void Unit::test_route() { t1.join(); t2.join(); + + test_prod_cons(); // test & verify } void Unit::test_route_rtt() { diff --git a/test/test_shm.cpp b/test/test_shm.cpp index 5fa39c9..01a2a34 100644 --- a/test/test_shm.cpp +++ b/test/test_shm.cpp @@ -38,15 +38,15 @@ void Unit::test_acquire() { QVERIFY(!shm_hd__.valid()); QVERIFY(shm_hd__.acquire("my-test-1", 1024)); - QVERIFY(shm_hd__.size() == 1024); + QVERIFY(shm_hd__.valid()); QCOMPARE(shm_hd__.name(), "my-test-1"); QVERIFY(shm_hd__.acquire("my-test-2", 2048)); - QVERIFY(shm_hd__.size() == 2048); + QVERIFY(shm_hd__.valid()); QCOMPARE(shm_hd__.name(), "my-test-2"); QVERIFY(shm_hd__.acquire("my-test-3", 4096)); - QVERIFY(shm_hd__.size() == 4096); + QVERIFY(shm_hd__.valid()); QCOMPARE(shm_hd__.name(), "my-test-3"); }