mirror of
https://git.rwth-aachen.de/acs/public/villas/node/
synced 2025-03-09 00:00:00 +01:00
replaced linked list by dynamic array (closes #6)
This commit is contained in:
parent
7b94198158
commit
9439a88877
8 changed files with 127 additions and 177 deletions
|
@ -14,83 +14,62 @@
|
|||
|
||||
#include <pthread.h>
|
||||
|
||||
/* Forward declarations */
|
||||
struct list_elm;
|
||||
struct node;
|
||||
struct path;
|
||||
struct interface;
|
||||
struct socket;
|
||||
struct gtfpga;
|
||||
struct opal;
|
||||
#define LIST_CHUNKSIZE 16
|
||||
|
||||
/** Static list initialization */
|
||||
#define LIST_INIT(dtor) { \
|
||||
.head = NULL, \
|
||||
.tail = NULL, \
|
||||
.length = 0, \
|
||||
.lock = PTHREAD_MUTEX_INITIALIZER, \
|
||||
.destructor = dtor \
|
||||
#define LIST_INIT(dtor) { \
|
||||
.start = NULL, \
|
||||
.end = NULL, \
|
||||
.length = 0, \
|
||||
.capacity = 0, \
|
||||
.lock = PTHREAD_MUTEX_INITIALIZER, \
|
||||
.destructor = dtor \
|
||||
}
|
||||
|
||||
#define FOREACH(list, elm) \
|
||||
for ( struct list_elm *elm = (list)->head; \
|
||||
elm; elm = elm->next )
|
||||
|
||||
#define FOREACH_R(list, elm) \
|
||||
for ( struct list_elm *elm = (list)->tail; \
|
||||
elm; elm = elm->prev )
|
||||
|
||||
#define list_first(list) ((list)->head)
|
||||
#define list_last(list) ((list)->head)
|
||||
#define list_length(list) ((list)->length)
|
||||
#define list_at(list, index) ((list)->length > index ? (list)->start[index] : NULL)
|
||||
|
||||
#define list_first(list) list_at(list, 0)
|
||||
#define list_last(list) list_at(list, (list)->length-1)
|
||||
#define list_foreach(ptr, list) for (int _i = 0, _p; _p = 1, _i < (list)->length; _i++) \
|
||||
for (ptr = (list)->start[_i]; _p--; )
|
||||
|
||||
/** Callback to destroy list elements.
|
||||
*
|
||||
* @param data A pointer to the data which should be freed.
|
||||
*/
|
||||
typedef void (*dtor_cb_t)(void *data);
|
||||
|
||||
typedef int (*cmp_cb_t)(void *, void *);
|
||||
typedef void (*dtor_cb_t)(void *);
|
||||
|
||||
/** Callback to search or sort a list. */
|
||||
typedef int (*cmp_cb_t)(const void *, const void *);
|
||||
|
||||
struct list {
|
||||
struct list_elm *head, *tail;
|
||||
int length;
|
||||
|
||||
dtor_cb_t destructor;
|
||||
pthread_mutex_t lock;
|
||||
};
|
||||
|
||||
struct list_elm {
|
||||
union {
|
||||
void *ptr;
|
||||
struct node *node;
|
||||
struct node_type *type;
|
||||
struct path *path;
|
||||
struct interface *interface;
|
||||
struct socket *socket;
|
||||
struct opal *opal;
|
||||
struct gtfpga *gtfpga;
|
||||
struct hook *hook;
|
||||
} /* anonymous */;
|
||||
|
||||
int priority;
|
||||
struct list_elm *prev, *next;
|
||||
void **start; /**< Array of pointers to list elements */
|
||||
void **end; /**< Array of pointers to list elements */
|
||||
size_t capacity; /**< Size of list::start in elements */
|
||||
size_t length; /**< Number of elements of list::start which are in use */
|
||||
dtor_cb_t destructor; /**< A destructor which gets called for every list elements during list_destroy() */
|
||||
pthread_mutex_t lock; /**< A mutex to allow thread-safe accesses */
|
||||
};
|
||||
|
||||
/** Initialize a list */
|
||||
void list_init(struct list *l, dtor_cb_t dtor);
|
||||
|
||||
/** Destroy a list and call destructors for all list elements */
|
||||
void list_destroy(struct list *l);
|
||||
|
||||
/** Append an element to the end of the list */
|
||||
void list_push(struct list *l, void *p);
|
||||
|
||||
void list_insert(struct list *l, int prio, void *p);
|
||||
|
||||
/** Search the list for an element whose first element is a character array which matches name.
|
||||
*
|
||||
* @see Only possible because of §1424 of http://c0x.coding-guidelines.com/6.7.2.1.html
|
||||
*/
|
||||
void * list_lookup(const struct list *l, const char *name);
|
||||
void * list_lookup(struct list *l, const char *name);
|
||||
|
||||
void * list_search(const struct list *l, cmp_cb_t cmp, void *ctx);
|
||||
void * list_search(struct list *l, cmp_cb_t cmp, void *ctx);
|
||||
|
||||
/** Sort the list using the quicksort algorithm of libc */
|
||||
void list_sort(struct list *l, cmp_cb_t cmp);
|
||||
|
||||
#endif /* _LIST_H_ */
|
||||
|
|
|
@ -117,7 +117,7 @@ int config_parse_path(config_setting_t *cfg,
|
|||
config_parse_nodelist(cfg_out, &p->destinations, nodes);
|
||||
|
||||
if (list_length(&p->destinations) >= 1)
|
||||
p->out = list_first(&p->destinations)->node;
|
||||
p->out = (struct node *) list_first(&p->destinations);
|
||||
else
|
||||
cerror(cfg, "Missing output node for path");
|
||||
|
||||
|
@ -141,9 +141,9 @@ int config_parse_path(config_setting_t *cfg,
|
|||
p->in->refcnt++;
|
||||
p->in->vt->refcnt++;
|
||||
|
||||
FOREACH(&p->destinations, it) {
|
||||
it->node->refcnt++;
|
||||
it->node->vt->refcnt++;
|
||||
list_foreach(struct node *node, &p->destinations) {
|
||||
node->refcnt++;
|
||||
node->vt->refcnt++;
|
||||
}
|
||||
|
||||
if (reverse) {
|
||||
|
|
|
@ -58,7 +58,7 @@ void if_destroy(struct interface *i)
|
|||
|
||||
int if_start(struct interface *i, int affinity)
|
||||
{
|
||||
info("Starting interface '%s' which is used by %u sockets", rtnl_link_get_name(i->nl_link), list_length(&i->sockets));
|
||||
info("Starting interface '%s' which is used by %zu sockets", rtnl_link_get_name(i->nl_link), list_length(&i->sockets));
|
||||
|
||||
{ INDENT
|
||||
/* Set affinity for network interfaces (skip _loopback_ dev) */
|
||||
|
@ -66,8 +66,7 @@ int if_start(struct interface *i, int affinity)
|
|||
|
||||
/* Assign fwmark's to socket nodes which have netem options */
|
||||
int ret, mark = 0;
|
||||
FOREACH(&i->sockets, it) {
|
||||
struct socket *s = it->socket;
|
||||
list_foreach(struct socket *s, &i->sockets) {
|
||||
if (s->tc_qdisc)
|
||||
s->mark = 1 + mark++;
|
||||
}
|
||||
|
@ -90,8 +89,7 @@ int if_start(struct interface *i, int affinity)
|
|||
error("Failed to setup priority queuing discipline: %s", nl_geterror(ret));
|
||||
|
||||
/* Create netem qdisks and appropriate filter per netem node */
|
||||
FOREACH(&i->sockets, it) {
|
||||
struct socket *s = it->socket;
|
||||
list_foreach(struct socket *s, &i->sockets) {
|
||||
if (s->tc_qdisc) {
|
||||
ret = tc_mark(i, &s->tc_classifier, TC_HANDLE(1, s->mark), s->mark);
|
||||
if (ret)
|
||||
|
@ -210,9 +208,9 @@ int if_set_affinity(struct interface *i, int affinity)
|
|||
|
||||
struct interface * if_lookup_index(int index)
|
||||
{
|
||||
FOREACH(&interfaces, it) {
|
||||
if (rtnl_link_get_ifindex(it->interface->nl_link) == index)
|
||||
return it->interface;
|
||||
list_foreach(struct interface *i, &interfaces) {
|
||||
if (rtnl_link_get_ifindex(i->nl_link) == index)
|
||||
return i;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
|
|
@ -8,9 +8,9 @@
|
|||
* Unauthorized copying of this file, via any medium is strictly prohibited.
|
||||
*********************************************************************************/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "utils.h"
|
||||
#include "list.h"
|
||||
|
||||
void list_init(struct list *l, dtor_cb_t dtor)
|
||||
|
@ -19,24 +19,28 @@ void list_init(struct list *l, dtor_cb_t dtor)
|
|||
|
||||
l->destructor = dtor;
|
||||
l->length = 0;
|
||||
l->head = NULL;
|
||||
l->tail = NULL;
|
||||
l->capacity = 0;
|
||||
|
||||
l->start = NULL;
|
||||
l->end = NULL;
|
||||
}
|
||||
|
||||
void list_destroy(struct list *l)
|
||||
{
|
||||
pthread_mutex_lock(&l->lock);
|
||||
|
||||
struct list_elm *elm = l->head;
|
||||
while (elm) {
|
||||
struct list_elm *tmp = elm;
|
||||
elm = elm->next;
|
||||
|
||||
if (l->destructor)
|
||||
l->destructor(tmp->ptr);
|
||||
|
||||
free(tmp);
|
||||
if (l->destructor) {
|
||||
for (void *e = l->start; e != l->end; e++)
|
||||
l->destructor(e);
|
||||
}
|
||||
|
||||
free(l->start);
|
||||
|
||||
l->start =
|
||||
l->end = NULL;
|
||||
|
||||
l->length =
|
||||
l->capacity = 0;
|
||||
|
||||
pthread_mutex_unlock(&l->lock);
|
||||
pthread_mutex_destroy(&l->lock);
|
||||
|
@ -44,83 +48,54 @@ void list_destroy(struct list *l)
|
|||
|
||||
void list_push(struct list *l, void *p)
|
||||
{
|
||||
struct list_elm *e = alloc(sizeof(struct list_elm));
|
||||
|
||||
pthread_mutex_lock(&l->lock);
|
||||
|
||||
e->ptr = p;
|
||||
e->prev = l->tail;
|
||||
e->next = NULL;
|
||||
|
||||
if (l->tail)
|
||||
l->tail->next = e;
|
||||
if (l->head)
|
||||
l->head->prev = e;
|
||||
else
|
||||
l->head = e;
|
||||
|
||||
l->tail = e;
|
||||
|
||||
/* Resize array if out of capacity */
|
||||
if (l->end == l->start + l->capacity) {
|
||||
l->capacity += LIST_CHUNKSIZE;
|
||||
l->start = realloc(l->start, l->capacity * sizeof(void *));
|
||||
}
|
||||
|
||||
l->start[l->length] = p;
|
||||
l->length++;
|
||||
l->end = &l->start[l->length];
|
||||
|
||||
pthread_mutex_unlock(&l->lock);
|
||||
}
|
||||
|
||||
void list_insert(struct list *l, int prio, void *p)
|
||||
void * list_lookup(struct list *l, const char *name)
|
||||
{
|
||||
struct list_elm *d;
|
||||
struct list_elm *e = alloc(sizeof(struct list_elm));
|
||||
int cmp(const void *a, const void *b) {
|
||||
return strcmp(*(char **) a, b);
|
||||
}
|
||||
|
||||
e->priority = prio;
|
||||
e->ptr = p;
|
||||
return list_search(l, cmp, (void *) name);
|
||||
}
|
||||
|
||||
void * list_search(struct list *l, cmp_cb_t cmp, void *ctx)
|
||||
{
|
||||
pthread_mutex_lock(&l->lock);
|
||||
|
||||
void *e;
|
||||
list_foreach(e, l) {
|
||||
if (!cmp(e, ctx))
|
||||
goto out;
|
||||
}
|
||||
|
||||
e = NULL; /* not found */
|
||||
|
||||
out: pthread_mutex_unlock(&l->lock);
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
void list_sort(struct list *l, cmp_cb_t cmp)
|
||||
{
|
||||
int cmp_helper(const void *a, const void *b) {
|
||||
return cmp(*(void **) a, *(void **) b);
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&l->lock);
|
||||
|
||||
/* Search for first entry with higher priority */
|
||||
for (d = l->head; d && d->priority < prio; d = d->next);
|
||||
|
||||
/* Insert new element in front of d */
|
||||
e->next = d;
|
||||
|
||||
if (d) { /* Between or Head */
|
||||
e->prev = d->prev;
|
||||
|
||||
if (d == l->head) /* Head */
|
||||
l->head = e;
|
||||
else /* Between */
|
||||
d->prev = e;
|
||||
}
|
||||
else { /* Tail or Head */
|
||||
e->prev = l->tail;
|
||||
|
||||
if (l->length == 0) /* List was empty */
|
||||
l->head = e;
|
||||
else
|
||||
l->tail->next = e;
|
||||
|
||||
l->tail = e;
|
||||
}
|
||||
|
||||
l->length++;
|
||||
|
||||
qsort(l->start, l->length, sizeof(void *), cmp_helper);
|
||||
pthread_mutex_unlock(&l->lock);
|
||||
}
|
||||
|
||||
void * list_lookup(const struct list *l, const char *name)
|
||||
{
|
||||
FOREACH(l, it) {
|
||||
if (!strcmp(*(char **) it->ptr, name))
|
||||
return it->ptr;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void * list_search(const struct list *l, cmp_cb_t cmp, void *ctx)
|
||||
{
|
||||
FOREACH(l, it) {
|
||||
if (!cmp(it->ptr, ctx))
|
||||
return it->ptr;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
}
|
|
@ -35,8 +35,7 @@ struct list node_types = LIST_INIT(NULL);
|
|||
|
||||
int node_init(int argc, char *argv[], struct settings *set)
|
||||
{ INDENT
|
||||
FOREACH(&node_types, it) {
|
||||
const struct node_type *vt = it->type;
|
||||
list_foreach(const struct node_type *vt, &node_types) {
|
||||
if (vt->refcnt) {
|
||||
info("Initializing '%s' node type", vt->name);
|
||||
vt->init(argc, argv, set);
|
||||
|
@ -49,8 +48,7 @@ int node_init(int argc, char *argv[], struct settings *set)
|
|||
int node_deinit()
|
||||
{ INDENT
|
||||
/* De-initialize node types */
|
||||
FOREACH(&node_types, it) {
|
||||
struct node_type *vt = it->type;
|
||||
list_foreach(const struct node_type *vt, &node_types) {
|
||||
if (vt->refcnt) {
|
||||
info("De-initializing '%s' node type", vt->name);
|
||||
vt->deinit();
|
||||
|
|
|
@ -23,16 +23,16 @@ extern struct settings settings;
|
|||
|
||||
static void path_write(struct path *p)
|
||||
{
|
||||
FOREACH(&p->destinations, it) {
|
||||
list_foreach(struct node *n, &p->destinations) {
|
||||
int sent = node_write(
|
||||
it->node, /* Destination node */
|
||||
p->pool, /* Pool of received messages */
|
||||
p->poolsize, /* Size of the pool */
|
||||
p->received - it->node->combine,/* Index of the first message which should be sent */
|
||||
it->node->combine /* Number of messages which should be sent */
|
||||
n, /* Destination node */
|
||||
p->pool, /* Pool of received messages */
|
||||
p->poolsize, /* Size of the pool */
|
||||
p->received - n->combine,/* Index of the first message which should be sent */
|
||||
n->combine /* Number of messages which should be sent */
|
||||
);
|
||||
|
||||
debug(1, "Sent %u messages to node '%s'", sent, it->node->name);
|
||||
debug(1, "Sent %u messages to node '%s'", sent, n->name);
|
||||
p->sent += sent;
|
||||
|
||||
clock_gettime(CLOCK_REALTIME, &p->ts_sent);
|
||||
|
@ -42,8 +42,9 @@ static void path_write(struct path *p)
|
|||
int path_run_hook(struct path *p, enum hook_type t)
|
||||
{
|
||||
int ret = 0;
|
||||
FOREACH(&p->hooks[t], it)
|
||||
ret += ((hook_cb_t) it->ptr)(p);
|
||||
list_foreach(struct hook *h, &p->hooks) {
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -177,8 +178,8 @@ char * path_print(struct path *p)
|
|||
|
||||
if (list_length(&p->destinations) > 1) {
|
||||
strcatf(&buf, " [");
|
||||
FOREACH(&p->destinations, it)
|
||||
strcatf(&buf, " %s", it->node->name);
|
||||
list_foreach(struct node *n, &p->destinations)
|
||||
strcatf(&buf, " %s", n->name);
|
||||
strcatf(&buf, " ]");
|
||||
}
|
||||
else
|
||||
|
|
|
@ -38,12 +38,12 @@ static config_t config;
|
|||
static void quit()
|
||||
{
|
||||
info("Stopping paths");
|
||||
FOREACH(&paths, it)
|
||||
path_stop(it->path);
|
||||
list_foreach(struct path *p, &paths)
|
||||
path_stop(p);
|
||||
|
||||
info("Stopping nodes");
|
||||
FOREACH(&nodes, it)
|
||||
node_stop(it->node);
|
||||
list_foreach(struct node *n, &nodes)
|
||||
node_stop(n);
|
||||
|
||||
info("De-initializing node types");
|
||||
node_deinit();
|
||||
|
@ -185,21 +185,21 @@ int main(int argc, char *argv[])
|
|||
node_init(argc, argv, &settings);
|
||||
|
||||
info("Starting nodes");
|
||||
FOREACH(&nodes, it)
|
||||
node_start(it->node);
|
||||
list_foreach(struct node *n, &nodes)
|
||||
node_start(n);
|
||||
|
||||
info("Starting paths");
|
||||
FOREACH(&paths, it)
|
||||
path_start(it->path);
|
||||
list_foreach(struct path *p, &paths)
|
||||
path_start(p);
|
||||
|
||||
/* Run! */
|
||||
if (settings.stats > 0) {
|
||||
stats_header();
|
||||
|
||||
for (;;) FOREACH(&paths, it) {
|
||||
do list_foreach(struct path *p, &paths) {
|
||||
usleep(settings.stats * 1e6);
|
||||
path_run_hook(it->path, HOOK_PERIODIC);
|
||||
}
|
||||
path_run_hook(p, HOOK_PERIODIC);
|
||||
} while (1);
|
||||
}
|
||||
else
|
||||
pause();
|
||||
|
|
|
@ -47,8 +47,7 @@ int socket_init(int argc, char * argv[], struct settings *set)
|
|||
list_init(&interfaces, (dtor_cb_t) if_destroy);
|
||||
|
||||
/* Gather list of used network interfaces */
|
||||
FOREACH(&sockets, it) {
|
||||
struct socket *s = it->socket;
|
||||
list_foreach(struct socket *s, &sockets) {
|
||||
struct rtnl_link *link;
|
||||
|
||||
/* Determine outgoing interface */
|
||||
|
@ -67,16 +66,16 @@ int socket_init(int argc, char * argv[], struct settings *set)
|
|||
}
|
||||
|
||||
/** @todo Improve mapping of NIC IRQs per path */
|
||||
FOREACH(&interfaces, it)
|
||||
if_start(it->interface, set->affinity);
|
||||
list_foreach(struct interface *i, &interfaces)
|
||||
if_start(i, set->affinity);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int socket_deinit()
|
||||
{ INDENT
|
||||
FOREACH(&interfaces, it)
|
||||
if_stop(it->interface);
|
||||
list_foreach(struct interface *i, &interfaces)
|
||||
if_stop(i);
|
||||
|
||||
list_destroy(&interfaces);
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue