1
0
mirror of https://github.com/VDR4Arch/vdr.git synced 2023-10-10 13:36:52 +02:00

The cRwLock class now allows nested read locks within a write lock from the same thread

This commit is contained in:
Klaus Schmidinger 2016-12-08 10:18:32 +01:00
parent ce6c90a450
commit 85ae27e372
3 changed files with 34 additions and 10 deletions

View File

@ -8839,3 +8839,7 @@ Video Disk Recorder Revision History
instead.
- The SVDRP command DELC now refuses to delete the very last channel in the list,
to avoid ending up with an empty channel list.
- The cRwLock class now allows nested read locks within a write lock from the
same thread. This fixes possible crashes when moving or deleting channels in
the menu or through SVDRP (as well as other operations that try to acquire a
read lock within a write lock).

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: thread.c 4.1 2015/08/29 14:43:03 kls Exp $
* $Id: thread.c 4.2 2016/12/08 10:18:32 kls Exp $
*/
#include "thread.h"
@ -151,6 +151,8 @@ void cCondVar::Broadcast(void)
cRwLock::cRwLock(bool PreferWriter)
{
locked = 0;
writeLockThreadId = 0;
pthread_rwlockattr_t attr;
pthread_rwlockattr_init(&attr);
pthread_rwlockattr_setkind_np(&attr, PreferWriter ? PTHREAD_RWLOCK_PREFER_WRITER_NP : PTHREAD_RWLOCK_PREFER_READER_NP);
@ -170,8 +172,15 @@ bool cRwLock::Lock(bool Write, int TimeoutMs)
if (!GetAbsTime(&abstime, TimeoutMs))
TimeoutMs = 0;
}
if (Write)
if (Write) {
Result = TimeoutMs ? pthread_rwlock_timedwrlock(&rwlock, &abstime) : pthread_rwlock_wrlock(&rwlock);
if (Result == 0)
writeLockThreadId = cThread::ThreadId();
}
else if (writeLockThreadId == cThread::ThreadId()) {
locked++; // there can be any number of stacked read locks, so we keep track here
Result = 0; // aquiring a read lock while holding a write lock within the same thread is OK
}
else
Result = TimeoutMs ? pthread_rwlock_timedrdlock(&rwlock, &abstime) : pthread_rwlock_rdlock(&rwlock);
return Result == 0;
@ -179,6 +188,13 @@ bool cRwLock::Lock(bool Write, int TimeoutMs)
void cRwLock::Unlock(void)
{
if (writeLockThreadId == cThread::ThreadId()) { // this is the thread that obtained the initial write lock
if (locked) { // this is the unlock of a read lock within the write lock
locked--;
return;
}
}
writeLockThreadId = 0;
pthread_rwlock_unlock(&rwlock);
}
@ -206,8 +222,8 @@ void cMutex::Lock(void)
void cMutex::Unlock(void)
{
if (!--locked)
pthread_mutex_unlock(&mutex);
if (!--locked)
pthread_mutex_unlock(&mutex);
}
// --- cThread ---------------------------------------------------------------
@ -474,9 +490,11 @@ void cStateLock::Unlock(cStateKey &StateKey, bool IncState)
if (StateKey.write && IncState && !explicitModify)
state++;
StateKey.state = state;
StateKey.write = false;
threadId = 0;
explicitModify = false;
if (StateKey.write) {
StateKey.write = false;
threadId = 0;
explicitModify = false;
}
rwLock.Unlock();
}

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: thread.h 4.1 2015/08/17 13:06:24 kls Exp $
* $Id: thread.h 4.2 2016/12/08 10:18:32 kls Exp $
*/
#ifndef __THREAD_H
@ -14,6 +14,8 @@
#include <stdio.h>
#include <sys/types.h>
typedef pid_t tThreadId;
class cCondWait {
private:
pthread_mutex_t mutex;
@ -53,6 +55,8 @@ public:
class cRwLock {
private:
pthread_rwlock_t rwlock;
int locked;
tThreadId writeLockThreadId;
public:
cRwLock(bool PreferWriter = false);
~cRwLock();
@ -72,8 +76,6 @@ public:
void Unlock(void);
};
typedef pid_t tThreadId;
class cThread {
friend class cThreadLock;
private: