From 415be36477bad1615ddf83f54f773dd2059a0267 Mon Sep 17 00:00:00 2001 From: mutouyun Date: Sat, 11 Sep 2021 15:52:48 +0800 Subject: [PATCH] ipc::sync::mutex for linux --- src/libipc/memory/resource.h | 19 ++++++- src/libipc/platform/mutex_linux.h | 84 ++++++++++++++++++++----------- test/test_sync.cpp | 2 +- 3 files changed, 72 insertions(+), 33 deletions(-) diff --git a/src/libipc/memory/resource.h b/src/libipc/memory/resource.h index 063e8dc..38b6fb6 100755 --- a/src/libipc/memory/resource.h +++ b/src/libipc/memory/resource.h @@ -45,14 +45,17 @@ constexpr char const * pf(long double) { return "%Lf" ; } } // internal-linkage +template +struct hash : public std::hash {}; + template using unordered_map = std::unordered_map< - Key, T, std::hash, std::equal_to, ipc::mem::allocator> + Key, T, ipc::hash, std::equal_to, ipc::mem::allocator> >; template using map = std::map< - Key, T, std::less, ipc::mem::allocator> + Key, T, std::less, ipc::mem::allocator> >; template @@ -63,6 +66,18 @@ using basic_string = std::basic_string< using string = basic_string; using wstring = basic_string; +template <> struct hash { + std::size_t operator()(string const &val) const noexcept { + return std::hash{}(val.c_str()); + } +}; + +template <> struct hash { + std::size_t operator()(wstring const &val) const noexcept { + return std::hash{}(val.c_str()); + } +}; + template ipc::string to_string(T val) { char buf[std::numeric_limits::digits10 + 1] {}; diff --git a/src/libipc/platform/mutex_linux.h b/src/libipc/platform/mutex_linux.h index 30c04e4..50d6b1a 100644 --- a/src/libipc/platform/mutex_linux.h +++ b/src/libipc/platform/mutex_linux.h @@ -3,6 +3,7 @@ #include #include #include +#include #include @@ -10,6 +11,7 @@ #include "libipc/platform/detail.h" #include "libipc/utility/log.h" #include "libipc/utility/scope_guard.h" +#include "libipc/memory/resource.h" #include "libipc/shm.h" namespace ipc { @@ -20,6 +22,32 @@ class mutex { ipc::shm::handle shm_; pthread_mutex_t *mutex_ = nullptr; + pthread_mutex_t *acquire_mutex(char const *name) { + if (!shm_.acquire(name, sizeof(pthread_mutex_t))) { + ipc::error("fail shm.acquire: %s\n", name); + return nullptr; + } + return static_cast(shm_.get()); + } + + pthread_mutex_t *get_mutex(char const *name) { + if (name == nullptr) { + return nullptr; + } + static ipc::map mutex_handles; + static std::mutex lock; + IPC_UNUSED_ std::lock_guard guard {lock}; + auto it = mutex_handles.find(name); + if (it == mutex_handles.end()) { + auto ptr = acquire_mutex(name); + if (ptr != nullptr) { + mutex_handles.emplace(name, ptr); + } + return ptr; + } + return it->second; + } + public: mutex() = default; explicit mutex(char const *name) noexcept { @@ -38,45 +66,41 @@ public: bool valid() const noexcept { static const char tmp[sizeof(pthread_mutex_t)] {}; - return shm_.valid() - && (mutex_ != nullptr) + return (mutex_ != nullptr) && (std::memcmp(tmp, mutex_, sizeof(pthread_mutex_t)) != 0); } bool open(char const *name) noexcept { close(); - if (!shm_.acquire(name, sizeof(pthread_mutex_t))) { - ipc::error("fail shm.acquire: %s\n", name); + if ((mutex_ = get_mutex(name)) == nullptr) { return false; } - mutex_ = static_cast(shm_.get()); - assert(mutex_ != nullptr); - if ((shm_.ref() == 1) && valid()/*it means mutex has been inited*/) { + if (shm_.ref() == 1) { ::pthread_mutex_destroy(mutex_); + auto finally = ipc::guard([this] { close(); }); // close when failed + // init mutex + int eno; + pthread_mutexattr_t mutex_attr; + if ((eno = ::pthread_mutexattr_init(&mutex_attr)) != 0) { + ipc::error("fail pthread_mutexattr_init[%d]\n", eno); + return false; + } + IPC_UNUSED_ auto guard_mutex_attr = unique_ptr(&mutex_attr, ::pthread_mutexattr_destroy); + if ((eno = ::pthread_mutexattr_setpshared(&mutex_attr, PTHREAD_PROCESS_SHARED)) != 0) { + ipc::error("fail pthread_mutexattr_setpshared[%d]\n", eno); + return false; + } + if ((eno = ::pthread_mutexattr_setrobust(&mutex_attr, PTHREAD_MUTEX_ROBUST)) != 0) { + ipc::error("fail pthread_mutexattr_setrobust[%d]\n", eno); + return false; + } + *mutex_ = PTHREAD_MUTEX_INITIALIZER; + if ((eno = ::pthread_mutex_init(mutex_, &mutex_attr)) != 0) { + ipc::error("fail pthread_mutex_init[%d]\n", eno); + return false; + } + finally.dismiss(); } - auto finally = ipc::guard([this] { close(); }); // close when failed - // init mutex - int eno; - pthread_mutexattr_t mutex_attr; - if ((eno = ::pthread_mutexattr_init(&mutex_attr)) != 0) { - ipc::error("fail pthread_mutexattr_init[%d]\n", eno); - return false; - } - IPC_UNUSED_ auto guard_mutex_attr = unique_ptr(&mutex_attr, ::pthread_mutexattr_destroy); - if ((eno = ::pthread_mutexattr_setpshared(&mutex_attr, PTHREAD_PROCESS_SHARED)) != 0) { - ipc::error("fail pthread_mutexattr_setpshared[%d]\n", eno); - return false; - } - if ((eno = ::pthread_mutexattr_setrobust(&mutex_attr, PTHREAD_MUTEX_ROBUST)) != 0) { - ipc::error("fail pthread_mutexattr_setrobust[%d]\n", eno); - return false; - } - *mutex_ = PTHREAD_MUTEX_INITIALIZER; - if ((eno = ::pthread_mutex_init(mutex_, &mutex_attr)) != 0) { - ipc::error("fail pthread_mutex_init[%d]\n", eno); - return false; - } - finally.dismiss(); return valid(); } diff --git a/test/test_sync.cpp b/test/test_sync.cpp index d413376..d854e44 100644 --- a/test/test_sync.cpp +++ b/test/test_sync.cpp @@ -14,6 +14,7 @@ TEST(PThread, Robust) { pthread_mutexattr_t ma; pthread_mutexattr_init(&ma); + pthread_mutexattr_setpshared(&ma, PTHREAD_PROCESS_SHARED); pthread_mutexattr_setrobust(&ma, PTHREAD_MUTEX_ROBUST); pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_init(&mutex, &ma); @@ -55,7 +56,6 @@ TEST(PThread, Robust) { TEST(Sync, Mutex) { ipc::sync::mutex lock; EXPECT_TRUE(lock.open("test-mutex-robust")); - std::thread{[] { ipc::sync::mutex lock{"test-mutex-robust"}; EXPECT_TRUE(lock.valid());