commit-gnuradio
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Commit-gnuradio] [gnuradio] 01/05: runtime: fix wait() race condition


From: git
Subject: [Commit-gnuradio] [gnuradio] 01/05: runtime: fix wait() race condition
Date: Sat, 4 Apr 2015 17:39:30 +0000 (UTC)

This is an automated email from the git hooks/post-receive script.

jcorgan pushed a commit to branch maint
in repository gnuradio.

commit 2aded1af5e55dca76c0b9cd4476b083b8fd8d3f7
Author: Jiří Pinkava <address@hidden>
Date:   Tue Mar 17 23:32:35 2015 +0100

    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().
---
 gnuradio-runtime/lib/top_block_impl.cc | 23 +++++++++++++++++++++--
 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 b7322c8..48404a6 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 67395e0..1ac5136 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 */



reply via email to

[Prev in Thread] Current Thread [Next in Thread]