summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CONTRIBUTORS2
-rw-r--r--HISTORY7
-rw-r--r--cutter.c18
-rw-r--r--device.c3
-rw-r--r--recorder.c3
-rw-r--r--ringbuffer.c18
-rw-r--r--ringbuffer.h4
-rw-r--r--thread.c44
-rw-r--r--thread.h25
9 files changed, 116 insertions, 8 deletions
diff --git a/CONTRIBUTORS b/CONTRIBUTORS
index 0137743c..419dc216 100644
--- a/CONTRIBUTORS
+++ b/CONTRIBUTORS
@@ -2891,6 +2891,8 @@ Torsten Lang <info@torstenlang.de>
if the editing point merges two seamlessly fitting parts of the same stream
for reporting a sluggish response when manipulating editing marks while a cutting
thread is running
+ for suggesting to allow I/O intense threads to temporarily suspend their activities
+ in case buffers run full
Christian Ruppert <idl0r@gentoo.org>
for some improvements to the Makefiles
diff --git a/HISTORY b/HISTORY
index e4a3fc4c..acfdda73 100644
--- a/HISTORY
+++ b/HISTORY
@@ -7235,7 +7235,7 @@ Video Disk Recorder Revision History
function in order to make use of this new feature. See, for instance, the function
cSkinClassicDisplayMenu::SetButtons() in skinclassic.c for details.
-2012-09-19: Version 1.7.31
+2012-09-22: Version 1.7.31
- If regenerating an index file fails and no data is written to the file, VDR now
reports this error and removes the empty index file.
@@ -7251,3 +7251,8 @@ Video Disk Recorder Revision History
(suggested by Jens Vogel).
- Fixed a leftover frame counter in the LCARS skin's replay display after jumping to
an editing mark and resuming replay.
+- The new class cIoThrottle is used to allow I/O intense threads to temporarily
+ suspend their activities in case buffers run full (suggested by Torsten Lang).
+ Currently the cutter thread is suspended if the TS or Recorder buffer use more
+ than 50% of their capacity. Plugin authors may want to participate in this
+ mechanism if they use intense background I/O.
diff --git a/cutter.c b/cutter.c
index 62eae822..bcae2b72 100644
--- a/cutter.c
+++ b/cutter.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: cutter.c 2.13 2012/06/10 14:33:36 kls Exp $
+ * $Id: cutter.c 2.14 2012/09/20 09:12:47 kls Exp $
*/
#include "cutter.h"
@@ -88,12 +88,28 @@ void cCuttingThread::Action(void)
bool CheckForSeamlessStream = false;
bool LastMark = false;
bool cutIn = true;
+ bool suspensionLogged = false;
while (Running()) {
uint16_t FileNumber;
off_t FileOffset;
int Length;
bool Independent;
+ // Suspend cutting if we have severe throughput problems:
+
+ if (cIoThrottle::Engaged()) {
+ if (!suspensionLogged) {
+ dsyslog("suspending cutter thread");
+ suspensionLogged = true;
+ }
+ cCondWait::SleepMs(100);
+ continue;
+ }
+ else if (suspensionLogged) {
+ dsyslog("resuming cutter thread");
+ suspensionLogged = false;
+ }
+
// Make sure there is enough disk space:
AssertFreeDiskSpace(-1);
diff --git a/device.c b/device.c
index 6518e820..aa93a8e5 100644
--- a/device.c
+++ b/device.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: device.c 2.67 2012/09/02 09:26:36 kls Exp $
+ * $Id: device.c 2.68 2012/09/20 09:32:26 kls Exp $
*/
#include "device.h"
@@ -1721,6 +1721,7 @@ cTSBuffer::cTSBuffer(int File, int Size, int CardIndex)
delivered = false;
ringBuffer = new cRingBufferLinear(Size, TS_SIZE, true, "TS");
ringBuffer->SetTimeouts(100, 100);
+ ringBuffer->SetIoThrottle();
Start();
}
diff --git a/recorder.c b/recorder.c
index a6cab473..c11fdf7c 100644
--- a/recorder.c
+++ b/recorder.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: recorder.c 2.15 2011/09/04 09:26:44 kls Exp $
+ * $Id: recorder.c 2.16 2012/09/22 11:52:33 kls Exp $
*/
#include "recorder.h"
@@ -33,6 +33,7 @@ cRecorder::cRecorder(const char *FileName, const cChannel *Channel, int Priority
ringBuffer = new cRingBufferLinear(RECORDERBUFSIZE, MIN_TS_PACKETS_FOR_FRAME_DETECTOR * TS_SIZE, true, "Recorder");
ringBuffer->SetTimeouts(0, 100);
+ ringBuffer->SetIoThrottle();
int Pid = Channel->Vpid();
int Type = Channel->Vtype();
diff --git a/ringbuffer.c b/ringbuffer.c
index 269623d4..abe78990 100644
--- a/ringbuffer.c
+++ b/ringbuffer.c
@@ -7,7 +7,7 @@
* Parts of this file were inspired by the 'ringbuffy.c' from the
* LinuxDVB driver (see linuxtv.org).
*
- * $Id: ringbuffer.c 2.4 2012/09/17 08:23:43 kls Exp $
+ * $Id: ringbuffer.c 2.5 2012/09/22 11:26:49 kls Exp $
*/
#include "ringbuffer.h"
@@ -20,6 +20,8 @@
#define OVERFLOWREPORTDELTA 5 // seconds between reports
#define PERCENTAGEDELTA 10
#define PERCENTAGETHRESHOLD 70
+#define IOTHROTTLELOW 20
+#define IOTHROTTLEHIGH 50
cRingBuffer::cRingBuffer(int Size, bool Statistics)
{
@@ -31,10 +33,12 @@ cRingBuffer::cRingBuffer(int Size, bool Statistics)
putTimeout = getTimeout = 0;
lastOverflowReport = 0;
overflowCount = overflowBytes = 0;
+ ioThrottle = NULL;
}
cRingBuffer::~cRingBuffer()
{
+ delete ioThrottle;
if (statistics)
dsyslog("buffer stats: %d (%d%%) used", maxFill, maxFill * 100 / (size - 1));
}
@@ -50,6 +54,12 @@ void cRingBuffer::UpdatePercentage(int Fill)
lastPercent = percent;
}
}
+ if (ioThrottle) {
+ if (percent >= IOTHROTTLEHIGH)
+ ioThrottle->Activate();
+ else if (percent < IOTHROTTLELOW)
+ ioThrottle->Release();
+ }
}
void cRingBuffer::WaitForPut(void)
@@ -82,6 +92,12 @@ void cRingBuffer::SetTimeouts(int PutTimeout, int GetTimeout)
getTimeout = GetTimeout;
}
+void cRingBuffer::SetIoThrottle(void)
+{
+ if (!ioThrottle)
+ ioThrottle = new cIoThrottle;
+}
+
void cRingBuffer::ReportOverflow(int Bytes)
{
overflowCount++;
diff --git a/ringbuffer.h b/ringbuffer.h
index d234502d..5b2eeb1c 100644
--- a/ringbuffer.h
+++ b/ringbuffer.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: ringbuffer.h 2.3 2011/12/04 13:38:17 kls Exp $
+ * $Id: ringbuffer.h 2.4 2012/09/20 09:29:32 kls Exp $
*/
#ifndef __RINGBUFFER_H
@@ -22,6 +22,7 @@ private:
time_t lastOverflowReport;
int overflowCount;
int overflowBytes;
+ cIoThrottle *ioThrottle;
protected:
tThreadId getThreadTid;
int maxFill;//XXX
@@ -40,6 +41,7 @@ public:
cRingBuffer(int Size, bool Statistics = false);
virtual ~cRingBuffer();
void SetTimeouts(int PutTimeout, int GetTimeout);
+ void SetIoThrottle(void);
void ReportOverflow(int Bytes);
};
diff --git a/thread.c b/thread.c
index 5bcc9a54..a650fab8 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 2.4 2012/05/08 11:15:57 kls Exp $
+ * $Id: thread.c 2.5 2012/09/20 09:05:50 kls Exp $
*/
#include "thread.h"
@@ -398,6 +398,48 @@ bool cThreadLock::Lock(cThread *Thread)
return false;
}
+// --- cIoThrottle -----------------------------------------------------------
+
+cMutex cIoThrottle::mutex;
+int cIoThrottle::count = 0;
+
+cIoThrottle::cIoThrottle(void)
+{
+ active = false;
+}
+
+cIoThrottle::~cIoThrottle()
+{
+ Release();
+}
+
+void cIoThrottle::Activate(void)
+{
+ if (!active) {
+ mutex.Lock();
+ count++;
+ active = true;
+ dsyslog("i/o throttle activated, count = %d (tid=%d)", count, cThread::ThreadId());
+ mutex.Unlock();
+ }
+}
+
+void cIoThrottle::Release(void)
+{
+ if (active) {
+ mutex.Lock();
+ count--;
+ active = false;
+ dsyslog("i/o throttle released, count = %d (tid=%d)", count, cThread::ThreadId());
+ mutex.Unlock();
+ }
+}
+
+bool cIoThrottle::Engaged(void)
+{
+ return count > 0;
+}
+
// --- cPipe -----------------------------------------------------------------
// cPipe::Open() and cPipe::Close() are based on code originally received from
diff --git a/thread.h b/thread.h
index d4919eb6..f77e8198 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 2.1 2009/04/13 13:50:39 kls Exp $
+ * $Id: thread.h 2.2 2012/09/20 08:46:27 kls Exp $
*/
#ifndef __THREAD_H
@@ -157,6 +157,29 @@ public:
#define LOCK_THREAD cThreadLock ThreadLock(this)
+class cIoThrottle {
+private:
+ static cMutex mutex;
+ static int count;
+ bool active;
+public:
+ cIoThrottle(void);
+ ~cIoThrottle();
+ void Activate(void);
+ ///< Activates the global I/O throttling mechanism.
+ ///< This function may be called any number of times, but only
+ ///< the first call after an inactive state will have an effect.
+ void Release(void);
+ ///< Releases the global I/O throttling mechanism.
+ ///< This function may be called any number of times, but only
+ ///< the first call after an active state will have an effect.
+ bool Active(void) { return active; }
+ ///< Returns true if this I/O throttling object is currently active.
+ static bool Engaged(void);
+ ///< Returns true if any I/O throttling object is currently active.
+ };
+
+
// cPipe implements a pipe that closes all unnecessary file descriptors in
// the child process.