diff options
Diffstat (limited to 'ringbuffer.c')
-rw-r--r-- | ringbuffer.c | 252 |
1 files changed, 198 insertions, 54 deletions
diff --git a/ringbuffer.c b/ringbuffer.c index 79ece885..7e09b2af 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.3 2001/08/02 13:48:38 kls Exp $ + * $Id: ringbuffer.c 1.4 2001/08/05 12:17:45 kls Exp $ */ #include "ringbuffer.h" @@ -41,60 +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; - mutex.Unlock(); - return (diff >= 0) ? diff : size + diff; + 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); } @@ -119,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) @@ -145,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; +} |