mirror of
https://github.com/mutouyun/cpp-ipc.git
synced 2025-12-07 01:06:45 +08:00
Merge pull request #160 from mutouyun/issue/156
Fix FreeBSD test failures in POSIX implementation
This commit is contained in:
commit
0ba12144bd
@ -72,15 +72,9 @@
|
|||||||
|
|
||||||
#if __cplusplus >= 201703L
|
#if __cplusplus >= 201703L
|
||||||
|
|
||||||
namespace std {
|
|
||||||
|
|
||||||
// deduction guides for std::unique_ptr
|
// C++17 and later: std library already provides deduction guides
|
||||||
template <typename T>
|
// No need to add custom ones, just use the standard ones directly
|
||||||
unique_ptr(T* p) -> unique_ptr<T>;
|
|
||||||
template <typename T, typename D>
|
|
||||||
unique_ptr(T* p, D&& d) -> unique_ptr<T, std::decay_t<D>>;
|
|
||||||
|
|
||||||
} // namespace std
|
|
||||||
|
|
||||||
namespace ipc {
|
namespace ipc {
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|||||||
@ -150,6 +150,17 @@ public:
|
|||||||
|
|
||||||
void close() noexcept {
|
void close() noexcept {
|
||||||
if ((ref_ != nullptr) && (shm_ != nullptr) && (mutex_ != nullptr)) {
|
if ((ref_ != nullptr) && (shm_ != nullptr) && (mutex_ != nullptr)) {
|
||||||
|
// Try to unlock the mutex before destroying it.
|
||||||
|
// This is important for robust mutexes on FreeBSD, which maintain
|
||||||
|
// a per-thread robust list. If we destroy a mutex while it's in
|
||||||
|
// the robust list (even if not locked), FreeBSD may encounter
|
||||||
|
// dangling pointers later, leading to segfaults.
|
||||||
|
// We ignore any errors from unlock() since:
|
||||||
|
// 1. If we don't hold the lock, EPERM is expected and harmless
|
||||||
|
// 2. If the mutex is already unlocked, this is a no-op
|
||||||
|
// 3. If there's an error, we still want to proceed with cleanup
|
||||||
|
::pthread_mutex_unlock(mutex_);
|
||||||
|
|
||||||
if (shm_->name() != nullptr) {
|
if (shm_->name() != nullptr) {
|
||||||
release_mutex(shm_->name(), [this] {
|
release_mutex(shm_->name(), [this] {
|
||||||
auto self_ref = ref_->fetch_sub(1, std::memory_order_relaxed);
|
auto self_ref = ref_->fetch_sub(1, std::memory_order_relaxed);
|
||||||
@ -171,6 +182,9 @@ public:
|
|||||||
|
|
||||||
void clear() noexcept {
|
void clear() noexcept {
|
||||||
if ((shm_ != nullptr) && (mutex_ != nullptr)) {
|
if ((shm_ != nullptr) && (mutex_ != nullptr)) {
|
||||||
|
// Try to unlock before destroying, same reasoning as in close()
|
||||||
|
::pthread_mutex_unlock(mutex_);
|
||||||
|
|
||||||
if (shm_->name() != nullptr) {
|
if (shm_->name() != nullptr) {
|
||||||
release_mutex(shm_->name(), [this] {
|
release_mutex(shm_->name(), [this] {
|
||||||
int eno;
|
int eno;
|
||||||
@ -206,21 +220,17 @@ public:
|
|||||||
case ETIMEDOUT:
|
case ETIMEDOUT:
|
||||||
return false;
|
return false;
|
||||||
case EOWNERDEAD: {
|
case EOWNERDEAD: {
|
||||||
if (shm_->ref() > 1) {
|
// EOWNERDEAD means we have successfully acquired the lock,
|
||||||
shm_->sub_ref();
|
// but the previous owner died. We need to make it consistent.
|
||||||
}
|
|
||||||
int eno2 = ::pthread_mutex_consistent(mutex_);
|
int eno2 = ::pthread_mutex_consistent(mutex_);
|
||||||
if (eno2 != 0) {
|
if (eno2 != 0) {
|
||||||
ipc::error("fail pthread_mutex_lock[%d], pthread_mutex_consistent[%d]\n", eno, eno2);
|
ipc::error("fail pthread_mutex_lock[%d], pthread_mutex_consistent[%d]\n", eno, eno2);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
int eno3 = ::pthread_mutex_unlock(mutex_);
|
// After calling pthread_mutex_consistent(), the mutex is now in a
|
||||||
if (eno3 != 0) {
|
// consistent state and we hold the lock. Return success.
|
||||||
ipc::error("fail pthread_mutex_lock[%d], pthread_mutex_unlock[%d]\n", eno, eno3);
|
return true;
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
break; // loop again
|
|
||||||
default:
|
default:
|
||||||
ipc::error("fail pthread_mutex_lock[%d]\n", eno);
|
ipc::error("fail pthread_mutex_lock[%d]\n", eno);
|
||||||
return false;
|
return false;
|
||||||
@ -238,21 +248,17 @@ public:
|
|||||||
case ETIMEDOUT:
|
case ETIMEDOUT:
|
||||||
return false;
|
return false;
|
||||||
case EOWNERDEAD: {
|
case EOWNERDEAD: {
|
||||||
if (shm_->ref() > 1) {
|
// EOWNERDEAD means we have successfully acquired the lock,
|
||||||
shm_->sub_ref();
|
// but the previous owner died. We need to make it consistent.
|
||||||
}
|
|
||||||
int eno2 = ::pthread_mutex_consistent(mutex_);
|
int eno2 = ::pthread_mutex_consistent(mutex_);
|
||||||
if (eno2 != 0) {
|
if (eno2 != 0) {
|
||||||
ipc::error("fail pthread_mutex_timedlock[%d], pthread_mutex_consistent[%d]\n", eno, eno2);
|
ipc::error("fail pthread_mutex_timedlock[%d], pthread_mutex_consistent[%d]\n", eno, eno2);
|
||||||
break;
|
throw std::system_error{eno2, std::system_category()};
|
||||||
}
|
}
|
||||||
int eno3 = ::pthread_mutex_unlock(mutex_);
|
// After calling pthread_mutex_consistent(), the mutex is now in a
|
||||||
if (eno3 != 0) {
|
// consistent state and we hold the lock. Return success.
|
||||||
ipc::error("fail pthread_mutex_timedlock[%d], pthread_mutex_unlock[%d]\n", eno, eno3);
|
return true;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
ipc::error("fail pthread_mutex_timedlock[%d]\n", eno);
|
ipc::error("fail pthread_mutex_timedlock[%d]\n", eno);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@ -19,6 +19,7 @@ namespace sync {
|
|||||||
class semaphore {
|
class semaphore {
|
||||||
ipc::shm::handle shm_;
|
ipc::shm::handle shm_;
|
||||||
sem_t *h_ = SEM_FAILED;
|
sem_t *h_ = SEM_FAILED;
|
||||||
|
std::string sem_name_; // Store the actual semaphore name used
|
||||||
|
|
||||||
public:
|
public:
|
||||||
semaphore() = default;
|
semaphore() = default;
|
||||||
@ -38,9 +39,16 @@ public:
|
|||||||
ipc::error("[open_semaphore] fail shm.acquire: %s\n", name);
|
ipc::error("[open_semaphore] fail shm.acquire: %s\n", name);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
h_ = ::sem_open(name, O_CREAT, 0666, static_cast<unsigned>(count));
|
// POSIX semaphore names must start with "/" on some platforms (e.g., FreeBSD)
|
||||||
|
// Use a separate namespace for semaphores to avoid conflicts with shm
|
||||||
|
if (name[0] == '/') {
|
||||||
|
sem_name_ = std::string(name) + "_sem";
|
||||||
|
} else {
|
||||||
|
sem_name_ = std::string("/") + name + "_sem";
|
||||||
|
}
|
||||||
|
h_ = ::sem_open(sem_name_.c_str(), O_CREAT, 0666, static_cast<unsigned>(count));
|
||||||
if (h_ == SEM_FAILED) {
|
if (h_ == SEM_FAILED) {
|
||||||
ipc::error("fail sem_open[%d]: %s\n", errno, name);
|
ipc::error("fail sem_open[%d]: %s\n", errno, sem_name_.c_str());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -52,14 +60,14 @@ public:
|
|||||||
ipc::error("fail sem_close[%d]: %s\n", errno);
|
ipc::error("fail sem_close[%d]: %s\n", errno);
|
||||||
}
|
}
|
||||||
h_ = SEM_FAILED;
|
h_ = SEM_FAILED;
|
||||||
if (shm_.name() != nullptr) {
|
if (!sem_name_.empty() && shm_.name() != nullptr) {
|
||||||
std::string name = shm_.name();
|
|
||||||
if (shm_.release() <= 1) {
|
if (shm_.release() <= 1) {
|
||||||
if (::sem_unlink(name.c_str()) != 0) {
|
if (::sem_unlink(sem_name_.c_str()) != 0) {
|
||||||
ipc::error("fail sem_unlink[%d]: %s, name: %s\n", errno, name.c_str());
|
ipc::error("fail sem_unlink[%d]: %s, name: %s\n", errno, sem_name_.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
sem_name_.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void clear() noexcept {
|
void clear() noexcept {
|
||||||
@ -69,14 +77,22 @@ public:
|
|||||||
}
|
}
|
||||||
h_ = SEM_FAILED;
|
h_ = SEM_FAILED;
|
||||||
}
|
}
|
||||||
char const *name = shm_.name();
|
if (!sem_name_.empty()) {
|
||||||
if (name == nullptr) return;
|
::sem_unlink(sem_name_.c_str());
|
||||||
::sem_unlink(name);
|
sem_name_.clear();
|
||||||
|
}
|
||||||
shm_.clear(); // Make sure the storage is cleaned up.
|
shm_.clear(); // Make sure the storage is cleaned up.
|
||||||
}
|
}
|
||||||
|
|
||||||
static void clear_storage(char const *name) noexcept {
|
static void clear_storage(char const *name) noexcept {
|
||||||
::sem_unlink(name);
|
// Construct the semaphore name same way as open() does
|
||||||
|
std::string sem_name;
|
||||||
|
if (name[0] == '/') {
|
||||||
|
sem_name = std::string(name) + "_sem";
|
||||||
|
} else {
|
||||||
|
sem_name = std::string("/") + name + "_sem";
|
||||||
|
}
|
||||||
|
::sem_unlink(sem_name.c_str());
|
||||||
ipc::shm::handle::clear_storage(name);
|
ipc::shm::handle::clear_storage(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user