diff options
-rw-r--r-- | gnuradio-runtime/include/gnuradio/thread/thread_body_wrapper.h | 31 | ||||
-rw-r--r-- | gnuradio-runtime/include/gnuradio/top_block.h | 8 | ||||
-rw-r--r-- | gnuradio-runtime/lib/scheduler.cc | 6 | ||||
-rw-r--r-- | gnuradio-runtime/lib/scheduler.h | 2 | ||||
-rw-r--r-- | gnuradio-runtime/lib/scheduler_tpb.cc | 15 | ||||
-rw-r--r-- | gnuradio-runtime/lib/scheduler_tpb.h | 6 | ||||
-rw-r--r-- | gnuradio-runtime/lib/top_block.cc | 8 | ||||
-rw-r--r-- | gnuradio-runtime/lib/top_block_impl.cc | 22 | ||||
-rw-r--r-- | gnuradio-runtime/lib/top_block_impl.h | 3 | ||||
-rw-r--r-- | gnuradio-runtime/python/gnuradio/gr/qa_uncaught_exception.py | 54 | ||||
-rw-r--r-- | gnuradio-runtime/python/gnuradio/gr/top_block.py | 4 | ||||
-rw-r--r-- | gnuradio-runtime/swig/top_block.i | 4 |
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(); |