summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKlaus Schmidinger <vdr@tvdr.de>2016-12-08 10:18:32 +0100
committerKlaus Schmidinger <vdr@tvdr.de>2016-12-08 10:18:32 +0100
commit85ae27e372fa1c433bd01809848cbba46e6706a6 (patch)
treedd41eaeb12f5ef81f8798593fbd6ee5514209408
parentce6c90a4506a80bf7e8fa55d2ab643478e97183f (diff)
downloadvdr-85ae27e372fa1c433bd01809848cbba46e6706a6.tar.gz
vdr-85ae27e372fa1c433bd01809848cbba46e6706a6.tar.bz2
The cRwLock class now allows nested read locks within a write lock from the same thread
-rw-r--r--HISTORY4
-rw-r--r--thread.c32
-rw-r--r--thread.h8
3 files changed, 34 insertions, 10 deletions
diff --git a/HISTORY b/HISTORY
index 503f7707..4ae2b0e1 100644
--- a/HISTORY
+++ b/HISTORY
@@ -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).
diff --git a/thread.c b/thread.c
index 993d16dd..2f57f815 100644
--- a/thread.c
+++ b/thread.c
@@ -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();
}
diff --git a/thread.h b/thread.h
index b5a07c79..9df677d3 100644
--- a/thread.h
+++ b/thread.h
@@ -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: