Commit 24415ced authored by Kenton Varda's avatar Kenton Varda

Apparently read locks are not recursive on BSD/OSX. Adjust test so that it doesn't deadlock.

parent 02386c72
...@@ -57,11 +57,28 @@ TEST(Mutex, MutexGuarded) { ...@@ -57,11 +57,28 @@ TEST(Mutex, MutexGuarded) {
{ {
auto rlock1 = value.lockShared(); auto rlock1 = value.lockShared();
{
auto rlock2 = value.lockShared();
EXPECT_EQ(789, *rlock2);
auto rlock3 = value.lockShared();
EXPECT_EQ(789, *rlock3);
auto rlock4 = value.lockShared();
EXPECT_EQ(789, *rlock4);
}
Thread thread2([&]() { Thread thread2([&]() {
Locked<uint> threadLock = value.lockExclusive(); Locked<uint> threadLock = value.lockExclusive();
*threadLock = 321; *threadLock = 321;
}); });
#if KJ_USE_FUTEX
// So, it turns out that pthread_rwlock on BSD "prioritizes" readers over writers. The result
// is that if one thread tries to take multiple read locks, but another thread happens to
// request a write lock it between, you get a deadlock. This seems to contradict the man pages
// and common sense, but this is how it is. The futex-based implementation doesn't currently
// have this problem because it does not prioritize writers. Perhaps it will in the future,
// but we'll leave this test here until then to make sure we notice the change.
delay(); delay();
EXPECT_EQ(789, *rlock1); EXPECT_EQ(789, *rlock1);
...@@ -73,6 +90,7 @@ TEST(Mutex, MutexGuarded) { ...@@ -73,6 +90,7 @@ TEST(Mutex, MutexGuarded) {
auto rlock4 = value.lockShared(); auto rlock4 = value.lockShared();
EXPECT_EQ(789, *rlock4); EXPECT_EQ(789, *rlock4);
} }
#endif
delay(); delay();
EXPECT_EQ(789, *rlock1); EXPECT_EQ(789, *rlock1);
......
...@@ -174,7 +174,14 @@ class MutexGuarded { ...@@ -174,7 +174,14 @@ class MutexGuarded {
// An object of type T, guarded by a mutex. In order to access the object, you must lock it. // An object of type T, guarded by a mutex. In order to access the object, you must lock it.
// //
// Write locks are not "recursive" -- trying to lock again in a thread that already holds a lock // Write locks are not "recursive" -- trying to lock again in a thread that already holds a lock
// will deadlock. If you think you need recursive locks, you are wrong. Get over it. // will deadlock. Recursive write locks are usually a sign of bad design.
//
// Unfortunately, **READ LOCKS ARE NOT RECURSIVE** either. Common sense says they should be.
// But on many operating systems (BSD, OSX), recursively read-locking a pthread_rwlock is
// actually unsafe. The problem is that writers are "prioritized" over readers, so a read lock
// request will block if any write lock requests are outstanding. So, if thread A takes a read
// lock, thread B requests a write lock (and starts waiting), and then thread A tries to take
// another read lock recursively, the result is deadlock.
public: public:
template <typename... Params> template <typename... Params>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment