summaryrefslogtreecommitdiff
path: root/tools.c
diff options
context:
space:
mode:
authorKlaus Schmidinger <vdr@tvdr.de>2015-09-01 11:14:27 +0200
committerKlaus Schmidinger <vdr@tvdr.de>2015-09-01 11:14:27 +0200
commit3cd5294d8a337ee5cd2ec894c9fbe04ad3a7690d (patch)
treeda57ce74189de9bfb27e1a747063c37cd62de501 /tools.c
parent8a7bc6a0bbf60cae8b6391a630880aad5cba3363 (diff)
downloadvdr-3cd5294d8a337ee5cd2ec894c9fbe04ad3a7690d.tar.gz
vdr-3cd5294d8a337ee5cd2ec894c9fbe04ad3a7690d.tar.bz2
Implemented strict locking of global lists
Diffstat (limited to 'tools.c')
-rw-r--r--tools.c90
1 files changed, 84 insertions, 6 deletions
diff --git a/tools.c b/tools.c
index d8e4ac7d..005e4027 100644
--- a/tools.c
+++ b/tools.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: tools.c 4.1 2015/05/11 14:15:15 kls Exp $
+ * $Id: tools.c 4.2 2015/08/29 12:11:20 kls Exp $
*/
#include "tools.h"
@@ -2044,12 +2044,58 @@ int cListObject::Index(void) const
return i;
}
+// --- cListGarbageCollector -------------------------------------------------
+
+#define LIST_GARBAGE_COLLECTOR_TIMEOUT 5 // seconds
+
+cListGarbageCollector ListGarbageCollector;
+
+cListGarbageCollector::cListGarbageCollector(void)
+{
+ objects = NULL;
+ lastPut = 0;
+}
+
+cListGarbageCollector::~cListGarbageCollector()
+{
+ if (objects)
+ esyslog("ERROR: ListGarbageCollector destroyed without prior Purge()!");
+}
+
+void cListGarbageCollector::Put(cListObject *Object)
+{
+ mutex.Lock();
+ Object->next = objects;
+ objects = Object;
+ lastPut = time(NULL);
+ mutex.Unlock();
+}
+
+void cListGarbageCollector::Purge(bool Force)
+{
+ mutex.Lock();
+ if (objects && (time(NULL) - lastPut > LIST_GARBAGE_COLLECTOR_TIMEOUT || Force)) {
+ // We make sure that any object stays in the garbage collector for at least
+ // LIST_GARBAGE_COLLECTOR_TIMEOUT seconds, to give objects that have pointers
+ // to them a chance to drop these references before the object is finally
+ // deleted.
+ while (cListObject *Object = objects) {
+ objects = Object->next;
+ delete Object;
+ }
+ }
+ mutex.Unlock();
+}
+
// --- cListBase -------------------------------------------------------------
-cListBase::cListBase(void)
+cListBase::cListBase(const char *NeedsLocking)
+:stateLock(NeedsLocking)
{
objects = lastObject = NULL;
count = 0;
+ needsLocking = NeedsLocking;
+ useGarbageCollector = needsLocking;
}
cListBase::~cListBase()
@@ -2057,6 +2103,15 @@ cListBase::~cListBase()
Clear();
}
+bool cListBase::Lock(cStateKey &StateKey, bool Write, int TimeoutMs) const
+{
+ if (needsLocking)
+ return stateLock.Lock(StateKey, Write, TimeoutMs);
+ else
+ esyslog("ERROR: cListBase::Lock() called for a list that doesn't require locking");
+ return false;
+}
+
void cListBase::Add(cListObject *Object, cListObject *After)
{
if (After && After != lastObject) {
@@ -2096,8 +2151,12 @@ void cListBase::Del(cListObject *Object, bool DeleteObject)
if (Object == lastObject)
lastObject = Object->Prev();
Object->Unlink();
- if (DeleteObject)
- delete Object;
+ if (DeleteObject) {
+ if (useGarbageCollector)
+ ListGarbageCollector.Put(Object);
+ else
+ delete Object;
+ }
count--;
}
@@ -2141,11 +2200,30 @@ void cListBase::Clear(void)
count = 0;
}
-cListObject *cListBase::Get(int Index) const
+bool cListBase::Contains(const cListObject *Object) const
+{
+ for (const cListObject *o = objects; o; o = o->Next()) {
+ if (o == Object)
+ return true;
+ }
+ return false;
+}
+
+void cListBase::SetExplicitModify(void)
+{
+ stateLock.SetExplicitModify();
+}
+
+void cListBase::SetModified(void)
+{
+ stateLock.IncState();
+}
+
+const cListObject *cListBase::Get(int Index) const
{
if (Index < 0)
return NULL;
- cListObject *object = objects;
+ const cListObject *object = objects;
while (object && Index-- > 0)
object = object->Next();
return object;