summaryrefslogtreecommitdiff
path: root/ringbuffer.c
diff options
context:
space:
mode:
authorKlaus Schmidinger <vdr@tvdr.de>2004-10-16 09:36:28 +0200
committerKlaus Schmidinger <vdr@tvdr.de>2004-10-16 09:36:28 +0200
commit6415cc900de3361925d22f879077be687fce3858 (patch)
tree98ab10cda016e125e33966e371ccfe01e5fd9bd1 /ringbuffer.c
parent15030f6acece1060f9736f875fe3abbcf9392263 (diff)
downloadvdr-6415cc900de3361925d22f879077be687fce3858.tar.gz
vdr-6415cc900de3361925d22f879077be687fce3858.tar.bz2
Improved buffer handling
Diffstat (limited to 'ringbuffer.c')
-rw-r--r--ringbuffer.c230
1 files changed, 173 insertions, 57 deletions
diff --git a/ringbuffer.c b/ringbuffer.c
index b52c37e5..3473a9e7 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 1.20 2004/06/19 12:27:56 kls Exp $
+ * $Id: ringbuffer.c 1.21 2004/10/15 13:49:25 kls Exp $
*/
#include "ringbuffer.h"
@@ -18,11 +18,14 @@
// --- cRingBuffer -----------------------------------------------------------
#define OVERFLOWREPORTDELTA 5 // seconds between reports
+#define PERCENTAGEDELTA 10
+#define PERCENTAGETHRESHOLD 70
cRingBuffer::cRingBuffer(int Size, bool Statistics)
{
size = Size;
statistics = Statistics;
+ getThreadTid = 0;
maxFill = 0;
lastPercent = 0;
putTimeout = getTimeout = 0;
@@ -36,34 +39,41 @@ cRingBuffer::~cRingBuffer()
dsyslog("buffer stats: %d (%d%%) used", maxFill, maxFill * 100 / (size - 1));
}
-void cRingBuffer::WaitForPut(void)
+void cRingBuffer::UpdatePercentage(int Fill)
{
- if (putTimeout) {
- putMutex.Lock();
- readyForPut.TimedWait(putMutex, putTimeout);
- putMutex.Unlock();
+ if (Fill > maxFill)
+ maxFill = Fill;
+ int percent = Fill * 100 / (Size() - 1) / PERCENTAGEDELTA * PERCENTAGEDELTA;
+ if (percent != lastPercent) {
+ if (percent >= PERCENTAGETHRESHOLD && percent > lastPercent || percent < PERCENTAGETHRESHOLD && lastPercent >= PERCENTAGETHRESHOLD) {
+ dsyslog("buffer usage: %d%% (tid=%ld)", percent, getThreadTid);
+ lastPercent = percent;
+ }
}
}
+void cRingBuffer::WaitForPut(void)
+{
+ if (putTimeout)
+ readyForPut.Wait(putTimeout);
+}
+
void cRingBuffer::WaitForGet(void)
{
- if (getTimeout) {
- getMutex.Lock();
- readyForGet.TimedWait(getMutex, getTimeout);
- getMutex.Unlock();
- }
+ if (getTimeout)
+ readyForGet.Wait(getTimeout);
}
void cRingBuffer::EnablePut(void)
{
- if (putTimeout)
- readyForPut.Broadcast();
+ if (putTimeout && Free() > Size() / 3)
+ readyForPut.Signal();
}
void cRingBuffer::EnableGet(void)
{
- if (getTimeout)
- readyForGet.Broadcast();
+ if (getTimeout && Available() > Size() / 3)
+ readyForGet.Signal();
}
void cRingBuffer::SetTimeouts(int PutTimeout, int GetTimeout)
@@ -85,70 +95,168 @@ void cRingBuffer::ReportOverflow(int Bytes)
// --- cRingBufferLinear -----------------------------------------------------
-cRingBufferLinear::cRingBufferLinear(int Size, int Margin, bool Statistics)
+#ifdef DEBUGRINGBUFFERS
+#define MAXRBLS 30
+#define DEBUGRBLWIDTH 45
+
+cRingBufferLinear *cRingBufferLinear::RBLS[MAXRBLS] = { NULL };
+
+void cRingBufferLinear::AddDebugRBL(cRingBufferLinear *RBL)
+{
+ for (int i = 0; i < MAXRBLS; i++) {
+ if (!RBLS[i]) {
+ RBLS[i] = RBL;
+ break;
+ }
+ }
+}
+
+void cRingBufferLinear::DelDebugRBL(cRingBufferLinear *RBL)
+{
+ for (int i = 0; i < MAXRBLS; i++) {
+ if (RBLS[i] == RBL) {
+ RBLS[i] = NULL;
+ break;
+ }
+ }
+}
+
+void cRingBufferLinear::PrintDebugRBL(void)
+{
+ bool printed = false;
+ for (int i = 0; i < MAXRBLS; i++) {
+ cRingBufferLinear *p = RBLS[i];
+ if (p) {
+ printed = true;
+ int lh = p->lastHead;
+ int lt = p->lastTail;
+ int h = lh * DEBUGRBLWIDTH / p->Size();
+ int t = lt * DEBUGRBLWIDTH / p->Size();
+ char buf[DEBUGRBLWIDTH + 10];
+ memset(buf, '-', DEBUGRBLWIDTH);
+ if (lt <= lh)
+ memset(buf + t, '*', max(h - t, 1));
+ else {
+ memset(buf, '*', h);
+ memset(buf + t, '*', DEBUGRBLWIDTH - t);
+ }
+ buf[t] = '<';
+ buf[h] = '>';
+ buf[DEBUGRBLWIDTH] = 0;
+ printf("%2d %s %8d %8d %s\n", i, buf, p->lastPut, p->lastGet, p->description);
+ }
+ }
+ if (printed)
+ printf("\n");
+ }
+#endif
+
+cRingBufferLinear::cRingBufferLinear(int Size, int Margin, bool Statistics, const char *Description)
:cRingBuffer(Size, Statistics)
{
- margin = Margin;
+ description = Description ? strdup(Description) : NULL;
+ tail = head = margin = Margin;
buffer = NULL;
- getThreadTid = 0;
if (Size > 1) { // 'Size - 1' must not be 0!
- buffer = MALLOC(uchar, Size);
- if (!buffer)
- esyslog("ERROR: can't allocate ring buffer (size=%d)", Size);
- Clear();
+ if (Margin <= Size / 2) {
+ buffer = MALLOC(uchar, Size);
+ if (!buffer)
+ esyslog("ERROR: can't allocate ring buffer (size=%d)", Size);
+ Clear();
+ }
+ else
+ esyslog("ERROR: illegal margin for ring buffer (%d > %d)", Margin, Size / 2);
}
else
esyslog("ERROR: illegal size for ring buffer (%d)", Size);
+#ifdef DEBUGRINGBUFFERS
+ lastHead = head;
+ lastTail = tail;
+ lastPut = lastGet = -1;
+ AddDebugRBL(this);
+#endif
}
cRingBufferLinear::~cRingBufferLinear()
{
+#ifdef DEBUGRINGBUFFERS
+ DelDebugRBL(this);
+#endif
free(buffer);
+ free(description);
}
int cRingBufferLinear::Available(void)
{
- Lock();
int diff = head - tail;
- Unlock();
return (diff >= 0) ? diff : Size() + diff - margin;
}
void cRingBufferLinear::Clear(void)
{
- Lock();
- head = tail = margin;
- lastGet = -1;
- Unlock();
+ tail = head;
+#ifdef DEBUGRINGBUFFERS
+ lastHead = head;
+ lastTail = tail;
+ lastPut = lastGet = -1;
+#endif
+ maxFill = 0;
EnablePut();
+}
+
+int cRingBufferLinear::Read(int FileHandle, int Max)
+{
+ int Tail = tail;
+ int diff = Tail - head;
+ int free = (diff > 0) ? diff - 1 : Size() - head;
+ if (Tail <= margin)
+ free--;
+ int Count = 0;
+ if (free > 0) {
+ if (0 < Max && Max < free)
+ free = Max;
+ Count = safe_read(FileHandle, buffer + head, free);
+ if (Count > 0) {
+ int Head = head + Count;
+ if (Head >= Size())
+ Head = margin;
+ head = Head;
+ if (statistics) {
+ int fill = head - Tail;
+ if (fill < 0)
+ fill = Size() + fill;
+ else if (fill >= Size())
+ fill = Size() - 1;
+ UpdatePercentage(fill);
+ }
+ }
+ }
+#ifdef DEBUGRINGBUFFERS
+ lastHead = head;
+ lastPut = Count;
+#endif
EnableGet();
+ if (free == 0)
+ WaitForPut();
+ return Count;
}
int cRingBufferLinear::Put(const uchar *Data, int Count)
{
if (Count > 0) {
- Lock();
+ int Tail = tail;
int rest = Size() - head;
- int diff = tail - head;
- int free = ((tail < margin) ? rest : (diff > 0) ? diff : Size() + diff - margin) - 1;
+ int diff = Tail - head;
+ int free = ((Tail < margin) ? rest : (diff > 0) ? diff : Size() + diff - margin) - 1;
if (statistics) {
int fill = Size() - free - 1 + Count;
if (fill >= Size())
fill = Size() - 1;
- if (fill > maxFill)
- maxFill = fill;
- int percent = maxFill * 100 / (Size() - 1) / 5 * 5;
- if (abs(lastPercent - percent) >= 5) {
- if (percent > 75)
- dsyslog("buffer usage: %d%% (tid=%ld)", percent, getThreadTid);
- lastPercent = percent;
- }
+ UpdatePercentage(fill);
}
if (free > 0) {
if (free < Count)
Count = free;
- if (Count > maxFill)
- maxFill = Count;
if (Count >= rest) {
memcpy(buffer + head, Data, rest);
if (Count - rest)
@@ -162,7 +270,10 @@ int cRingBufferLinear::Put(const uchar *Data, int Count)
}
else
Count = 0;
- Unlock();
+#ifdef DEBUGRINGBUFFERS
+ lastHead = head;
+ lastPut = Count;
+#endif
EnableGet();
if (Count == 0)
WaitForPut();
@@ -173,25 +284,24 @@ int cRingBufferLinear::Put(const uchar *Data, int Count)
uchar *cRingBufferLinear::Get(int &Count)
{
uchar *p = NULL;
- Lock();
+ int Head = head;
if (getThreadTid <= 0)
getThreadTid = pthread_self();
int rest = Size() - tail;
- if (rest < margin && head < tail) {
+ if (rest < margin && Head < tail) {
int t = margin - rest;
memcpy(buffer + t, buffer + tail, rest);
tail = t;
- rest = head - tail;
+ rest = Head - tail;
}
- int diff = head - tail;
+ int diff = Head - tail;
int cont = (diff >= 0) ? diff : Size() + diff - margin;
if (cont > rest)
cont = rest;
if (cont >= margin) {
p = buffer + tail;
- Count = lastGet = cont;
+ Count = gotten = cont;
}
- Unlock();
if (!p)
WaitForGet();
return p;
@@ -199,17 +309,23 @@ uchar *cRingBufferLinear::Get(int &Count)
void cRingBufferLinear::Del(int Count)
{
- if (Count > 0 && Count <= lastGet) {
- Lock();
- tail += Count;
- lastGet -= Count;
- if (tail >= Size())
- tail = margin;
- Unlock();
+ if (Count > gotten) {
+ esyslog("ERROR: invalid Count in cRingBufferLinear::Del: %d (limited to %d)", Count, gotten);
+ Count = gotten;
+ }
+ if (Count > 0) {
+ int Tail = tail;
+ Tail += Count;
+ gotten -= Count;
+ if (Tail >= Size())
+ Tail = margin;
+ tail = Tail;
EnablePut();
}
- else
- esyslog("ERROR: invalid Count in cRingBufferLinear::Del: %d", Count);
+#ifdef DEBUGRINGBUFFERS
+ lastTail = tail;
+ lastGet = Count;
+#endif
}
// --- cFrame ----------------------------------------------------------------