From 8d3e4718aa1fe278b6f696dd3d91275d8f4ff5b2 Mon Sep 17 00:00:00 2001 From: David Robillard Date: Sat, 29 Mar 2014 22:02:13 +0000 Subject: Eliminate long-term lock from Get event. git-svn-id: http://svn.drobilla.net/lad/trunk/ingen@5344 a436a847-0d15-0410-975c-d299462d15a1 --- src/server/events/Get.cpp | 156 +++++++++++++++++++++++++--------------------- src/server/events/Get.hpp | 45 ++++++++++--- 2 files changed, 124 insertions(+), 77 deletions(-) (limited to 'src/server') diff --git a/src/server/events/Get.cpp b/src/server/events/Get.cpp index f7fa5e6a..6269aa2a 100644 --- a/src/server/events/Get.cpp +++ b/src/server/events/Get.cpp @@ -16,6 +16,8 @@ #include +#include + #include "ingen/Interface.hpp" #include "ingen/Node.hpp" #include "ingen/Store.hpp" @@ -34,95 +36,116 @@ namespace Ingen { namespace Server { namespace Events { -static void -send_graph(Interface* client, const GraphImpl* graph); - -Get::Get(Engine& engine, - SPtr client, - int32_t id, - SampleCount timestamp, - const Raul::URI& uri) - : Event(engine, client, id, timestamp) - , _uri(uri) - , _object(NULL) - , _plugin(NULL) - , _lock(engine.store()->lock(), Glib::NOT_LOCK) +void +Get::Response::put(const Raul::URI& uri, + const Resource::Properties& props, + Resource::Graph ctx) { + const Get::Response::Put put = { uri, props, ctx }; + puts.push_back(put); } -bool -Get::pre_process() -{ - _lock.acquire(); - - if (_uri == "ingen:/plugins") { - _plugins = _engine.block_factory()->plugins(); - return Event::pre_process_done(Status::SUCCESS); - } else if (_uri == "ingen:/engine") { - return Event::pre_process_done(Status::SUCCESS); - } else if (Node::uri_is_path(_uri)) { - _object = _engine.store()->get(Node::uri_to_path(_uri)); - return Event::pre_process_done( - _object ? Status::SUCCESS : Status::NOT_FOUND, _uri); - } else { - _plugin = _engine.block_factory()->plugin(_uri); - return Event::pre_process_done( - _plugin ? Status::SUCCESS : Status::NOT_FOUND, _uri); - } -} - -static void -send_port(Interface* client, const PortImpl* port) +void +Get::Response::put_port(const PortImpl* port) { if (port->is_a(PortType::CONTROL) || port->is_a(PortType::CV)) { Resource::Properties props = port->properties(); props.erase(port->bufs().uris().ingen_value); props.insert(std::make_pair(port->bufs().uris().ingen_value, port->value())); - client->put(port->uri(), props); + put(port->uri(), props); } else { - client->put(port->uri(), port->properties()); + put(port->uri(), port->properties()); } } -static void -send_block(Interface* client, const BlockImpl* block) +void +Get::Response::put_block(const BlockImpl* block) { PluginImpl* const plugin = block->plugin_impl(); if (plugin->type() == Plugin::Graph) { - send_graph(client, (const GraphImpl*)block); + put_graph((const GraphImpl*)block); } else { - client->put(block->uri(), block->properties()); + put(block->uri(), block->properties()); for (size_t j = 0; j < block->num_ports(); ++j) { - send_port(client, block->port_impl(j)); + put_port(block->port_impl(j)); } } } -static void -send_graph(Interface* client, const GraphImpl* graph) +void +Get::Response::put_graph(const GraphImpl* graph) { - client->put(graph->uri(), - graph->properties(Resource::Graph::INTERNAL), - Resource::Graph::INTERNAL); + put(graph->uri(), + graph->properties(Resource::Graph::INTERNAL), + Resource::Graph::INTERNAL); - client->put(graph->uri(), - graph->properties(Resource::Graph::EXTERNAL), - Resource::Graph::EXTERNAL); + put(graph->uri(), + graph->properties(Resource::Graph::EXTERNAL), + Resource::Graph::EXTERNAL); - // Send blocks + // Enqueue locks for (const auto& b : graph->blocks()) { - send_block(client, &b); + put_block(&b); } - // Send ports + // Enqueue ports for (uint32_t i = 0; i < graph->num_ports_non_rt(); ++i) { - send_port(client, graph->port_impl(i)); + put_port(graph->port_impl(i)); } - // Send arcs + // Enqueue arcs for (const auto& a : graph->arcs()) { - client->connect(a.second->tail_path(), a.second->head_path()); + const SPtr arc = a.second; + const Connect connect = { arc->tail_path(), arc->head_path() }; + connects.push_back(connect); + } +} + +Get::Get(Engine& engine, + SPtr client, + int32_t id, + SampleCount timestamp, + const Raul::URI& uri) + : Event(engine, client, id, timestamp) + , _uri(uri) + , _object(NULL) + , _plugin(NULL) +{} + +bool +Get::pre_process() +{ + Glib::RWLock::ReaderLock lock(_engine.store()->lock()); + + if (_uri == "ingen:/plugins") { + _plugins = _engine.block_factory()->plugins(); + return Event::pre_process_done(Status::SUCCESS); + } else if (_uri == "ingen:/engine") { + return Event::pre_process_done(Status::SUCCESS); + } else if (Node::uri_is_path(_uri)) { + if ((_object = _engine.store()->get(Node::uri_to_path(_uri)))) { + const BlockImpl* block = NULL; + const GraphImpl* graph = NULL; + const PortImpl* port = NULL; + if ((graph = dynamic_cast(_object))) { + _response.put_graph(graph); + } else if ((block = dynamic_cast(_object))) { + _response.put_block(block); + } else if ((port = dynamic_cast(_object))) { + _response.put_port(port); + } else { + return Event::pre_process_done(Status::BAD_OBJECT_TYPE, _uri); + } + return Event::pre_process_done(Status::SUCCESS); + } + return Event::pre_process_done(Status::NOT_FOUND, _uri); + } else { + if ((_plugin = _engine.block_factory()->plugin(_uri))) { + _response.put(_uri, _plugin->properties()); + return Event::pre_process_done(Status::SUCCESS); + } + return Event::pre_process_done(Status::NOT_FOUND, _uri); } } @@ -140,22 +163,15 @@ Get::post_process() Raul::URI("ingen:/engine"), uris.param_sampleRate, uris.forge.make(int32_t(_engine.driver()->sample_rate()))); - } else if (_object) { - const BlockImpl* block = NULL; - const GraphImpl* graph = NULL; - const PortImpl* port = NULL; - if ((graph = dynamic_cast(_object))) { - send_graph(_request_client.get(), graph); - } else if ((block = dynamic_cast(_object))) { - send_block(_request_client.get(), block); - } else if ((port = dynamic_cast(_object))) { - send_port(_request_client.get(), port); + } else { + for (const Response::Put& put : _response.puts) { + _request_client->put(put.uri, put.properties, put.ctx); + } + for (const Response::Connect& connect : _response.connects) { + _request_client->connect(connect.tail, connect.head); } - } else if (_plugin) { - _request_client->put(_uri, _plugin->properties()); } } - _lock.release(); } } // namespace Events diff --git a/src/server/events/Get.hpp b/src/server/events/Get.hpp index 7a5830a3..7aea8c77 100644 --- a/src/server/events/Get.hpp +++ b/src/server/events/Get.hpp @@ -17,8 +17,6 @@ #ifndef INGEN_EVENTS_GET_HPP #define INGEN_EVENTS_GET_HPP -#include - #include "Event.hpp" #include "BlockFactory.hpp" #include "types.hpp" @@ -48,11 +46,44 @@ public: void post_process(); private: - const Raul::URI _uri; - const Node* _object; - const PluginImpl* _plugin; - BlockFactory::Plugins _plugins; - Glib::RWLock::ReaderLock _lock; + /** A sequence of puts and connects to respond to client with. + * This is constructed in the pre_process() and later sent in + * post_process() to avoid the need to lock. + * + * Ideally events (both server and client) would always be in a standard + * message format so the Ingen protocol went the whole way through the + * system, but for now things are controlled procedurally through + * Interface, so this interim structure is necessary. + */ + struct Response { + void put(const Raul::URI& uri, + const Resource::Properties& props, + Resource::Graph ctx=Resource::Graph::DEFAULT); + + void put_port(const PortImpl* port); + void put_block(const BlockImpl* block); + void put_graph(const GraphImpl* graph); + + struct Put { + Raul::URI uri; + Resource::Properties properties; + Resource::Graph ctx; + }; + + struct Connect { + Raul::Path tail; + Raul::Path head; + }; + + std::vector puts; + std::vector connects; + }; + + const Raul::URI _uri; + const Node* _object; + const PluginImpl* _plugin; + BlockFactory::Plugins _plugins; + Response _response; }; } // namespace Events -- cgit v1.2.1