Fix deadlock/race introduced in aaf301321
Port::_connections_lock must not be locked when calling port_engine.connect().
This commit is contained in:
parent
abd27b765e
commit
10b2380b14
@ -714,52 +714,62 @@ Port::has_ext_connection () const
|
|||||||
int
|
int
|
||||||
Port::reconnect ()
|
Port::reconnect ()
|
||||||
{
|
{
|
||||||
/* caller must hold process lock; intended to be used only after reestablish() */
|
|
||||||
|
|
||||||
int count = 0;
|
|
||||||
|
|
||||||
std::string const bid (AudioEngine::instance()->backend_id (receives_input ()));
|
std::string const bid (AudioEngine::instance()->backend_id (receives_input ()));
|
||||||
|
|
||||||
Glib::Threads::RWLock::WriterLock lm (_connections_lock);
|
std::vector <std::string> c_int, c_ext, f_int, f_ext;
|
||||||
|
|
||||||
|
Glib::Threads::RWLock::ReaderLock lm (_connections_lock);
|
||||||
|
|
||||||
if (_ext_connections.find (bid) != _ext_connections.end ()) {
|
if (_ext_connections.find (bid) != _ext_connections.end ()) {
|
||||||
if (_int_connections.empty () && _ext_connections[bid].empty ()) {
|
if (_int_connections.empty () && _ext_connections[bid].empty ()) {
|
||||||
return 0; /* OK */
|
return 0; /* OK */
|
||||||
}
|
}
|
||||||
count = _int_connections.size() + _ext_connections[bid].size();
|
c_int.insert (c_int.end(), _int_connections.begin(), _int_connections.end());
|
||||||
|
c_ext.insert (c_ext.end(), _ext_connections.at(bid).begin(), _ext_connections.at(bid).end());
|
||||||
} else {
|
} else {
|
||||||
if (_int_connections.empty ()) {
|
if (_int_connections.empty ()) {
|
||||||
return 0; /* OK */
|
return 0; /* OK */
|
||||||
}
|
}
|
||||||
count = _int_connections.size();
|
c_int.insert (c_int.end(), _int_connections.begin(), _int_connections.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUG_TRACE (DEBUG::Ports, string_compose ("Port::reconnect() Connect %1 to %2 destinations\n",name(), count));
|
/* Must hold the lock while calling port_engine.connect. It could lead to deadlock:
|
||||||
|
*
|
||||||
|
* XXBackend::main_process_thread -> PortManager::connect_callback
|
||||||
|
* -> Port::port_connected_or_disconnected -> Port::insert_connection -> take WriterLock
|
||||||
|
*/
|
||||||
|
lm.release ();
|
||||||
|
|
||||||
count = 0;
|
DEBUG_TRACE (DEBUG::Ports, string_compose ("Port::reconnect() Connect %1 to %2 destinations\n",name(), c_int.size () + c_ext.size ()));
|
||||||
|
|
||||||
ConnectionSet::iterator i = _int_connections.begin();
|
int count = 0;
|
||||||
while (i != _int_connections.end()) {
|
|
||||||
ConnectionSet::iterator current = i++;
|
for (auto const& c : c_int) {
|
||||||
if (connect_internal (*current)) {
|
if (connect_internal (c)) {
|
||||||
DEBUG_TRACE (DEBUG::Ports, string_compose ("Port::reconnect() failed to connect %1 to %2\n", name(), (*current)));
|
DEBUG_TRACE (DEBUG::Ports, string_compose ("Port::reconnect() failed to connect %1 to %2\n", name(), (c)));
|
||||||
_int_connections.erase (current);
|
f_int.push_back (c);
|
||||||
} else {
|
} else {
|
||||||
++count;
|
++count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_ext_connections.find (bid) != _ext_connections.end ()) {
|
for (auto const& c : c_ext) {
|
||||||
i = _ext_connections[bid].begin();
|
if (connect_internal (c)) {
|
||||||
while (i != _ext_connections[bid].end()) {
|
DEBUG_TRACE (DEBUG::Ports, string_compose ("Port::reconnect() failed to connect %1 to %2\n", name(), (c)));
|
||||||
ConnectionSet::iterator current = i++;
|
f_ext.push_back (c);
|
||||||
if (connect_internal (*current)) {
|
|
||||||
DEBUG_TRACE (DEBUG::Ports, string_compose ("Port::reconnect() failed to connect %1 to %2\n", name(), (*current)));
|
|
||||||
_ext_connections[bid].erase (current);
|
|
||||||
} else {
|
} else {
|
||||||
++count;
|
++count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lm.acquire ();
|
||||||
|
|
||||||
|
for (auto const& c : f_int) {
|
||||||
|
_int_connections.erase (c);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto const& c : f_ext) {
|
||||||
|
_ext_connections[bid].erase (c);
|
||||||
}
|
}
|
||||||
|
|
||||||
return count == 0 ? -1 : 0;
|
return count == 0 ? -1 : 0;
|
||||||
|
Loading…
Reference in New Issue
Block a user