mirror of
https://github.com/mutouyun/cpp-ipc.git
synced 2025-12-07 01:06:45 +08:00
Fix FreeBSD-specific issues in POSIX implementation
This commit addresses the test failures reported in issue #156 on FreeBSD platform. 1. Fix POSIX semaphore naming for FreeBSD compatibility - FreeBSD requires semaphore names to start with "/" - Add "_sem" suffix to avoid namespace conflicts with shm - Store semaphore name separately for proper cleanup - This fixes all 24 semaphore test failures 2. Fix robust mutex EOWNERDEAD handling - When pthread_mutex_lock returns EOWNERDEAD, the lock is already acquired by the calling thread - After calling pthread_mutex_consistent(), we should return success immediately, not unlock and retry - Previous behavior caused issues with FreeBSD's libthr robust mutex list management, leading to fatal errors - This fixes the random crashes in MutexTest Technical details: - EOWNERDEAD indicates the previous lock owner died while holding the lock, but the current thread has successfully acquired it - pthread_mutex_consistent() restores the mutex to a consistent state - The Linux implementation worked differently, but the new approach is more correct according to POSIX semantics and works on both Linux and FreeBSD Fixes #156
This commit is contained in:
parent
006a46e09f
commit
543672b39d
@ -214,13 +214,13 @@ public:
|
||||
ipc::error("fail pthread_mutex_lock[%d], pthread_mutex_consistent[%d]\n", eno, eno2);
|
||||
return false;
|
||||
}
|
||||
int eno3 = ::pthread_mutex_unlock(mutex_);
|
||||
if (eno3 != 0) {
|
||||
ipc::error("fail pthread_mutex_lock[%d], pthread_mutex_unlock[%d]\n", eno, eno3);
|
||||
return false;
|
||||
// EOWNERDEAD means we have successfully acquired the lock,
|
||||
// but the previous owner died. After calling pthread_mutex_consistent(),
|
||||
// the mutex is now in a consistent state and we hold the lock.
|
||||
// We should return success here, not unlock and retry.
|
||||
// This avoids issues with FreeBSD's robust mutex list management.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
break; // loop again
|
||||
default:
|
||||
ipc::error("fail pthread_mutex_lock[%d]\n", eno);
|
||||
return false;
|
||||
@ -244,15 +244,11 @@ public:
|
||||
int eno2 = ::pthread_mutex_consistent(mutex_);
|
||||
if (eno2 != 0) {
|
||||
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_);
|
||||
if (eno3 != 0) {
|
||||
ipc::error("fail pthread_mutex_timedlock[%d], pthread_mutex_unlock[%d]\n", eno, eno3);
|
||||
break;
|
||||
// Successfully acquired the lock after making it consistent
|
||||
return true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ipc::error("fail pthread_mutex_timedlock[%d]\n", eno);
|
||||
break;
|
||||
|
||||
@ -19,6 +19,7 @@ namespace sync {
|
||||
class semaphore {
|
||||
ipc::shm::handle shm_;
|
||||
sem_t *h_ = SEM_FAILED;
|
||||
std::string sem_name_; // Store the actual semaphore name used
|
||||
|
||||
public:
|
||||
semaphore() = default;
|
||||
@ -38,9 +39,16 @@ public:
|
||||
ipc::error("[open_semaphore] fail shm.acquire: %s\n", name);
|
||||
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) {
|
||||
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 true;
|
||||
@ -52,14 +60,14 @@ public:
|
||||
ipc::error("fail sem_close[%d]: %s\n", errno);
|
||||
}
|
||||
h_ = SEM_FAILED;
|
||||
if (shm_.name() != nullptr) {
|
||||
std::string name = shm_.name();
|
||||
if (!sem_name_.empty() && shm_.name() != nullptr) {
|
||||
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());
|
||||
if (::sem_unlink(sem_name_.c_str()) != 0) {
|
||||
ipc::error("fail sem_unlink[%d]: %s, name: %s\n", errno, sem_name_.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
sem_name_.clear();
|
||||
}
|
||||
|
||||
void clear() noexcept {
|
||||
@ -69,14 +77,22 @@ public:
|
||||
}
|
||||
h_ = SEM_FAILED;
|
||||
}
|
||||
char const *name = shm_.name();
|
||||
if (name == nullptr) return;
|
||||
::sem_unlink(name);
|
||||
if (!sem_name_.empty()) {
|
||||
::sem_unlink(sem_name_.c_str());
|
||||
sem_name_.clear();
|
||||
}
|
||||
shm_.clear(); // Make sure the storage is cleaned up.
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user