diff --git a/server/include/list.h b/server/include/list.h index 335b26365..f1611cc00 100644 --- a/server/include/list.h +++ b/server/include/list.h @@ -14,83 +14,62 @@ #include -/* 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_ */ diff --git a/server/src/cfg.c b/server/src/cfg.c index 18db5fa85..6d547379c 100644 --- a/server/src/cfg.c +++ b/server/src/cfg.c @@ -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) { diff --git a/server/src/if.c b/server/src/if.c index 18e839d92..2b4783b74 100644 --- a/server/src/if.c +++ b/server/src/if.c @@ -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; diff --git a/server/src/list.c b/server/src/list.c index 5ef309b33..4bbdb89f4 100644 --- a/server/src/list.c +++ b/server/src/list.c @@ -8,9 +8,9 @@ * Unauthorized copying of this file, via any medium is strictly prohibited. *********************************************************************************/ +#include #include -#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; -} +} \ No newline at end of file diff --git a/server/src/node.c b/server/src/node.c index 034ac2d61..352fa3814 100644 --- a/server/src/node.c +++ b/server/src/node.c @@ -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(); diff --git a/server/src/path.c b/server/src/path.c index 858dbbfe9..1bb5e3ed2 100644 --- a/server/src/path.c +++ b/server/src/path.c @@ -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 diff --git a/server/src/server.c b/server/src/server.c index 5c5f29e7f..ba21a6443 100644 --- a/server/src/server.c +++ b/server/src/server.c @@ -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(); diff --git a/server/src/socket.c b/server/src/socket.c index 4629efa93..3a7ad6a8c 100644 --- a/server/src/socket.c +++ b/server/src/socket.c @@ -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);