fix crash when copy'ing latent plugins
[ardour.git] / libs / ardour / graph.cc
index 3e878533193afcada7f3d5d9f0bcb3958c890c2d..563c882efec76706c6b6c2032a10e343ecc56af9 100644 (file)
@@ -32,7 +32,7 @@
 #include "ardour/process_thread.h"
 #include "ardour/audioengine.h"
 
-#include "i18n.h"
+#include "pbd/i18n.h"
 
 using namespace ARDOUR;
 using namespace PBD;
@@ -53,7 +53,7 @@ int alloc_allowed ()
 
 Graph::Graph (Session & session)
         : SessionHandleRef (session)
-        , _quit_threads (false)
+        , _threads_active (false)
        , _execution_sem ("graph_execution", 0)
        , _callback_start_sem ("graph_start", 0)
        , _callback_done_sem ("graph_done", 0)
@@ -71,9 +71,13 @@ Graph::Graph (Session & session)
         _current_chain = 0;
         _pending_chain = 0;
         _setup_chain   = 1;
-        _quit_threads = false;
         _graph_empty = true;
 
+
+       ARDOUR::AudioEngine::instance()->Running.connect_same_thread (engine_connections, boost::bind (&Graph::reset_thread_list, this));
+       ARDOUR::AudioEngine::instance()->Stopped.connect_same_thread (engine_connections, boost::bind (&Graph::engine_stopped, this));
+       ARDOUR::AudioEngine::instance()->Halted.connect_same_thread (engine_connections, boost::bind (&Graph::engine_stopped, this));
+
         reset_thread_list ();
 
 #ifdef DEBUG_RT_ALLOC
@@ -82,6 +86,14 @@ Graph::Graph (Session & session)
 #endif
 }
 
+void
+Graph::engine_stopped ()
+{
+       if (AudioEngine::instance()->process_thread_count() != 0) {
+               drop_threads ();
+       }
+}
+
 /** Set up threads for running the graph */
 void
 Graph::reset_thread_list ()
@@ -105,6 +117,8 @@ Graph::reset_thread_list ()
                 drop_threads ();
         }
 
+        _threads_active = true;
+
        if (AudioEngine::instance()->create_process_thread (boost::bind (&Graph::main_thread, this)) != 0) {
                throw failed_constructor ();
        }
@@ -132,21 +146,24 @@ Graph::session_going_away()
 void
 Graph::drop_threads ()
 {
-        _quit_threads = true;
+        Glib::Threads::Mutex::Lock ls (_swap_mutex);
+        _threads_active = false;
 
         uint32_t thread_count = AudioEngine::instance()->process_thread_count ();
 
         for (unsigned int i=0; i < thread_count; i++) {
+               pthread_mutex_lock (&_trigger_mutex);
                _execution_sem.signal ();
+               pthread_mutex_unlock (&_trigger_mutex);
         }
 
+       pthread_mutex_lock (&_trigger_mutex);
         _callback_start_sem.signal ();
+       pthread_mutex_unlock (&_trigger_mutex);
 
        AudioEngine::instance()->join_process_threads ();
 
        _execution_tokens = 0;
-
-        _quit_threads = false;
 }
 
 void
@@ -243,13 +260,13 @@ Graph::restart_cycle()
         /* Block until the a process callback triggers us */
         _callback_start_sem.wait();
 
-        if (_quit_threads) {
+        if (!_threads_active) {
                 return;
         }
 
        prep ();
 
-        if (_graph_empty) {
+        if (_graph_empty && _threads_active) {
                 goto again;
         }
 
@@ -368,7 +385,7 @@ Graph::run_one()
                 pthread_mutex_unlock (&_trigger_mutex);
                 DEBUG_TRACE (DEBUG::ProcessThreads, string_compose ("%1 goes to sleep\n", pthread_name()));
                 _execution_sem.wait ();
-                if (_quit_threads) {
+                if (!_threads_active) {
                         return true;
                 }
                 DEBUG_TRACE (DEBUG::ProcessThreads, string_compose ("%1 is awake\n", pthread_name()));
@@ -385,7 +402,7 @@ Graph::run_one()
 
         DEBUG_TRACE(DEBUG::ProcessThreads, string_compose ("%1 has finished run_one()\n", pthread_name()));
 
-        return false;
+        return !_threads_active;
 }
 
 void
@@ -395,15 +412,16 @@ Graph::helper_thread()
        ProcessThread* pt = new ProcessThread ();
        resume_rt_malloc_checks ();
 
-        pt->get_buffers();
+       pt->get_buffers();
 
-        while(1) {
-                if (run_one()) {
-                        break;
-                }
-        }
+       while(1) {
+               if (run_one()) {
+                       break;
+               }
+       }
 
-        pt->drop_buffers();
+       pt->drop_buffers();
+       delete pt;
 }
 
 /** Here's the main graph thread */
@@ -414,34 +432,35 @@ Graph::main_thread()
        ProcessThread* pt = new ProcessThread ();
        resume_rt_malloc_checks ();
 
-        pt->get_buffers();
+       pt->get_buffers();
+
+again:
+       _callback_start_sem.wait ();
 
-  again:
-        _callback_start_sem.wait ();
-       
        DEBUG_TRACE(DEBUG::ProcessThreads, "main thread is awake\n");
 
-        if (_quit_threads) {
-                return;
-        }
+       if (!_threads_active) {
+               return;
+       }
 
        prep ();
 
-        if (_graph_empty && !_quit_threads) {
-                _callback_done_sem.signal ();
-                DEBUG_TRACE(DEBUG::ProcessThreads, "main thread sees graph done, goes back to sleep\n");
-                goto again;
-        }
+       if (_graph_empty && _threads_active) {
+               _callback_done_sem.signal ();
+               DEBUG_TRACE(DEBUG::ProcessThreads, "main thread sees graph done, goes back to sleep\n");
+               goto again;
+       }
 
        /* This loop will run forever */
-        while (1) {
+       while (1) {
                DEBUG_TRACE(DEBUG::ProcessThreads, "main thread runs one graph node\n");
-                if (run_one()) {
-                        break;
-                }
-        }
+               if (run_one()) {
+                       break;
+               }
+       }
 
-        pt->drop_buffers();
+       pt->drop_buffers();
+       delete (pt);
 }
 
 void
@@ -474,6 +493,8 @@ Graph::dump (int chain)
 int
 Graph::silent_process_routes (pframes_t nframes, framepos_t start_frame, framepos_t end_frame, bool& need_butler)
 {
+       if (!_threads_active) return 0;
+
         _process_nframes = nframes;
         _process_start_frame = start_frame;
         _process_end_frame = end_frame;
@@ -499,6 +520,8 @@ Graph::process_routes (pframes_t nframes, framepos_t start_frame, framepos_t end
 {
        DEBUG_TRACE (DEBUG::ProcessThreads, string_compose ("graph execution from %1 to %2 = %3\n", start_frame, end_frame, nframes));
 
+       if (!_threads_active) return 0;
+
         _process_nframes = nframes;
         _process_start_frame = start_frame;
         _process_end_frame = end_frame;
@@ -526,6 +549,8 @@ Graph::routes_no_roll (pframes_t nframes, framepos_t start_frame, framepos_t end
 {
        DEBUG_TRACE (DEBUG::ProcessThreads, string_compose ("no-roll graph execution from %1 to %2 = %3\n", start_frame, end_frame, nframes));
 
+       if (!_threads_active) return 0;
+
         _process_nframes = nframes;
         _process_start_frame = start_frame;
         _process_end_frame = end_frame;