mirror of
				https://github.com/vdr-projects/vdr.git
				synced 2025-03-01 10:50:46 +00:00 
			
		
		
		
	The new class cIoThrottle is used to allow I/O intense threads to temporarily suspend their activities in case buffers run full
This commit is contained in:
		@@ -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
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										7
									
								
								HISTORY
									
									
									
									
									
								
							
							
						
						
									
										7
									
								
								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.
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										18
									
								
								cutter.c
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								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);
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										3
									
								
								device.c
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								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();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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();
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										18
									
								
								ringbuffer.c
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								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++;
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										44
									
								
								thread.c
									
									
									
									
									
								
							
							
						
						
									
										44
									
								
								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
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										25
									
								
								thread.h
									
									
									
									
									
								
							
							
						
						
									
										25
									
								
								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.
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user