-
Notifications
You must be signed in to change notification settings - Fork 399
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Iox #325 deadlock in shared mem mutex #330
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -23,7 +23,7 @@ namespace iox | |
{ | ||
namespace posix | ||
{ | ||
mutex::mutex(bool f_isRecursive) | ||
mutex::mutex(const Recursive recursive, const Robust robust) | ||
{ | ||
pthread_mutexattr_t attr; | ||
bool isInitialized{true}; | ||
|
@@ -41,7 +41,7 @@ mutex::mutex(bool f_isRecursive) | |
{0}, | ||
{}, | ||
&attr, | ||
f_isRecursive ? PTHREAD_MUTEX_RECURSIVE_NP : PTHREAD_MUTEX_FAST_NP) | ||
recursive == Recursive::ON ? PTHREAD_MUTEX_RECURSIVE_NP : PTHREAD_MUTEX_FAST_NP) | ||
.hasErrors(); | ||
isInitialized &= !cxx::makeSmartC(pthread_mutexattr_setprotocol, | ||
cxx::ReturnMode::PRE_DEFINED_SUCCESS_CODE, | ||
|
@@ -50,6 +50,16 @@ mutex::mutex(bool f_isRecursive) | |
&attr, | ||
PTHREAD_PRIO_NONE) | ||
.hasErrors(); | ||
if (robust == Robust::ON) | ||
{ | ||
isInitialized &= !cxx::makeSmartC(pthread_mutexattr_setrobust, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this call is not supported for Mac OS and therefore has to be reimplemented and I am not aware if Windows is supporting robust mutexes?! But maybe you can follow up this link: https://stackoverflow.com/questions/24946886/is-there-pthread-mutex-robust-equivalent-in-mac-os-x or contact me and we can work together on a solution. |
||
cxx::ReturnMode::PRE_DEFINED_SUCCESS_CODE, | ||
{0}, | ||
{}, | ||
&attr, | ||
PTHREAD_MUTEX_ROBUST) | ||
.hasErrors(); | ||
} | ||
|
||
isInitialized &= | ||
!cxx::makeSmartC(pthread_mutex_init, cxx::ReturnMode::PRE_DEFINED_SUCCESS_CODE, {0}, {}, &m_handle, &attr) | ||
|
@@ -69,10 +79,8 @@ mutex::~mutex() | |
|
||
if (destroyCall.hasErrors()) | ||
{ | ||
std::cerr << "could not destroy mutex ::: pthread_mutex_destroy returned " << destroyCall.getReturnValue() | ||
<< " " | ||
<< "( " << strerror(destroyCall.getReturnValue()) << ") " << std::endl; | ||
std::terminate(); | ||
std::cerr << "Could not destroy mutex ::: pthread_mutex_destroy returned " << destroyCall.getReturnValue() | ||
<< " (error: " << destroyCall.getErrorString() << "). This is a resource leak." << std::endl; | ||
} | ||
} | ||
|
||
|
@@ -83,8 +91,21 @@ pthread_mutex_t mutex::get_native_handle() const noexcept | |
|
||
bool mutex::lock() | ||
{ | ||
return !cxx::makeSmartC(pthread_mutex_lock, cxx::ReturnMode::PRE_DEFINED_SUCCESS_CODE, {0}, {}, &m_handle) | ||
.hasErrors(); | ||
auto lockMutex = | ||
cxx::makeSmartC(pthread_mutex_lock, cxx::ReturnMode::PRE_DEFINED_SUCCESS_CODE, {0, EOWNERDEAD}, {}, &m_handle); | ||
if (lockMutex.getReturnValue() == EOWNERDEAD) | ||
{ | ||
auto consistent = | ||
cxx::makeSmartC(pthread_mutex_consistent, cxx::ReturnMode::PRE_DEFINED_SUCCESS_CODE, {0}, {}, &m_handle); | ||
if (consistent.hasErrors()) | ||
{ | ||
std::cerr << "Could not make robust mutex consistent :::: " | ||
<< "pthread_mutex_consistent returned " << consistent.getReturnValue() | ||
<< " (error: " << consistent.getErrorString() << ")." << std::endl; | ||
return false; | ||
} | ||
} | ||
return !lockMutex.hasErrors(); | ||
} | ||
|
||
bool mutex::unlock() | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -24,11 +24,12 @@ using namespace iox::units::duration_literals; | |
class Mutex_test : public Test | ||
{ | ||
public: | ||
class MutexMock : public iox::posix::mutex | ||
using mutex_t = iox::posix::mutex; | ||
class MutexMock : public mutex_t | ||
{ | ||
public: | ||
MutexMock(const bool isRecursive) | ||
: iox::posix::mutex(isRecursive) | ||
MutexMock(const Recursive recursive, const Robust robust) | ||
: mutex_t(recursive, robust) | ||
{ | ||
} | ||
}; | ||
|
@@ -47,7 +48,7 @@ class Mutex_test : public Test | |
} | ||
} | ||
|
||
iox::posix::mutex sut{false}; | ||
mutex_t sut{mutex_t::Recursive::OFF, mutex_t::Robust::OFF}; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Test cases for recursive and robust mutexes are missing.
|
||
}; | ||
|
||
TEST_F(Mutex_test, TryLockWithNoLock) | ||
|
@@ -68,33 +69,3 @@ TEST_F(Mutex_test, LockAndUnlock) | |
EXPECT_THAT(sut.lock(), Eq(true)); | ||
EXPECT_THAT(sut.unlock(), Eq(true)); | ||
} | ||
|
||
// in qnx you can destroy a locked mutex, without error if the thread holding the lock is destructing it. | ||
TEST_F(Mutex_test, DestructorFailsOnLockedMutex) | ||
{ | ||
std::string output = internal::GetCapturedStderr(); | ||
std::set_terminate([]() { std::cout << "", std::abort(); }); | ||
|
||
EXPECT_DEATH( | ||
{ | ||
std::thread* t; | ||
{ | ||
iox::posix::mutex mtx{false}; | ||
iox::posix::Timer hold(1000_ms); | ||
t = new std::thread([&] { | ||
mtx.lock(); | ||
iox::posix::Timer ct(5000_ms); | ||
while (!ct.hasExpiredComparedToCreationTime()) // come back in any case! | ||
; | ||
}); | ||
|
||
while (!hold.hasExpiredComparedToCreationTime()) | ||
; | ||
} | ||
t->join(); | ||
delete t; | ||
}, | ||
".*"); | ||
|
||
internal::CaptureStderr(); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add noexcept