Problem: The previous fix unconditionally called pthread_mutex_unlock() at the
beginning of close(), which could interfere with other threads/processes that
still had valid references to the mutex. This caused test failures on FreeBSD
when running tests multiple times (ShmTest.RemoveByName would fail on the second run).
Root cause: Calling unlock() too early could affect the mutex state for other
references that are still using it, leading to unexpected behavior.
Solution: Move pthread_mutex_unlock() to only be called when we're about to
destroy the mutex (i.e., when we're the last reference: shm_->ref() <= 1 &&
self_ref <= 1). This ensures:
1. We don't interfere with other threads/processes using the mutex
2. We still unlock before destroying to avoid FreeBSD robust list issues
3. The unlock happens at the correct time - right before pthread_mutex_destroy()
This is the correct approach because:
- Only the last reference holder should clean up the mutex
- Unlocking should be paired with destroying for the final cleanup
- Other references should not be affected by one reference closing
Fixes the second-run test failure on FreeBSD while maintaining the segfault fix.
Root cause: FreeBSD's robust mutex implementation (libthr) maintains a per-thread
robust list of mutexes. The error 'rb error 14' (EFAULT - Bad address) indicates
that the robust list contained a dangling pointer to a destroyed mutex.
When a mutex object is destroyed (via close() or clear()), if the mutex is still
in the current thread's robust list, FreeBSD's libthr may try to access it later
and encounter an invalid pointer, causing a segmentation fault.
This happened in MutexTest.TryLockExceptionSafety because:
1. The test called try_lock() which successfully acquired the lock
2. The test ended without calling unlock()
3. The mutex destructor called close()
4. close() called pthread_mutex_destroy() on a mutex that was:
- Still locked by the current thread, OR
- Still in the thread's robust list
Solution:
Call pthread_mutex_unlock() before pthread_mutex_destroy() in both close()
and clear() methods. This ensures:
1. The mutex is unlocked if we hold the lock
2. The mutex is removed from the thread's robust list
3. Subsequent pthread_mutex_destroy() is safe
We ignore errors from pthread_mutex_unlock() because:
- If we don't hold the lock, EPERM is expected and harmless
- If the mutex is already unlocked, this is a no-op
- Even if there's an error, we still want to proceed with cleanup
This fix is platform-agnostic and should not affect Linux/QNX behavior,
as both also use pthread robust mutexes with similar semantics.
Fixes the segfault in MutexTest.TryLockExceptionSafety on FreeBSD 15.
Root cause: The previous code incorrectly called shm_->sub_ref() when handling
EOWNERDEAD, which could cause the shared memory to be freed prematurely while
the mutex pointer was still in use, leading to segmentation fault.
Fix: Remove the shm_->sub_ref() call. When EOWNERDEAD is returned, it means
we have successfully acquired the lock. We only need to call pthread_mutex_consistent()
to make the mutex usable again, then return success. The shared memory reference
count should not be modified in this path.
This fixes the segfault in MutexTest.TryLockExceptionSafety on FreeBSD 15.
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
Problem:
- Both linux/get_wait_time.h and posix/get_wait_time.h define inline functions
make_timespec() and calc_wait_time() in namespace ipc::detail
- On Linux, semaphore uses posix implementation, but may include both headers
- This causes ODR (One Definition Rule) violation - undefined behavior
- Different inline function definitions with same name violates C++ standard
- Manifested as test failures in SemaphoreTest::WaitTimeout
Solution:
- Add platform-specific namespace layer between ipc and detail:
- linux/get_wait_time.h: ipc::linux::detail::make_timespec()
- posix/get_wait_time.h: ipc::posix::detail::make_timespec()
- Update all call sites to use fully qualified names:
- linux/condition.h: linux::detail::make_timespec()
- linux/mutex.h: linux::detail::make_timespec() (2 places)
- posix/condition.h: posix::detail::make_timespec()
- posix/mutex.h: posix::detail::make_timespec() (2 places)
- posix/semaphore_impl.h: posix::detail::make_timespec()
This ensures each platform's implementation is uniquely named, preventing
ODR violations and ensuring correct function resolution at compile time.