From 961386ebb103995bd323efed53fcbff99f5357d1 Mon Sep 17 00:00:00 2001 From: Aaron Krebs Date: Mon, 11 Aug 2014 12:13:25 +0200 Subject: [PATCH] Changed meshlink_get_all_edges_state to re-use memory. --- src/meshlink.c | 35 ++++++++++++++++++++++++++--------- src/meshlink.h | 25 ++++++++++++++++++++----- 2 files changed, 46 insertions(+), 14 deletions(-) diff --git a/src/meshlink.c b/src/meshlink.c index 90118793..0799c4d7 100644 --- a/src/meshlink.c +++ b/src/meshlink.c @@ -1840,8 +1840,8 @@ void meshlink_hint_address(meshlink_handle_t *mesh, meshlink_node_t *node, const * Data captures the current state and will not be updated. * Caller must deallocate data when done. */ -meshlink_edge_t **meshlink_get_all_edges_state(meshlink_handle_t *mesh, size_t *nmemb) { - if(!mesh || !nmemb) { +meshlink_edge_t **meshlink_get_all_edges_state(meshlink_handle_t *mesh, meshlink_edge_t **edges, size_t *nmemb) { + if(!mesh || !nmemb || (*nmemb && !edges)) { meshlink_errno = MESHLINK_EINVAL; return NULL; } @@ -1850,22 +1850,34 @@ meshlink_edge_t **meshlink_get_all_edges_state(meshlink_handle_t *mesh, size_t * meshlink_edge_t **result = NULL; meshlink_edge_t *copy = NULL; + int result_size = 0; - // mesh->edges->count is the max size - *nmemb = mesh->edges->count; + result_size = mesh->edges->count; - result = xzalloc(*nmemb * sizeof (meshlink_edge_t*)); + // if result is smaller than edges, we have to dealloc all the excess meshlink_edge_t + if(result_size > *nmemb) { + result = realloc(edges, result_size * sizeof (meshlink_edge_t*)); + } else { + result = edges; + } if(result) { meshlink_edge_t **p = result; + int n = 0; for splay_each(edge_t, e, mesh->edges) { // skip edges that do not represent a two-directional connection if((!e->reverse) || (e->reverse->to != e->from)) { - *nmemb--; + result_size--; continue; } - // copy the edge so it can't be mutated - copy = xzalloc(sizeof *copy); + n++; + // the first *nmemb members of result can be re-used + if(n > *nmemb) { + copy = xzalloc(sizeof *copy); + } + else { + copy = *p; + } copy->from = (meshlink_node_t*)e->from; copy->to = (meshlink_node_t*)e->to; #ifdef HAVE_STRUCT_SOCKADDR_STORAGE @@ -1876,9 +1888,14 @@ meshlink_edge_t **meshlink_get_all_edges_state(meshlink_handle_t *mesh, size_t * *p++ = copy; } // shrink result to the actual amount of memory used - result = realloc(result, *nmemb * sizeof (meshlink_edge_t*)); + for(int i = *nmemb; i > result_size; i--) { + free(result[i - 1]); + } + result = realloc(result, result_size * sizeof (meshlink_edge_t*)); + *nmemb = result_size; } else { *nmemb = 0; + free(result); meshlink_errno = MESHLINK_ENOMEM; } diff --git a/src/meshlink.h b/src/meshlink.h index 404a8fde..4b240429 100644 --- a/src/meshlink.h +++ b/src/meshlink.h @@ -637,16 +637,31 @@ extern void meshlink_hint_address(meshlink_handle_t *mesh, meshlink_node_t *node * to meshlink_get_all_nodes(). * * @param mesh A handle which represents an instance of MeshLink. - * @param nmemb A pointer to a variable that will be filled with the number - * of edges in the returned array. - * + * @param edges A pointer to a previously allocated array of pointers to + * meshlink_edge_t, or NULL in which case MeshLink will + * allocate a new array. The application CANNOT supply an + * array it allocated itself with malloc, but CAN use + * the return value from the previous call to this function + * (which is the preferred way). + * The pointers in the array are valid until meshlink_close() is called. + * @param nmemb A pointer to a variable holding the number of nodes that + * are stored in the array. In case the @a nodes @a + * argument is not NULL, MeshLink might call realloc() + * on the array to change its size. + * The contents of this variable will be changed to reflect + * the new size of the array. + * * @return A pointer to an array containing pointers to all known * edges, or NULL in case of an error. - * The caller must call free() on each element of this + * If the @a edges @a argument was not NULL, then the + * retun value can be either the same value or a different + * value. If the new values is NULL, then the old array + * will have been freed by Meshlink. + * The caller must call free() on each element of this * array (but not the contents of said elements), * as well as the array itself when it is finished. */ -extern meshlink_edge_t **meshlink_get_all_edges_state(meshlink_handle_t *mesh, size_t *nmemb); +extern meshlink_edge_t **meshlink_get_all_edges_state(meshlink_handle_t *mesh, meshlink_edge_t **edges, size_t *nmemb); #ifdef __cplusplus } -- 2.39.2