diff --git a/include/libipc/ipc.h b/include/libipc/ipc.h index 92cd83d..e6fe61a 100755 --- a/include/libipc/ipc.h +++ b/include/libipc/ipc.h @@ -19,7 +19,7 @@ enum : unsigned { template struct IPC_EXPORT chan_impl { - static ipc::handle_t inited(); + static ipc::handle_t init_first(); static bool connect (ipc::handle_t * ph, char const * name, unsigned mode); static bool connect (ipc::handle_t * ph, prefix, char const * name, unsigned mode); @@ -29,6 +29,9 @@ struct IPC_EXPORT chan_impl { static char const * name(ipc::handle_t h); + // Release memory without waiting for the connection to disconnect. + static void release(ipc::handle_t h) noexcept; + // Force cleanup of all shared memory storage that handles depend on. static void clear(ipc::handle_t h) noexcept; static void clear_storage(char const * name) noexcept; @@ -49,7 +52,7 @@ class chan_wrapper { private: using detail_t = chan_impl; - ipc::handle_t h_ = detail_t::inited(); + ipc::handle_t h_ = detail_t::init_first(); unsigned mode_ = ipc::sender; bool connected_ = false; @@ -88,15 +91,24 @@ public: return detail_t::name(h_); } + // Release memory without waiting for the connection to disconnect. + void release() noexcept { + detail_t::release(h_); + h_ = nullptr; + } + // Clear shared memory files under opened handle. void clear() noexcept { detail_t::clear(h_); + h_ = nullptr; } + // Clear shared memory files under a specific name. static void clear_storage(char const * name) noexcept { detail_t::clear_storage(name); } + // Clear shared memory files under a specific name with a prefix. static void clear_storage(prefix pref, char const * name) noexcept { detail_t::clear_storage(pref, name); } diff --git a/src/libipc/ipc.cpp b/src/libipc/ipc.cpp index f19fe22..7d919dd 100755 --- a/src/libipc/ipc.cpp +++ b/src/libipc/ipc.cpp @@ -395,10 +395,10 @@ struct queue_generator { conn_info_head::init(); if (!que_.valid()) { que_.open(ipc::make_prefix(prefix_, { - "QU_CONN__", - ipc::to_string(DataSize), "__", - ipc::to_string(AlignSize), "__", - this->name_}).c_str()); + "QU_CONN__", + this->name_, + "__", ipc::to_string(DataSize), + "__", ipc::to_string(AlignSize)}).c_str()); } } @@ -408,11 +408,11 @@ struct queue_generator { } static void clear_storage(char const * prefix, char const * name) noexcept { - queue_t::clear_storage(ipc::make_prefix(prefix, { - "QU_CONN__", - ipc::to_string(DataSize), "__", - ipc::to_string(AlignSize), "__", - name}).c_str()); + queue_t::clear_storage(ipc::make_prefix(ipc::make_string(prefix), { + "QU_CONN__", + ipc::make_string(name), + "__", ipc::to_string(DataSize), + "__", ipc::to_string(AlignSize)}).c_str()); conn_info_head::clear_storage(prefix, name); } @@ -489,8 +489,7 @@ static bool reconnect(ipc::handle_t * ph, bool start_to_recv) { return que->ready_sending(); } -static void destroy(ipc::handle_t h) { - disconnect(h); +static void destroy(ipc::handle_t h) noexcept { ipc::mem::free(info_of(h)); } @@ -733,7 +732,7 @@ using policy_t = ipc::policy::choose; namespace ipc { template -ipc::handle_t chan_impl::inited() { +ipc::handle_t chan_impl::init_first() { ipc::detail::waiter::init(); return nullptr; } @@ -760,6 +759,12 @@ void chan_impl::disconnect(ipc::handle_t h) { template void chan_impl::destroy(ipc::handle_t h) { + disconnect(h); + detail_impl>::destroy(h); +} + +template +void chan_impl::release(ipc::handle_t h) noexcept { detail_impl>::destroy(h); } diff --git a/src/libipc/platform/linux/mutex.h b/src/libipc/platform/linux/mutex.h index 6c684f0..8fd84d5 100644 --- a/src/libipc/platform/linux/mutex.h +++ b/src/libipc/platform/linux/mutex.h @@ -195,9 +195,11 @@ public: void clear() noexcept { if (mutex_ != nullptr) { if (mutex_->name() != nullptr) { - release_mutex(mutex_->name(), [] { return true; }); - } - mutex_->clear(); + release_mutex(mutex_->name(), [this] { + mutex_->clear(); + return true; + }); + } else mutex_->clear(); } mutex_ = nullptr; ref_ = nullptr; diff --git a/src/libipc/platform/posix/mutex.h b/src/libipc/platform/posix/mutex.h index 40284b0..d84736f 100644 --- a/src/libipc/platform/posix/mutex.h +++ b/src/libipc/platform/posix/mutex.h @@ -177,10 +177,10 @@ public: if ((eno = ::pthread_mutex_destroy(mutex_)) != 0) { ipc::error("fail pthread_mutex_destroy[%d]\n", eno); } + shm_->clear(); return true; }); - } - shm_->clear(); + } else shm_->clear(); } shm_ = nullptr; ref_ = nullptr; diff --git a/test/test_ipc.cpp b/test/test_ipc.cpp index fb46670..5bd828b 100755 --- a/test/test_ipc.cpp +++ b/test/test_ipc.cpp @@ -151,6 +151,50 @@ void test_sr(char const * name, int s_cnt, int r_cnt) { } // internal-linkage +TEST(IPC, clear) { + { + chan c{"ssu"}; + EXPECT_TRUE(ipc_ut::expect_exist("__IPC_SHM__AC_CONN__ssu", true)); + EXPECT_TRUE(ipc_ut::expect_exist("__IPC_SHM__CC_CONN__ssu_WAITER_COND_", true)); + EXPECT_TRUE(ipc_ut::expect_exist("__IPC_SHM__CC_CONN__ssu_WAITER_LOCK_", true)); + EXPECT_TRUE(ipc_ut::expect_exist("__IPC_SHM__RD_CONN__ssu_WAITER_COND_", true)); + EXPECT_TRUE(ipc_ut::expect_exist("__IPC_SHM__RD_CONN__ssu_WAITER_LOCK_", true)); + EXPECT_TRUE(ipc_ut::expect_exist("__IPC_SHM__WT_CONN__ssu_WAITER_COND_", true)); + EXPECT_TRUE(ipc_ut::expect_exist("__IPC_SHM__WT_CONN__ssu_WAITER_LOCK_", true)); + EXPECT_TRUE(ipc_ut::expect_exist("__IPC_SHM__QU_CONN__ssu__64__16", true)); + c.clear(); + EXPECT_TRUE(ipc_ut::expect_exist("__IPC_SHM__AC_CONN__ssu", false)); + EXPECT_TRUE(ipc_ut::expect_exist("__IPC_SHM__CC_CONN__ssu_WAITER_COND_", false)); + EXPECT_TRUE(ipc_ut::expect_exist("__IPC_SHM__CC_CONN__ssu_WAITER_LOCK_", false)); + EXPECT_TRUE(ipc_ut::expect_exist("__IPC_SHM__RD_CONN__ssu_WAITER_COND_", false)); + EXPECT_TRUE(ipc_ut::expect_exist("__IPC_SHM__RD_CONN__ssu_WAITER_LOCK_", false)); + EXPECT_TRUE(ipc_ut::expect_exist("__IPC_SHM__WT_CONN__ssu_WAITER_COND_", false)); + EXPECT_TRUE(ipc_ut::expect_exist("__IPC_SHM__WT_CONN__ssu_WAITER_LOCK_", false)); + EXPECT_TRUE(ipc_ut::expect_exist("__IPC_SHM__QU_CONN__ssu__64__16", false)); + } + { + chan c{"ssu"}; + EXPECT_TRUE(ipc_ut::expect_exist("__IPC_SHM__AC_CONN__ssu", true)); + EXPECT_TRUE(ipc_ut::expect_exist("__IPC_SHM__CC_CONN__ssu_WAITER_COND_", true)); + EXPECT_TRUE(ipc_ut::expect_exist("__IPC_SHM__CC_CONN__ssu_WAITER_LOCK_", true)); + EXPECT_TRUE(ipc_ut::expect_exist("__IPC_SHM__RD_CONN__ssu_WAITER_COND_", true)); + EXPECT_TRUE(ipc_ut::expect_exist("__IPC_SHM__RD_CONN__ssu_WAITER_LOCK_", true)); + EXPECT_TRUE(ipc_ut::expect_exist("__IPC_SHM__WT_CONN__ssu_WAITER_COND_", true)); + EXPECT_TRUE(ipc_ut::expect_exist("__IPC_SHM__WT_CONN__ssu_WAITER_LOCK_", true)); + EXPECT_TRUE(ipc_ut::expect_exist("__IPC_SHM__QU_CONN__ssu__64__16", true)); + chan::clear_storage("ssu"); + EXPECT_TRUE(ipc_ut::expect_exist("__IPC_SHM__AC_CONN__ssu", false)); + EXPECT_TRUE(ipc_ut::expect_exist("__IPC_SHM__CC_CONN__ssu_WAITER_COND_", false)); + EXPECT_TRUE(ipc_ut::expect_exist("__IPC_SHM__CC_CONN__ssu_WAITER_LOCK_", false)); + EXPECT_TRUE(ipc_ut::expect_exist("__IPC_SHM__RD_CONN__ssu_WAITER_COND_", false)); + EXPECT_TRUE(ipc_ut::expect_exist("__IPC_SHM__RD_CONN__ssu_WAITER_LOCK_", false)); + EXPECT_TRUE(ipc_ut::expect_exist("__IPC_SHM__WT_CONN__ssu_WAITER_COND_", false)); + EXPECT_TRUE(ipc_ut::expect_exist("__IPC_SHM__WT_CONN__ssu_WAITER_LOCK_", false)); + EXPECT_TRUE(ipc_ut::expect_exist("__IPC_SHM__QU_CONN__ssu__64__16", false)); + c.release(); // Call this interface to prevent destruction-time exceptions. + } +} + TEST(IPC, basic_ssu) { test_basic("ssu"); } diff --git a/test/test_sync.cpp b/test/test_sync.cpp index e905df9..61d82d1 100644 --- a/test/test_sync.cpp +++ b/test/test_sync.cpp @@ -205,4 +205,4 @@ TEST(Sync, ConditionRobust) { ASSERT_TRUE(lock.unlock()); printf("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 6\n"); unlock.join(); -} \ No newline at end of file +} diff --git a/test/test_waiter.cpp b/test/test_waiter.cpp index 727cca0..c38c605 100755 --- a/test/test_waiter.cpp +++ b/test/test_waiter.cpp @@ -4,8 +4,6 @@ #include "libipc/waiter.h" #include "test.h" -namespace { - TEST(Waiter, broadcast) { for (int i = 0; i < 10; ++i) { ipc::detail::waiter waiter; @@ -65,4 +63,23 @@ TEST(Waiter, quit_waiting) { std::cout << "quit... \n"; } -} // internal-linkage +TEST(Waiter, clear) { + { + ipc::detail::waiter w{"my-waiter"}; + ASSERT_TRUE(w.valid()); + EXPECT_TRUE(ipc_ut::expect_exist("my-waiter_WAITER_COND_", true)); + EXPECT_TRUE(ipc_ut::expect_exist("my-waiter_WAITER_LOCK_", true)); + w.clear(); + ASSERT_TRUE(!w.valid()); + EXPECT_TRUE(ipc_ut::expect_exist("my-waiter_WAITER_COND_", false)); + EXPECT_TRUE(ipc_ut::expect_exist("my-waiter_WAITER_LOCK_", false)); + } + { + ipc::detail::waiter w{"my-waiter"}; + EXPECT_TRUE(ipc_ut::expect_exist("my-waiter_WAITER_COND_", true)); + EXPECT_TRUE(ipc_ut::expect_exist("my-waiter_WAITER_LOCK_", true)); + ipc::detail::waiter::clear_storage("my-waiter"); + EXPECT_TRUE(ipc_ut::expect_exist("my-waiter_WAITER_COND_", false)); + EXPECT_TRUE(ipc_ut::expect_exist("my-waiter_WAITER_LOCK_", false)); + } +}