Skip to content

Commit 0ba1214

Browse files
authored
Merge pull request #160 from mutouyun/issue/156
Fix FreeBSD test failures in POSIX implementation
2 parents 006a46e + 5517f48 commit 0ba1214

File tree

3 files changed

+53
-37
lines changed

3 files changed

+53
-37
lines changed

src/libipc/platform/detail.h

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -72,15 +72,9 @@
7272

7373
#if __cplusplus >= 201703L
7474

75-
namespace std {
7675

77-
// deduction guides for std::unique_ptr
78-
template <typename T>
79-
unique_ptr(T* p) -> unique_ptr<T>;
80-
template <typename T, typename D>
81-
unique_ptr(T* p, D&& d) -> unique_ptr<T, std::decay_t<D>>;
82-
83-
} // namespace std
76+
// C++17 and later: std library already provides deduction guides
77+
// No need to add custom ones, just use the standard ones directly
8478

8579
namespace ipc {
8680
namespace detail {

src/libipc/platform/posix/mutex.h

Lines changed: 25 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,17 @@ class mutex {
150150

151151
void close() noexcept {
152152
if ((ref_ != nullptr) && (shm_ != nullptr) && (mutex_ != nullptr)) {
153+
// Try to unlock the mutex before destroying it.
154+
// This is important for robust mutexes on FreeBSD, which maintain
155+
// a per-thread robust list. If we destroy a mutex while it's in
156+
// the robust list (even if not locked), FreeBSD may encounter
157+
// dangling pointers later, leading to segfaults.
158+
// We ignore any errors from unlock() since:
159+
// 1. If we don't hold the lock, EPERM is expected and harmless
160+
// 2. If the mutex is already unlocked, this is a no-op
161+
// 3. If there's an error, we still want to proceed with cleanup
162+
::pthread_mutex_unlock(mutex_);
163+
153164
if (shm_->name() != nullptr) {
154165
release_mutex(shm_->name(), [this] {
155166
auto self_ref = ref_->fetch_sub(1, std::memory_order_relaxed);
@@ -171,6 +182,9 @@ class mutex {
171182

172183
void clear() noexcept {
173184
if ((shm_ != nullptr) && (mutex_ != nullptr)) {
185+
// Try to unlock before destroying, same reasoning as in close()
186+
::pthread_mutex_unlock(mutex_);
187+
174188
if (shm_->name() != nullptr) {
175189
release_mutex(shm_->name(), [this] {
176190
int eno;
@@ -206,21 +220,17 @@ class mutex {
206220
case ETIMEDOUT:
207221
return false;
208222
case EOWNERDEAD: {
209-
if (shm_->ref() > 1) {
210-
shm_->sub_ref();
211-
}
223+
// EOWNERDEAD means we have successfully acquired the lock,
224+
// but the previous owner died. We need to make it consistent.
212225
int eno2 = ::pthread_mutex_consistent(mutex_);
213226
if (eno2 != 0) {
214227
ipc::error("fail pthread_mutex_lock[%d], pthread_mutex_consistent[%d]\n", eno, eno2);
215228
return false;
216229
}
217-
int eno3 = ::pthread_mutex_unlock(mutex_);
218-
if (eno3 != 0) {
219-
ipc::error("fail pthread_mutex_lock[%d], pthread_mutex_unlock[%d]\n", eno, eno3);
220-
return false;
221-
}
230+
// After calling pthread_mutex_consistent(), the mutex is now in a
231+
// consistent state and we hold the lock. Return success.
232+
return true;
222233
}
223-
break; // loop again
224234
default:
225235
ipc::error("fail pthread_mutex_lock[%d]\n", eno);
226236
return false;
@@ -238,21 +248,17 @@ class mutex {
238248
case ETIMEDOUT:
239249
return false;
240250
case EOWNERDEAD: {
241-
if (shm_->ref() > 1) {
242-
shm_->sub_ref();
243-
}
251+
// EOWNERDEAD means we have successfully acquired the lock,
252+
// but the previous owner died. We need to make it consistent.
244253
int eno2 = ::pthread_mutex_consistent(mutex_);
245254
if (eno2 != 0) {
246255
ipc::error("fail pthread_mutex_timedlock[%d], pthread_mutex_consistent[%d]\n", eno, eno2);
247-
break;
248-
}
249-
int eno3 = ::pthread_mutex_unlock(mutex_);
250-
if (eno3 != 0) {
251-
ipc::error("fail pthread_mutex_timedlock[%d], pthread_mutex_unlock[%d]\n", eno, eno3);
252-
break;
256+
throw std::system_error{eno2, std::system_category()};
253257
}
258+
// After calling pthread_mutex_consistent(), the mutex is now in a
259+
// consistent state and we hold the lock. Return success.
260+
return true;
254261
}
255-
break;
256262
default:
257263
ipc::error("fail pthread_mutex_timedlock[%d]\n", eno);
258264
break;

src/libipc/platform/posix/semaphore_impl.h

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ namespace sync {
1919
class semaphore {
2020
ipc::shm::handle shm_;
2121
sem_t *h_ = SEM_FAILED;
22+
std::string sem_name_; // Store the actual semaphore name used
2223

2324
public:
2425
semaphore() = default;
@@ -38,9 +39,16 @@ class semaphore {
3839
ipc::error("[open_semaphore] fail shm.acquire: %s\n", name);
3940
return false;
4041
}
41-
h_ = ::sem_open(name, O_CREAT, 0666, static_cast<unsigned>(count));
42+
// POSIX semaphore names must start with "/" on some platforms (e.g., FreeBSD)
43+
// Use a separate namespace for semaphores to avoid conflicts with shm
44+
if (name[0] == '/') {
45+
sem_name_ = std::string(name) + "_sem";
46+
} else {
47+
sem_name_ = std::string("/") + name + "_sem";
48+
}
49+
h_ = ::sem_open(sem_name_.c_str(), O_CREAT, 0666, static_cast<unsigned>(count));
4250
if (h_ == SEM_FAILED) {
43-
ipc::error("fail sem_open[%d]: %s\n", errno, name);
51+
ipc::error("fail sem_open[%d]: %s\n", errno, sem_name_.c_str());
4452
return false;
4553
}
4654
return true;
@@ -52,14 +60,14 @@ class semaphore {
5260
ipc::error("fail sem_close[%d]: %s\n", errno);
5361
}
5462
h_ = SEM_FAILED;
55-
if (shm_.name() != nullptr) {
56-
std::string name = shm_.name();
63+
if (!sem_name_.empty() && shm_.name() != nullptr) {
5764
if (shm_.release() <= 1) {
58-
if (::sem_unlink(name.c_str()) != 0) {
59-
ipc::error("fail sem_unlink[%d]: %s, name: %s\n", errno, name.c_str());
65+
if (::sem_unlink(sem_name_.c_str()) != 0) {
66+
ipc::error("fail sem_unlink[%d]: %s, name: %s\n", errno, sem_name_.c_str());
6067
}
6168
}
6269
}
70+
sem_name_.clear();
6371
}
6472

6573
void clear() noexcept {
@@ -69,14 +77,22 @@ class semaphore {
6977
}
7078
h_ = SEM_FAILED;
7179
}
72-
char const *name = shm_.name();
73-
if (name == nullptr) return;
74-
::sem_unlink(name);
80+
if (!sem_name_.empty()) {
81+
::sem_unlink(sem_name_.c_str());
82+
sem_name_.clear();
83+
}
7584
shm_.clear(); // Make sure the storage is cleaned up.
7685
}
7786

7887
static void clear_storage(char const *name) noexcept {
79-
::sem_unlink(name);
88+
// Construct the semaphore name same way as open() does
89+
std::string sem_name;
90+
if (name[0] == '/') {
91+
sem_name = std::string(name) + "_sem";
92+
} else {
93+
sem_name = std::string("/") + name + "_sem";
94+
}
95+
::sem_unlink(sem_name.c_str());
8096
ipc::shm::handle::clear_storage(name);
8197
}
8298

0 commit comments

Comments
 (0)