diff options
author | Klaus Schmidinger <vdr@tvdr.de> | 2016-12-08 10:18:32 +0100 |
---|---|---|
committer | Klaus Schmidinger <vdr@tvdr.de> | 2016-12-08 10:18:32 +0100 |
commit | 85ae27e372fa1c433bd01809848cbba46e6706a6 (patch) | |
tree | dd41eaeb12f5ef81f8798593fbd6ee5514209408 | |
parent | ce6c90a4506a80bf7e8fa55d2ab643478e97183f (diff) | |
download | vdr-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-- | HISTORY | 4 | ||||
-rw-r--r-- | thread.c | 32 | ||||
-rw-r--r-- | thread.h | 8 |
3 files changed, 34 insertions, 10 deletions
@@ -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). @@ -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(); } @@ -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: |