From ef22788409473e8fbc04b41c90027bbd7f34a9df Mon Sep 17 00:00:00 2001 From: David Robillard Date: Wed, 13 Aug 2008 23:12:52 +0000 Subject: Fix race condition resulting in duplicate connections if several identical requests come in rapid succession. git-svn-id: http://svn.drobilla.net/lad/ingen@1359 a436a847-0d15-0410-975c-d299462d15a1 --- src/libs/engine/events/ConnectionEvent.cpp | 18 ++++++++------ src/libs/engine/events/DisconnectionEvent.cpp | 36 ++++++++++++++++++--------- src/libs/engine/events/DisconnectionEvent.hpp | 7 +++--- 3 files changed, 38 insertions(+), 23 deletions(-) (limited to 'src/libs/engine/events') diff --git a/src/libs/engine/events/ConnectionEvent.cpp b/src/libs/engine/events/ConnectionEvent.cpp index 893dc9cb..ac04d1cc 100644 --- a/src/libs/engine/events/ConnectionEvent.cpp +++ b/src/libs/engine/events/ConnectionEvent.cpp @@ -88,12 +88,6 @@ ConnectionEvent::pre_process() return; } - if (_dst_input_port->is_connected_to(_src_output_port)) { - _error = ALREADY_CONNECTED; - QueuedEvent::pre_process(); - return; - } - NodeImpl* const src_node = _src_port->parent_node(); NodeImpl* const dst_node = _dst_port->parent_node(); @@ -116,6 +110,13 @@ ConnectionEvent::pre_process() } assert(_patch); + + //if (_dst_input_port->is_connected_to(_src_output_port)) { + if (_patch->has_connection(_src_output_port, _dst_input_port)) { + _error = ALREADY_CONNECTED; + QueuedEvent::pre_process(); + return; + } if (src_node == NULL || dst_node == NULL) { _error = PARENTS_NOT_FOUND; @@ -139,6 +140,8 @@ ConnectionEvent::pre_process() dst_node->providers()->push_back(new Raul::List::Node(src_node)); src_node->dependants()->push_back(new Raul::List::Node(dst_node)); } + + _patch->add_connection(_patch_listnode); if (_patch->enabled()) _compiled_patch = _patch->compile(); @@ -153,9 +156,8 @@ ConnectionEvent::execute(ProcessContext& context) QueuedEvent::execute(context); if (_error == NO_ERROR) { - // These must be inserted here, since they're actually used by the audio thread + // This must be inserted here, since they're actually used by the audio thread _dst_input_port->add_connection(_port_listnode); - _patch->add_connection(_patch_listnode); if (_patch->compiled_patch() != NULL) _engine.maid()->push(_patch->compiled_patch()); _patch->compiled_patch(_compiled_patch); diff --git a/src/libs/engine/events/DisconnectionEvent.cpp b/src/libs/engine/events/DisconnectionEvent.cpp index e85b4fcf..03110f9e 100644 --- a/src/libs/engine/events/DisconnectionEvent.cpp +++ b/src/libs/engine/events/DisconnectionEvent.cpp @@ -44,6 +44,7 @@ DisconnectionEvent::DisconnectionEvent(Engine& engine, SharedPtr resp _src_port(NULL), _dst_port(NULL), _lookup(true), + _patch_connection(NULL), _compiled_patch(NULL), _error(NO_ERROR) { @@ -97,12 +98,6 @@ DisconnectionEvent::pre_process() assert(_src_output_port); assert(_dst_input_port); - if (!_dst_input_port->is_connected_to(_src_output_port)) { - _error = NOT_CONNECTED; - QueuedEvent::pre_process(); - return; - } - NodeImpl* const src_node = _src_port->parent_node(); NodeImpl* const dst_node = _dst_port->parent_node(); @@ -125,6 +120,13 @@ DisconnectionEvent::pre_process() } assert(_patch); + + //if (_dst_input_port->is_connected_to(_src_output_port)) { + if (!_patch->has_connection(_src_output_port, _dst_input_port)) { + _error = NOT_CONNECTED; + QueuedEvent::pre_process(); + return; + } if (src_node == NULL || dst_node == NULL) { _error = PARENTS_NOT_FOUND; @@ -143,6 +145,8 @@ DisconnectionEvent::pre_process() delete src_node->dependants()->erase(i); break; } + + _patch_connection = _patch->remove_connection(_src_port, _dst_port); if (_patch->enabled()) _compiled_patch = _patch->compile(); @@ -161,15 +165,23 @@ DisconnectionEvent::execute(ProcessContext& context) = _dst_input_port->remove_connection(_src_output_port); if (port_connection != NULL) { - PatchImpl::Connections::Node* const patch_connection - = _patch->remove_connection(_src_port, _dst_port); - - assert(patch_connection); - assert(port_connection->elem() == patch_connection->elem()); + assert(_patch_connection); + + if (port_connection->elem() != _patch_connection->elem()) { + cerr << "ERROR: Corrupt connections:" << endl; + cerr << "\t" << port_connection->elem() << ": " + << port_connection->elem()->src_port_path() + << " -> " << port_connection->elem()->dst_port_path() << endl + << "!=" << endl + << "\t" << _patch_connection->elem() << ": " + << _patch_connection->elem()->src_port_path() + << " -> " << _patch_connection->elem()->dst_port_path() << endl; + } + assert(port_connection->elem() == _patch_connection->elem()); // Destroy list node, which will drop reference to connection itself _engine.maid()->push(port_connection); - _engine.maid()->push(patch_connection); + _engine.maid()->push(_patch_connection); if (_patch->compiled_patch() != NULL) _engine.maid()->push(_patch->compiled_patch()); diff --git a/src/libs/engine/events/DisconnectionEvent.hpp b/src/libs/engine/events/DisconnectionEvent.hpp index ea4dbbda..700febeb 100644 --- a/src/libs/engine/events/DisconnectionEvent.hpp +++ b/src/libs/engine/events/DisconnectionEvent.hpp @@ -22,6 +22,7 @@ #include #include "QueuedEvent.hpp" #include "types.hpp" +#include "PatchImpl.hpp" using std::string; namespace Raul { @@ -31,7 +32,6 @@ namespace Raul { namespace Ingen { -class PatchImpl; class NodeImpl; class ConnectionImpl; class MidiMessage; @@ -76,8 +76,9 @@ private: OutputPort* _src_output_port; InputPort* _dst_input_port; - bool _lookup; - + bool _lookup; + + PatchImpl::Connections::Node* _patch_connection; CompiledPatch* _compiled_patch; ///< New process order for Patch ErrorType _error; -- cgit v1.2.1