From f8b5424d9f327754f8b17363d25e8e208b32f649 Mon Sep 17 00:00:00 2001 From: Robin Gareus Date: Tue, 8 Dec 2020 01:08:49 +0100 Subject: [PATCH] Fix deadlock during export When using the export-tool, the very first callback may already be freewheeling. In this case the first call to the butler also happens directly from the freewheel process-callback and initial session events are handled there. Setting PostTransportAdjustPlaybackBuffering took the process-lock, which caused a deadlock: Glib::Threads::Mutex::Lock::Lock(Glib::Threads::Mutex&) at /usr/include/glibmm-2.4/glibmm/threads.h:687 ARDOUR::Session::butler_transport_work() at ../libs/ardour/session_transport.cc:1157 ARDOUR::Session::process_export_fw(unsigned int) at ../libs/ardour/session_export.cc:303 ARDOUR::AudioEngine::process_callback(unsigned int) at ../libs/ardour/audioengine.cc:486 ARDOUR::DummyAudioBackend::main_process_thread() at ../libs/backends/dummy/dummy_audiobackend.cc:951 --- libs/ardour/ardour/session.h | 2 +- libs/ardour/session_export.cc | 2 +- libs/ardour/session_transport.cc | 12 +++++++++--- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h index acddc02539..9326bedb35 100644 --- a/libs/ardour/ardour/session.h +++ b/libs/ardour/ardour/session.h @@ -304,7 +304,7 @@ public: void refill_all_track_buffers (); Butler* butler() { return _butler; } - void butler_transport_work (); + void butler_transport_work (bool have_process_lock = false); void refresh_disk_space (); diff --git a/libs/ardour/session_export.cc b/libs/ardour/session_export.cc index 78aec6c759..f167b17f66 100644 --- a/libs/ardour/session_export.cc +++ b/libs/ardour/session_export.cc @@ -300,7 +300,7 @@ Session::process_export_fw (pframes_t nframes) } set_transport_speed (1.0, false, false, false); - butler_transport_work (); + butler_transport_work (true); g_atomic_int_set (&_butler->should_do_transport_work, 0); butler_completed_transport_work (); /* Session::process_with_events () sets _remaining_latency_preroll = 0 diff --git a/libs/ardour/session_transport.cc b/libs/ardour/session_transport.cc index 45275f6980..803012c3c1 100644 --- a/libs/ardour/session_transport.cc +++ b/libs/ardour/session_transport.cc @@ -1099,7 +1099,7 @@ Session::solo_selection (StripableList &list, bool new_state) void -Session::butler_transport_work () +Session::butler_transport_work (bool have_process_lock) { /* Note: this function executes in the butler thread context */ @@ -1154,7 +1154,10 @@ Session::butler_transport_work () if (ptw & PostTransportAdjustPlaybackBuffering) { /* need to prevent concurrency with ARDOUR::Reader::run(), * DiskWriter::adjust_buffering() re-allocates the ringbuffer */ - Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ()); + Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock (), Glib::Threads::NOT_LOCK); + if (!have_process_lock) { + lx.acquire (); + } for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { boost::shared_ptr tr = boost::dynamic_pointer_cast (*i); if (tr) { @@ -1172,7 +1175,10 @@ Session::butler_transport_work () if (ptw & PostTransportAdjustCaptureBuffering) { /* need to prevent concurrency with ARDOUR::DiskWriter::run(), * DiskWriter::adjust_buffering() re-allocates the ringbuffer */ - Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ()); + Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock (), Glib::Threads::NOT_LOCK); + if (!have_process_lock) { + lx.acquire (); + } for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { boost::shared_ptr tr = boost::dynamic_pointer_cast (*i); if (tr) {