mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-09 08:14:58 +01:00
Prevent deadlock when disconnecting
The backend holds `_port_callback_mutex` while disconnecting ports. In some cases disconnecting a port can drop the last reference resulting in a port-deletion from the connection handler. This in turn will eventually aquire the `_port_callback_mutex` and deadlock. This is now circumvented by using atomic operations instead of taking a lock to set the `_port_change_flag`. The flag is also used to trigger a latency update in some cases, atomic is preferable to taking a lock to set this flag. -- Full bt: https://paste.debian.net/1184056/ Short: #1 in pthread_mutex_lock () #2 in ARDOUR::PortEngineSharedImpl::port_connect_add_remove_callback() #3 in ARDOUR::BackendPort::~BackendPort() #4 in ARDOUR::DummyPort::~DummyPort() #6 in ARDOUR::DummyAudioPort::~DummyAudioPort() #7 in boost::checked_delete<ARDOUR::BackendPort>(ARDOUR::BackendPort*) #12 in boost::shared_ptr<ARDOUR::ProtoPort>::reset() #13 in ARDOUR::Port::drop() #14 in ARDOUR::Port::~Port() #15 in ARDOUR::AudioPort::~AudioPort() #17 in ARDOUR::AudioEngine::add_pending_port_deletion(ARDOUR::Port*) #20 in boost::detail::sp_counted_base::release() #37 in ARDOUR::PortManager::connect_callback() at libs/ardour/port_manager.cc:788 #38 in ARDOUR::DummyAudioBackend::main_process_thread() at libs/backends/dummy/dummy_audiobackend.cc:1018
This commit is contained in:
parent
30da8c00b5
commit
634d325e5d
7 changed files with 21 additions and 29 deletions
|
|
@ -183,7 +183,8 @@ protected:
|
||||||
|
|
||||||
std::vector<PortConnectData *> _port_connection_queue;
|
std::vector<PortConnectData *> _port_connection_queue;
|
||||||
pthread_mutex_t _port_callback_mutex;
|
pthread_mutex_t _port_callback_mutex;
|
||||||
bool _port_change_flag;
|
|
||||||
|
gint _port_change_flag; /* atomic */
|
||||||
|
|
||||||
void port_connect_callback (const std::string& a, const std::string& b, bool conn) {
|
void port_connect_callback (const std::string& a, const std::string& b, bool conn) {
|
||||||
pthread_mutex_lock (&_port_callback_mutex);
|
pthread_mutex_lock (&_port_callback_mutex);
|
||||||
|
|
@ -192,9 +193,7 @@ protected:
|
||||||
}
|
}
|
||||||
|
|
||||||
void port_connect_add_remove_callback () {
|
void port_connect_add_remove_callback () {
|
||||||
pthread_mutex_lock (&_port_callback_mutex);
|
g_atomic_int_set (&_port_change_flag, 1);
|
||||||
_port_change_flag = true;
|
|
||||||
pthread_mutex_unlock (&_port_callback_mutex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void update_system_port_latencies ();
|
virtual void update_system_port_latencies ();
|
||||||
|
|
|
||||||
|
|
@ -190,7 +190,7 @@ BackendPort::update_connected_latency (bool for_playback)
|
||||||
|
|
||||||
PortEngineSharedImpl::PortEngineSharedImpl (PortManager& mgr, std::string const & str)
|
PortEngineSharedImpl::PortEngineSharedImpl (PortManager& mgr, std::string const & str)
|
||||||
: _instance_name (str)
|
: _instance_name (str)
|
||||||
, _port_change_flag (false)
|
, _port_change_flag (0)
|
||||||
, _portmap (new PortMap)
|
, _portmap (new PortMap)
|
||||||
, _ports (new PortIndex)
|
, _ports (new PortIndex)
|
||||||
{
|
{
|
||||||
|
|
@ -435,8 +435,8 @@ PortEngineSharedImpl::clear_ports ()
|
||||||
_ports.flush ();
|
_ports.flush ();
|
||||||
_portmap.flush ();
|
_portmap.flush ();
|
||||||
|
|
||||||
|
g_atomic_int_set (&_port_change_flag, 0);
|
||||||
pthread_mutex_lock (&_port_callback_mutex);
|
pthread_mutex_lock (&_port_callback_mutex);
|
||||||
_port_change_flag = false;
|
|
||||||
_port_connection_queue.clear();
|
_port_connection_queue.clear();
|
||||||
pthread_mutex_unlock (&_port_callback_mutex);
|
pthread_mutex_unlock (&_port_callback_mutex);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -984,7 +984,7 @@ AlsaAudioBackend::_start (bool for_latency_measurement)
|
||||||
|
|
||||||
engine.reconnect_ports ();
|
engine.reconnect_ports ();
|
||||||
_run = true;
|
_run = true;
|
||||||
_port_change_flag = false;
|
g_atomic_int_set (&_port_change_flag, 0);
|
||||||
|
|
||||||
if (pbd_realtime_pthread_create (PBD_SCHED_FIFO, PBD_RT_PRI_MAIN, PBD_RT_STACKSIZE_PROC,
|
if (pbd_realtime_pthread_create (PBD_SCHED_FIFO, PBD_RT_PRI_MAIN, PBD_RT_STACKSIZE_PROC,
|
||||||
&_main_thread, pthread_process, this))
|
&_main_thread, pthread_process, this))
|
||||||
|
|
@ -2039,9 +2039,8 @@ AlsaAudioBackend::main_process_thread ()
|
||||||
bool connections_changed = false;
|
bool connections_changed = false;
|
||||||
bool ports_changed = false;
|
bool ports_changed = false;
|
||||||
if (!pthread_mutex_trylock (&_port_callback_mutex)) {
|
if (!pthread_mutex_trylock (&_port_callback_mutex)) {
|
||||||
if (_port_change_flag) {
|
if (g_atomic_int_compare_and_exchange (&_port_change_flag, 1, 0)) {
|
||||||
ports_changed = true;
|
ports_changed = true;
|
||||||
_port_change_flag = false;
|
|
||||||
}
|
}
|
||||||
if (!_port_connection_queue.empty ()) {
|
if (!_port_connection_queue.empty ()) {
|
||||||
connections_changed = true;
|
connections_changed = true;
|
||||||
|
|
|
||||||
|
|
@ -640,7 +640,7 @@ CoreAudioBackend::_start (bool for_latency_measurement)
|
||||||
|
|
||||||
_preinit = true;
|
_preinit = true;
|
||||||
_run = true;
|
_run = true;
|
||||||
_port_change_flag = false;
|
g_atomic_int_set (&_port_change_flag, 0);
|
||||||
|
|
||||||
if (_midi_driver_option == _("CoreMidi")) {
|
if (_midi_driver_option == _("CoreMidi")) {
|
||||||
_midiio->set_enabled(true);
|
_midiio->set_enabled(true);
|
||||||
|
|
@ -698,7 +698,7 @@ CoreAudioBackend::_start (bool for_latency_measurement)
|
||||||
engine.reconnect_ports ();
|
engine.reconnect_ports ();
|
||||||
|
|
||||||
// force an initial registration_callback() & latency re-compute
|
// force an initial registration_callback() & latency re-compute
|
||||||
_port_change_flag = true;
|
g_atomic_int_set (&_port_change_flag, 1);
|
||||||
pre_process ();
|
pre_process ();
|
||||||
|
|
||||||
_dsp_load_calc.reset ();
|
_dsp_load_calc.reset ();
|
||||||
|
|
@ -988,7 +988,7 @@ CoreAudioBackend::coremidi_rediscover()
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
printf("unregister MIDI Output: %s\n", (*it)->name().c_str());
|
printf("unregister MIDI Output: %s\n", (*it)->name().c_str());
|
||||||
#endif
|
#endif
|
||||||
_port_change_flag = true;
|
g_atomic_int_set (&_port_change_flag, 1);
|
||||||
unregister_port((*it));
|
unregister_port((*it));
|
||||||
it = _system_midi_out.erase(it);
|
it = _system_midi_out.erase(it);
|
||||||
}
|
}
|
||||||
|
|
@ -1008,7 +1008,7 @@ CoreAudioBackend::coremidi_rediscover()
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
printf("unregister MIDI Input: %s\n", (*it)->name().c_str());
|
printf("unregister MIDI Input: %s\n", (*it)->name().c_str());
|
||||||
#endif
|
#endif
|
||||||
_port_change_flag = true;
|
g_atomic_int_set (&_port_change_flag, 1);
|
||||||
unregister_port((*it));
|
unregister_port((*it));
|
||||||
it = _system_midi_in.erase(it);
|
it = _system_midi_in.erase(it);
|
||||||
}
|
}
|
||||||
|
|
@ -1034,7 +1034,7 @@ CoreAudioBackend::coremidi_rediscover()
|
||||||
BackendPortPtr pp = boost::dynamic_pointer_cast<BackendPort>(p);
|
BackendPortPtr pp = boost::dynamic_pointer_cast<BackendPort>(p);
|
||||||
pp->set_hw_port_name(_midiio->port_name(i, true));
|
pp->set_hw_port_name(_midiio->port_name(i, true));
|
||||||
_system_midi_in.push_back(pp);
|
_system_midi_in.push_back(pp);
|
||||||
_port_change_flag = true;
|
g_atomic_int_set (&_port_change_flag, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < _midiio->n_midi_outputs(); ++i) {
|
for (size_t i = 0; i < _midiio->n_midi_outputs(); ++i) {
|
||||||
|
|
@ -1057,7 +1057,7 @@ CoreAudioBackend::coremidi_rediscover()
|
||||||
BackendPortPtr pp = boost::dynamic_pointer_cast<BackendPort>(p);
|
BackendPortPtr pp = boost::dynamic_pointer_cast<BackendPort>(p);
|
||||||
pp->set_hw_port_name(_midiio->port_name(i, false));
|
pp->set_hw_port_name(_midiio->port_name(i, false));
|
||||||
_system_midi_out.push_back(pp);
|
_system_midi_out.push_back(pp);
|
||||||
_port_change_flag = true;
|
g_atomic_int_set (&_port_change_flag, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1229,9 +1229,8 @@ CoreAudioBackend::pre_process ()
|
||||||
bool connections_changed = false;
|
bool connections_changed = false;
|
||||||
bool ports_changed = false;
|
bool ports_changed = false;
|
||||||
if (!pthread_mutex_trylock (&_port_callback_mutex)) {
|
if (!pthread_mutex_trylock (&_port_callback_mutex)) {
|
||||||
if (_port_change_flag) {
|
if (g_atomic_int_compare_and_exchange (&_port_change_flag, 1, 0)) {
|
||||||
ports_changed = true;
|
ports_changed = true;
|
||||||
_port_change_flag = false;
|
|
||||||
}
|
}
|
||||||
if (!_port_connection_queue.empty ()) {
|
if (!_port_connection_queue.empty ()) {
|
||||||
connections_changed = true;
|
connections_changed = true;
|
||||||
|
|
|
||||||
|
|
@ -460,7 +460,7 @@ DummyAudioBackend::_start (bool /*for_latency_measurement*/)
|
||||||
}
|
}
|
||||||
|
|
||||||
engine.reconnect_ports ();
|
engine.reconnect_ports ();
|
||||||
_port_change_flag = false;
|
g_atomic_int_set (&_port_change_flag, 0);
|
||||||
|
|
||||||
if (pbd_pthread_create (PBD_RT_STACKSIZE_PROC, &_main_thread, pthread_process, this)) {
|
if (pbd_pthread_create (PBD_RT_STACKSIZE_PROC, &_main_thread, pthread_process, this)) {
|
||||||
PBD::error << _("DummyAudioBackend: cannot start.") << endmsg;
|
PBD::error << _("DummyAudioBackend: cannot start.") << endmsg;
|
||||||
|
|
@ -1006,9 +1006,8 @@ DummyAudioBackend::main_process_thread ()
|
||||||
bool connections_changed = false;
|
bool connections_changed = false;
|
||||||
bool ports_changed = false;
|
bool ports_changed = false;
|
||||||
if (!pthread_mutex_trylock (&_port_callback_mutex)) {
|
if (!pthread_mutex_trylock (&_port_callback_mutex)) {
|
||||||
if (_port_change_flag) {
|
if (g_atomic_int_compare_and_exchange (&_port_change_flag, 1, 0)) {
|
||||||
ports_changed = true;
|
ports_changed = true;
|
||||||
_port_change_flag = false;
|
|
||||||
}
|
}
|
||||||
if (!_port_connection_queue.empty ()) {
|
if (!_port_connection_queue.empty ()) {
|
||||||
connections_changed = true;
|
connections_changed = true;
|
||||||
|
|
|
||||||
|
|
@ -636,8 +636,6 @@ PortAudioBackend::_start (bool for_latency_measurement)
|
||||||
|
|
||||||
_measure_latency = for_latency_measurement;
|
_measure_latency = for_latency_measurement;
|
||||||
|
|
||||||
_port_change_flag = false;
|
|
||||||
|
|
||||||
if (_midi_driver_option == winmme_driver_name) {
|
if (_midi_driver_option == winmme_driver_name) {
|
||||||
_midiio->set_enabled(true);
|
_midiio->set_enabled(true);
|
||||||
//_midiio->set_port_changed_callback(midi_port_change, this);
|
//_midiio->set_port_changed_callback(midi_port_change, this);
|
||||||
|
|
@ -674,7 +672,7 @@ PortAudioBackend::_start (bool for_latency_measurement)
|
||||||
_run = true;
|
_run = true;
|
||||||
|
|
||||||
engine.reconnect_ports ();
|
engine.reconnect_ports ();
|
||||||
_port_change_flag = false;
|
g_atomic_int_set (&_port_change_flag, 0);
|
||||||
|
|
||||||
_dsp_calc.reset ();
|
_dsp_calc.reset ();
|
||||||
|
|
||||||
|
|
@ -1728,9 +1726,8 @@ PortAudioBackend::process_port_connection_changes ()
|
||||||
bool connections_changed = false;
|
bool connections_changed = false;
|
||||||
bool ports_changed = false;
|
bool ports_changed = false;
|
||||||
if (!pthread_mutex_trylock (&_port_callback_mutex)) {
|
if (!pthread_mutex_trylock (&_port_callback_mutex)) {
|
||||||
if (_port_change_flag) {
|
if (g_atomic_int_compare_and_exchange (&_port_change_flag, 1, 0)) {
|
||||||
ports_changed = true;
|
ports_changed = true;
|
||||||
_port_change_flag = false;
|
|
||||||
}
|
}
|
||||||
if (!_port_connection_queue.empty ()) {
|
if (!_port_connection_queue.empty ()) {
|
||||||
connections_changed = true;
|
connections_changed = true;
|
||||||
|
|
|
||||||
|
|
@ -625,7 +625,7 @@ PulseAudioBackend::_start (bool /*for_latency_measurement*/)
|
||||||
engine.reconnect_ports ();
|
engine.reconnect_ports ();
|
||||||
|
|
||||||
_run = true;
|
_run = true;
|
||||||
_port_change_flag = false;
|
g_atomic_int_set (&_port_change_flag, 0);
|
||||||
|
|
||||||
if (pbd_realtime_pthread_create (PBD_SCHED_FIFO, PBD_RT_PRI_MAIN, PBD_RT_STACKSIZE_PROC,
|
if (pbd_realtime_pthread_create (PBD_SCHED_FIFO, PBD_RT_PRI_MAIN, PBD_RT_STACKSIZE_PROC,
|
||||||
&_main_thread, pthread_process, this)) {
|
&_main_thread, pthread_process, this)) {
|
||||||
|
|
@ -1104,9 +1104,8 @@ PulseAudioBackend::main_process_thread ()
|
||||||
bool connections_changed = false;
|
bool connections_changed = false;
|
||||||
bool ports_changed = false;
|
bool ports_changed = false;
|
||||||
if (!pthread_mutex_trylock (&_port_callback_mutex)) {
|
if (!pthread_mutex_trylock (&_port_callback_mutex)) {
|
||||||
if (_port_change_flag) {
|
if (g_atomic_int_compare_and_exchange (&_port_change_flag, 1, 0)) {
|
||||||
ports_changed = true;
|
ports_changed = true;
|
||||||
_port_change_flag = false;
|
|
||||||
}
|
}
|
||||||
if (!_port_connection_queue.empty ()) {
|
if (!_port_connection_queue.empty ()) {
|
||||||
connections_changed = true;
|
connections_changed = true;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue