From 88ef85844d64de39b7f69fc4568d16d48f35cd3e Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Thu, 10 Sep 2020 11:16:56 +0200 Subject: [PATCH] loopback_internal: add new node-type for internal loopback --- include/villas/node_type.h | 3 +- include/villas/nodes/loopback_internal.hpp | 67 +++++++++ lib/nodes/CMakeLists.txt | 4 +- lib/nodes/loopback_internal.cpp | 158 +++++++++++++++++++++ 4 files changed, 230 insertions(+), 2 deletions(-) create mode 100644 include/villas/nodes/loopback_internal.hpp create mode 100644 lib/nodes/loopback_internal.cpp diff --git a/include/villas/node_type.h b/include/villas/node_type.h index e4db5bc27..ef9c77335 100644 --- a/include/villas/node_type.h +++ b/include/villas/node_type.h @@ -43,7 +43,8 @@ class SuperNode; } enum class NodeFlags { - PROVIDES_SIGNALS = (1 << 0) + PROVIDES_SIGNALS = (1 << 0), + INTERNAL = (1 << 1) }; /** C++ like vtable construct for node_types */ diff --git a/include/villas/nodes/loopback_internal.hpp b/include/villas/nodes/loopback_internal.hpp new file mode 100644 index 000000000..3c128b2be --- /dev/null +++ b/include/villas/nodes/loopback_internal.hpp @@ -0,0 +1,67 @@ +/** Node-type for internal loopback connections. + * + * @file + * @author Steffen Vogel + * @copyright 2014-2020, Institute for Automation of Complex Power Systems, EONERC + * @license GNU General Public License (version 3) + * + * VILLASnode + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + *********************************************************************************/ + +/** + * @ingroup node + * @addtogroup loopback Loopback connections + * @{ + */ + +#pragma once + +#include +#include + +/* Forward declarations */ +struct vnode; +struct sample; + +/** Node-type for signal generation. + * @see node_type + */ +struct loopback_internal { + int queuelen; + enum QueueSignalledMode mode; + struct queue_signalled queue; + + struct vnode *source; +}; + +/** @see node_type::print */ +char * loopback_internal_print(struct vnode *n); + +/** @see node_type::start */ +int loopback_internal_start(struct vnode *n); + +/** @see node_type::stop */ +int loopback_internal_stop(struct vnode *n); + +/** @see node_type::read */ +int loopback_internal_read(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *release); + +/** @see node_type::write */ +int loopback_internal_write(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *release); + +struct vnode * loopback_internal_create(struct vnode *orig); + +/** @} */ diff --git a/lib/nodes/CMakeLists.txt b/lib/nodes/CMakeLists.txt index 2e719be20..89f3e2f66 100644 --- a/lib/nodes/CMakeLists.txt +++ b/lib/nodes/CMakeLists.txt @@ -20,7 +20,9 @@ # along with this program. If not, see . ################################################################################### -set(NODE_SRC) +set(NODE_SRC + loopback_internal.cpp +) if(LIBNL3_ROUTE_FOUND) list(APPEND LIBRARIES PkgConfig::LIBNL3_ROUTE) diff --git a/lib/nodes/loopback_internal.cpp b/lib/nodes/loopback_internal.cpp new file mode 100644 index 000000000..69ea56265 --- /dev/null +++ b/lib/nodes/loopback_internal.cpp @@ -0,0 +1,158 @@ +/** Node-type for internal loopback_internal connections. + * + * @author Steffen Vogel + * @copyright 2014-2020, Institute for Automation of Complex Power Systems, EONERC + * @license GNU General Public License (version 3) + * + * VILLASnode + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + *********************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include + +using namespace villas; +using namespace villas::utils; + +static struct plugin p; + +int loopback_internal_init(struct vnode *n) +{ + struct loopback_internal *l = (struct loopback_internal *) n->_vd; + + l->mode = QueueSignalledMode::EVENTFD; + l->queuelen = DEFAULT_QUEUE_LENGTH; + + return 0; +} + +int loopback_internal_prepare(struct vnode *n) +{ + struct loopback_internal *l = (struct loopback_internal *) n->_vd; + + return queue_signalled_init(&l->queue, l->queuelen, memory_default, QueueSignalledMode::EVENTFD); +} + +int loopback_internal_destroy(struct vnode *n) +{ + struct loopback_internal *l= (struct loopback_internal *) n->_vd; + + return queue_signalled_destroy(&l->queue); +} + +int loopback_internal_read(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *release) +{ + int avail; + + struct loopback_internal *l = (struct loopback_internal *) n->_vd; + struct sample *cpys[cnt]; + + avail = queue_signalled_pull_many(&l->queue, (void **) cpys, cnt); + + for (int i = 0; i < avail; i++) { + sample_copy(smps[i], cpys[i]); + sample_decref(cpys[i]); + } + + return avail; +} + +int loopback_internal_write(struct vnode *n, struct sample *smps[], unsigned cnt, unsigned *release) +{ + struct loopback_internal *l = (struct loopback_internal *) n->_vd; + + sample_incref_many(smps, cnt); + + return queue_signalled_push_many(&l->queue, (void **) smps, cnt); +} + +char * loopback_internal_print(struct vnode *n) +{ + struct loopback_internal *l = (struct loopback_internal *) n->_vd; + char *buf = nullptr; + + strcatf(&buf, "queuelen=%d", l->queuelen); + + return buf; +} + +int loopback_internal_poll_fds(struct vnode *n, int fds[]) +{ + struct loopback_internal *l = (struct loopback_internal *) n->_vd; + + fds[0] = queue_signalled_fd(&l->queue); + + return 1; +} + +struct vnode * loopback_internal_create(struct vnode *orig) +{ + int ret; + struct vnode *n; + struct loopback_internal *l; + + n = new struct vnode; + if (!n) + throw MemoryAllocationError(); + + l = (struct loopback_internal *) n->_vd; + + ret = node_init(n, &p.node); + if (ret) + return nullptr; + + l->source = orig; + + asprintf(&n->name, "%s_lo%zu", node_name_short(orig), vlist_length(&orig->sources)); + + ret = signal_list_copy(&n->in.signals, &orig->in.signals); + if (ret) + return nullptr; + + return n; +} + +__attribute__((constructor(110))) +static void register_plugin() { + p.name = "loopback_internal"; + p.description = "internal loopback to connect multiple paths"; + p.type = PluginType::NODE; + p.node.instances.state = State::DESTROYED; + p.node.vectorize = 0; + p.node.flags = (int) NodeFlags::PROVIDES_SIGNALS | (int) NodeFlags::INTERNAL; + p.node.size = sizeof(struct loopback_internal); + p.node.print = loopback_internal_print; + p.node.prepare = loopback_internal_prepare; + p.node.init = loopback_internal_init; + p.node.destroy = loopback_internal_destroy; + p.node.read = loopback_internal_read; + p.node.write = loopback_internal_write; + p.node.poll_fds = loopback_internal_poll_fds; + + int ret = vlist_init(&p.node.instances); + if (!ret) + vlist_init_and_push(&plugins, &p); +} + +__attribute__((destructor(110))) +static void deregister_plugin() { + vlist_remove_all(&plugins, &p); +}