summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2014-03-29 22:02:13 +0000
committerDavid Robillard <d@drobilla.net>2014-03-29 22:02:13 +0000
commit8d3e4718aa1fe278b6f696dd3d91275d8f4ff5b2 (patch)
treec166c8f8a0b5dbd26a20bc3f7426b1dfded25627
parent2f18f7f73da0d4592135ce383be9156bca8acb5f (diff)
downloadingen-8d3e4718aa1fe278b6f696dd3d91275d8f4ff5b2.tar.gz
ingen-8d3e4718aa1fe278b6f696dd3d91275d8f4ff5b2.tar.bz2
ingen-8d3e4718aa1fe278b6f696dd3d91275d8f4ff5b2.zip
Eliminate long-term lock from Get event.
git-svn-id: http://svn.drobilla.net/lad/trunk/ingen@5344 a436a847-0d15-0410-975c-d299462d15a1
-rw-r--r--src/server/events/Get.cpp156
-rw-r--r--src/server/events/Get.hpp45
2 files changed, 124 insertions, 77 deletions
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 <utility>
+#include <glibmm/thread.h>
+
#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<Interface> 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<const Arc> arc = a.second;
+ const Connect connect = { arc->tail_path(), arc->head_path() };
+ connects.push_back(connect);
+ }
+}
+
+Get::Get(Engine& engine,
+ SPtr<Interface> 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<const GraphImpl*>(_object))) {
+ _response.put_graph(graph);
+ } else if ((block = dynamic_cast<const BlockImpl*>(_object))) {
+ _response.put_block(block);
+ } else if ((port = dynamic_cast<const PortImpl*>(_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<const GraphImpl*>(_object))) {
- send_graph(_request_client.get(), graph);
- } else if ((block = dynamic_cast<const BlockImpl*>(_object))) {
- send_block(_request_client.get(), block);
- } else if ((port = dynamic_cast<const PortImpl*>(_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 <glibmm/thread.h>
-
#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<Put> puts;
+ std::vector<Connect> connects;
+ };
+
+ const Raul::URI _uri;
+ const Node* _object;
+ const PluginImpl* _plugin;
+ BlockFactory::Plugins _plugins;
+ Response _response;
};
} // namespace Events