From 96613df7830699dbbfb5c2d9fe3ebdb0598e6aca Mon Sep 17 00:00:00 2001 From: David Robillard Date: Fri, 29 Jan 2010 04:35:48 +0000 Subject: Remove references to deleted ports with control bindings (fix crash when applying binding to deleted port). git-svn-id: http://svn.drobilla.net/lad/trunk/ingen@2393 a436a847-0d15-0410-975c-d299462d15a1 --- src/engine/ControlBindings.cpp | 34 ++++++++++++++++++++++++++++++---- src/engine/ControlBindings.hpp | 15 ++++++++++++--- src/engine/events/Delete.cpp | 25 +++++++++++++------------ src/engine/events/Delete.hpp | 3 +++ 4 files changed, 58 insertions(+), 19 deletions(-) diff --git a/src/engine/ControlBindings.cpp b/src/engine/ControlBindings.cpp index b74a3124..2c2a1888 100644 --- a/src/engine/ControlBindings.cpp +++ b/src/engine/ControlBindings.cpp @@ -60,7 +60,7 @@ ControlBindings::set_port_value(ProcessContext& context, PortImpl* port, int8_t void ControlBindings::bind(ProcessContext& context, int8_t cc_num) { - _bindings.insert(make_pair(cc_num, _learn_port)); + _bindings->insert(make_pair(cc_num, _learn_port)); const Events::SendBinding ev(context.engine(), context.start(), _learn_port, MessageType(MessageType::MIDI_CC, cc_num)); @@ -70,6 +70,30 @@ ControlBindings::bind(ProcessContext& context, int8_t cc_num) } +SharedPtr +ControlBindings::remove(const Raul::Path& path) +{ + ThreadManager::assert_thread(THREAD_PRE_PROCESS); + + SharedPtr old_bindings = _bindings; + + SharedPtr copy(new Bindings(*_bindings.get())); + + for (Bindings::iterator i = copy->begin(); i != copy->end();) { + Bindings::iterator next = i; + ++next; + + if (i->second->path() == path || i->second->path().is_child_of(path)) + copy->erase(i); + + i = next; + } + + _bindings = copy; + return old_bindings; +} + + void ControlBindings::process(ProcessContext& context, EventBuffer* buffer) { @@ -79,6 +103,8 @@ ControlBindings::process(ProcessContext& context, EventBuffer* buffer) uint16_t size = 0; uint8_t* buf = NULL; + SharedPtr bindings = _bindings; + if (_learn_port) { buffer->rewind(); while (buffer->get_event(&frames, &subframes, &type, &size, &buf)) { @@ -91,14 +117,14 @@ ControlBindings::process(ProcessContext& context, EventBuffer* buffer) } } - if (!_bindings.empty()) { + if (!bindings->empty()) { buffer->rewind(); while (buffer->get_event(&frames, &subframes, &type, &size, &buf)) { if (type == _map->midi_event && (buf[0] & 0xF0) == MIDI_CMD_CONTROL) { const int8_t controller = static_cast(buf[1]); const int8_t value = static_cast(buf[2]); - Bindings::const_iterator i = _bindings.find(controller); - if (i != _bindings.end()) { + Bindings::const_iterator i = bindings->find(controller); + if (i != bindings->end()) { set_port_value(context, i->second, value); } } diff --git a/src/engine/ControlBindings.hpp b/src/engine/ControlBindings.hpp index 8477a0fa..8823ecb1 100644 --- a/src/engine/ControlBindings.hpp +++ b/src/engine/ControlBindings.hpp @@ -15,12 +15,13 @@ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef CONTROL_BINDIGNS_HPP +#ifndef CONTROL_BINDINGS_HPP #define CONTROL_BINDINGS_HPP #include #include #include "raul/SharedPtr.hpp" +#include "raul/Path.hpp" #include "shared/LV2URIMap.hpp" namespace Ingen { @@ -32,15 +33,24 @@ class PortImpl; class ControlBindings { public: + typedef std::map Bindings; + ControlBindings(Engine& engine, SharedPtr map) : _engine(engine) , _map(map) , _learn_port(NULL) + , _bindings(new Bindings()) {} void learn(PortImpl* port); void process(ProcessContext& context, EventBuffer* buffer); + /** Remove all bindings for @a path or children of @a path. + * The caller must safely drop the returned reference in the + * post-processing thread after at least one process thread has run. + */ + SharedPtr remove(const Raul::Path& path); + private: Engine& _engine; SharedPtr _map; @@ -49,8 +59,7 @@ private: void set_port_value(ProcessContext& context, PortImpl* port, int8_t cc_value); void bind(ProcessContext& context, int8_t cc_num); - typedef std::map Bindings; - Bindings _bindings; + SharedPtr _bindings; }; } // namespace Ingen diff --git a/src/engine/events/Delete.cpp b/src/engine/events/Delete.cpp index 956253d6..11d355a4 100644 --- a/src/engine/events/Delete.cpp +++ b/src/engine/events/Delete.cpp @@ -17,18 +17,19 @@ #include "raul/Maid.hpp" #include "raul/Path.hpp" +#include "ClientBroadcaster.hpp" +#include "ControlBindings.hpp" #include "Delete.hpp" -#include "Responder.hpp" -#include "Engine.hpp" -#include "PatchImpl.hpp" -#include "NodeBase.hpp" -#include "PluginImpl.hpp" -#include "Driver.hpp" #include "DisconnectAll.hpp" -#include "ClientBroadcaster.hpp" +#include "Driver.hpp" +#include "Engine.hpp" #include "EngineStore.hpp" #include "EventSource.hpp" +#include "NodeBase.hpp" +#include "PatchImpl.hpp" +#include "PluginImpl.hpp" #include "PortImpl.hpp" +#include "Responder.hpp" using namespace std; @@ -62,6 +63,8 @@ Delete::~Delete() void Delete::pre_process() { + _removed_bindings = _engine.control_bindings()->remove(_path); + _store_iterator = _engine.engine_store()->find(_path); if (_store_iterator != _engine.engine_store()->end()) { @@ -75,7 +78,7 @@ Delete::pre_process() _removed_table = _engine.engine_store()->remove(_store_iterator); } - if (_node != NULL && !_path.is_root()) { + if (_node && !_path.is_root()) { assert(_node->parent_patch()); _patch_node_listnode = _node->parent_patch()->remove_node(_path.name()); if (_patch_node_listnode) { @@ -153,10 +156,6 @@ Delete::execute(ProcessContext& context) if ( ! _port->parent_patch()->parent()) { _driver_port = _engine.driver()->remove_port(_port->path()); - - // Apparently this needs to be called in post_process?? - //if (_driver_port) - // _driver_port->elem()->unregister(); } } @@ -168,6 +167,8 @@ Delete::execute(ProcessContext& context) void Delete::post_process() { + _removed_bindings.reset(); + if (!_node && !_port) { if (_path.is_root()) { _responder->respond_error("You can not destroy the root patch (/)"); diff --git a/src/engine/events/Delete.hpp b/src/engine/events/Delete.hpp index ac46030f..e4cb6732 100644 --- a/src/engine/events/Delete.hpp +++ b/src/engine/events/Delete.hpp @@ -21,6 +21,7 @@ #include "QueuedEvent.hpp" #include "EngineStore.hpp" #include "PatchImpl.hpp" +#include "ControlBindings.hpp" namespace Raul { template class Array; @@ -82,6 +83,8 @@ private: CompiledPatch* _compiled_patch; ///< Patch's new process order DisconnectAll* _disconnect_event; + SharedPtr _removed_bindings; + SharedPtr< Raul::Table > > _removed_table; }; -- cgit v1.2.1