summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gnuradio-runtime/include/gnuradio/thread/thread_body_wrapper.h31
-rw-r--r--gnuradio-runtime/include/gnuradio/top_block.h8
-rw-r--r--gnuradio-runtime/lib/scheduler.cc6
-rw-r--r--gnuradio-runtime/lib/scheduler.h2
-rw-r--r--gnuradio-runtime/lib/scheduler_tpb.cc15
-rw-r--r--gnuradio-runtime/lib/scheduler_tpb.h6
-rw-r--r--gnuradio-runtime/lib/top_block.cc8
-rw-r--r--gnuradio-runtime/lib/top_block_impl.cc22
-rw-r--r--gnuradio-runtime/lib/top_block_impl.h3
-rw-r--r--gnuradio-runtime/python/gnuradio/gr/qa_uncaught_exception.py54
-rw-r--r--gnuradio-runtime/python/gnuradio/gr/top_block.py4
-rw-r--r--gnuradio-runtime/swig/top_block.i4
12 files changed, 106 insertions, 57 deletions
diff --git a/gnuradio-runtime/include/gnuradio/thread/thread_body_wrapper.h b/gnuradio-runtime/include/gnuradio/thread/thread_body_wrapper.h
index c25aad9af4..22e5aa3015 100644
--- a/gnuradio-runtime/include/gnuradio/thread/thread_body_wrapper.h
+++ b/gnuradio-runtime/include/gnuradio/thread/thread_body_wrapper.h
@@ -38,9 +38,13 @@ class thread_body_wrapper
private:
F d_f;
std::string d_name;
+ bool d_catch_exceptions;
public:
- explicit thread_body_wrapper(F f, const std::string& name = "") : d_f(f), d_name(name)
+ explicit thread_body_wrapper(F f,
+ const std::string& name = "",
+ bool catch_exceptions = true)
+ : d_f(f), d_name(name), d_catch_exceptions(catch_exceptions)
{
}
@@ -48,14 +52,25 @@ public:
{
mask_signals();
- try {
- d_f();
- }
- catch(boost::thread_interrupted const &)
- {
+ if (d_catch_exceptions) {
+ try {
+ d_f();
+ } catch (boost::thread_interrupted const&) {
+ } catch (std::exception const& e) {
+ std::cerr << "thread[" << d_name << "]: " << e.what() << std::endl;
+ } catch (...) {
+ std::cerr << "thread[" << d_name << "]: "
+ << "caught unrecognized exception\n";
+ }
+
+ } else {
+ try {
+ d_f();
+ } catch (boost::thread_interrupted const&) {
+ }
}
- }
- };
+ }
+};
} /* namespace thread */
} /* namespace gr */
diff --git a/gnuradio-runtime/include/gnuradio/top_block.h b/gnuradio-runtime/include/gnuradio/top_block.h
index d0e62d1aaf..a097a65f42 100644
--- a/gnuradio-runtime/include/gnuradio/top_block.h
+++ b/gnuradio-runtime/include/gnuradio/top_block.h
@@ -30,7 +30,8 @@ namespace gr {
class top_block_impl;
-GR_RUNTIME_API top_block_sptr make_top_block(const std::string& name);
+GR_RUNTIME_API top_block_sptr make_top_block(const std::string& name,
+ bool catch_exceptions = true);
/*!
*\brief Top-level hierarchical block representing a flowgraph
@@ -39,12 +40,13 @@ GR_RUNTIME_API top_block_sptr make_top_block(const std::string& name);
class GR_RUNTIME_API top_block : public hier_block2
{
private:
- friend GR_RUNTIME_API top_block_sptr make_top_block(const std::string& name);
+ friend GR_RUNTIME_API top_block_sptr make_top_block(const std::string& name,
+ bool catch_exceptions);
top_block_impl* d_impl;
protected:
- top_block(const std::string& name);
+ top_block(const std::string& name, bool catch_exceptions = true);
public:
~top_block();
diff --git a/gnuradio-runtime/lib/scheduler.cc b/gnuradio-runtime/lib/scheduler.cc
index f054e4c753..b0e1f67dff 100644
--- a/gnuradio-runtime/lib/scheduler.cc
+++ b/gnuradio-runtime/lib/scheduler.cc
@@ -27,7 +27,11 @@
namespace gr {
-scheduler::scheduler(flat_flowgraph_sptr ffg, int max_noutput_items) {}
+scheduler::scheduler(flat_flowgraph_sptr ffg,
+ int max_noutput_items,
+ bool catch_exceptions)
+{
+}
scheduler::~scheduler() {}
diff --git a/gnuradio-runtime/lib/scheduler.h b/gnuradio-runtime/lib/scheduler.h
index 8041771f3c..e76b2ac005 100644
--- a/gnuradio-runtime/lib/scheduler.h
+++ b/gnuradio-runtime/lib/scheduler.h
@@ -48,7 +48,7 @@ public:
* The scheduler will continue running until all blocks
* report that they are done or the stop method is called.
*/
- scheduler(flat_flowgraph_sptr ffg, int max_noutput_items);
+ scheduler(flat_flowgraph_sptr ffg, int max_noutput_items, bool catch_exceptions);
virtual ~scheduler();
diff --git a/gnuradio-runtime/lib/scheduler_tpb.cc b/gnuradio-runtime/lib/scheduler_tpb.cc
index a255aa4946..7e240d7f61 100644
--- a/gnuradio-runtime/lib/scheduler_tpb.cc
+++ b/gnuradio-runtime/lib/scheduler_tpb.cc
@@ -51,13 +51,16 @@ public:
}
};
-scheduler_sptr scheduler_tpb::make(flat_flowgraph_sptr ffg, int max_noutput_items)
+scheduler_sptr
+scheduler_tpb::make(flat_flowgraph_sptr ffg, int max_noutput_items, bool catch_exceptions)
{
- return scheduler_sptr(new scheduler_tpb(ffg, max_noutput_items));
+ return scheduler_sptr(new scheduler_tpb(ffg, max_noutput_items, catch_exceptions));
}
-scheduler_tpb::scheduler_tpb(flat_flowgraph_sptr ffg, int max_noutput_items)
- : scheduler(ffg, max_noutput_items)
+scheduler_tpb::scheduler_tpb(flat_flowgraph_sptr ffg,
+ int max_noutput_items,
+ bool catch_exceptions)
+ : scheduler(ffg, max_noutput_items, catch_exceptions)
{
int block_max_noutput_items;
@@ -91,7 +94,9 @@ scheduler_tpb::scheduler_tpb(flat_flowgraph_sptr ffg, int max_noutput_items)
block_max_noutput_items = max_noutput_items;
}
d_threads.create_thread(thread::thread_body_wrapper<tpb_container>(
- tpb_container(blocks[i], block_max_noutput_items, start_sync), name.str()));
+ tpb_container(blocks[i], block_max_noutput_items, start_sync),
+ name.str(),
+ catch_exceptions));
}
start_sync->wait();
}
diff --git a/gnuradio-runtime/lib/scheduler_tpb.h b/gnuradio-runtime/lib/scheduler_tpb.h
index 152b11c8f3..35e8c557da 100644
--- a/gnuradio-runtime/lib/scheduler_tpb.h
+++ b/gnuradio-runtime/lib/scheduler_tpb.h
@@ -42,10 +42,12 @@ protected:
* The scheduler will continue running until all blocks until they
* report that they are done or the stop method is called.
*/
- scheduler_tpb(flat_flowgraph_sptr ffg, int max_noutput_items);
+ scheduler_tpb(flat_flowgraph_sptr ffg, int max_noutput_items, bool catch_exceptions);
public:
- static scheduler_sptr make(flat_flowgraph_sptr ffg, int max_noutput_items = 100000);
+ static scheduler_sptr make(flat_flowgraph_sptr ffg,
+ int max_noutput_items = 100000,
+ bool catch_exceptions = true);
~scheduler_tpb();
diff --git a/gnuradio-runtime/lib/top_block.cc b/gnuradio-runtime/lib/top_block.cc
index 7485124bac..3e81d71951 100644
--- a/gnuradio-runtime/lib/top_block.cc
+++ b/gnuradio-runtime/lib/top_block.cc
@@ -33,15 +33,15 @@
#include <iostream>
namespace gr {
-top_block_sptr make_top_block(const std::string& name)
+top_block_sptr make_top_block(const std::string& name, bool catch_exceptions)
{
- return gnuradio::get_initial_sptr(new top_block(name));
+ return gnuradio::get_initial_sptr(new top_block(name, catch_exceptions));
}
-top_block::top_block(const std::string& name)
+top_block::top_block(const std::string& name, bool catch_exceptions)
: hier_block2(name, io_signature::make(0, 0, 0), io_signature::make(0, 0, 0))
{
- d_impl = new top_block_impl(this);
+ d_impl = new top_block_impl(this, catch_exceptions);
}
top_block::~top_block()
diff --git a/gnuradio-runtime/lib/top_block_impl.cc b/gnuradio-runtime/lib/top_block_impl.cc
index 16acb3826d..79cb4088fd 100644
--- a/gnuradio-runtime/lib/top_block_impl.cc
+++ b/gnuradio-runtime/lib/top_block_impl.cc
@@ -40,7 +40,9 @@ namespace gr {
#define GR_TOP_BLOCK_IMPL_DEBUG 0
-typedef scheduler_sptr (*scheduler_maker)(flat_flowgraph_sptr ffg, int max_noutput_items);
+typedef scheduler_sptr (*scheduler_maker)(flat_flowgraph_sptr ffg,
+ int max_noutput_items,
+ bool catch_exceptions);
static struct scheduler_table {
const char* name;
@@ -49,7 +51,8 @@ static struct scheduler_table {
{ "TPB", scheduler_tpb::make } // first entry is default
};
-static scheduler_sptr make_scheduler(flat_flowgraph_sptr ffg, int max_noutput_items)
+static scheduler_sptr
+make_scheduler(flat_flowgraph_sptr ffg, int max_noutput_items, bool catch_exceptions)
{
static scheduler_maker factory = 0;
@@ -72,11 +75,16 @@ static scheduler_sptr make_scheduler(flat_flowgraph_sptr ffg, int max_noutput_it
}
}
}
- return factory(ffg, max_noutput_items);
+ return factory(ffg, max_noutput_items, catch_exceptions);
}
-top_block_impl::top_block_impl(top_block* owner)
- : d_owner(owner), d_ffg(), d_state(IDLE), d_lock_count(0), d_retry_wait(false)
+top_block_impl::top_block_impl(top_block* owner, bool catch_exceptions = true)
+ : d_owner(owner),
+ d_ffg(),
+ d_state(IDLE),
+ d_lock_count(0),
+ d_retry_wait(false),
+ d_catch_exceptions(catch_exceptions)
{
}
@@ -115,7 +123,7 @@ void top_block_impl::start(int max_noutput_items)
p->get_bool("PerfCounters", "export", false))
d_ffg->enable_pc_rpc();
- d_scheduler = make_scheduler(d_ffg, d_max_noutput_items);
+ d_scheduler = make_scheduler(d_ffg, d_max_noutput_items, d_catch_exceptions);
d_state = RUNNING;
}
@@ -195,7 +203,7 @@ void top_block_impl::restart()
d_ffg = new_ffg;
// Create a new scheduler to execute it
- d_scheduler = make_scheduler(d_ffg, d_max_noutput_items);
+ d_scheduler = make_scheduler(d_ffg, d_max_noutput_items, d_catch_exceptions);
d_retry_wait = true;
}
diff --git a/gnuradio-runtime/lib/top_block_impl.h b/gnuradio-runtime/lib/top_block_impl.h
index 84611b3f85..888b0fe0ab 100644
--- a/gnuradio-runtime/lib/top_block_impl.h
+++ b/gnuradio-runtime/lib/top_block_impl.h
@@ -39,7 +39,7 @@ namespace gr {
class GR_RUNTIME_API top_block_impl
{
public:
- top_block_impl(top_block* owner);
+ top_block_impl(top_block* owner, bool catch_exceptions);
~top_block_impl();
// Create and start scheduler threads
@@ -85,6 +85,7 @@ protected:
bool d_retry_wait;
boost::condition_variable d_lock_cond;
int d_max_noutput_items;
+ bool d_catch_exceptions;
private:
void restart();
diff --git a/gnuradio-runtime/python/gnuradio/gr/qa_uncaught_exception.py b/gnuradio-runtime/python/gnuradio/gr/qa_uncaught_exception.py
index 18799d152d..a098d78684 100644
--- a/gnuradio-runtime/python/gnuradio/gr/qa_uncaught_exception.py
+++ b/gnuradio-runtime/python/gnuradio/gr/qa_uncaught_exception.py
@@ -46,38 +46,50 @@ class except_block(gr.sync_block):
return len(output_items[0])
-class test_uncaught_exception(gr_unittest.TestCase):
+def process_func(catch_exceptions):
+ tb = gr.top_block(catch_exceptions=catch_exceptions)
+ # some test data
+ src_data = [complex(x, x + 1) for x in range(65536)]
+ src = blocks.vector_source_c(src_data)
+ src.set_repeat(True)
- def test_exception_throw(self):
- # Test to ensure that throwing an exception causes the
- # process running top_block to exit
+ e_block_1 = except_block(False)
+ e_block_2 = except_block(True)
- def process_func():
- tb = gr.top_block()
- # some test data
- src_data = [complex(x, x + 1) for x in range(65536)]
- src = blocks.vector_source_c(src_data)
- src.set_repeat(True)
+ sink_1 = blocks.null_sink(gr.sizeof_gr_complex)
+ sink_2 = blocks.null_sink(gr.sizeof_gr_complex)
- e_block_1 = except_block(False)
- e_block_2 = except_block(True)
+ tb.connect(src, e_block_1)
+ tb.connect(src, e_block_2)
+ tb.connect(e_block_1, sink_1)
+ tb.connect(e_block_2, sink_2)
+ tb.run()
- sink_1 = blocks.null_sink(gr.sizeof_gr_complex)
- sink_2 = blocks.null_sink(gr.sizeof_gr_complex)
- tb.connect(src, e_block_1)
- tb.connect(src, e_block_2)
- tb.connect(e_block_1, sink_1)
- tb.connect(e_block_2, sink_2)
- tb.run()
+class test_uncaught_exception(gr_unittest.TestCase):
- p = Process(target=process_func)
+ def test_exception_throw_uncaught(self):
+ # Test to ensure that throwing an exception causes the
+ # process running top_block to exit
+ p = Process(target=process_func, args=(False,))
p.daemon = True
p.start()
- p.join(1)
+ p.join(0.5)
exit_code = p.exitcode
self.assertIsNotNone(
exit_code, "exception did not cause flowgraph exit")
+ def test_exception_throw_caught(self):
+ # Test to ensure that throwing an exception does not cause the process
+ # running top_block to exit (in catch_exceptions mode)
+ p = Process(target=process_func, args=(True,))
+ p.daemon = True
+ p.start()
+ p.join(0.5)
+ exit_code = p.exitcode
+ self.assertIsNone(
+ exit_code, "exception caused flowgraph exit")
+
+
if __name__ == '__main__':
gr_unittest.run(test_uncaught_exception, "test_uncaught_exception.xml")
diff --git a/gnuradio-runtime/python/gnuradio/gr/top_block.py b/gnuradio-runtime/python/gnuradio/gr/top_block.py
index 87c3a81852..2b949ff398 100644
--- a/gnuradio-runtime/python/gnuradio/gr/top_block.py
+++ b/gnuradio-runtime/python/gnuradio/gr/top_block.py
@@ -96,12 +96,12 @@ class top_block(hier_block2):
python subclassing.
"""
- def __init__(self, name="top_block"):
+ def __init__(self, name="top_block", catch_exceptions=True):
"""
Create a top block with a given name.
"""
# not calling hier_block2.__init__, we set our own _impl
- self._impl = top_block_swig(name)
+ self._impl = top_block_swig(name, catch_exceptions)
self.handle_sigint = True
def start(self, max_noutput_items=10000000):
diff --git a/gnuradio-runtime/swig/top_block.i b/gnuradio-runtime/swig/top_block.i
index 6d0632a9a7..8cfe759336 100644
--- a/gnuradio-runtime/swig/top_block.i
+++ b/gnuradio-runtime/swig/top_block.i
@@ -26,13 +26,13 @@ namespace gr {
// Hack to have a Python shim implementation of gr.top_block
// that instantiates one of these and passes through calls
%rename(top_block_swig) make_top_block;
- gr::top_block_sptr make_top_block(const std::string name)
+ gr::top_block_sptr make_top_block(const std::string name, bool catch_exceptions)
throw (std::logic_error);
class top_block : public gr::hier_block2
{
private:
- top_block(const std::string &name);
+ top_block(const std::string &name, bool catch_exceptions=true);
public:
~top_block();