diff --git a/include/libipc/pool_alloc.h b/include/libipc/pool_alloc.h index a889be7..c6be5a0 100755 --- a/include/libipc/pool_alloc.h +++ b/include/libipc/pool_alloc.h @@ -11,8 +11,8 @@ namespace mem { class IPC_EXPORT pool_alloc { public: - static void* alloc(std::size_t size); - static void free (void* p, std::size_t size); + static void* alloc(std::size_t size) noexcept; + static void free (void* p, std::size_t size) noexcept; }; //////////////////////////////////////////////////////////////// diff --git a/include/libipc/shm.h b/include/libipc/shm.h index 12e3223..dc24ab4 100755 --- a/include/libipc/shm.h +++ b/include/libipc/shm.h @@ -17,9 +17,9 @@ enum : unsigned { 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 std::int32_t release(id_t id); -IPC_EXPORT void remove (id_t id); -IPC_EXPORT void remove (char const * name); +IPC_EXPORT std::int32_t release(id_t id) noexcept; +IPC_EXPORT void remove (id_t id) noexcept; +IPC_EXPORT void remove (char const * name) noexcept; IPC_EXPORT std::int32_t get_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); std::int32_t release(); + // Clean the handle file. + void clear() noexcept; + static void clear_storage(char const * name) noexcept; + void* get() const; void attach(id_t); diff --git a/src/libipc/memory/alloc.h b/src/libipc/memory/alloc.h index 16bebc9..3a4ce20 100755 --- a/src/libipc/memory/alloc.h +++ b/src/libipc/memory/alloc.h @@ -19,17 +19,17 @@ namespace mem { class static_alloc { 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; } - static void free(void* p) { + static void free(void* p) noexcept { std::free(p); } - static void free(void* p, std::size_t /*size*/) { + static void free(void* p, std::size_t /*size*/) noexcept { free(p); } }; diff --git a/src/libipc/platform/posix/shm_posix.cpp b/src/libipc/platform/posix/shm_posix.cpp index e29bd6f..142fab4 100644 --- a/src/libipc/platform/posix/shm_posix.cpp +++ b/src/libipc/platform/posix/shm_posix.cpp @@ -153,7 +153,7 @@ void * get_mem(id_t id, std::size_t * size) { return mem; } -std::int32_t release(id_t id) { +std::int32_t release(id_t id) noexcept { if (id == nullptr) { ipc::error("fail release: invalid id (null)\n"); return -1; @@ -175,7 +175,7 @@ std::int32_t release(id_t id) { return ret; } -void remove(id_t id) { +void remove(id_t id) noexcept { if (id == nullptr) { ipc::error("fail remove: invalid id (null)\n"); return; diff --git a/src/libipc/pool_alloc.cpp b/src/libipc/pool_alloc.cpp index d19a13c..9824df9 100755 --- a/src/libipc/pool_alloc.cpp +++ b/src/libipc/pool_alloc.cpp @@ -5,11 +5,11 @@ namespace ipc { 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); } -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); } diff --git a/src/libipc/shm.cpp b/src/libipc/shm.cpp index 0845474..32b761e 100755 --- a/src/libipc/shm.cpp +++ b/src/libipc/shm.cpp @@ -89,6 +89,18 @@ std::int32_t handle::release() { 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 { return impl(p_)->m_; } diff --git a/test/test.h b/test/test.h index 19bd22b..ac60a3a 100755 --- a/test/test.h +++ b/test/test.h @@ -1,86 +1,110 @@ -#pragma once - -#include -#include -#include -#include -#include -#include -#include - -#include "gtest/gtest.h" - -#include "capo/stopwatch.hpp" - -#include "thread_pool.h" - -namespace ipc_ut { - -template -struct unit; - -template <> struct unit { - constexpr static char const * str() noexcept { - return "ns"; - } -}; - -template <> struct unit { - constexpr static char const * str() noexcept { - return "us"; - } -}; - -template <> struct unit { - constexpr static char const * str() noexcept { - return "ms"; - } -}; - -template <> struct unit { - constexpr static char const * str() noexcept { - return "sec"; - } -}; - -struct test_stopwatch { - capo::stopwatch<> sw_; - std::atomic_flag started_ = ATOMIC_FLAG_INIT; - - void start() { - if (!started_.test_and_set()) { - sw_.start(); - } - } - - template - void print_elapsed(int N, int Loops, char const * message = "") { - auto ts = sw_.elapsed(); - std::cout << "[" << N << ", \t" << Loops << "] " << message << "\t" - << (double(ts) / double(Loops)) << " " << unit::str() << std::endl; - } - - template - void print_elapsed(int N, int M, int Loops, char const * message = "") { - auto ts = sw_.elapsed(); - std::cout << "[" << N << "-" << M << ", \t" << Loops << "] " << message << "\t" - << (double(ts) / double(Factor ? (Loops * Factor) : (Loops * N))) << " " << unit::str() << std::endl; - } - - template - void print_elapsed(int N, int M, int Loops, char const * message = "") { - print_elapsed<0, ToDur>(N, M, Loops, message); - } -}; - -inline static thread_pool & sender() { - static thread_pool pool; - return pool; -} - -inline static thread_pool & reader() { - static thread_pool pool; - return pool; -} - -} // namespace ipc_ut \ No newline at end of file +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +#include "gtest/gtest.h" + +#include "capo/stopwatch.hpp" + +#include "thread_pool.h" + +#include "libipc/platform/detail.h" +#ifdef IPC_OS_LINUX_ +#include // ::open +#endif + +namespace ipc_ut { + +template +struct unit; + +template <> struct unit { + constexpr static char const * str() noexcept { + return "ns"; + } +}; + +template <> struct unit { + constexpr static char const * str() noexcept { + return "us"; + } +}; + +template <> struct unit { + constexpr static char const * str() noexcept { + return "ms"; + } +}; + +template <> struct unit { + constexpr static char const * str() noexcept { + return "sec"; + } +}; + +struct test_stopwatch { + capo::stopwatch<> sw_; + std::atomic_flag started_ = ATOMIC_FLAG_INIT; + + void start() { + if (!started_.test_and_set()) { + sw_.start(); + } + } + + template + void print_elapsed(int N, int Loops, char const * message = "") { + auto ts = sw_.elapsed(); + std::cout << "[" << N << ", \t" << Loops << "] " << message << "\t" + << (double(ts) / double(Loops)) << " " << unit::str() << std::endl; + } + + template + void print_elapsed(int N, int M, int Loops, char const * message = "") { + auto ts = sw_.elapsed(); + std::cout << "[" << N << "-" << M << ", \t" << Loops << "] " << message << "\t" + << (double(ts) / double(Factor ? (Loops * Factor) : (Loops * N))) << " " << unit::str() << std::endl; + } + + template + void print_elapsed(int N, int M, int Loops, char const * message = "") { + print_elapsed<0, ToDur>(N, M, Loops, message); + } +}; + +inline static thread_pool & sender() { + static thread_pool pool; + return pool; +} + +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 diff --git a/test/test_shm.cpp b/test/test_shm.cpp index 3272dcc..23d486b 100755 --- a/test/test_shm.cpp +++ b/test/test_shm.cpp @@ -1,102 +1,134 @@ -#include -#include -#include - -#include "libipc/shm.h" -#include "test.h" - -using namespace ipc::shm; - -namespace { - -TEST(SHM, acquire) { - handle shm_hd; - EXPECT_FALSE(shm_hd.valid()); - - EXPECT_TRUE(shm_hd.acquire("my-test-1", 1024)); - 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_STREQ(shm_hd.name(), "my-test-2"); - - EXPECT_TRUE(shm_hd.acquire("my-test-3", 4096)); - EXPECT_TRUE(shm_hd.valid()); - EXPECT_STREQ(shm_hd.name(), "my-test-3"); -} - -TEST(SHM, release) { - handle shm_hd; - EXPECT_FALSE(shm_hd.valid()); - shm_hd.release(); - EXPECT_FALSE(shm_hd.valid()); - EXPECT_TRUE(shm_hd.acquire("release-test-1", 512)); - EXPECT_TRUE(shm_hd.valid()); - shm_hd.release(); - EXPECT_FALSE(shm_hd.valid()); -} - -TEST(SHM, get) { - handle shm_hd; - EXPECT_TRUE(shm_hd.get() == nullptr); - EXPECT_TRUE(shm_hd.acquire("get-test", 2048)); - - auto 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); - - handle shm_other(shm_hd.name(), shm_hd.size()); - EXPECT_TRUE(shm_other.get() != shm_hd.get()); -} - -TEST(SHM, hello) { - handle shm_hd; - EXPECT_TRUE(shm_hd.acquire("hello-test", 128)); - auto mem = shm_hd.get(); - EXPECT_TRUE(mem != nullptr); - - constexpr char hello[] = "hello!"; - std::memcpy(mem, hello, sizeof(hello)); - EXPECT_STREQ((char const *)shm_hd.get(), hello); - - shm_hd.release(); - EXPECT_TRUE(shm_hd.get() == nullptr); - EXPECT_TRUE(shm_hd.acquire("hello-test", 1024)); - - mem = shm_hd.get(); - EXPECT_TRUE(mem != nullptr); - 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); -} - -TEST(SHM, mt) { - handle shm_hd; - EXPECT_TRUE(shm_hd.acquire("mt-test", 256)); - constexpr char hello[] = "hello!"; - std::memcpy(shm_hd.get(), hello, sizeof(hello)); - - std::thread { - [&shm_hd] { - handle shm_mt(shm_hd.name(), shm_hd.size()); - shm_hd.release(); - constexpr char hello[] = "hello!"; - EXPECT_STREQ((char const *)shm_mt.get(), hello); - } - }.join(); - - 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(memcmp(shm_hd.get(), buf, sizeof(buf)) == 0); -} - -} // internal-linkage +#include +#include +#include + +#include "libipc/shm.h" + +#include "test.h" + +using namespace ipc::shm; + +namespace { + +TEST(SHM, acquire) { + handle shm_hd; + EXPECT_FALSE(shm_hd.valid()); + + EXPECT_TRUE(shm_hd.acquire("my-test-1", 1024)); + 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_STREQ(shm_hd.name(), "my-test-2"); + + EXPECT_TRUE(shm_hd.acquire("my-test-3", 4096)); + EXPECT_TRUE(shm_hd.valid()); + EXPECT_STREQ(shm_hd.name(), "my-test-3"); +} + +TEST(SHM, release) { + handle shm_hd; + EXPECT_FALSE(shm_hd.valid()); + shm_hd.release(); + EXPECT_FALSE(shm_hd.valid()); + EXPECT_TRUE(shm_hd.acquire("release-test-1", 512)); + EXPECT_TRUE(shm_hd.valid()); + shm_hd.release(); + EXPECT_FALSE(shm_hd.valid()); +} + +TEST(SHM, get) { + handle shm_hd; + EXPECT_TRUE(shm_hd.get() == nullptr); + EXPECT_TRUE(shm_hd.acquire("get-test", 2048)); + + auto 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); + + handle shm_other(shm_hd.name(), shm_hd.size()); + EXPECT_TRUE(shm_other.get() != shm_hd.get()); +} + +TEST(SHM, hello) { + handle shm_hd; + EXPECT_TRUE(shm_hd.acquire("hello-test", 128)); + auto mem = shm_hd.get(); + EXPECT_TRUE(mem != nullptr); + + constexpr char hello[] = "hello!"; + std::memcpy(mem, hello, sizeof(hello)); + EXPECT_STREQ((char const *)shm_hd.get(), hello); + + shm_hd.release(); + EXPECT_TRUE(shm_hd.get() == nullptr); + EXPECT_TRUE(shm_hd.acquire("hello-test", 1024)); + + mem = shm_hd.get(); + EXPECT_TRUE(mem != nullptr); + 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); +} + +TEST(SHM, mt) { + handle shm_hd; + EXPECT_TRUE(shm_hd.acquire("mt-test", 256)); + constexpr char hello[] = "hello!"; + std::memcpy(shm_hd.get(), hello, sizeof(hello)); + + std::thread { + [&shm_hd] { + handle shm_mt(shm_hd.name(), shm_hd.size()); + shm_hd.release(); + constexpr char hello[] = "hello!"; + EXPECT_STREQ((char const *)shm_mt.get(), hello); + } + }.join(); + + 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(memcmp(shm_hd.get(), buf, sizeof(buf)) == 0); +} + +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