mirror of
https://github.com/mutouyun/cpp-ipc.git
synced 2025-12-06 16:56:45 +08:00
fix some bugs for linux-mutex
This commit is contained in:
parent
a9cb81bee9
commit
ed8b1fd608
@ -15,13 +15,13 @@ enum : unsigned {
|
|||||||
open = 0x02
|
open = 0x02
|
||||||
};
|
};
|
||||||
|
|
||||||
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 void release(id_t id);
|
IPC_EXPORT std::int32_t release(id_t id);
|
||||||
IPC_EXPORT void remove (id_t id);
|
IPC_EXPORT void remove (id_t id);
|
||||||
IPC_EXPORT void remove (char const * name);
|
IPC_EXPORT void remove (char const * name);
|
||||||
|
|
||||||
IPC_EXPORT std::uint32_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);
|
||||||
|
|
||||||
class IPC_EXPORT handle {
|
class IPC_EXPORT handle {
|
||||||
@ -39,11 +39,11 @@ public:
|
|||||||
std::size_t size () const noexcept;
|
std::size_t size () const noexcept;
|
||||||
char const * name () const noexcept;
|
char const * name () const noexcept;
|
||||||
|
|
||||||
std::uint32_t ref() const noexcept;
|
std::int32_t ref() const noexcept;
|
||||||
void sub_ref() noexcept;
|
void sub_ref() noexcept;
|
||||||
|
|
||||||
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);
|
||||||
void release();
|
std::int32_t release();
|
||||||
|
|
||||||
void* get() const;
|
void* get() const;
|
||||||
|
|
||||||
|
|||||||
@ -50,33 +50,34 @@ public:
|
|||||||
if ((cond_ = acquire_cond(name)) == nullptr) {
|
if ((cond_ = acquire_cond(name)) == nullptr) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (shm_.ref() == 1) {
|
if (shm_.ref() > 1) {
|
||||||
::pthread_cond_destroy(cond_);
|
return valid();
|
||||||
auto finally = ipc::guard([this] { close(); }); // close when failed
|
|
||||||
// init condition
|
|
||||||
int eno;
|
|
||||||
pthread_condattr_t cond_attr;
|
|
||||||
if ((eno = ::pthread_condattr_init(&cond_attr)) != 0) {
|
|
||||||
ipc::error("fail pthread_condattr_init[%d]\n", eno);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
IPC_UNUSED_ auto guard_cond_attr = unique_ptr(&cond_attr, ::pthread_condattr_destroy);
|
|
||||||
if ((eno = ::pthread_condattr_setpshared(&cond_attr, PTHREAD_PROCESS_SHARED)) != 0) {
|
|
||||||
ipc::error("fail pthread_condattr_setpshared[%d]\n", eno);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
*cond_ = PTHREAD_COND_INITIALIZER;
|
|
||||||
if ((eno = ::pthread_cond_init(cond_, &cond_attr)) != 0) {
|
|
||||||
ipc::error("fail pthread_cond_init[%d]\n", eno);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
finally.dismiss();
|
|
||||||
}
|
}
|
||||||
|
::pthread_cond_destroy(cond_);
|
||||||
|
auto finally = ipc::guard([this] { close(); }); // close when failed
|
||||||
|
// init condition
|
||||||
|
int eno;
|
||||||
|
pthread_condattr_t cond_attr;
|
||||||
|
if ((eno = ::pthread_condattr_init(&cond_attr)) != 0) {
|
||||||
|
ipc::error("fail pthread_condattr_init[%d]\n", eno);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
IPC_UNUSED_ auto guard_cond_attr = unique_ptr(&cond_attr, ::pthread_condattr_destroy);
|
||||||
|
if ((eno = ::pthread_condattr_setpshared(&cond_attr, PTHREAD_PROCESS_SHARED)) != 0) {
|
||||||
|
ipc::error("fail pthread_condattr_setpshared[%d]\n", eno);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
*cond_ = PTHREAD_COND_INITIALIZER;
|
||||||
|
if ((eno = ::pthread_cond_init(cond_, &cond_attr)) != 0) {
|
||||||
|
ipc::error("fail pthread_cond_init[%d]\n", eno);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
finally.dismiss();
|
||||||
return valid();
|
return valid();
|
||||||
}
|
}
|
||||||
|
|
||||||
void close() noexcept {
|
void close() noexcept {
|
||||||
if (shm_.ref() == 1) {
|
if ((shm_.ref() <= 1) && cond_ != nullptr) {
|
||||||
int eno;
|
int eno;
|
||||||
if ((eno = ::pthread_cond_destroy(cond_)) != 0) {
|
if ((eno = ::pthread_cond_destroy(cond_)) != 0) {
|
||||||
ipc::error("fail pthread_cond_destroy[%d]\n", eno);
|
ipc::error("fail pthread_cond_destroy[%d]\n", eno);
|
||||||
@ -87,9 +88,8 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool wait(ipc::sync::mutex &mtx, std::uint64_t tm) noexcept {
|
bool wait(ipc::sync::mutex &mtx, std::uint64_t tm) noexcept {
|
||||||
|
if (!valid()) return false;
|
||||||
switch (tm) {
|
switch (tm) {
|
||||||
case 0:
|
|
||||||
return true;
|
|
||||||
case invalid_value: {
|
case invalid_value: {
|
||||||
int eno;
|
int eno;
|
||||||
if ((eno = ::pthread_cond_wait(cond_, static_cast<pthread_mutex_t *>(mtx.native()))) != 0) {
|
if ((eno = ::pthread_cond_wait(cond_, static_cast<pthread_mutex_t *>(mtx.native()))) != 0) {
|
||||||
@ -115,6 +115,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool notify() noexcept {
|
bool notify() noexcept {
|
||||||
|
if (!valid()) return false;
|
||||||
int eno;
|
int eno;
|
||||||
if ((eno = ::pthread_cond_signal(cond_)) != 0) {
|
if ((eno = ::pthread_cond_signal(cond_)) != 0) {
|
||||||
ipc::error("fail pthread_cond_signal[%d]\n", eno);
|
ipc::error("fail pthread_cond_signal[%d]\n", eno);
|
||||||
@ -124,6 +125,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool broadcast() noexcept {
|
bool broadcast() noexcept {
|
||||||
|
if (!valid()) return false;
|
||||||
int eno;
|
int eno;
|
||||||
if ((eno = ::pthread_cond_broadcast(cond_)) != 0) {
|
if ((eno = ::pthread_cond_broadcast(cond_)) != 0) {
|
||||||
ipc::error("fail pthread_cond_broadcast[%d]\n", eno);
|
ipc::error("fail pthread_cond_broadcast[%d]\n", eno);
|
||||||
|
|||||||
@ -2,8 +2,10 @@
|
|||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
#include <cstdint>
|
||||||
#include <system_error>
|
#include <system_error>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
#include <atomic>
|
||||||
|
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
|
|
||||||
@ -19,33 +21,61 @@ namespace detail {
|
|||||||
namespace sync {
|
namespace sync {
|
||||||
|
|
||||||
class mutex {
|
class mutex {
|
||||||
ipc::shm::handle shm_;
|
ipc::shm::handle *shm_ = nullptr;
|
||||||
|
std::atomic<std::int32_t> *ref_ = nullptr;
|
||||||
pthread_mutex_t *mutex_ = nullptr;
|
pthread_mutex_t *mutex_ = nullptr;
|
||||||
|
|
||||||
pthread_mutex_t *acquire_mutex(char const *name) {
|
struct curr_prog {
|
||||||
if (!shm_.acquire(name, sizeof(pthread_mutex_t))) {
|
struct shm_data {
|
||||||
ipc::error("[acquire_mutex] fail shm.acquire: %s\n", name);
|
ipc::shm::handle shm;
|
||||||
return nullptr;
|
std::atomic<std::int32_t> ref;
|
||||||
}
|
|
||||||
return static_cast<pthread_mutex_t *>(shm_.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
pthread_mutex_t *get_mutex(char const *name) {
|
struct init {
|
||||||
|
char const *name;
|
||||||
|
std::size_t size;
|
||||||
|
};
|
||||||
|
shm_data(init arg)
|
||||||
|
: shm{arg.name, arg.size}, ref{0} {}
|
||||||
|
};
|
||||||
|
ipc::map<ipc::string, shm_data> mutex_handles;
|
||||||
|
std::mutex lock;
|
||||||
|
|
||||||
|
static curr_prog &get() {
|
||||||
|
static curr_prog info;
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pthread_mutex_t *acquire_mutex(char const *name) {
|
||||||
if (name == nullptr) {
|
if (name == nullptr) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
static ipc::map<ipc::string, pthread_mutex_t *> mutex_handles;
|
auto &info = curr_prog::get();
|
||||||
static std::mutex lock;
|
IPC_UNUSED_ std::lock_guard<std::mutex> guard {info.lock};
|
||||||
IPC_UNUSED_ std::lock_guard<std::mutex> guard {lock};
|
auto it = info.mutex_handles.find(name);
|
||||||
auto it = mutex_handles.find(name);
|
if (it == info.mutex_handles.end()) {
|
||||||
if (it == mutex_handles.end()) {
|
it = curr_prog::get().mutex_handles.emplace(name,
|
||||||
auto ptr = acquire_mutex(name);
|
curr_prog::shm_data::init{name, sizeof(pthread_mutex_t)}).first;
|
||||||
if (ptr != nullptr) {
|
}
|
||||||
mutex_handles.emplace(name, ptr);
|
shm_ = &it->second.shm;
|
||||||
}
|
ref_ = &it->second.ref;
|
||||||
return ptr;
|
if (shm_ == nullptr) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return static_cast<pthread_mutex_t *>(shm_->get());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename F>
|
||||||
|
void release_mutex(ipc::string const &name, F &&clear) {
|
||||||
|
if (name.empty()) return;
|
||||||
|
IPC_UNUSED_ std::lock_guard<std::mutex> guard {curr_prog::get().lock};
|
||||||
|
auto it = curr_prog::get().mutex_handles.find(name);
|
||||||
|
if (it == curr_prog::get().mutex_handles.end()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (clear()) {
|
||||||
|
curr_prog::get().mutex_handles.erase(it);
|
||||||
}
|
}
|
||||||
return it->second;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -62,56 +92,69 @@ public:
|
|||||||
|
|
||||||
bool valid() const noexcept {
|
bool valid() const noexcept {
|
||||||
static const char tmp[sizeof(pthread_mutex_t)] {};
|
static const char tmp[sizeof(pthread_mutex_t)] {};
|
||||||
return (mutex_ != nullptr)
|
return (shm_ != nullptr) && (ref_ != nullptr) && (mutex_ != nullptr)
|
||||||
&& (std::memcmp(tmp, mutex_, sizeof(pthread_mutex_t)) != 0);
|
&& (std::memcmp(tmp, mutex_, sizeof(pthread_mutex_t)) != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool open(char const *name) noexcept {
|
bool open(char const *name) noexcept {
|
||||||
close();
|
close();
|
||||||
if ((mutex_ = get_mutex(name)) == nullptr) {
|
if ((mutex_ = acquire_mutex(name)) == nullptr) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (shm_.ref() == 1) {
|
auto self_ref = ref_->fetch_add(1, std::memory_order_relaxed);
|
||||||
::pthread_mutex_destroy(mutex_);
|
if (shm_->ref() > 1 || self_ref > 0) {
|
||||||
auto finally = ipc::guard([this] { close(); }); // close when failed
|
return valid();
|
||||||
// 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();
|
|
||||||
}
|
}
|
||||||
|
::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();
|
||||||
return valid();
|
return valid();
|
||||||
}
|
}
|
||||||
|
|
||||||
void close() noexcept {
|
void close() noexcept {
|
||||||
if (shm_.ref() == 1) {
|
if ((ref_ != nullptr) && (shm_ != nullptr) && (mutex_ != nullptr)) {
|
||||||
int eno;
|
if (shm_->name() != nullptr) {
|
||||||
if ((eno = ::pthread_mutex_destroy(mutex_)) != 0) {
|
release_mutex(shm_->name(), [this] {
|
||||||
ipc::error("fail pthread_mutex_destroy[%d]\n", eno);
|
auto self_ref = ref_->fetch_sub(1, std::memory_order_relaxed);
|
||||||
}
|
if ((shm_->ref() <= 1) && (self_ref <= 1)) {
|
||||||
|
int eno;
|
||||||
|
if ((eno = ::pthread_mutex_destroy(mutex_)) != 0) {
|
||||||
|
ipc::error("fail pthread_mutex_destroy[%d]\n", eno);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
} else shm_->release();
|
||||||
}
|
}
|
||||||
shm_.release();
|
shm_ = nullptr;
|
||||||
|
ref_ = nullptr;
|
||||||
mutex_ = nullptr;
|
mutex_ = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool lock(std::uint64_t tm) noexcept {
|
bool lock(std::uint64_t tm) noexcept {
|
||||||
|
if (!valid()) return false;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
auto ts = detail::make_timespec(tm);
|
auto ts = detail::make_timespec(tm);
|
||||||
int eno = (tm == invalid_value)
|
int eno = (tm == invalid_value)
|
||||||
@ -123,8 +166,8 @@ public:
|
|||||||
case ETIMEDOUT:
|
case ETIMEDOUT:
|
||||||
return false;
|
return false;
|
||||||
case EOWNERDEAD: {
|
case EOWNERDEAD: {
|
||||||
if (shm_.ref() > 1) {
|
if (shm_->ref() > 1) {
|
||||||
shm_.sub_ref();
|
shm_->sub_ref();
|
||||||
}
|
}
|
||||||
int eno2 = ::pthread_mutex_consistent(mutex_);
|
int eno2 = ::pthread_mutex_consistent(mutex_);
|
||||||
if (eno2 != 0) {
|
if (eno2 != 0) {
|
||||||
@ -146,6 +189,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool try_lock() noexcept(false) {
|
bool try_lock() noexcept(false) {
|
||||||
|
if (!valid()) return false;
|
||||||
auto ts = detail::make_timespec(0);
|
auto ts = detail::make_timespec(0);
|
||||||
int eno = ::pthread_mutex_timedlock(mutex_, &ts);
|
int eno = ::pthread_mutex_timedlock(mutex_, &ts);
|
||||||
switch (eno) {
|
switch (eno) {
|
||||||
@ -154,8 +198,8 @@ public:
|
|||||||
case ETIMEDOUT:
|
case ETIMEDOUT:
|
||||||
return false;
|
return false;
|
||||||
case EOWNERDEAD: {
|
case EOWNERDEAD: {
|
||||||
if (shm_.ref() > 1) {
|
if (shm_->ref() > 1) {
|
||||||
shm_.sub_ref();
|
shm_->sub_ref();
|
||||||
}
|
}
|
||||||
int eno2 = ::pthread_mutex_consistent(mutex_);
|
int eno2 = ::pthread_mutex_consistent(mutex_);
|
||||||
if (eno2 != 0) {
|
if (eno2 != 0) {
|
||||||
@ -177,6 +221,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool unlock() noexcept {
|
bool unlock() noexcept {
|
||||||
|
if (!valid()) return false;
|
||||||
int eno;
|
int eno;
|
||||||
if ((eno = ::pthread_mutex_unlock(mutex_)) != 0) {
|
if ((eno = ::pthread_mutex_unlock(mutex_)) != 0) {
|
||||||
ipc::error("fail pthread_mutex_unlock[%d]\n", eno);
|
ipc::error("fail pthread_mutex_unlock[%d]\n", eno);
|
||||||
|
|||||||
@ -50,13 +50,15 @@ public:
|
|||||||
if (::sem_close(h_) != 0) {
|
if (::sem_close(h_) != 0) {
|
||||||
ipc::error("fail sem_close[%d]: %s\n", errno);
|
ipc::error("fail sem_close[%d]: %s\n", errno);
|
||||||
}
|
}
|
||||||
if (shm_.ref() == 1) {
|
h_ = SEM_FAILED;
|
||||||
if (::sem_unlink(shm_.name()) != 0) {
|
if (shm_.name() != nullptr) {
|
||||||
ipc::error("fail sem_unlink[%d]: %s\n", errno);
|
std::string name = shm_.name();
|
||||||
|
if (shm_.release() <= 1) {
|
||||||
|
if (::sem_unlink(name.c_str()) != 0) {
|
||||||
|
ipc::error("fail sem_unlink[%d]: %s, name: %s\n", errno, name.c_str());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
shm_.release();
|
|
||||||
h_ = SEM_FAILED;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool wait(std::uint64_t tm) noexcept {
|
bool wait(std::uint64_t tm) noexcept {
|
||||||
|
|||||||
@ -22,7 +22,7 @@
|
|||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
struct info_t {
|
struct info_t {
|
||||||
std::atomic<std::uint32_t> acc_;
|
std::atomic<std::int32_t> acc_;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct id_info_t {
|
struct id_info_t {
|
||||||
@ -81,7 +81,7 @@ id_t acquire(char const * name, std::size_t size, unsigned mode) {
|
|||||||
return ii;
|
return ii;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::uint32_t get_ref(id_t id) {
|
std::int32_t get_ref(id_t id) {
|
||||||
if (id == nullptr) {
|
if (id == nullptr) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -152,16 +152,17 @@ void * get_mem(id_t id, std::size_t * size) {
|
|||||||
return mem;
|
return mem;
|
||||||
}
|
}
|
||||||
|
|
||||||
void release(id_t id) {
|
std::int32_t release(id_t id) {
|
||||||
if (id == nullptr) {
|
if (id == nullptr) {
|
||||||
ipc::error("fail release: invalid id (null)\n");
|
ipc::error("fail release: invalid id (null)\n");
|
||||||
return;
|
return -1;
|
||||||
}
|
}
|
||||||
|
std::int32_t ret = -1;
|
||||||
auto ii = static_cast<id_info_t*>(id);
|
auto ii = static_cast<id_info_t*>(id);
|
||||||
if (ii->mem_ == nullptr || ii->size_ == 0) {
|
if (ii->mem_ == nullptr || ii->size_ == 0) {
|
||||||
ipc::error("fail release: invalid id (mem = %p, size = %zd)\n", ii->mem_, ii->size_);
|
ipc::error("fail release: invalid id (mem = %p, size = %zd)\n", ii->mem_, ii->size_);
|
||||||
}
|
}
|
||||||
else if (acc_of(ii->mem_, ii->size_).fetch_sub(1, std::memory_order_acq_rel) == 1) {
|
else if ((ret = acc_of(ii->mem_, ii->size_).fetch_sub(1, std::memory_order_acq_rel)) <= 1) {
|
||||||
::munmap(ii->mem_, ii->size_);
|
::munmap(ii->mem_, ii->size_);
|
||||||
if (!ii->name_.empty()) {
|
if (!ii->name_.empty()) {
|
||||||
::shm_unlink(ii->name_.c_str());
|
::shm_unlink(ii->name_.c_str());
|
||||||
@ -169,6 +170,7 @@ void release(id_t id) {
|
|||||||
}
|
}
|
||||||
else ::munmap(ii->mem_, ii->size_);
|
else ::munmap(ii->mem_, ii->size_);
|
||||||
mem::free(ii);
|
mem::free(ii);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void remove(id_t id) {
|
void remove(id_t id) {
|
||||||
|
|||||||
@ -58,7 +58,7 @@ id_t acquire(char const * name, std::size_t size, unsigned mode) {
|
|||||||
return ii;
|
return ii;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::uint32_t get_ref(id_t) {
|
std::int32_t get_ref(id_t) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,10 +96,10 @@ void * get_mem(id_t id, std::size_t * size) {
|
|||||||
return static_cast<void *>(mem);
|
return static_cast<void *>(mem);
|
||||||
}
|
}
|
||||||
|
|
||||||
void release(id_t id) {
|
std::int32_t release(id_t id) {
|
||||||
if (id == nullptr) {
|
if (id == nullptr) {
|
||||||
ipc::error("fail release: invalid id (null)\n");
|
ipc::error("fail release: invalid id (null)\n");
|
||||||
return;
|
return -1;
|
||||||
}
|
}
|
||||||
auto ii = static_cast<id_info_t*>(id);
|
auto ii = static_cast<id_info_t*>(id);
|
||||||
if (ii->mem_ == nullptr || ii->size_ == 0) {
|
if (ii->mem_ == nullptr || ii->size_ == 0) {
|
||||||
@ -111,6 +111,7 @@ void release(id_t id) {
|
|||||||
}
|
}
|
||||||
else ::CloseHandle(ii->h_);
|
else ::CloseHandle(ii->h_);
|
||||||
mem::free(ii);
|
mem::free(ii);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void remove(id_t id) {
|
void remove(id_t id) {
|
||||||
|
|||||||
@ -59,7 +59,7 @@ char const * handle::name() const noexcept {
|
|||||||
return impl(p_)->n_.c_str();
|
return impl(p_)->n_.c_str();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::uint32_t handle::ref() const noexcept {
|
std::int32_t handle::ref() const noexcept {
|
||||||
return shm::get_ref(impl(p_)->id_);
|
return shm::get_ref(impl(p_)->id_);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,9 +74,9 @@ bool handle::acquire(char const * name, std::size_t size, unsigned mode) {
|
|||||||
return valid();
|
return valid();
|
||||||
}
|
}
|
||||||
|
|
||||||
void handle::release() {
|
std::int32_t handle::release() {
|
||||||
if (impl(p_)->id_ == nullptr) return;
|
if (impl(p_)->id_ == nullptr) return -1;
|
||||||
shm::release(detach());
|
return shm::release(detach());
|
||||||
}
|
}
|
||||||
|
|
||||||
void* handle::get() const {
|
void* handle::get() const {
|
||||||
|
|||||||
@ -42,8 +42,8 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void close() noexcept {
|
void close() noexcept {
|
||||||
cond_.close();
|
// cond_.close();
|
||||||
lock_.close();
|
// lock_.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename F>
|
template <typename F>
|
||||||
|
|||||||
@ -7,28 +7,31 @@
|
|||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
TEST(Waiter, broadcast) {
|
TEST(Waiter, broadcast) {
|
||||||
ipc::detail::waiter waiter;
|
for (int i = 0; i < 10; ++i) {
|
||||||
std::thread ts[10];
|
ipc::detail::waiter waiter;
|
||||||
|
std::thread ts[10];
|
||||||
|
|
||||||
int k = 0;
|
int k = 0;
|
||||||
for (auto& t : ts) {
|
for (auto& t : ts) {
|
||||||
t = std::thread([&k] {
|
t = std::thread([&k] {
|
||||||
ipc::detail::waiter waiter {"test-ipc-waiter"};
|
ipc::detail::waiter waiter {"test-ipc-waiter"};
|
||||||
EXPECT_TRUE(waiter.valid());
|
EXPECT_TRUE(waiter.valid());
|
||||||
for (int i = 0; i < 99; ++i) {
|
for (int i = 0; i < 9; ++i) {
|
||||||
ASSERT_TRUE(waiter.wait_if([&k, &i] { return k == i; }));
|
while (!waiter.wait_if([&k, &i] { return k == i; })) ;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPECT_TRUE(waiter.open("test-ipc-waiter"));
|
EXPECT_TRUE(waiter.open("test-ipc-waiter"));
|
||||||
std::cout << "waiting for broadcast...\n";
|
std::cout << "waiting for broadcast...\n";
|
||||||
for (k = 1; k < 100; ++k) {
|
for (k = 1; k < 10; ++k) {
|
||||||
std::cout << "broadcast: " << k << "\n";
|
std::cout << "broadcast: " << k << "\n";
|
||||||
ASSERT_TRUE(waiter.broadcast());
|
ASSERT_TRUE(waiter.broadcast());
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||||
|
}
|
||||||
|
for (auto& t : ts) t.join();
|
||||||
|
std::cout << "quit... " << i << "\n";
|
||||||
}
|
}
|
||||||
for (auto& t : ts) t.join();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // internal-linkage
|
} // internal-linkage
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user