Fix race condition when closing a session
~Session calls AudioEngine::remove_session(), which fades out, then unsets the session, and then in libs/ardour/audioengine.cc:460 ``` session_removed.signal(); // wakes up thread that initiated session removal ``` Session d'tor continues, and calls Port::PortDrop(), which unregisters all ports one at a time. Concurrently, AudioEngine continues, and calls PortManager::silence_outputs which gets all ports first (!), and then iterates over them. There is a race condition which can lead to DummyAudioBackend::get_buffer: Assertion `valid_port (port)' failed
This commit is contained in:
parent
40738b2bee
commit
95de61f74e
@ -270,6 +270,7 @@ class LIBARDOUR_API AudioEngine : public PortManager, public SessionHandlePtr
|
||||
Glib::Threads::Cond session_removed;
|
||||
bool session_remove_pending;
|
||||
sampleoffset_t session_removal_countdown;
|
||||
bool session_deleted;
|
||||
gain_t session_removal_gain;
|
||||
gain_t session_removal_gain_step;
|
||||
bool _running;
|
||||
|
@ -84,6 +84,7 @@ static std::atomic<int> audioengine_thread_cnt (1);
|
||||
AudioEngine::AudioEngine ()
|
||||
: session_remove_pending (false)
|
||||
, session_removal_countdown (-1)
|
||||
, session_deleted (false)
|
||||
, _running (false)
|
||||
, _freewheeling (false)
|
||||
, monitor_check_interval (INT32_MAX)
|
||||
@ -261,12 +262,12 @@ AudioEngine::process_callback (pframes_t nframes)
|
||||
if (_session) {
|
||||
Xrun();
|
||||
}
|
||||
/* really only JACK requires this
|
||||
* (other backends clear the output buffers
|
||||
* before the process_callback. it may even be
|
||||
* jack/alsa only). but better safe than sorry.
|
||||
/* only JACK requires this (other backends clear the
|
||||
* output buffers before the process_callback.
|
||||
*/
|
||||
PortManager::silence_outputs (nframes);
|
||||
if (!session_deleted) {
|
||||
PortManager::silence_outputs (nframes);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -454,7 +455,9 @@ AudioEngine::process_callback (pframes_t nframes)
|
||||
|
||||
} else {
|
||||
/* fade out done */
|
||||
_session = 0;
|
||||
PortManager::silence_outputs (nframes);
|
||||
session_deleted = true;
|
||||
SessionHandlePtr::set_session (0);
|
||||
session_removal_countdown = -1; // reset to "not in progress"
|
||||
session_remove_pending = false;
|
||||
session_removed.signal(); // wakes up thread that initiated session removal
|
||||
@ -475,7 +478,7 @@ AudioEngine::process_callback (pframes_t nframes)
|
||||
|
||||
if (_session == 0) {
|
||||
|
||||
if (!_freewheeling) {
|
||||
if (!_freewheeling && !session_deleted) {
|
||||
PortManager::silence_outputs (nframes);
|
||||
}
|
||||
|
||||
@ -799,6 +802,7 @@ AudioEngine::set_session (Session *s)
|
||||
SessionHandlePtr::set_session (s);
|
||||
|
||||
if (_session) {
|
||||
session_deleted = false;
|
||||
_init_countdown = std::max (4, (int)(_backend->sample_rate () / _backend->buffer_size ()) / 8);
|
||||
_pending_playback_latency_callback.store (0);
|
||||
_pending_capture_latency_callback.store (0);
|
||||
@ -820,6 +824,7 @@ AudioEngine::remove_session ()
|
||||
}
|
||||
|
||||
} else {
|
||||
session_deleted = true;
|
||||
SessionHandlePtr::set_session (0);
|
||||
}
|
||||
|
||||
|
@ -155,7 +155,7 @@ Port::drop ()
|
||||
if (_port_handle) {
|
||||
DEBUG_TRACE (DEBUG::Ports, string_compose ("drop handle for port %1\n", name()));
|
||||
port_engine.unregister_port (_port_handle);
|
||||
_port_handle.reset ();;
|
||||
_port_handle.reset ();
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user