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:
parent
ce6c90a450
commit
85ae27e372
4
HISTORY
4
HISTORY
@ -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).
|
||||||
|
22
thread.c
22
thread.c
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
8
thread.h
8
thread.h
@ -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:
|
||||||
|
Loading…
Reference in New Issue
Block a user