[PATCH] gr-osmosdr/rtl: REPOST overflow fixes and draining

This is merely a historical archive of years 2008-2021, before the migration to mailman3.

A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/osmocom-sdr@lists.osmocom.org/.

Baffo32 0xloem at gmail.com
Sun Sep 23 12:32:19 UTC 2018


From: Karl Semich <0xloem at gmail.com>

Previously overflow was handled by outputting "O" on stderr and
placing the extra data at the start of the buffer queue.

This had a number of issues:
- as only 1 buffer advanced on overflow, many overflows could occur in
  sequence, as only small amounts of data was allowed to drain
- if the work function was partway through reading the head of the
  queue, it would continue reading at the same offset from the new
  head rather than from the start, causing extra loss of data
- buffer processing in work function is not guarded with a lock,
  so it was possible for overflow to overwrite data while it was
  being copied, resulting in garbage passed on

This patch rewrites overflow handling such that streaming is paused
until the work function can catch up.  This resolves all 3 issues.
---
 lib/rtl/rtl_source_c.cc | 32 ++++++++++++++++++++++++++------
 lib/rtl/rtl_source_c.h  |  2 ++
 2 files changed, 28 insertions(+), 6 deletions(-)

diff --git a/lib/rtl/rtl_source_c.cc b/lib/rtl/rtl_source_c.cc
index a371464..0d26831 100644
--- a/lib/rtl/rtl_source_c.cc
+++ b/lib/rtl/rtl_source_c.cc
@@ -48,6 +48,7 @@ using namespace boost::assign;
 #define BUF_LEN  (16 * 32 * 512) /* must be multiple of 512 */
 #define BUF_NUM   15
 #define BUF_SKIP  1 // buffers to skip due to initial garbage
+#define BUF_MIN   3 /* minimum buffers to run work function */
 
 #define BYTES_PER_SAMPLE  2 // rtl device delivers 8 bit unsigned IQ data
 
@@ -87,8 +88,7 @@ rtl_source_c::rtl_source_c (const std::string &args)
     _running(false),
     _no_tuner(false),
     _auto_gain(false),
-    _if_gain(0),
-    _skipped(0)
+    _if_gain(0)
 {
   int ret;
   int index;
@@ -297,6 +297,9 @@ void rtl_source_c::rtlsdr_callback(unsigned char *buf, uint32_t len)
     return;
   }
 
+  if (_overflow)
+    return;
+
   {
     boost::mutex::scoped_lock lock( _buf_mutex );
 
@@ -304,8 +307,9 @@ void rtl_source_c::rtlsdr_callback(unsigned char *buf, uint32_t len)
     memcpy(_buf[buf_tail], buf, len);
 
     if (_buf_used == _buf_num) {
-      std::cerr << "O" << std::flush;
-      _buf_head = (_buf_head + 1) % _buf_num;
+      std::cerr << "OVERFLOW: rtl-sdr stream restarting after draining unread buffers" << std::endl;
+      _overflow = true;
+      rtlsdr_cancel_async( _dev );
     } else {
       _buf_used++;
     }
@@ -321,7 +325,20 @@ void rtl_source_c::_rtlsdr_wait(rtl_source_c *obj)
 
 void rtl_source_c::rtlsdr_wait()
 {
-  int ret = rtlsdr_read_async( _dev, _rtlsdr_callback, (void *)this, _buf_num, _buf_len );
+  int ret;
+
+  do {
+    {
+      boost::mutex::scoped_lock lock( _buf_mutex );
+      // let unread buffers from last run drain
+      while ( _buf_used >= BUF_MIN )
+        _work_cond.wait( lock );
+    }
+
+    _overflow = false;
+    _skipped = 0;
+    ret = rtlsdr_read_async( _dev, _rtlsdr_callback, (void *)this, _buf_num, _buf_len );
+  } while ( _overflow );
 
   _running = false;
 
@@ -340,7 +357,7 @@ int rtl_source_c::work( int noutput_items,
   {
     boost::mutex::scoped_lock lock( _buf_mutex );
 
-    while (_buf_used < 3 && _running) // collect at least 3 buffers
+    while (_buf_used < BUF_MIN && _running) // collect at least BUF_MIN buffers
       _buf_cond.wait( lock );
   }
 
@@ -364,6 +381,9 @@ int rtl_source_c::work( int noutput_items,
         _buf_head = (_buf_head + 1) % _buf_num;
         _buf_used--;
       }
+
+      _work_cond.notify_one();
+
       _samp_avail = _buf_len / BYTES_PER_SAMPLE;
       _buf_offset = 0;
     } else {
diff --git a/lib/rtl/rtl_source_c.h b/lib/rtl/rtl_source_c.h
index 902b386..aafea5f 100644
--- a/lib/rtl/rtl_source_c.h
+++ b/lib/rtl/rtl_source_c.h
@@ -133,6 +133,8 @@ private:
   unsigned int _buf_used;
   boost::mutex _buf_mutex;
   boost::condition_variable _buf_cond;
+  boost::condition_variable _work_cond;
+  bool _overflow;
   bool _running;
 
   unsigned int _buf_offset;
-- 
2.11.0




More information about the osmocom-sdr mailing list