33#include < cstring>
44#include < cassert>
55#include < system_error>
6+ #include < mutex>
67
78#include < pthread.h>
89
910#include " libipc/platform/get_wait_time.h"
1011#include " libipc/platform/detail.h"
1112#include " libipc/utility/log.h"
1213#include " libipc/utility/scope_guard.h"
14+ #include " libipc/memory/resource.h"
1315#include " libipc/shm.h"
1416
1517namespace ipc {
@@ -20,6 +22,32 @@ class mutex {
2022 ipc::shm::handle shm_;
2123 pthread_mutex_t *mutex_ = nullptr ;
2224
25+ pthread_mutex_t *acquire_mutex (char const *name) {
26+ if (!shm_.acquire (name, sizeof (pthread_mutex_t ))) {
27+ ipc::error (" fail shm.acquire: %s\n " , name);
28+ return nullptr ;
29+ }
30+ return static_cast <pthread_mutex_t *>(shm_.get ());
31+ }
32+
33+ pthread_mutex_t *get_mutex (char const *name) {
34+ if (name == nullptr ) {
35+ return nullptr ;
36+ }
37+ static ipc::map<ipc::string, pthread_mutex_t *> mutex_handles;
38+ static std::mutex lock;
39+ IPC_UNUSED_ std::lock_guard<std::mutex> guard {lock};
40+ auto it = mutex_handles.find (name);
41+ if (it == mutex_handles.end ()) {
42+ auto ptr = acquire_mutex (name);
43+ if (ptr != nullptr ) {
44+ mutex_handles.emplace (name, ptr);
45+ }
46+ return ptr;
47+ }
48+ return it->second ;
49+ }
50+
2351public:
2452 mutex () = default ;
2553 explicit mutex (char const *name) noexcept {
@@ -38,45 +66,41 @@ class mutex {
3866
3967 bool valid () const noexcept {
4068 static const char tmp[sizeof (pthread_mutex_t )] {};
41- return shm_.valid ()
42- && (mutex_ != nullptr )
69+ return (mutex_ != nullptr )
4370 && (std::memcmp (tmp, mutex_, sizeof (pthread_mutex_t )) != 0 );
4471 }
4572
4673 bool open (char const *name) noexcept {
4774 close ();
48- if (!shm_.acquire (name, sizeof (pthread_mutex_t ))) {
49- ipc::error (" fail shm.acquire: %s\n " , name);
75+ if ((mutex_ = get_mutex (name)) == nullptr ) {
5076 return false ;
5177 }
52- mutex_ = static_cast <pthread_mutex_t *>(shm_.get ());
53- assert (mutex_ != nullptr );
54- if ((shm_.ref () == 1 ) && valid ()/* it means mutex has been inited*/ ) {
78+ if (shm_.ref () == 1 ) {
5579 ::pthread_mutex_destroy (mutex_);
80+ auto finally = ipc::guard ([this ] { close (); }); // close when failed
81+ // init mutex
82+ int eno;
83+ pthread_mutexattr_t mutex_attr;
84+ if ((eno = ::pthread_mutexattr_init (&mutex_attr)) != 0 ) {
85+ ipc::error (" fail pthread_mutexattr_init[%d]\n " , eno);
86+ return false ;
87+ }
88+ IPC_UNUSED_ auto guard_mutex_attr = unique_ptr (&mutex_attr, ::pthread_mutexattr_destroy);
89+ if ((eno = ::pthread_mutexattr_setpshared (&mutex_attr, PTHREAD_PROCESS_SHARED)) != 0 ) {
90+ ipc::error (" fail pthread_mutexattr_setpshared[%d]\n " , eno);
91+ return false ;
92+ }
93+ if ((eno = ::pthread_mutexattr_setrobust (&mutex_attr, PTHREAD_MUTEX_ROBUST)) != 0 ) {
94+ ipc::error (" fail pthread_mutexattr_setrobust[%d]\n " , eno);
95+ return false ;
96+ }
97+ *mutex_ = PTHREAD_MUTEX_INITIALIZER;
98+ if ((eno = ::pthread_mutex_init (mutex_, &mutex_attr)) != 0 ) {
99+ ipc::error (" fail pthread_mutex_init[%d]\n " , eno);
100+ return false ;
101+ }
102+ finally.dismiss ();
56103 }
57- auto finally = ipc::guard ([this ] { close (); }); // close when failed
58- // init mutex
59- int eno;
60- pthread_mutexattr_t mutex_attr;
61- if ((eno = ::pthread_mutexattr_init (&mutex_attr)) != 0 ) {
62- ipc::error (" fail pthread_mutexattr_init[%d]\n " , eno);
63- return false ;
64- }
65- IPC_UNUSED_ auto guard_mutex_attr = unique_ptr (&mutex_attr, ::pthread_mutexattr_destroy);
66- if ((eno = ::pthread_mutexattr_setpshared (&mutex_attr, PTHREAD_PROCESS_SHARED)) != 0 ) {
67- ipc::error (" fail pthread_mutexattr_setpshared[%d]\n " , eno);
68- return false ;
69- }
70- if ((eno = ::pthread_mutexattr_setrobust (&mutex_attr, PTHREAD_MUTEX_ROBUST)) != 0 ) {
71- ipc::error (" fail pthread_mutexattr_setrobust[%d]\n " , eno);
72- return false ;
73- }
74- *mutex_ = PTHREAD_MUTEX_INITIALIZER;
75- if ((eno = ::pthread_mutex_init (mutex_, &mutex_attr)) != 0 ) {
76- ipc::error (" fail pthread_mutex_init[%d]\n " , eno);
77- return false ;
78- }
79- finally.dismiss ();
80104 return valid ();
81105 }
82106
0 commit comments