summaryrefslogtreecommitdiff
path: root/ringbuffer.c
diff options
context:
space:
mode:
Diffstat (limited to 'ringbuffer.c')
-rw-r--r--ringbuffer.c253
1 files changed, 198 insertions, 55 deletions
diff --git a/ringbuffer.c b/ringbuffer.c
index 8511a1c..7e09b2a 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.2 2001/05/20 11:58:08 kls Exp $
+ * $Id: ringbuffer.c 1.4 2001/08/05 12:17:45 kls Exp $
*/
#include "ringbuffer.h"
@@ -41,61 +41,128 @@ cRingBuffer::cRingBuffer(int Size, bool Statistics)
{
size = Size;
statistics = Statistics;
- buffer = NULL;
inputThread = NULL;
outputThread = NULL;
+ busy = false;
maxFill = 0;
+}
+
+cRingBuffer::~cRingBuffer()
+{
+ delete inputThread;
+ delete outputThread;
+ if (statistics)
+ dsyslog(LOG_INFO, "buffer stats: %d (%d%%) used", maxFill, maxFill * 100 / (size - 1));
+}
+
+void cRingBuffer::WaitForPut(void)
+{
+ putMutex.Lock();
+ readyForPut.Wait(putMutex);
+ putMutex.Unlock();
+}
+
+void cRingBuffer::WaitForGet(void)
+{
+ getMutex.Lock();
+ readyForGet.Wait(getMutex);
+ getMutex.Unlock();
+}
+
+void cRingBuffer::EnablePut(void)
+{
+ readyForPut.Broadcast();
+}
+
+void cRingBuffer::EnableGet(void)
+{
+ readyForGet.Broadcast();
+}
+
+bool cRingBuffer::Start(void)
+{
+ if (!busy) {
+ busy = true;
+ outputThread = new cRingBufferOutputThread(this);
+ if (!outputThread->Start())
+ DELETENULL(outputThread);
+ inputThread = new cRingBufferInputThread(this);
+ if (!inputThread->Start()) {
+ DELETENULL(inputThread);
+ DELETENULL(outputThread);
+ }
+ busy = outputThread && inputThread;
+ }
+ return busy;
+}
+
+bool cRingBuffer::Active(void)
+{
+ return outputThread && outputThread->Active() && inputThread && inputThread->Active();
+}
+
+void cRingBuffer::Stop(void)
+{
busy = false;
- if (size > 1) { // 'size - 1' must not be 0!
- buffer = new uchar[size];
+ for (time_t t0 = time(NULL) + 3; time(NULL) < t0; ) {
+ if (!((outputThread && outputThread->Active()) || (inputThread && inputThread->Active())))
+ break;
+ }
+ DELETENULL(inputThread);
+ DELETENULL(outputThread);
+}
+
+// --- cRingBufferLinear ----------------------------------------------------
+
+cRingBufferLinear::cRingBufferLinear(int Size, bool Statistics)
+:cRingBuffer(Size, Statistics)
+{
+ buffer = NULL;
+ if (Size > 1) { // 'Size - 1' must not be 0!
+ buffer = new uchar[Size];
if (!buffer)
- esyslog(LOG_ERR, "ERROR: can't allocate ring buffer (size=%d)", size);
+ esyslog(LOG_ERR, "ERROR: can't allocate ring buffer (size=%d)", Size);
Clear();
}
else
- esyslog(LOG_ERR, "ERROR: illegal size for ring buffer (%d)", size);
+ esyslog(LOG_ERR, "ERROR: illegal size for ring buffer (%d)", Size);
}
-cRingBuffer::~cRingBuffer()
+cRingBufferLinear::~cRingBufferLinear()
{
- delete inputThread;
- delete outputThread;
delete buffer;
- if (statistics)
- dsyslog(LOG_INFO, "buffer stats: %d (%d%%) used", maxFill, maxFill * 100 / (size - 1));
}
-int cRingBuffer::Available(void)
+int cRingBufferLinear::Available(void)
{
- mutex.Lock();
+ Lock();
int diff = head - tail;
- int cont = (diff >= 0) ? diff : size + diff;
- mutex.Unlock();
- return cont;
+ Unlock();
+ return (diff >= 0) ? diff : Size() + diff;
}
-void cRingBuffer::Clear(void)
+void cRingBufferLinear::Clear(void)
{
- mutex.Lock();
+ Lock();
head = tail = 0;
- mutex.Unlock();
+ Unlock();
}
-int cRingBuffer::Put(const uchar *Data, int Count)
+int cRingBufferLinear::Put(const uchar *Data, int Count)
{
if (Count > 0) {
- mutex.Lock();
- int rest = size - head;
+ Lock();
+ int rest = Size() - head;
int diff = tail - head;
- mutex.Unlock();
- int free = (diff > 0) ? diff - 1 : size + diff - 1;
+ Unlock();
+ int free = (diff > 0) ? diff - 1 : Size() + diff - 1;
if (statistics) {
- int fill = size - free - 1 + Count;
- if (fill >= size)
- fill = size - 1;
+ int fill = Size() - free - 1 + Count;
+ if (fill >= Size())
+ fill = Size() - 1;
if (fill > maxFill) {
maxFill = fill;
- int percent = maxFill * 100 / (size - 1);
+ int percent = maxFill * 100 / (Size() - 1);
if (percent > 75)
dsyslog(LOG_INFO, "buffer usage: %d%%", percent);
}
@@ -120,14 +187,14 @@ int cRingBuffer::Put(const uchar *Data, int Count)
return Count;
}
-int cRingBuffer::Get(uchar *Data, int Count)
+int cRingBufferLinear::Get(uchar *Data, int Count)
{
if (Count > 0) {
- mutex.Lock();
- int rest = size - tail;
+ Lock();
+ int rest = Size() - tail;
int diff = head - tail;
- mutex.Unlock();
- int cont = (diff >= 0) ? diff : size + diff;
+ Unlock();
+ int cont = (diff >= 0) ? diff : Size() + diff;
if (rest <= 0)
return 0;
if (cont < Count)
@@ -146,36 +213,112 @@ int cRingBuffer::Get(uchar *Data, int Count)
return Count;
}
-bool cRingBuffer::Start(void)
+// --- cFrame ----------------------------------------------------------------
+
+cFrame::cFrame(const uchar *Data, int Count, int Index)
{
- if (!busy) {
- busy = true;
- outputThread = new cRingBufferOutputThread(this);
- if (!outputThread->Start())
- DELETENULL(outputThread);
- inputThread = new cRingBufferInputThread(this);
- if (!inputThread->Start()) {
- DELETENULL(inputThread);
- DELETENULL(outputThread);
+ count = Count;
+ index = Index;
+ data = new uchar[count];
+ if (data)
+ memcpy(data, Data, count);
+ else
+ esyslog(LOG_ERR, "ERROR: can't allocate frame buffer (count=%d)", count);
+ next = NULL;
+}
+
+cFrame::~cFrame()
+{
+ delete data;
+}
+
+// --- cRingBufferFrame ------------------------------------------------------
+
+cRingBufferFrame::cRingBufferFrame(int Size, bool Statistics = false)
+:cRingBuffer(Size, Statistics)
+{
+ head = NULL;
+ currentFill = 0;
+}
+
+cRingBufferFrame::~cRingBufferFrame()
+{
+ Clear();
+}
+
+void cRingBufferFrame::Clear(void)
+{
+ Lock();
+ const cFrame *p;
+ while ((p = Get(false)) != NULL)
+ Drop(p);
+ Unlock();
+ EnablePut();
+ EnableGet();
+}
+
+bool cRingBufferFrame::Put(cFrame *Frame)
+{
+ if (Frame->Count() <= Free()) {
+ Lock();
+ if (head) {
+ Frame->next = head->next;
+ head->next = Frame;
+ head = Frame;
}
- busy = outputThread && inputThread;
+ else {
+ head = Frame->next = Frame;
+ }
+ currentFill += Frame->Count();
+ Unlock();
+ EnableGet();
+ return true;
}
- return busy;
+ WaitForPut();
+ return false;
}
-bool cRingBuffer::Active(void)
+const cFrame *cRingBufferFrame::Get(bool Wait)
{
- return outputThread && outputThread->Active() && inputThread && inputThread->Active();
+ Lock();
+ cFrame *p = head ? head->next : NULL;
+ Unlock();
+ if (!p && Wait)
+ WaitForGet();
+ return p;
}
-void cRingBuffer::Stop(void)
+void cRingBufferFrame::Delete(const cFrame *Frame)
{
- busy = false;
- for (time_t t0 = time(NULL) + 3; time(NULL) < t0; ) {
- if (!((outputThread && outputThread->Active()) || (inputThread && inputThread->Active())))
- break;
- }
- DELETENULL(inputThread);
- DELETENULL(outputThread);
+ currentFill -= Frame->Count();
+ delete Frame;
+}
+
+void cRingBufferFrame::Drop(const cFrame *Frame)
+{
+ Lock();
+ if (head) {
+ if (Frame == head->next) {
+ if (head->next != head) {
+ head->next = Frame->next;
+ Delete(Frame);
+ }
+ else {
+ Delete(head);
+ head = NULL;
+ }
+ }
+ else
+ esyslog(LOG_ERR, "ERROR: attempt to drop wrong frame from ring buffer!");
+ }
+ Unlock();
+ EnablePut();
}
+int cRingBufferFrame::Available(void)
+{
+ Lock();
+ int av = currentFill;
+ Unlock();
+ return av;
+}