diff options
author | Jiří Pinkava <j-pi@seznam.cz> | 2015-03-17 23:32:35 +0100 |
---|---|---|
committer | Jiří Pinkava <j-pi@seznam.cz> | 2015-04-01 14:35:05 +0200 |
commit | 2aded1af5e55dca76c0b9cd4476b083b8fd8d3f7 (patch) | |
tree | d2c51ac5e0b09723c0aebe581e5734d0ae48b64f | |
parent | d817c5fd35dd71d5e4591f04d39e565935215ae9 (diff) |
runtime: fix wait() race condition
Func. wait() should wait until all work is completed, but should not
exit when block is locked()/unlocked() for flow-graph reconfiguration.
It is unprobable, but during unlock() thread context might be switched
after stop() is called but before new thread are executed by scheduller.
This can cause exit from wait() when it is called (eg. from Python
wrapper).
Call of stop() is moved into lock(), no new work should be started on
locked block and this gives threads some time to finish before join()
is called from unlock().
-rw-r--r-- | gnuradio-runtime/lib/top_block_impl.cc | 23 | ||||
-rw-r--r-- | gnuradio-runtime/lib/top_block_impl.h | 2 |
2 files changed, 23 insertions, 2 deletions
diff --git a/gnuradio-runtime/lib/top_block_impl.cc b/gnuradio-runtime/lib/top_block_impl.cc index b7322c8e2a..48404a6832 100644 --- a/gnuradio-runtime/lib/top_block_impl.cc +++ b/gnuradio-runtime/lib/top_block_impl.cc @@ -86,6 +86,9 @@ namespace gr { top_block_impl::~top_block_impl() { + if (d_lock_count) { + std::cerr << "error: destroying locked block." << std::endl; + } d_owner = 0; } @@ -129,6 +132,21 @@ namespace gr { void top_block_impl::wait() { + do { + wait_for_jobs(); + { + gr::thread::scoped_lock lock(d_mutex); + if (!d_lock_count) { + break; + } + d_lock_cond.wait(lock); + } + } while(true); + } + + void + top_block_impl::wait_for_jobs() + { if(d_scheduler) d_scheduler->wait(); @@ -141,6 +159,7 @@ namespace gr { top_block_impl::lock() { gr::thread::scoped_lock lock(d_mutex); + stop(); d_lock_count++; } @@ -158,6 +177,7 @@ namespace gr { if(d_lock_count > 0 || d_state == IDLE) // nothing to do return; + d_lock_cond.notify_all(); restart(); } @@ -167,8 +187,7 @@ namespace gr { void top_block_impl::restart() { - stop(); // Stop scheduler and wait for completion - wait(); + wait_for_jobs(); // Create new simple flow graph flat_flowgraph_sptr new_ffg = d_owner->flatten(); diff --git a/gnuradio-runtime/lib/top_block_impl.h b/gnuradio-runtime/lib/top_block_impl.h index 67395e0c35..1ac5136ddf 100644 --- a/gnuradio-runtime/lib/top_block_impl.h +++ b/gnuradio-runtime/lib/top_block_impl.h @@ -82,10 +82,12 @@ namespace gr { gr::thread::mutex d_mutex; // protects d_state and d_lock_count tb_state d_state; int d_lock_count; + boost::condition_variable d_lock_cond; int d_max_noutput_items; private: void restart(); + void wait_for_jobs(); }; } /* namespace gr */ |