summaryrefslogtreecommitdiff
path: root/gnuradio-runtime/lib/top_block_impl.cc
diff options
context:
space:
mode:
authorJiří Pinkava <j-pi@seznam.cz>2015-03-17 23:32:35 +0100
committerJiří Pinkava <j-pi@seznam.cz>2015-04-01 14:35:05 +0200
commit2aded1af5e55dca76c0b9cd4476b083b8fd8d3f7 (patch)
treed2c51ac5e0b09723c0aebe581e5734d0ae48b64f /gnuradio-runtime/lib/top_block_impl.cc
parentd817c5fd35dd71d5e4591f04d39e565935215ae9 (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().
Diffstat (limited to 'gnuradio-runtime/lib/top_block_impl.cc')
-rw-r--r--gnuradio-runtime/lib/top_block_impl.cc23
1 files changed, 21 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();