13
0

Fix export race condition (and crash)

Previously the freewheel export thread directly called
Session::butler_transport_work(). The butler thread
may concurrently call the same function. This can lead
double free or memory corruption (see below)

Now export thread summons the butler and does nothing
until it completed its work.

```
Export Thread:
3   XMLNode::~XMLNode
4   ARDOUR::AutomationList::snapshot_history
5   ARDOUR::AutomationList::start_write_pass
6   ARDOUR::Automatable::non_realtime_locate
7   ARDOUR::Route::non_realtime_locate
8   ARDOUR::Session::non_realtime_locate
9   ARDOUR::Session::butler_transport_work
10  ARDOUR::Session::process_export_fw

Butler thread:
7   XMLNode::~XMLNode
8   ARDOUR::AutomationList::snapshot_history
9   ARDOUR::AutomationList::start_write_pass
10  ARDOUR::Automatable::non_realtime_locate
11  ARDOUR::Route::non_realtime_locate
12  ARDOUR::Session::non_realtime_locate
13  ARDOUR::Session::butler_transport_work
14  ARDOUR::Butler::thread_work
15  ARDOUR::Butler::_thread_work
```
This commit is contained in:
Robin Gareus 2021-05-08 23:29:49 +02:00
parent cc83cdd9df
commit 79bf025862
Signed by: rgareus
GPG Key ID: A090BCE02CF57F04

View File

@ -307,9 +307,8 @@ Session::process_export_fw (pframes_t nframes)
TFSM_SPEED (1.0, false);
TFSM_ROLL ();
butler_transport_work (true);
g_atomic_int_set (&_butler->should_do_transport_work, 0);
butler_completed_transport_work ();
_butler->schedule_transport_work ();
/* Session::process_with_events () sets _remaining_latency_preroll = 0
* when being called with _transport_fsm->transport_speed() == 0.
*
@ -323,6 +322,16 @@ Session::process_export_fw (pframes_t nframes)
return;
}
/* wait for butler to complete schedule_transport_work(),
* compare to Session::process */
if (non_realtime_work_pending ()) {
if (_butler->transport_work_requested ()) {
/* butler is still processing */
return;
}
butler_completed_transport_work ();
}
if (_remaining_latency_preroll > 0) {
samplepos_t remain = std::min ((samplepos_t)nframes, _remaining_latency_preroll);