mirror of
https://github.com/mutouyun/cpp-ipc.git
synced 2025-12-07 01:06:45 +08:00
update shm interfaces
This commit is contained in:
parent
10e6cca8b0
commit
557a849bdf
@ -29,7 +29,6 @@ using uint_t = typename uint<N>::type;
|
|||||||
enum : std::size_t {
|
enum : std::size_t {
|
||||||
invalid_value = (std::numeric_limits<std::size_t>::max)(),
|
invalid_value = (std::numeric_limits<std::size_t>::max)(),
|
||||||
data_length = 64,
|
data_length = 64,
|
||||||
name_length = 64,
|
|
||||||
default_timeut = 100 // ms
|
default_timeut = 100 // ms
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -15,8 +15,8 @@ enum : unsigned {
|
|||||||
};
|
};
|
||||||
|
|
||||||
IPC_EXPORT id_t acquire(char const * name, std::size_t size, unsigned mode = create | open);
|
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 * get_mem(id_t id, std::size_t * size);
|
||||||
IPC_EXPORT void release(id_t id, void * mem, std::size_t size);
|
IPC_EXPORT void release(id_t id);
|
||||||
IPC_EXPORT void remove (char const * name);
|
IPC_EXPORT void remove (char const * name);
|
||||||
|
|
||||||
class IPC_EXPORT handle {
|
class IPC_EXPORT handle {
|
||||||
|
|||||||
@ -3,6 +3,7 @@
|
|||||||
#include <sys/shm.h>
|
#include <sys/shm.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
|
#include <sys/types.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
@ -14,13 +15,19 @@
|
|||||||
|
|
||||||
#include "def.h"
|
#include "def.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "memory/resource.h"
|
#include "pool_alloc.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
struct info_t {
|
struct info_t {
|
||||||
std::atomic_size_t acc_;
|
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) {
|
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<info_t*>(static_cast<ipc::byte_t*>(mem) + size - sizeof(info_t))->acc_;
|
return reinterpret_cast<info_t*>(static_cast<ipc::byte_t*>(mem) + size - sizeof(info_t))->acc_;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline auto& str_of(void* mem, std::size_t size) {
|
|
||||||
return reinterpret_cast<info_t*>(static_cast<ipc::byte_t*>(mem) + size - sizeof(info_t))->name_;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // internal-linkage
|
} // internal-linkage
|
||||||
|
|
||||||
namespace ipc {
|
namespace ipc {
|
||||||
namespace shm {
|
namespace shm {
|
||||||
|
|
||||||
id_t acquire(char const * name, std::size_t size, unsigned mode) {
|
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;
|
return nullptr;
|
||||||
}
|
}
|
||||||
std::string op_name = std::string{"__IPC_SHM__"} + name;
|
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<int>(op_name.size()), op_name.c_str());
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
// Open the object for read-write access.
|
// Open the object for read-write access.
|
||||||
int flag = O_RDWR;
|
int flag = O_RDWR;
|
||||||
switch (mode) {
|
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);
|
ipc::error("fail shm_open[%d]: %s\n", errno, name);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
size = calc_size(size);
|
auto ii = mem::alloc<id_info_t>();
|
||||||
if (::ftruncate(fd, static_cast<off_t>(size)) != 0) {
|
ii->fd_ = fd;
|
||||||
ipc::error("fail ftruncate[%d]: %s\n", errno, name);
|
ii->size_ = size;
|
||||||
::close(fd);
|
ii->name_ = std::move(op_name);
|
||||||
::shm_unlink(op_name.c_str());
|
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;
|
return nullptr;
|
||||||
}
|
}
|
||||||
void* mem = ::mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
auto ii = static_cast<id_info_t*>(id);
|
||||||
::close(fd);
|
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<std::size_t>(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<off_t>(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) {
|
if (mem == MAP_FAILED) {
|
||||||
ipc::error("fail mmap[%d]: %s\n", errno, name);
|
ipc::error("fail mmap[%d]: %s, size = %zd\n", errno, ii->name_.c_str(), ii->size_);
|
||||||
::shm_unlink(op_name.c_str());
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
if (acc_of(mem, size).fetch_add(1, std::memory_order_release) == 0) {
|
::close(fd);
|
||||||
std::memcpy(&str_of(mem, size), op_name.c_str(), op_name.size());
|
ii->fd_ = -1;
|
||||||
}
|
ii->mem_ = mem;
|
||||||
return static_cast<id_t>(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) {
|
void release(id_t id) {
|
||||||
return static_cast<void *>(id);
|
if (id == nullptr) {
|
||||||
}
|
ipc::error("fail release: invalid id (null)\n");
|
||||||
|
|
||||||
void release(id_t id, void * mem, std::size_t size) {
|
|
||||||
if (mem == nullptr) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (mem != to_mem(id)) {
|
auto ii = static_cast<id_info_t*>(id);
|
||||||
|
if (ii->mem_ == nullptr || ii->size_ == 0) {
|
||||||
|
ipc::error("fail release: invalid id (mem = %p, size = %zd)\n", ii->mem_, ii->size_);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
size = calc_size(size);
|
if (acc_of(ii->mem_, ii->size_).fetch_sub(1, std::memory_order_acquire) == 1) {
|
||||||
if (acc_of(mem, size).fetch_sub(1, std::memory_order_acquire) == 1) {
|
::munmap(ii->mem_, ii->size_);
|
||||||
char name[ipc::name_length] = {};
|
::shm_unlink(ii->name_.c_str());
|
||||||
std::memcpy(name, &str_of(mem, size), sizeof(name));
|
|
||||||
::munmap(mem, size);
|
|
||||||
::shm_unlink(name);
|
|
||||||
}
|
}
|
||||||
else ::munmap(mem, size);
|
else ::munmap(ii->mem_, ii->size_);
|
||||||
|
mem::free(ii);
|
||||||
}
|
}
|
||||||
|
|
||||||
void remove(char const * name) {
|
void remove(char const * name) {
|
||||||
if (name == nullptr || name[0] == '\0') {
|
if (name == nullptr || name[0] == '\0') {
|
||||||
|
ipc::error("fail remove: name is empty\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
std::string op_name = std::string{"__IPC_SHM__"} + name;
|
::shm_unlink((std::string{"__IPC_SHM__"} + name).c_str());
|
||||||
if (op_name.size() >= ipc::name_length) {
|
|
||||||
ipc::error("name is too long!: [%d]%s\n", static_cast<int>(op_name.size()), op_name.c_str());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
::shm_unlink(op_name.c_str());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace shm
|
} // namespace shm
|
||||||
|
|||||||
@ -7,14 +7,26 @@
|
|||||||
|
|
||||||
#include "def.h"
|
#include "def.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "memory/resource.h"
|
#include "pool_alloc.h"
|
||||||
|
|
||||||
#include "platform/to_tchar.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 ipc {
|
||||||
namespace shm {
|
namespace shm {
|
||||||
|
|
||||||
id_t acquire(char const * name, std::size_t size, unsigned mode) {
|
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;
|
return nullptr;
|
||||||
}
|
}
|
||||||
HANDLE h;
|
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<int>(::GetLastError()), name);
|
ipc::error("fail CreateFileMapping/OpenFileMapping[%d]: %s\n", static_cast<int>(::GetLastError()), name);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return static_cast<id_t>(h);
|
auto ii = mem::alloc<id_info_t>();
|
||||||
|
ii->h_ = h;
|
||||||
|
ii->size_ = size;
|
||||||
|
return ii;
|
||||||
}
|
}
|
||||||
|
|
||||||
void * to_mem(id_t id) {
|
void * get_mem(id_t id, std::size_t * size) {
|
||||||
if (id == nullptr) return nullptr;
|
if (id == nullptr) {
|
||||||
HANDLE h = static_cast<HANDLE>(id);
|
ipc::error("fail get_mem: invalid id (null)\n");
|
||||||
LPVOID mem = ::MapViewOfFile(h, FILE_MAP_ALL_ACCESS, 0, 0, 0);
|
return nullptr;
|
||||||
|
}
|
||||||
|
auto ii = static_cast<id_info_t*>(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) {
|
if (mem == NULL) {
|
||||||
ipc::error("fail MapViewOfFile[%d]\n", static_cast<int>(::GetLastError()));
|
ipc::error("fail MapViewOfFile[%d]\n", static_cast<int>(::GetLastError()));
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
PMEMORY_BASIC_INFORMATION mem_info;
|
||||||
|
if (::VirtualQuery(mem, &mem_info, sizeof(mem_info)) == 0) {
|
||||||
|
ipc::error("fail VirtualQuery[%d]\n", static_cast<int>(::GetLastError()));
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
ii->mem_ = mem;
|
||||||
|
ii->size_ = static_cast<std::size_t>(mem_info.RegionSize);
|
||||||
|
if (size != nullptr) *size = ii->size_;
|
||||||
return static_cast<void *>(mem);
|
return static_cast<void *>(mem);
|
||||||
}
|
}
|
||||||
|
|
||||||
void release(id_t id, void * mem, std::size_t /*size*/) {
|
void release(id_t id) {
|
||||||
if (id == nullptr) return;
|
if (id == nullptr) {
|
||||||
if (mem == nullptr) return;
|
ipc::error("fail release: invalid id (null)\n");
|
||||||
::UnmapViewOfFile(static_cast<LPVOID>(mem));
|
return;
|
||||||
::CloseHandle(static_cast<HANDLE>(id));
|
}
|
||||||
|
auto ii = static_cast<id_info_t*>(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<LPCVOID>(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
|
} // namespace shm
|
||||||
|
|||||||
@ -59,15 +59,14 @@ char const * handle::name() const {
|
|||||||
|
|
||||||
bool handle::acquire(char const * name, std::size_t size, unsigned mode) {
|
bool handle::acquire(char const * name, std::size_t size, unsigned mode) {
|
||||||
release();
|
release();
|
||||||
impl(p_)->id_ = shm::acquire((impl(p_)->n_ = name).c_str(),
|
impl(p_)->id_ = shm::acquire((impl(p_)->n_ = name).c_str(), size, mode);
|
||||||
impl(p_)->s_ = size, mode);
|
impl(p_)->m_ = shm::get_mem(impl(p_)->id_, &(impl(p_)->s_));
|
||||||
impl(p_)->m_ = shm::to_mem (impl(p_)->id_);
|
|
||||||
return valid();
|
return valid();
|
||||||
}
|
}
|
||||||
|
|
||||||
void handle::release() {
|
void handle::release() {
|
||||||
if (!valid()) return;
|
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_)->id_ = nullptr;
|
||||||
impl(p_)->m_ = nullptr;
|
impl(p_)->m_ = nullptr;
|
||||||
impl(p_)->s_ = 0;
|
impl(p_)->s_ = 0;
|
||||||
|
|||||||
@ -347,6 +347,8 @@ void Unit::test_route() {
|
|||||||
|
|
||||||
t1.join();
|
t1.join();
|
||||||
t2.join();
|
t2.join();
|
||||||
|
|
||||||
|
test_prod_cons<ipc::route, 1, 1>(); // test & verify
|
||||||
}
|
}
|
||||||
|
|
||||||
void Unit::test_route_rtt() {
|
void Unit::test_route_rtt() {
|
||||||
|
|||||||
@ -38,15 +38,15 @@ void Unit::test_acquire() {
|
|||||||
QVERIFY(!shm_hd__.valid());
|
QVERIFY(!shm_hd__.valid());
|
||||||
|
|
||||||
QVERIFY(shm_hd__.acquire("my-test-1", 1024));
|
QVERIFY(shm_hd__.acquire("my-test-1", 1024));
|
||||||
QVERIFY(shm_hd__.size() == 1024);
|
QVERIFY(shm_hd__.valid());
|
||||||
QCOMPARE(shm_hd__.name(), "my-test-1");
|
QCOMPARE(shm_hd__.name(), "my-test-1");
|
||||||
|
|
||||||
QVERIFY(shm_hd__.acquire("my-test-2", 2048));
|
QVERIFY(shm_hd__.acquire("my-test-2", 2048));
|
||||||
QVERIFY(shm_hd__.size() == 2048);
|
QVERIFY(shm_hd__.valid());
|
||||||
QCOMPARE(shm_hd__.name(), "my-test-2");
|
QCOMPARE(shm_hd__.name(), "my-test-2");
|
||||||
|
|
||||||
QVERIFY(shm_hd__.acquire("my-test-3", 4096));
|
QVERIFY(shm_hd__.acquire("my-test-3", 4096));
|
||||||
QVERIFY(shm_hd__.size() == 4096);
|
QVERIFY(shm_hd__.valid());
|
||||||
QCOMPARE(shm_hd__.name(), "my-test-3");
|
QCOMPARE(shm_hd__.name(), "my-test-3");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user