pthread: fix deadlock in pthread_rwlock_*

Properly initialize and reset the _owner member, otherwise
correlating the unlock operation with the respective read/write
lock does not work.

Move locking the _nbr_mutex in the unlock operation after the
owner check. Otherwise, a reader holding that mutex and waiting
for the write lock would deadlock a writer trying to unlock the
_global_mutex.

Ref. Componolit/componolit#86
Ref. #2656
Fixes #2832
This commit is contained in:
Alexander Senier 2018-04-09 07:13:17 +02:00 committed by Christian Helmuth
parent 230ed1de37
commit 43faf63fde

View File

@ -38,7 +38,7 @@ extern "C" {
{ {
private: private:
Genode::Thread *_owner; Genode::Thread *_owner = nullptr;
Genode::Lock _nbr_mutex {}; Genode::Lock _nbr_mutex {};
Genode::Lock _global_mutex {}; Genode::Lock _global_mutex {};
int _nbr = 0; int _nbr = 0;
@ -51,6 +51,7 @@ extern "C" {
++_nbr; ++_nbr;
if (_nbr == 1) { if (_nbr == 1) {
_global_mutex.lock(); _global_mutex.lock();
_owner = nullptr;
} }
} }
@ -62,12 +63,12 @@ extern "C" {
int unlock() int unlock()
{ {
Genode::Lock_guard<Genode::Lock> guard(_nbr_mutex);
/* Read lock */ /* Read lock */
if (_owner == nullptr) { if (_owner == nullptr) {
Genode::Lock_guard<Genode::Lock> guard(_nbr_mutex);
_nbr--; _nbr--;
if (_nbr == 0) { if (_nbr == 0) {
_owner = nullptr;
_global_mutex.unlock(); _global_mutex.unlock();
} }
return 0; return 0;
@ -80,6 +81,7 @@ extern "C" {
}; };
/* Write lock owned by us */ /* Write lock owned by us */
_owner = nullptr;
_global_mutex.unlock(); _global_mutex.unlock();
return 0; return 0;
} }