From b5444577b4e3516addc7861d4a0fdcb0d13a7d71 Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Sat, 16 Mar 2019 10:04:23 +0100 Subject: [PATCH] hook: separate hook_list_*() and hook_*() functions --- include/villas/hook.h | 36 +----- include/villas/hook_list.h | 84 ++++++++++++++ include/villas/path.h | 1 - lib/CMakeLists.txt | 1 + lib/hook.c | 150 ------------------------ lib/hook_list.c | 230 +++++++++++++++++++++++++++++++++++++ lib/node.c | 1 + lib/node_direction.c | 25 ++-- lib/path.c | 25 ++-- lib/path_source.c | 2 + lib/super_node.cpp | 29 +---- src/villas-node.cpp | 1 - 12 files changed, 341 insertions(+), 244 deletions(-) create mode 100644 include/villas/hook_list.h create mode 100644 lib/hook_list.c diff --git a/include/villas/hook.h b/include/villas/hook.h index 07e9e90fc..b3099a92d 100644 --- a/include/villas/hook.h +++ b/include/villas/hook.h @@ -1,8 +1,8 @@ -/** Hook funktions +/** Hook functions * - * Every path can register a hook function which is called for every received - * message. This can be used to debug the data flow, get statistics - * or alter the message. + * Every node or path can register hook functions which is called for every + * processed sample. This can be used to debug the data flow, get statistics + * or alter the sample contents. * * This file includes some examples. * @@ -101,34 +101,6 @@ struct hook_type * hook_type(struct hook *h) return h->_vt; } -int hook_list_init(struct vlist *hs); - -int hook_list_destroy(struct vlist *hs); - -/** Parses an object of hooks - * - * Example: - * - * { - * stats = { - * output = "stdout" - * }, - * skip_first = { - * seconds = 10 - * }, - * hooks = [ "print" ] - * } - */ -int hook_list_parse(struct vlist *hs, json_t *cfg, int mask, struct path *p, struct node *n); - -int hook_list_prepare(struct vlist *hs, struct vlist *sigs, int mask, struct path *p, struct node *n); - -int hook_list_prepare_signals(struct vlist *hs, struct vlist *signals); - -int hook_list_add(struct vlist *hs, int mask, struct path *p, struct node *n); - -int hook_list_process(struct vlist *hs, struct sample *smps[], unsigned cnt); - #ifdef __cplusplus } #endif diff --git a/include/villas/hook_list.h b/include/villas/hook_list.h new file mode 100644 index 000000000..7a706ed38 --- /dev/null +++ b/include/villas/hook_list.h @@ -0,0 +1,84 @@ +/** Hook list functions + * + * This file includes some examples. + * + * @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 hooks User-defined hook functions + * @ingroup path + * @{ + *********************************************************************************/ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/* Forward declarations */ +struct vlist; +struct sample; +struct path; +struct node; + +int hook_list_init(struct vlist *hs); + +int hook_list_destroy(struct vlist *hs); + +/** Parses an object of hooks + * + * Example: + * + * { + * stats = { + * output = "stdout" + * }, + * skip_first = { + * seconds = 10 + * }, + * hooks = [ "print" ] + * } + */ +int hook_list_parse(struct vlist *hs, json_t *cfg, int mask, struct path *p, struct node *n); + +int hook_list_prepare(struct vlist *hs, struct vlist *sigs, int mask, struct path *p, struct node *n); + +int hook_list_prepare_signals(struct vlist *hs, struct vlist *signals); + +int hook_list_add(struct vlist *hs, int mask, struct path *p, struct node *n); + +int hook_list_process(struct vlist *hs, struct sample *smps[], unsigned cnt); + +int hook_list_periodic(struct vlist *hs); + +int hook_list_start(struct vlist *hs); + +int hook_list_stop(struct vlist *hs); + +struct vlist * hook_list_get_signals(struct vlist *hs); + +#ifdef __cplusplus +} +#endif diff --git a/include/villas/path.h b/include/villas/path.h index e899fe036..7f8083672 100644 --- a/include/villas/path.h +++ b/include/villas/path.h @@ -37,7 +37,6 @@ #include #include #include -#include #include #include diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 055ac29aa..3fd2bd8e7 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -89,6 +89,7 @@ if(WITH_HOOKS) list(APPEND LIB_SRC hook.c hook_type.c + hook_list.c ) add_subdirectory(hooks) diff --git a/lib/hook.c b/lib/hook.c index fe5e9a2a6..905e509ca 100644 --- a/lib/hook.c +++ b/lib/hook.c @@ -229,157 +229,7 @@ int hook_cmp_priority(const void *a, const void *b) return ha->priority - hb->priority; } -int hook_list_init(struct vlist *hs) -{ - int ret; - - ret = vlist_init(hs); - if (ret) - return ret; - - return 0; -} - -int hook_list_destroy(struct vlist *hs) -{ - int ret; - - ret = vlist_destroy(hs, (dtor_cb_t) hook_destroy, true); - if (ret) - return ret; - - return 0; -} - -int hook_list_parse(struct vlist *hs, json_t *cfg, int mask, struct path *o, struct node *n) -{ - if (!json_is_array(cfg)) - error("Hooks must be configured as a list of objects"); - - size_t i; - json_t *json_hook; - json_array_foreach(cfg, i, json_hook) { - int ret; - const char *type; - struct hook_type *ht; - json_error_t err; - - ret = json_unpack_ex(json_hook, &err, 0, "{ s: s }", "type", &type); - if (ret) - jerror(&err, "Failed to parse hook"); - - ht = hook_type_lookup(type); - if (!ht) - jerror(&err, "Unkown hook type '%s'", type); - - if (!(ht->flags & mask)) - error("Hook %s not allowed here.", type); - - struct hook *h = (struct hook *) alloc(sizeof(struct hook)); - - ret = hook_init(h, ht, o, n); - if (ret) - error("Failed to initialize hook: %s", type); - - ret = hook_parse(h, json_hook); - if (ret) - jerror(&err, "Failed to parse hook configuration"); - - vlist_push(hs, h); - } - - return 0; -} - -int hook_list_prepare(struct vlist *hs, struct vlist *sigs, int m, struct path *p, struct node *n) -{ - int ret; - - /* Add internal hooks if they are not already in the list */ - ret = hook_list_add(hs, m, p, n); - if (ret) - return ret; - - /* We sort the hooks according to their priority */ - vlist_sort(hs, hook_cmp_priority); - - for (size_t i = 0; i < vlist_length(hs); i++) { - struct hook *h = (struct hook *) vlist_at(hs, i); - - ret = hook_prepare(h, sigs); - if (ret) - return ret; - - sigs = &h->signals; - } - - return 0; -} - -int hook_list_add(struct vlist *hs, int mask, struct path *p, struct node *n) -{ - int ret; - - assert(hs->state == STATE_INITIALIZED); - - for (size_t i = 0; i < vlist_length(&plugins); i++) { - struct plugin *q = (struct plugin *) vlist_at(&plugins, i); - - struct hook *h; - struct hook_type *vt = &q->hook; - - if (q->type != PLUGIN_TYPE_HOOK) - continue; - - if ((vt->flags & mask) == mask) { - h = (struct hook *) alloc(sizeof(struct hook)); - if (!h) - return -1; - - ret = hook_init(h, vt, p, n); - if (ret) - return ret; - - vlist_push(hs, h); - } - } - - return 0; -} - const char * hook_type_name(struct hook_type *vt) { return plugin_name(vt); } - -int hook_list_process(struct vlist *hs, struct sample *smps[], unsigned cnt) -{ - unsigned ret, curent, processed = 0; - - for (curent = 0; curent < cnt; curent++) { - struct sample *smp = smps[curent]; - - for (size_t i = 0; i < vlist_length(hs); i++) { - struct hook *h = (struct hook *) vlist_at(hs, i); - - ret = hook_process(h, smp); - switch (ret) { - case HOOK_ERROR: - return -1; - - case HOOK_OK: - smps[processed++] = smp; - break; - - case HOOK_SKIP_SAMPLE: - goto skip; - - case HOOK_STOP_PROCESSING: - goto stop; - } - } -skip: {} - } - -stop: return processed; -} diff --git a/lib/hook_list.c b/lib/hook_list.c new file mode 100644 index 000000000..870707118 --- /dev/null +++ b/lib/hook_list.c @@ -0,0 +1,230 @@ +/** Hook-releated functions. + * + * @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 +#include +#include + +int hook_list_init(struct vlist *hs) +{ + int ret; + + ret = vlist_init(hs); + if (ret) + return ret; + + return 0; +} + +int hook_list_destroy(struct vlist *hs) +{ + int ret; + + ret = vlist_destroy(hs, (dtor_cb_t) hook_destroy, true); + if (ret) + return ret; + + return 0; +} + +int hook_list_parse(struct vlist *hs, json_t *cfg, int mask, struct path *o, struct node *n) +{ + if (!json_is_array(cfg)) + error("Hooks must be configured as a list of objects"); + + size_t i; + json_t *json_hook; + json_array_foreach(cfg, i, json_hook) { + int ret; + const char *type; + struct hook_type *ht; + json_error_t err; + + ret = json_unpack_ex(json_hook, &err, 0, "{ s: s }", "type", &type); + if (ret) + jerror(&err, "Failed to parse hook"); + + ht = hook_type_lookup(type); + if (!ht) + jerror(&err, "Unkown hook type '%s'", type); + + if (!(ht->flags & mask)) + error("Hook %s not allowed here.", type); + + struct hook *h = (struct hook *) alloc(sizeof(struct hook)); + + ret = hook_init(h, ht, o, n); + if (ret) + error("Failed to initialize hook: %s", type); + + ret = hook_parse(h, json_hook); + if (ret) + jerror(&err, "Failed to parse hook configuration"); + + vlist_push(hs, h); + } + + return 0; +} + +int hook_list_prepare(struct vlist *hs, struct vlist *sigs, int m, struct path *p, struct node *n) +{ + int ret; + + /* Add internal hooks if they are not already in the list */ + ret = hook_list_add(hs, m, p, n); + if (ret) + return ret; + + /* We sort the hooks according to their priority */ + vlist_sort(hs, hook_cmp_priority); + + for (size_t i = 0; i < vlist_length(hs); i++) { + struct hook *h = (struct hook *) vlist_at(hs, i); + + ret = hook_prepare(h, sigs); + if (ret) + return ret; + + sigs = &h->signals; + } + + return 0; +} + +int hook_list_add(struct vlist *hs, int mask, struct path *p, struct node *n) +{ + int ret; + + assert(hs->state == STATE_INITIALIZED); + + for (size_t i = 0; i < vlist_length(&plugins); i++) { + struct plugin *q = (struct plugin *) vlist_at(&plugins, i); + + struct hook *h; + struct hook_type *vt = &q->hook; + + if (q->type != PLUGIN_TYPE_HOOK) + continue; + + if ((vt->flags & mask) == mask) { + h = (struct hook *) alloc(sizeof(struct hook)); + if (!h) + return -1; + + ret = hook_init(h, vt, p, n); + if (ret) + return ret; + + vlist_push(hs, h); + } + } + + return 0; +} + +int hook_list_process(struct vlist *hs, struct sample *smps[], unsigned cnt) +{ + unsigned ret, curent, processed = 0; + + for (curent = 0; curent < cnt; curent++) { + struct sample *smp = smps[curent]; + + for (size_t i = 0; i < vlist_length(hs); i++) { + struct hook *h = (struct hook *) vlist_at(hs, i); + + ret = hook_process(h, smp); + switch (ret) { + case HOOK_ERROR: + return -1; + + case HOOK_OK: + smps[processed++] = smp; + break; + + case HOOK_SKIP_SAMPLE: + goto skip; + + case HOOK_STOP_PROCESSING: + goto stop; + } + } +skip: {} + } + +stop: return processed; +} + +int hook_list_periodic(struct vlist *hs) +{ + int ret; + + for (size_t j = 0; j < vlist_length(hs); j++) { + struct hook *h = (struct hook *) vlist_at(hs, j); + + ret = hook_periodic(h); + if (ret) + return ret; + } + + return 0; +} + +int hook_list_start(struct vlist *hs) +{ + int ret; + + for (size_t i = 0; i < vlist_length(hs); i++) { + struct hook *h = (struct hook *) vlist_at(hs, i); + + ret = hook_start(h); + if (ret) + return ret; + } + + return 0; +} + +int hook_list_stop(struct vlist *hs) +{ + int ret; + + for (size_t i = 0; i < vlist_length(hs); i++) { + struct hook *h = (struct hook *) vlist_at(hs, i); + + ret = hook_stop(h); + if (ret) + return ret; + } + + return 0; +} + +struct vlist * hook_list_get_signals(struct vlist *hs) +{ + struct hook *h = vlist_last(hs); + + return &h->signals; +} diff --git a/lib/node.c b/lib/node.c index 2850bf77a..a2cdf9f2c 100644 --- a/lib/node.c +++ b/lib/node.c @@ -25,6 +25,7 @@ #include #include +#include #include #include #include diff --git a/lib/node_direction.c b/lib/node_direction.c index 535988e8f..f8939c262 100644 --- a/lib/node_direction.c +++ b/lib/node_direction.c @@ -23,6 +23,7 @@ #include #include +#include #include #include @@ -193,13 +194,9 @@ 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; - } + ret = hook_list_start(&nd->hooks); + if (ret) + return ret; #endif /* WITH_HOOKS */ nd->state = STATE_STARTED; @@ -214,13 +211,9 @@ 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; - } + ret = hook_list_stop(&nd->hooks); + if (ret) + return ret; #endif /* WITH_HOOKS */ nd->state = STATE_STOPPED; @@ -233,9 +226,7 @@ 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; + return hook_list_get_signals(&nd->hooks); #else return &nd->signals; #endif diff --git a/lib/path.c b/lib/path.c index 767fd2abf..ec484a67c 100644 --- a/lib/path.c +++ b/lib/path.c @@ -32,7 +32,7 @@ #include #include #include -#include +#include #include #include #include @@ -204,9 +204,6 @@ int path_prepare(struct path *p) ret = hook_list_prepare(&p->hooks, &p->signals, m, p, NULL); if (ret) return ret; - - /* We sort the hooks according to their priority before starting the path */ - vlist_sort(&p->hooks, hook_cmp_priority); #endif /* WITH_HOOKS */ /* Initialize destinations */ @@ -561,13 +558,9 @@ int path_start(struct path *p) free(mask); #ifdef WITH_HOOKS - for (size_t i = 0; i < vlist_length(&p->hooks); i++) { - struct hook *h = (struct hook *) vlist_at(&p->hooks, i); - - ret = hook_start(h); - if (ret) - return ret; - } + ret = hook_list_start(&p->hooks); + if (ret) + return ret; #endif /* WITH_HOOKS */ p->last_sequence = 0; @@ -627,13 +620,9 @@ int path_stop(struct path *p) return ret; #ifdef WITH_HOOKS - for (size_t i = 0; i < vlist_length(&p->hooks); i++) { - struct hook *h = (struct hook *) vlist_at(&p->hooks, i); - - ret = hook_stop(h); - if (ret) - return ret; - } + ret = hook_list_stop(&p->hooks); + if (ret) + return ret; #endif /* WITH_HOOKS */ sample_decref(p->last_sample); diff --git a/lib/path_source.c b/lib/path_source.c index 21bd21f36..d1ca51c05 100644 --- a/lib/path_source.c +++ b/lib/path_source.c @@ -25,6 +25,8 @@ #include #include #include +#include + #include #include diff --git a/lib/super_node.cpp b/lib/super_node.cpp index 78c241e04..47c9d35ed 100644 --- a/lib/super_node.cpp +++ b/lib/super_node.cpp @@ -30,7 +30,7 @@ #include #include #include -#include +#include #include #include #include @@ -571,8 +571,6 @@ SuperNode::~SuperNode() int SuperNode::periodic() { - int ret; - int started = 0; for (size_t i = 0; i < vlist_length(&paths); i++) { @@ -582,13 +580,7 @@ int SuperNode::periodic() started++; #ifdef WITH_HOOKS - for (size_t j = 0; j < vlist_length(&p->hooks); j++) { - hook *h = (struct hook *) vlist_at(&p->hooks, j); - - ret = hook_periodic(h); - if (ret) - return ret; - } + hook_list_periodic(&p->hooks); #endif /* WITH_HOOKS */ } } @@ -600,21 +592,8 @@ int SuperNode::periodic() continue; #ifdef WITH_HOOKS - for (size_t j = 0; j < vlist_length(&n->in.hooks); j++) { - auto *h = (struct hook *) vlist_at(&n->in.hooks, j); - - ret = hook_periodic(h); - if (ret) - return ret; - } - - for (size_t j = 0; j < vlist_length(&n->out.hooks); j++) { - auto *h = (struct hook *) vlist_at(&n->out.hooks, j); - - ret = hook_periodic(h); - if (ret) - return ret; - } + hook_list_periodic(&n->in.hooks); + hook_list_periodic(&n->out.hooks); #endif /* WITH_HOOKS */ } diff --git a/src/villas-node.cpp b/src/villas-node.cpp index 5c5a14e8e..a95750f8f 100644 --- a/src/villas-node.cpp +++ b/src/villas-node.cpp @@ -44,7 +44,6 @@ #include #include #include -#include #include #ifdef ENABLE_OPAL_ASYNC