summaryrefslogtreecommitdiff
path: root/ringbuffer.c
diff options
context:
space:
mode:
authorKlaus Schmidinger <kls (at) cadsoft (dot) de>2001-04-01 18:00:00 +0200
committerKlaus Schmidinger <kls (at) cadsoft (dot) de>2001-04-01 18:00:00 +0200
commit610c5600df98b35226536ffe92b1fd231128c7d4 (patch)
treef0df8ce83dd3e4829be7def61126871f425e2f23 /ringbuffer.c
parentf2937af95ceaf3a52c327e96571367ef5475b3a1 (diff)
downloadvdr-patch-lnbsharing-610c5600df98b35226536ffe92b1fd231128c7d4.tar.gz
vdr-patch-lnbsharing-610c5600df98b35226536ffe92b1fd231128c7d4.tar.bz2
Version 0.72vdr-0.72
- Fixed SVDRP commands LSTC and LSTT to make them return an error message if no channels or timers are defined. - Enhanced 'channels.conf.cable' (thanks to Hans-Peter Raschke). - Fixed switching to another channel via the EPG while a recording is being replayed. - Fixed a memory leak in the EIT processor that happened when the system time was set. - Removed some redundant code from the cListBase destructor. - Fixed internationalization of some Main menu texts. - Updated 'channels.conf' after the recent changes of Premiere World (thanks to Axel Gruber). - Redesigned the ring buffer to make it work with two separate threads for input and output (also prepared for using a remultiplexer). - Fixed setting system time from transponders. - Fixed a segfault in the Schedule menu in case there is no EPG information. - The 'runvdr' script now kills any leftover vdr threads before restarting it. - Fixed a problem with Daylight Saving Time when displaying the times of recordings. - Added Dutch language texts (thanks to Arnold Niessen). - The new command line option -t can be used to set the controlling terminal (thanks to Jürgen Sauer). This is especially useful when starting VDR through an entry in /etc/inittab (see INSTALL). - Since the CAM module only works if it is installed in the "highest" DVB card, recordings now search for a free DVB card from lowest to highest index (as opposed to the previous "highest to lowest" search) in order to not use the CAM card for FTA recordings unless necessary. This is only important for systems with three or more DVB cards. - Added the "statdvb2vdr" tool from Hans-Peter Raschke. - Fixed a segfault that sometimes happened when killing VDR. - VDR now returns an exit status of '2' in case of an error at startup, instead of terminating with 'abort()' (which caused a core dump). - SVDRP now also works with clients that don't do line buffering (like the Windows 'telnet'). - Empty lines in config files no longer cause error messages. - New SVDRP command LSTE to list the EPG data. - The SVDRP HELP command now prints the topics in several columns.
Diffstat (limited to 'ringbuffer.c')
-rw-r--r--ringbuffer.c170
1 files changed, 170 insertions, 0 deletions
diff --git a/ringbuffer.c b/ringbuffer.c
new file mode 100644
index 0000000..4870713
--- /dev/null
+++ b/ringbuffer.c
@@ -0,0 +1,170 @@
+/*
+ * ringbuffer.c: A threaded ring buffer
+ *
+ * See the main source file 'vdr.c' for copyright information and
+ * how to reach the author.
+ *
+ * Parts of this file were inspired by the 'ringbuffy.c' from the
+ * LinuxDVB driver (see linuxtv.org).
+ *
+ * $Id: ringbuffer.c 1.1 2001/03/10 17:11:34 kls Exp $
+ */
+
+#include "ringbuffer.h"
+#include "tools.h"
+
+// --- cRingBufferInputThread -------------------------------------------------
+
+class cRingBufferInputThread : public cThread {
+private:
+ cRingBuffer *ringBuffer;
+protected:
+ virtual void Action(void) { ringBuffer->Input(); }
+public:
+ cRingBufferInputThread(cRingBuffer *RingBuffer) { ringBuffer = RingBuffer; }
+ };
+
+// --- cRingBufferOutputThread ------------------------------------------------
+
+class cRingBufferOutputThread : public cThread {
+private:
+ cRingBuffer *ringBuffer;
+protected:
+ virtual void Action(void) { ringBuffer->Output(); }
+public:
+ cRingBufferOutputThread(cRingBuffer *RingBuffer) { ringBuffer = RingBuffer; }
+ };
+
+// --- cRingBuffer ------------------------------------------------------------
+
+cRingBuffer::cRingBuffer(int Size)
+{
+ size = Size;
+ buffer = NULL;
+ inputThread = NULL;
+ outputThread = NULL;
+ maxFill = 0;
+ busy = false;
+ 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);
+ Clear();
+ }
+ else
+ esyslog(LOG_ERR, "ERROR: illegal size for ring buffer (%d)", size);
+}
+
+cRingBuffer::~cRingBuffer()
+{
+ delete inputThread;
+ delete outputThread;
+ delete buffer;
+ dsyslog(LOG_INFO, "buffer stats: %d (%d%%) used", maxFill, maxFill * 100 / (size - 1));
+}
+
+void cRingBuffer::Clear(void)
+{
+ mutex.Lock();
+ head = tail = 0;
+ mutex.Unlock();
+}
+
+int cRingBuffer::Put(const uchar *Data, int Count)
+{
+ if (Count > 0) {
+ mutex.Lock();
+ int rest = size - head;
+ int diff = tail - head;
+ mutex.Unlock();
+ int free = (diff > 0) ? diff - 1 : size + diff - 1;
+ // Statistics:
+ int fill = size - free - 1 + Count;
+ if (fill >= size)
+ fill = size - 1;
+ if (fill > maxFill) {
+ maxFill = fill;
+ int percent = maxFill * 100 / (size - 1);
+ if (percent > 75)
+ dsyslog(LOG_INFO, "buffer usage: %d%%", percent);
+ }
+ //
+ if (free <= 0)
+ return 0;
+ if (free < Count)
+ Count = free;
+ if (Count > maxFill)
+ maxFill = Count;
+ if (Count >= rest) {
+ memcpy(buffer + head, Data, rest);
+ if (Count - rest)
+ memcpy(buffer, Data + rest, Count - rest);
+ head = Count - rest;
+ }
+ else {
+ memcpy(buffer + head, Data, Count);
+ head += Count;
+ }
+ }
+ return Count;
+}
+
+int cRingBuffer::Get(uchar *Data, int Count)
+{
+ if (Count > 0) {
+ mutex.Lock();
+ int rest = size - tail;
+ int diff = head - tail;
+ mutex.Unlock();
+ int cont = (diff >= 0) ? diff : size + diff;
+ if (rest <= 0)
+ return 0;
+ if (cont < Count)
+ Count = cont;
+ if (Count >= rest) {
+ memcpy(Data, buffer + tail, rest);
+ if (Count - rest)
+ memcpy(Data + rest, buffer, Count - rest);
+ tail = Count - rest;
+ }
+ else {
+ memcpy(Data, buffer + tail, Count);
+ tail += Count;
+ }
+ }
+ return Count;
+}
+
+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;
+ for (time_t t0 = time(NULL) + 3; time(NULL) < t0; ) {
+ if (!((outputThread && outputThread->Active()) || (inputThread && inputThread->Active())))
+ break;
+ }
+ DELETENULL(inputThread);
+ DELETENULL(outputThread);
+}
+