diff --git a/include/villas/node.h b/include/villas/node.h index 59a3b111f..8f166b2e9 100644 --- a/include/villas/node.h +++ b/include/villas/node.h @@ -33,6 +33,7 @@ #include #include +#include #include #include #include @@ -52,17 +53,6 @@ extern "C" { struct rtnl_cls; #endif /* WITH_NETEM */ -struct node_direction { - int enabled; - int builtin; /**< This node should use built-in hooks by default. */ - int vectorize; /**< Number of messages to send / recv at once (scatter / gather) */ - - struct vlist hooks; /**< List of read / write hooks (struct hook). */ - struct vlist signals; /**< Signal description. */ - - json_t *cfg; /**< A JSON object containing the configuration of the node. */ -}; - /** The data structure for a node. * * Every entity which exchanges messages is represented by a node. diff --git a/include/villas/node_direction.h b/include/villas/node_direction.h new file mode 100644 index 000000000..1fd86ccfb --- /dev/null +++ b/include/villas/node_direction.h @@ -0,0 +1,74 @@ +/** Node direction + * + * @file + * @author Steffen Vogel + * @copyright 2014-2019, 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 . + *********************************************************************************/ + +/** + * @addtogroup node Node + * @{ + */ + +#pragma once + +#include + +#include +#include + +/* Forward declarations */ +struct node; + +enum node_dir { + NODE_DIR_IN, /**< VILLASnode is receiving/reading */ + NODE_DIR_OUT /**< VILLASnode is sending/writing */ +}; + +struct node_direction { + enum state state; + enum node_dir direction; + + int enabled; + int builtin; /**< This node should use built-in hooks by default. */ + int vectorize; /**< Number of messages to send / recv at once (scatter / gather) */ + + struct vlist hooks; /**< List of read / write hooks (struct hook). */ + struct vlist signals; /**< Signal description. */ + + json_t *cfg; /**< A JSON object containing the configuration of the node. */ +}; + +int node_direction_init(struct node_direction *nd, enum node_dir dir, struct node *n); + +int node_direction_parse(struct node_direction *nd, struct node *n, json_t *cfg); + +int node_direction_check(struct node_direction *nd, struct node *n); + +int node_direction_prepare(struct node_direction *nd, struct node *n); + +int node_direction_start(struct node_direction *nd, struct node *n); + +int node_direction_stop(struct node_direction *nd, struct node *n); + +int node_direction_destroy(struct node_direction *nd, struct node *n); + +struct vlist * node_direction_get_signals(struct node_direction *nd); + +/** @} */ diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 85318fcbb..055ac29aa 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -49,9 +49,10 @@ set(LIB_SRC path_source.c path_destination.c node.c + node_type.c + node_direction.c memory.c plugin.c - node_type.c stats.c mapping.c shmem.c diff --git a/lib/node.c b/lib/node.c index d3659d39a..b49c01eb3 100644 --- a/lib/node.c +++ b/lib/node.c @@ -41,177 +41,6 @@ #include #endif /* WITH_NETEM */ -int node_direction_prepare(struct node_direction *nd, struct node *n) -{ -#ifdef WITH_HOOKS - int ret; - int m = nd == &n->out - ? HOOK_NODE_WRITE - : HOOK_NODE_READ; - - /* Add internal hooks if they are not already in the list */ - ret = hook_init_builtin_list(&nd->hooks, nd->builtin, m, NULL, n); - if (ret) - return ret; - - /* We sort the hooks according to their priority before starting the path */ - vlist_sort(&nd->hooks, hook_cmp_priority); -#endif /* WITH_HOOKS */ - - return 0; -} - -static int node_direction_init(struct node_direction *nd, struct node *n) -{ - int ret; - - nd->enabled = 1; - nd->vectorize = 1; - nd->builtin = 1; - - nd->hooks.state = STATE_DESTROYED; - nd->signals.state = STATE_DESTROYED; - -#ifdef WITH_HOOKS - ret = vlist_init(&nd->hooks); - if (ret) - return ret; -#endif /* WITH_HOOKS */ - - ret = signal_list_init(&nd->signals); - if (ret) - return ret; - - return 0; -} - -static int node_direction_destroy(struct node_direction *nd, struct node *n) -{ - int ret = 0; - -#ifdef WITH_HOOKS - ret = vlist_destroy(&nd->hooks, (dtor_cb_t) hook_destroy, true); - if (ret) - return ret; -#endif /* WITH_HOOKS */ - - ret = signal_list_destroy(&nd->signals); - if (ret) - return ret; - - return ret; -} - -static int node_direction_parse(struct node_direction *nd, struct node *n, json_t *cfg) -{ - int ret; - - json_error_t err; - json_t *json_hooks = NULL; - json_t *json_signals = NULL; - - nd->cfg = cfg; - - ret = json_unpack_ex(cfg, &err, 0, "{ s?: o, s?: o, s?: i, s?: b, s?: b }", - "hooks", &json_hooks, - "signals", &json_signals, - "vectorize", &nd->vectorize, - "builtin", &nd->builtin, - "enabled", &nd->enabled - ); - if (ret) - jerror(&err, "Failed to parse node %s", node_name(n)); - - if (n->_vt->flags & NODE_TYPE_PROVIDES_SIGNALS) { - if (json_signals) - error("Node %s does not support signal definitions", node_name(n)); - } - else if (json_is_array(json_signals)) { - ret = signal_list_parse(&nd->signals, json_signals); - if (ret) - error("Failed to parse signal definition of node %s", node_name(n)); - } - else { - int count = DEFAULT_SAMPLE_LENGTH; - const char *type_str = "float"; - - if (json_is_object(json_signals)) { - json_unpack_ex(json_signals, &err, 0, "{ s: i, s: s }", - "count", &count, - "type", &type_str - ); - } - else - warning("No signal definition found for node %s. Using the default config of %d floating point signals.", node_name(n), DEFAULT_SAMPLE_LENGTH); - - int type = signal_type_from_str(type_str); - if (type < 0) - error("Invalid signal type %s", type_str); - - signal_list_generate(&nd->signals, count, type); - } - -#ifdef WITH_HOOKS - int m = nd == &n->out - ? HOOK_NODE_WRITE - : HOOK_NODE_READ; - - if (json_hooks) { - ret = hook_parse_list(&nd->hooks, json_hooks, m, NULL, n); - if (ret < 0) - return ret; - } -#endif /* WITH_HOOKS */ - - return 0; -} - -static int node_direction_check(struct node_direction *nd, struct node *n) -{ - if (nd->vectorize <= 0) - error("Invalid setting 'vectorize' with value %d for node %s. Must be natural number!", nd->vectorize, node_name(n)); - - if (node_type(n)->vectorize && node_type(n)->vectorize < nd->vectorize) - error("Invalid value for setting 'vectorize'. Node type requires a number smaller than %d!", - node_type(n)->vectorize); - - return 0; -} - -static int node_direction_start(struct node_direction *nd, struct node *n) -{ -#ifdef WITH_HOOKS - int ret; - - for (size_t i = 0; i < vlist_length(&nd->hooks); i++) { - struct hook *h = (struct hook *) vlist_at(&nd->hooks, i); - - ret = hook_start(h); - if (ret) - return ret; - } -#endif /* WITH_HOOKS */ - - return 0; -} - -static int node_direction_stop(struct node_direction *nd, struct node *n) -{ -#ifdef WITH_HOOKS - int ret; - - for (size_t i = 0; i < vlist_length(&nd->hooks); i++) { - struct hook *h = (struct hook *) vlist_at(&nd->hooks, i); - - ret = hook_stop(h); - if (ret) - return ret; - } -#endif /* WITH_HOOKS */ - - return 0; -} - int node_init(struct node *n, struct node_type *vt) { int ret; diff --git a/lib/node_direction.c b/lib/node_direction.c new file mode 100644 index 000000000..7029f7549 --- /dev/null +++ b/lib/node_direction.c @@ -0,0 +1,233 @@ + +/** Node direction + * + * @author Steffen Vogel + * @copyright 2014-2019, 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 + +int node_direction_prepare(struct node_direction *nd, struct node *n) +{ + assert(nd->state == STATE_CHECKED); + +#ifdef WITH_HOOKS + int ret; + int t = nd->direction == NODE_DIR_OUT ? HOOK_NODE_WRITE : HOOK_NODE_READ; + int m = nd->builtin ? t | HOOK_BUILTIN : 0; + + ret = hook_list_prepare(&nd->hooks, &nd->signals, m, NULL, n); + if (ret) + return ret; +#endif /* WITH_HOOKS */ + + nd->state = STATE_PREPARED; + + return 0; +} + +int node_direction_init(struct node_direction *nd, enum node_dir dir, struct node *n) +{ + int ret; + + assert(nd->state == STATE_DESTROYED); + + nd->direction = dir; + nd->enabled = 1; + nd->vectorize = 1; + nd->builtin = 1; + + nd->hooks.state = STATE_DESTROYED; + nd->signals.state = STATE_DESTROYED; + +#ifdef WITH_HOOKS + ret = hook_list_init(&nd->hooks); + if (ret) + return ret; +#endif /* WITH_HOOKS */ + + ret = signal_list_init(&nd->signals); + if (ret) + return ret; + + nd->state = STATE_INITIALIZED; + + return 0; +} + +int node_direction_destroy(struct node_direction *nd, struct node *n) +{ + int ret = 0; + + assert(nd->state != STATE_DESTROYED && nd->state != STATE_STARTED); + +#ifdef WITH_HOOKS + ret = hook_list_destroy(&nd->hooks); + if (ret) + return ret; +#endif /* WITH_HOOKS */ + + ret = signal_list_destroy(&nd->signals); + if (ret) + return ret; + + nd->state = STATE_DESTROYED; + + return 0; +} + +int node_direction_parse(struct node_direction *nd, struct node *n, json_t *cfg) +{ + int ret; + + assert(nd->state == STATE_INITIALIZED); + + json_error_t err; + json_t *json_hooks = NULL; + json_t *json_signals = NULL; + + nd->cfg = cfg; + + ret = json_unpack_ex(cfg, &err, 0, "{ s?: o, s?: o, s?: i, s?: b, s?: b }", + "hooks", &json_hooks, + "signals", &json_signals, + "vectorize", &nd->vectorize, + "builtin", &nd->builtin, + "enabled", &nd->enabled + ); + if (ret) + jerror(&err, "Failed to parse node %s", node_name(n)); + + if (n->_vt->flags & NODE_TYPE_PROVIDES_SIGNALS) { + if (json_signals) + error("Node %s does not support signal definitions", node_name(n)); + } + else if (json_is_array(json_signals)) { + ret = signal_list_parse(&nd->signals, json_signals); + if (ret) + error("Failed to parse signal definition of node %s", node_name(n)); + } + else { + int count = DEFAULT_SAMPLE_LENGTH; + const char *type_str = "float"; + + if (json_is_object(json_signals)) { + json_unpack_ex(json_signals, &err, 0, "{ s: i, s: s }", + "count", &count, + "type", &type_str + ); + } + else + warning("No signal definition found for node %s. Using the default config of %d floating point signals.", node_name(n), DEFAULT_SAMPLE_LENGTH); + + int type = signal_type_from_str(type_str); + if (type < 0) + error("Invalid signal type %s", type_str); + + signal_list_generate(&nd->signals, count, type); + } + +#ifdef WITH_HOOKS + if (json_hooks) { + int m = nd->direction == NODE_DIR_OUT ? HOOK_NODE_WRITE : HOOK_NODE_READ; + + ret = hook_list_parse(&nd->hooks, json_hooks, m, NULL, n); + if (ret < 0) + return ret; + } +#endif /* WITH_HOOKS */ + + nd->state = STATE_PARSED; + + return 0; +} + +int node_direction_check(struct node_direction *nd, struct node *n) +{ + assert(nd->state == STATE_PARSED); + + if (nd->vectorize <= 0) + error("Invalid setting 'vectorize' with value %d for node %s. Must be natural number!", nd->vectorize, node_name(n)); + + if (node_type(n)->vectorize && node_type(n)->vectorize < nd->vectorize) + error("Invalid value for setting 'vectorize'. Node type requires a number smaller than %d!", + node_type(n)->vectorize); + + nd->state = STATE_CHECKED; + + return 0; +} + +int node_direction_start(struct node_direction *nd, struct node *n) +{ + assert(nd->state == STATE_PREPARED); + +#ifdef WITH_HOOKS + int ret; + + for (size_t i = 0; i < vlist_length(&nd->hooks); i++) { + struct hook *h = (struct hook *) vlist_at(&nd->hooks, i); + + ret = hook_start(h); + if (ret) + return ret; + } +#endif /* WITH_HOOKS */ + + nd->state = STATE_STARTED; + + return 0; +} + +int node_direction_stop(struct node_direction *nd, struct node *n) +{ + assert(nd->state == STATE_STARTED); + +#ifdef WITH_HOOKS + int ret; + + for (size_t i = 0; i < vlist_length(&nd->hooks); i++) { + struct hook *h = (struct hook *) vlist_at(&nd->hooks, i); + + ret = hook_stop(h); + if (ret) + return ret; + } +#endif /* WITH_HOOKS */ + + nd->state = STATE_STOPPED; + + return 0; +} + +struct vlist * node_direction_get_signals(struct node_direction *nd) +{ +#ifdef WITH_HOOKS + assert(nd->state == STATE_PREPARED); + + struct hook *h = vlist_last(&nd->hooks); + + return h->signals; +#else + return &nd->signals; +#endif +}