mirror of
https://github.com/mutouyun/cpp-ipc.git
synced 2025-12-06 16:56:45 +08:00
Added a cleanup interface for shared memory handles
This commit is contained in:
parent
805490605e
commit
5071fb5db6
@ -11,8 +11,8 @@ namespace mem {
|
|||||||
|
|
||||||
class IPC_EXPORT pool_alloc {
|
class IPC_EXPORT pool_alloc {
|
||||||
public:
|
public:
|
||||||
static void* alloc(std::size_t size);
|
static void* alloc(std::size_t size) noexcept;
|
||||||
static void free (void* p, std::size_t size);
|
static void free (void* p, std::size_t size) noexcept;
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////
|
||||||
|
|||||||
@ -17,9 +17,9 @@ 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 * get_mem(id_t id, std::size_t * size);
|
IPC_EXPORT void * get_mem(id_t id, std::size_t * size);
|
||||||
IPC_EXPORT std::int32_t release(id_t id);
|
IPC_EXPORT std::int32_t release(id_t id) noexcept;
|
||||||
IPC_EXPORT void remove (id_t id);
|
IPC_EXPORT void remove (id_t id) noexcept;
|
||||||
IPC_EXPORT void remove (char const * name);
|
IPC_EXPORT void remove (char const * name) noexcept;
|
||||||
|
|
||||||
IPC_EXPORT std::int32_t get_ref(id_t id);
|
IPC_EXPORT std::int32_t get_ref(id_t id);
|
||||||
IPC_EXPORT void sub_ref(id_t id);
|
IPC_EXPORT void sub_ref(id_t id);
|
||||||
@ -45,6 +45,10 @@ public:
|
|||||||
bool acquire(char const * name, std::size_t size, unsigned mode = create | open);
|
bool acquire(char const * name, std::size_t size, unsigned mode = create | open);
|
||||||
std::int32_t release();
|
std::int32_t release();
|
||||||
|
|
||||||
|
// Clean the handle file.
|
||||||
|
void clear() noexcept;
|
||||||
|
static void clear_storage(char const * name) noexcept;
|
||||||
|
|
||||||
void* get() const;
|
void* get() const;
|
||||||
|
|
||||||
void attach(id_t);
|
void attach(id_t);
|
||||||
|
|||||||
@ -19,17 +19,17 @@ namespace mem {
|
|||||||
|
|
||||||
class static_alloc {
|
class static_alloc {
|
||||||
public:
|
public:
|
||||||
static void swap(static_alloc&) {}
|
static void swap(static_alloc&) noexcept {}
|
||||||
|
|
||||||
static void* alloc(std::size_t size) {
|
static void* alloc(std::size_t size) noexcept {
|
||||||
return size ? std::malloc(size) : nullptr;
|
return size ? std::malloc(size) : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void free(void* p) {
|
static void free(void* p) noexcept {
|
||||||
std::free(p);
|
std::free(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void free(void* p, std::size_t /*size*/) {
|
static void free(void* p, std::size_t /*size*/) noexcept {
|
||||||
free(p);
|
free(p);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@ -153,7 +153,7 @@ void * get_mem(id_t id, std::size_t * size) {
|
|||||||
return mem;
|
return mem;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::int32_t release(id_t id) {
|
std::int32_t release(id_t id) noexcept {
|
||||||
if (id == nullptr) {
|
if (id == nullptr) {
|
||||||
ipc::error("fail release: invalid id (null)\n");
|
ipc::error("fail release: invalid id (null)\n");
|
||||||
return -1;
|
return -1;
|
||||||
@ -175,7 +175,7 @@ std::int32_t release(id_t id) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void remove(id_t id) {
|
void remove(id_t id) noexcept {
|
||||||
if (id == nullptr) {
|
if (id == nullptr) {
|
||||||
ipc::error("fail remove: invalid id (null)\n");
|
ipc::error("fail remove: invalid id (null)\n");
|
||||||
return;
|
return;
|
||||||
|
|||||||
@ -5,11 +5,11 @@
|
|||||||
namespace ipc {
|
namespace ipc {
|
||||||
namespace mem {
|
namespace mem {
|
||||||
|
|
||||||
void* pool_alloc::alloc(std::size_t size) {
|
void* pool_alloc::alloc(std::size_t size) noexcept {
|
||||||
return async_pool_alloc::alloc(size);
|
return async_pool_alloc::alloc(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pool_alloc::free(void* p, std::size_t size) {
|
void pool_alloc::free(void* p, std::size_t size) noexcept {
|
||||||
async_pool_alloc::free(p, size);
|
async_pool_alloc::free(p, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -89,6 +89,18 @@ std::int32_t handle::release() {
|
|||||||
return shm::release(detach());
|
return shm::release(detach());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void handle::clear() noexcept {
|
||||||
|
if (impl(p_)->id_ == nullptr) return;
|
||||||
|
shm::remove(detach());
|
||||||
|
}
|
||||||
|
|
||||||
|
void handle::clear_storage(char const * name) noexcept {
|
||||||
|
if (name == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
shm::remove(name);
|
||||||
|
}
|
||||||
|
|
||||||
void* handle::get() const {
|
void* handle::get() const {
|
||||||
return impl(p_)->m_;
|
return impl(p_)->m_;
|
||||||
}
|
}
|
||||||
|
|||||||
196
test/test.h
196
test/test.h
@ -1,86 +1,110 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#include "gtest/gtest.h"
|
#include "gtest/gtest.h"
|
||||||
|
|
||||||
#include "capo/stopwatch.hpp"
|
#include "capo/stopwatch.hpp"
|
||||||
|
|
||||||
#include "thread_pool.h"
|
#include "thread_pool.h"
|
||||||
|
|
||||||
namespace ipc_ut {
|
#include "libipc/platform/detail.h"
|
||||||
|
#ifdef IPC_OS_LINUX_
|
||||||
template <typename Dur>
|
#include <fcntl.h> // ::open
|
||||||
struct unit;
|
#endif
|
||||||
|
|
||||||
template <> struct unit<std::chrono::nanoseconds> {
|
namespace ipc_ut {
|
||||||
constexpr static char const * str() noexcept {
|
|
||||||
return "ns";
|
template <typename Dur>
|
||||||
}
|
struct unit;
|
||||||
};
|
|
||||||
|
template <> struct unit<std::chrono::nanoseconds> {
|
||||||
template <> struct unit<std::chrono::microseconds> {
|
constexpr static char const * str() noexcept {
|
||||||
constexpr static char const * str() noexcept {
|
return "ns";
|
||||||
return "us";
|
}
|
||||||
}
|
};
|
||||||
};
|
|
||||||
|
template <> struct unit<std::chrono::microseconds> {
|
||||||
template <> struct unit<std::chrono::milliseconds> {
|
constexpr static char const * str() noexcept {
|
||||||
constexpr static char const * str() noexcept {
|
return "us";
|
||||||
return "ms";
|
}
|
||||||
}
|
};
|
||||||
};
|
|
||||||
|
template <> struct unit<std::chrono::milliseconds> {
|
||||||
template <> struct unit<std::chrono::seconds> {
|
constexpr static char const * str() noexcept {
|
||||||
constexpr static char const * str() noexcept {
|
return "ms";
|
||||||
return "sec";
|
}
|
||||||
}
|
};
|
||||||
};
|
|
||||||
|
template <> struct unit<std::chrono::seconds> {
|
||||||
struct test_stopwatch {
|
constexpr static char const * str() noexcept {
|
||||||
capo::stopwatch<> sw_;
|
return "sec";
|
||||||
std::atomic_flag started_ = ATOMIC_FLAG_INIT;
|
}
|
||||||
|
};
|
||||||
void start() {
|
|
||||||
if (!started_.test_and_set()) {
|
struct test_stopwatch {
|
||||||
sw_.start();
|
capo::stopwatch<> sw_;
|
||||||
}
|
std::atomic_flag started_ = ATOMIC_FLAG_INIT;
|
||||||
}
|
|
||||||
|
void start() {
|
||||||
template <typename ToDur = std::chrono::nanoseconds>
|
if (!started_.test_and_set()) {
|
||||||
void print_elapsed(int N, int Loops, char const * message = "") {
|
sw_.start();
|
||||||
auto ts = sw_.elapsed<ToDur>();
|
}
|
||||||
std::cout << "[" << N << ", \t" << Loops << "] " << message << "\t"
|
}
|
||||||
<< (double(ts) / double(Loops)) << " " << unit<ToDur>::str() << std::endl;
|
|
||||||
}
|
template <typename ToDur = std::chrono::nanoseconds>
|
||||||
|
void print_elapsed(int N, int Loops, char const * message = "") {
|
||||||
template <int Factor, typename ToDur = std::chrono::nanoseconds>
|
auto ts = sw_.elapsed<ToDur>();
|
||||||
void print_elapsed(int N, int M, int Loops, char const * message = "") {
|
std::cout << "[" << N << ", \t" << Loops << "] " << message << "\t"
|
||||||
auto ts = sw_.elapsed<ToDur>();
|
<< (double(ts) / double(Loops)) << " " << unit<ToDur>::str() << std::endl;
|
||||||
std::cout << "[" << N << "-" << M << ", \t" << Loops << "] " << message << "\t"
|
}
|
||||||
<< (double(ts) / double(Factor ? (Loops * Factor) : (Loops * N))) << " " << unit<ToDur>::str() << std::endl;
|
|
||||||
}
|
template <int Factor, typename ToDur = std::chrono::nanoseconds>
|
||||||
|
void print_elapsed(int N, int M, int Loops, char const * message = "") {
|
||||||
template <typename ToDur = std::chrono::nanoseconds>
|
auto ts = sw_.elapsed<ToDur>();
|
||||||
void print_elapsed(int N, int M, int Loops, char const * message = "") {
|
std::cout << "[" << N << "-" << M << ", \t" << Loops << "] " << message << "\t"
|
||||||
print_elapsed<0, ToDur>(N, M, Loops, message);
|
<< (double(ts) / double(Factor ? (Loops * Factor) : (Loops * N))) << " " << unit<ToDur>::str() << std::endl;
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
template <typename ToDur = std::chrono::nanoseconds>
|
||||||
inline static thread_pool & sender() {
|
void print_elapsed(int N, int M, int Loops, char const * message = "") {
|
||||||
static thread_pool pool;
|
print_elapsed<0, ToDur>(N, M, Loops, message);
|
||||||
return pool;
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
inline static thread_pool & reader() {
|
inline static thread_pool & sender() {
|
||||||
static thread_pool pool;
|
static thread_pool pool;
|
||||||
return pool;
|
return pool;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace ipc_ut
|
inline static thread_pool & reader() {
|
||||||
|
static thread_pool pool;
|
||||||
|
return pool;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef IPC_OS_LINUX_
|
||||||
|
inline bool check_exist(char const *name) noexcept {
|
||||||
|
int fd = ::open((std::string{"/dev/shm/__IPC_SHM__"} + name).c_str(), O_RDONLY);
|
||||||
|
if (fd == -1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
::close(fd);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
inline bool expect_exist(char const *name, bool expected) noexcept {
|
||||||
|
#ifdef IPC_OS_LINUX_
|
||||||
|
return ipc_ut::check_exist(name) == expected;
|
||||||
|
#else
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace ipc_ut
|
||||||
|
|||||||
@ -1,102 +1,134 @@
|
|||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
#include "libipc/shm.h"
|
#include "libipc/shm.h"
|
||||||
#include "test.h"
|
|
||||||
|
#include "test.h"
|
||||||
using namespace ipc::shm;
|
|
||||||
|
using namespace ipc::shm;
|
||||||
namespace {
|
|
||||||
|
namespace {
|
||||||
TEST(SHM, acquire) {
|
|
||||||
handle shm_hd;
|
TEST(SHM, acquire) {
|
||||||
EXPECT_FALSE(shm_hd.valid());
|
handle shm_hd;
|
||||||
|
EXPECT_FALSE(shm_hd.valid());
|
||||||
EXPECT_TRUE(shm_hd.acquire("my-test-1", 1024));
|
|
||||||
EXPECT_TRUE(shm_hd.valid());
|
EXPECT_TRUE(shm_hd.acquire("my-test-1", 1024));
|
||||||
EXPECT_STREQ(shm_hd.name(), "my-test-1");
|
EXPECT_TRUE(shm_hd.valid());
|
||||||
|
EXPECT_STREQ(shm_hd.name(), "my-test-1");
|
||||||
EXPECT_TRUE(shm_hd.acquire("my-test-2", 2048));
|
|
||||||
EXPECT_TRUE(shm_hd.valid());
|
EXPECT_TRUE(shm_hd.acquire("my-test-2", 2048));
|
||||||
EXPECT_STREQ(shm_hd.name(), "my-test-2");
|
EXPECT_TRUE(shm_hd.valid());
|
||||||
|
EXPECT_STREQ(shm_hd.name(), "my-test-2");
|
||||||
EXPECT_TRUE(shm_hd.acquire("my-test-3", 4096));
|
|
||||||
EXPECT_TRUE(shm_hd.valid());
|
EXPECT_TRUE(shm_hd.acquire("my-test-3", 4096));
|
||||||
EXPECT_STREQ(shm_hd.name(), "my-test-3");
|
EXPECT_TRUE(shm_hd.valid());
|
||||||
}
|
EXPECT_STREQ(shm_hd.name(), "my-test-3");
|
||||||
|
}
|
||||||
TEST(SHM, release) {
|
|
||||||
handle shm_hd;
|
TEST(SHM, release) {
|
||||||
EXPECT_FALSE(shm_hd.valid());
|
handle shm_hd;
|
||||||
shm_hd.release();
|
EXPECT_FALSE(shm_hd.valid());
|
||||||
EXPECT_FALSE(shm_hd.valid());
|
shm_hd.release();
|
||||||
EXPECT_TRUE(shm_hd.acquire("release-test-1", 512));
|
EXPECT_FALSE(shm_hd.valid());
|
||||||
EXPECT_TRUE(shm_hd.valid());
|
EXPECT_TRUE(shm_hd.acquire("release-test-1", 512));
|
||||||
shm_hd.release();
|
EXPECT_TRUE(shm_hd.valid());
|
||||||
EXPECT_FALSE(shm_hd.valid());
|
shm_hd.release();
|
||||||
}
|
EXPECT_FALSE(shm_hd.valid());
|
||||||
|
}
|
||||||
TEST(SHM, get) {
|
|
||||||
handle shm_hd;
|
TEST(SHM, get) {
|
||||||
EXPECT_TRUE(shm_hd.get() == nullptr);
|
handle shm_hd;
|
||||||
EXPECT_TRUE(shm_hd.acquire("get-test", 2048));
|
EXPECT_TRUE(shm_hd.get() == nullptr);
|
||||||
|
EXPECT_TRUE(shm_hd.acquire("get-test", 2048));
|
||||||
auto mem = shm_hd.get();
|
|
||||||
EXPECT_TRUE(mem != nullptr);
|
auto mem = shm_hd.get();
|
||||||
EXPECT_TRUE(mem == shm_hd.get());
|
EXPECT_TRUE(mem != nullptr);
|
||||||
|
EXPECT_TRUE(mem == shm_hd.get());
|
||||||
std::uint8_t buf[1024] = {};
|
|
||||||
EXPECT_TRUE(memcmp(mem, buf, sizeof(buf)) == 0);
|
std::uint8_t buf[1024] = {};
|
||||||
|
EXPECT_TRUE(memcmp(mem, buf, sizeof(buf)) == 0);
|
||||||
handle shm_other(shm_hd.name(), shm_hd.size());
|
|
||||||
EXPECT_TRUE(shm_other.get() != shm_hd.get());
|
handle shm_other(shm_hd.name(), shm_hd.size());
|
||||||
}
|
EXPECT_TRUE(shm_other.get() != shm_hd.get());
|
||||||
|
}
|
||||||
TEST(SHM, hello) {
|
|
||||||
handle shm_hd;
|
TEST(SHM, hello) {
|
||||||
EXPECT_TRUE(shm_hd.acquire("hello-test", 128));
|
handle shm_hd;
|
||||||
auto mem = shm_hd.get();
|
EXPECT_TRUE(shm_hd.acquire("hello-test", 128));
|
||||||
EXPECT_TRUE(mem != nullptr);
|
auto mem = shm_hd.get();
|
||||||
|
EXPECT_TRUE(mem != nullptr);
|
||||||
constexpr char hello[] = "hello!";
|
|
||||||
std::memcpy(mem, hello, sizeof(hello));
|
constexpr char hello[] = "hello!";
|
||||||
EXPECT_STREQ((char const *)shm_hd.get(), hello);
|
std::memcpy(mem, hello, sizeof(hello));
|
||||||
|
EXPECT_STREQ((char const *)shm_hd.get(), hello);
|
||||||
shm_hd.release();
|
|
||||||
EXPECT_TRUE(shm_hd.get() == nullptr);
|
shm_hd.release();
|
||||||
EXPECT_TRUE(shm_hd.acquire("hello-test", 1024));
|
EXPECT_TRUE(shm_hd.get() == nullptr);
|
||||||
|
EXPECT_TRUE(shm_hd.acquire("hello-test", 1024));
|
||||||
mem = shm_hd.get();
|
|
||||||
EXPECT_TRUE(mem != nullptr);
|
mem = shm_hd.get();
|
||||||
std::uint8_t buf[1024] = {};
|
EXPECT_TRUE(mem != nullptr);
|
||||||
EXPECT_TRUE(memcmp(mem, buf, sizeof(buf)) == 0);
|
std::uint8_t buf[1024] = {};
|
||||||
|
EXPECT_TRUE(memcmp(mem, buf, sizeof(buf)) == 0);
|
||||||
std::memcpy(mem, hello, sizeof(hello));
|
|
||||||
EXPECT_STREQ((char const *)shm_hd.get(), hello);
|
std::memcpy(mem, hello, sizeof(hello));
|
||||||
}
|
EXPECT_STREQ((char const *)shm_hd.get(), hello);
|
||||||
|
}
|
||||||
TEST(SHM, mt) {
|
|
||||||
handle shm_hd;
|
TEST(SHM, mt) {
|
||||||
EXPECT_TRUE(shm_hd.acquire("mt-test", 256));
|
handle shm_hd;
|
||||||
constexpr char hello[] = "hello!";
|
EXPECT_TRUE(shm_hd.acquire("mt-test", 256));
|
||||||
std::memcpy(shm_hd.get(), hello, sizeof(hello));
|
constexpr char hello[] = "hello!";
|
||||||
|
std::memcpy(shm_hd.get(), hello, sizeof(hello));
|
||||||
std::thread {
|
|
||||||
[&shm_hd] {
|
std::thread {
|
||||||
handle shm_mt(shm_hd.name(), shm_hd.size());
|
[&shm_hd] {
|
||||||
shm_hd.release();
|
handle shm_mt(shm_hd.name(), shm_hd.size());
|
||||||
constexpr char hello[] = "hello!";
|
shm_hd.release();
|
||||||
EXPECT_STREQ((char const *)shm_mt.get(), hello);
|
constexpr char hello[] = "hello!";
|
||||||
}
|
EXPECT_STREQ((char const *)shm_mt.get(), hello);
|
||||||
}.join();
|
}
|
||||||
|
}.join();
|
||||||
EXPECT_TRUE(shm_hd.get() == nullptr);
|
|
||||||
EXPECT_FALSE(shm_hd.valid());
|
EXPECT_TRUE(shm_hd.get() == nullptr);
|
||||||
|
EXPECT_FALSE(shm_hd.valid());
|
||||||
EXPECT_TRUE(shm_hd.acquire("mt-test", 1024));
|
|
||||||
std::uint8_t buf[1024] = {};
|
EXPECT_TRUE(shm_hd.acquire("mt-test", 1024));
|
||||||
EXPECT_TRUE(memcmp(shm_hd.get(), buf, sizeof(buf)) == 0);
|
std::uint8_t buf[1024] = {};
|
||||||
}
|
EXPECT_TRUE(memcmp(shm_hd.get(), buf, sizeof(buf)) == 0);
|
||||||
|
}
|
||||||
} // internal-linkage
|
|
||||||
|
TEST(SHM, remove) {
|
||||||
|
{
|
||||||
|
auto id = ipc::shm::acquire("hello-remove", 111);
|
||||||
|
EXPECT_TRUE(ipc_ut::expect_exist("hello-remove", true));
|
||||||
|
ipc::shm::remove(id);
|
||||||
|
EXPECT_TRUE(ipc_ut::expect_exist("hello-remove", false));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
auto id = ipc::shm::acquire("hello-remove", 111);
|
||||||
|
EXPECT_TRUE(ipc_ut::expect_exist("hello-remove", true));
|
||||||
|
ipc::shm::release(id);
|
||||||
|
EXPECT_TRUE(ipc_ut::expect_exist("hello-remove", true));
|
||||||
|
ipc::shm::remove("hello-remove");
|
||||||
|
EXPECT_TRUE(ipc_ut::expect_exist("hello-remove", false));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
handle shm_hd;
|
||||||
|
EXPECT_TRUE(shm_hd.acquire("mt-test", 256));
|
||||||
|
EXPECT_TRUE(ipc_ut::expect_exist("mt-test", true));
|
||||||
|
shm_hd.clear();
|
||||||
|
EXPECT_TRUE(ipc_ut::expect_exist("mt-test", false));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
handle shm_hd;
|
||||||
|
EXPECT_TRUE(shm_hd.acquire("mt-test", 256));
|
||||||
|
EXPECT_TRUE(ipc_ut::expect_exist("mt-test", true));
|
||||||
|
shm_hd.clear_storage("mt-test");
|
||||||
|
EXPECT_TRUE(ipc_ut::expect_exist("mt-test", false));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // internal-linkage
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user