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. instead.
- The SVDRP command DELC now refuses to delete the very last channel in the list, - The SVDRP command DELC now refuses to delete the very last channel in the list,
to avoid ending up with an empty channel 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 * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * 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" #include "thread.h"
@ -151,6 +151,8 @@ void cCondVar::Broadcast(void)
cRwLock::cRwLock(bool PreferWriter) cRwLock::cRwLock(bool PreferWriter)
{ {
locked = 0;
writeLockThreadId = 0;
pthread_rwlockattr_t attr; pthread_rwlockattr_t attr;
pthread_rwlockattr_init(&attr); pthread_rwlockattr_init(&attr);
pthread_rwlockattr_setkind_np(&attr, PreferWriter ? PTHREAD_RWLOCK_PREFER_WRITER_NP : PTHREAD_RWLOCK_PREFER_READER_NP); 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)) if (!GetAbsTime(&abstime, TimeoutMs))
TimeoutMs = 0; TimeoutMs = 0;
} }
if (Write) if (Write) {
Result = TimeoutMs ? pthread_rwlock_timedwrlock(&rwlock, &abstime) : pthread_rwlock_wrlock(&rwlock); 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 else
Result = TimeoutMs ? pthread_rwlock_timedrdlock(&rwlock, &abstime) : pthread_rwlock_rdlock(&rwlock); Result = TimeoutMs ? pthread_rwlock_timedrdlock(&rwlock, &abstime) : pthread_rwlock_rdlock(&rwlock);
return Result == 0; return Result == 0;
@ -179,6 +188,13 @@ bool cRwLock::Lock(bool Write, int TimeoutMs)
void cRwLock::Unlock(void) 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); pthread_rwlock_unlock(&rwlock);
} }
@ -474,9 +490,11 @@ void cStateLock::Unlock(cStateKey &StateKey, bool IncState)
if (StateKey.write && IncState && !explicitModify) if (StateKey.write && IncState && !explicitModify)
state++; state++;
StateKey.state = state; StateKey.state = state;
if (StateKey.write) {
StateKey.write = false; StateKey.write = false;
threadId = 0; threadId = 0;
explicitModify = false; explicitModify = false;
}
rwLock.Unlock(); rwLock.Unlock();
} }

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * 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 #ifndef __THREAD_H
@ -14,6 +14,8 @@
#include <stdio.h> #include <stdio.h>
#include <sys/types.h> #include <sys/types.h>
typedef pid_t tThreadId;
class cCondWait { class cCondWait {
private: private:
pthread_mutex_t mutex; pthread_mutex_t mutex;
@ -53,6 +55,8 @@ public:
class cRwLock { class cRwLock {
private: private:
pthread_rwlock_t rwlock; pthread_rwlock_t rwlock;
int locked;
tThreadId writeLockThreadId;
public: public:
cRwLock(bool PreferWriter = false); cRwLock(bool PreferWriter = false);
~cRwLock(); ~cRwLock();
@ -72,8 +76,6 @@ public:
void Unlock(void); void Unlock(void);
}; };
typedef pid_t tThreadId;
class cThread { class cThread {
friend class cThreadLock; friend class cThreadLock;
private: private: