Home

Dokumentation

Impressum

Dokumentation VDR
 

Main Page   Class Hierarchy   Alphabetical List   Data Structures   File List   Data Fields   Globals  

ringbuffer.c

Go to the documentation of this file.
00001 /*
00002  * ringbuffer.c: A ring buffer
00003  *
00004  * See the main source file 'vdr.c' for copyright information and
00005  * how to reach the author.
00006  *
00007  * Parts of this file were inspired by the 'ringbuffy.c' from the
00008  * LinuxDVB driver (see linuxtv.org).
00009  *
00010  * $Id: ringbuffer.c 1.10 2002/07/28 12:47:32 kls Exp $
00011  */
00012 
00013 #include "ringbuffer.h"
00014 #include <stdlib.h>
00015 #include <unistd.h>
00016 #include "tools.h"
00017 
00018 // --- cRingBuffer -----------------------------------------------------------
00019 
00020 cRingBuffer::cRingBuffer(int Size, bool Statistics)
00021 {
00022   size = Size;
00023   statistics = Statistics;
00024   maxFill = 0;
00025   lastPercent = 0;
00026 }
00027 
00028 cRingBuffer::~cRingBuffer()
00029 {
00030   if (statistics)
00031      dsyslog("buffer stats: %d (%d%%) used", maxFill, maxFill * 100 / (size - 1));
00032 }
00033 
00034 void cRingBuffer::WaitForPut(void)
00035 {
00036   putMutex.Lock();
00037   readyForPut.Wait(putMutex);
00038   putMutex.Unlock();
00039 }
00040 
00041 void cRingBuffer::WaitForGet(void)
00042 {
00043   getMutex.Lock();
00044   readyForGet.Wait(getMutex);
00045   getMutex.Unlock();
00046 }
00047 
00048 void cRingBuffer::EnablePut(void)
00049 {
00050   readyForPut.Broadcast();
00051 }
00052 
00053 void cRingBuffer::EnableGet(void)
00054 {
00055   readyForGet.Broadcast();
00056 }
00057 
00058 // --- cRingBufferLinear -----------------------------------------------------
00059 
00060 cRingBufferLinear::cRingBufferLinear(int Size, bool Statistics)
00061 :cRingBuffer(Size, Statistics)
00062 {
00063   buffer = NULL;
00064   getThreadPid = -1;
00065   if (Size > 1) { // 'Size - 1' must not be 0!
00066      buffer = new uchar[Size];
00067      if (!buffer)
00068         esyslog("ERROR: can't allocate ring buffer (size=%d)", Size);
00069      Clear();
00070      }
00071   else
00072      esyslog("ERROR: illegal size for ring buffer (%d)", Size);
00073 }
00074 
00075 cRingBufferLinear::~cRingBufferLinear()
00076 {
00077   delete buffer;
00078 }
00079 
00080 int cRingBufferLinear::Available(void)
00081 {
00082   Lock();
00083   int diff = head - tail;
00084   Unlock();
00085   return (diff >= 0) ? diff : Size() + diff;
00086 }
00087 
00088 void cRingBufferLinear::Clear(void)
00089 {
00090   Lock();
00091   head = tail = 0;
00092   Unlock();
00093   EnablePut();
00094   EnableGet();
00095 }
00096 
00097 int cRingBufferLinear::Put(const uchar *Data, int Count)
00098 {
00099   if (Count > 0) {
00100      Lock();
00101      int rest = Size() - head;
00102      int diff = tail - head;
00103      int free = (diff > 0) ? diff - 1 : Size() + diff - 1;
00104      if (statistics) {
00105         int fill = Size() - free - 1 + Count;
00106         if (fill >= Size())
00107            fill = Size() - 1;
00108         if (fill > maxFill)
00109            maxFill = fill;
00110         int percent = maxFill * 100 / (Size() - 1) / 5 * 5;
00111         if (abs(lastPercent - percent) >= 5) {
00112            if (percent > 75)
00113               dsyslog("buffer usage: %d%% (pid=%d)", percent, getThreadPid);
00114            lastPercent = percent;
00115            }
00116         }
00117      if (free > 0) {
00118         if (free < Count)
00119            Count = free;
00120         if (Count > maxFill)
00121            maxFill = Count;
00122         if (Count >= rest) {
00123            memcpy(buffer + head, Data, rest);
00124            if (Count - rest)
00125               memcpy(buffer, Data + rest, Count - rest);
00126            head = Count - rest;
00127            }
00128         else {
00129            memcpy(buffer + head, Data, Count);
00130            head += Count;
00131            }
00132         }
00133      else
00134         Count = 0;
00135      Unlock();
00136      EnableGet();
00137      }
00138   return Count;
00139 }
00140 
00141 int cRingBufferLinear::Get(uchar *Data, int Count)
00142 {
00143   if (Count > 0) {
00144      Lock();
00145      if (getThreadPid < 0)
00146         getThreadPid = getpid();
00147      int rest = Size() - tail;
00148      int diff = head - tail;
00149      int cont = (diff >= 0) ? diff : Size() + diff;
00150      if (rest > 0) {
00151         if (cont < Count)
00152            Count = cont;
00153         if (Count >= rest) {
00154            memcpy(Data, buffer + tail, rest);
00155            if (Count - rest)
00156               memcpy(Data + rest, buffer, Count - rest);
00157            tail = Count - rest;
00158            }
00159         else {
00160            memcpy(Data, buffer + tail, Count);
00161            tail += Count;
00162            }
00163         }
00164      else
00165         Count = 0;
00166      Unlock();
00167      if (Count == 0)
00168         WaitForGet();
00169      }
00170   return Count;
00171 }
00172 
00173 // --- cFrame ----------------------------------------------------------------
00174 
00175 cFrame::cFrame(const uchar *Data, int Count, eFrameType Type, int Index)
00176 {
00177   count = Count;
00178   type = Type;
00179   index = Index;
00180   data = new uchar[count];
00181   if (data)
00182      memcpy(data, Data, count);
00183   else
00184      esyslog("ERROR: can't allocate frame buffer (count=%d)", count);
00185   next = NULL;
00186 }
00187 
00188 cFrame::~cFrame()
00189 {
00190   delete data;
00191 }
00192 
00193 // --- cRingBufferFrame ------------------------------------------------------
00194 
00195 cRingBufferFrame::cRingBufferFrame(int Size, bool Statistics)
00196 :cRingBuffer(Size, Statistics)
00197 {
00198   head = NULL;
00199   currentFill = 0;
00200 }
00201 
00202 cRingBufferFrame::~cRingBufferFrame()
00203 {
00204   Clear();
00205 }
00206 
00207 void cRingBufferFrame::Clear(void)
00208 {
00209   Lock();
00210   const cFrame *p;
00211   while ((p = Get()) != NULL)
00212         Drop(p);
00213   Unlock();
00214   EnablePut();
00215   EnableGet();
00216 }
00217 
00218 bool cRingBufferFrame::Put(cFrame *Frame)
00219 {
00220   if (Frame->Count() <= Free()) {
00221      Lock();
00222      if (head) {
00223         Frame->next = head->next;
00224         head->next = Frame;
00225         head = Frame;
00226         }
00227      else {
00228         head = Frame->next = Frame;
00229         }
00230      currentFill += Frame->Count();
00231      Unlock();
00232      EnableGet();
00233      return true;
00234      }
00235   return false;
00236 }
00237 
00238 const cFrame *cRingBufferFrame::Get(void)
00239 {
00240   Lock();
00241   cFrame *p = head ? head->next : NULL;
00242   Unlock();
00243   return p;
00244 }
00245 
00246 void cRingBufferFrame::Delete(const cFrame *Frame)
00247 {
00248   currentFill -= Frame->Count();
00249   delete Frame;
00250 }
00251 
00252 void cRingBufferFrame::Drop(const cFrame *Frame)
00253 {
00254   Lock();
00255   if (head) {
00256      if (Frame == head->next) {
00257         if (head->next != head) {
00258            head->next = Frame->next;
00259            Delete(Frame);
00260            }
00261         else {
00262            Delete(head);
00263            head = NULL;
00264            }
00265         }
00266      else
00267         esyslog("ERROR: attempt to drop wrong frame from ring buffer!");
00268      }
00269   Unlock();
00270   EnablePut();
00271 }
00272 
00273 int cRingBufferFrame::Available(void)
00274 {
00275   Lock();
00276   int av = currentFill;
00277   Unlock();
00278   return av;
00279 }

Generated on Wed Feb 5 23:30:11 2003 for VDR by doxygen1.3-rc2