Fix race-condition/deadlock, plugin-copy while rolling
authorRobin Gareus <robin@gareus.org>
Thu, 25 Oct 2018 00:00:08 +0000 (02:00 +0200)
committerRobin Gareus <robin@gareus.org>
Thu, 25 Oct 2018 00:00:08 +0000 (02:00 +0200)
lili93's session (#ardour) triggered this w/jackd 512fpp:
Drag/Drop copy a latent plugin from one track to another while rolling.
The GUI-thread as well as the auto-connect thread concurrently call
jack_recompute_total_latencies(). The auto-connect thread holds
a process lock while doing so. The GUI does not use any mutexes.
This randomly deadlocks in libjack.

backtrace: https://pastebin.com/6m3KGhWS

libs/ardour/ardour/session.h
libs/ardour/session.cc

index c18b76a98441c4c05f05422a9c57673a39d9d58e..b5997a3a8365eb0c1f4e3eed31714cbb81298cf0 100644 (file)
@@ -1540,6 +1540,8 @@ private:
                ChanCount output_offset;
        };
 
+       Glib::Threads::Mutex  _update_latency_lock;
+
        typedef std::queue<AutoConnectRequest> AutoConnectQueue;
        Glib::Threads::Mutex  _auto_connect_queue_lock;
        AutoConnectQueue _auto_connect_queue;
index 228c52ef08d59c2c3d00d471d5a62507d7b0a6d9..da4421d4a2d92b9f9a428b8d72d2d3a7f1d24334 100644 (file)
@@ -6944,6 +6944,17 @@ Session::update_latency_compensation (bool force_whole_graph)
        if (_state_of_the_state & (InitialConnecting|Deletion)) {
                return;
        }
+       /* this lock is not usually contended, but under certain conditions,
+        * update_latency_compensation may be called concurrently.
+        * e.g. drag/drop copy a latent plugin while rolling.
+        * GUI thread (via route_processors_changed) and
+        * auto_connect_thread_run may race.
+        */
+       Glib::Threads::Mutex::Lock lx (_update_latency_lock, Glib::Threads::TRY_LOCK);
+       if (!lx.locked()) {
+               /* no need to do this twice */
+               return;
+       }
 
        bool some_track_latency_changed = update_route_latency (false, false);