From: Rusty Russell Date: Tue, 5 Aug 2008 01:38:14 +0000 (+1000) Subject: Simplify external allocation (realloc only from Tridge) X-Git-Url: http://git.ozlabs.org/?p=ccan;a=commitdiff_plain;h=794a6678aa37e8864845c72b14213ca44b9e159e Simplify external allocation (realloc only from Tridge) --- diff --git a/ccan/talloc/TODO b/ccan/talloc/TODO deleted file mode 100644 index 0671a6dd..00000000 --- a/ccan/talloc/TODO +++ /dev/null @@ -1,2 +0,0 @@ -- Remove talloc.h cruft -- Restore errno around (successful) talloc_free. diff --git a/ccan/talloc/talloc.c b/ccan/talloc/talloc.c index ba998f54..8ec5b4b1 100644 --- a/ccan/talloc/talloc.c +++ b/ccan/talloc/talloc.c @@ -82,9 +82,7 @@ static void *null_context; static pid_t *autofree_context; -static void *(*tc_external_alloc)(void *parent, size_t size); -static void (*tc_external_free)(void *ptr, void *parent); -static void *(*tc_external_realloc)(void *ptr, void *parent, size_t size); +static void *(*tc_external_realloc)(const void *parent, void *ptr, size_t size); struct talloc_reference_handle { struct talloc_reference_handle *next, *prev; @@ -182,45 +180,23 @@ const char *talloc_parent_name(const void *ptr) return tc? tc->name : NULL; } -/* - Allocate a bit of memory as a child of an existing pointer -*/ -static inline void *__talloc(const void *context, size_t size) +static void *init_talloc(struct talloc_chunk *parent, + struct talloc_chunk *tc, + size_t size, int external) { - struct talloc_chunk *tc; - struct talloc_chunk *parent = NULL; /* Prevent spurious gcc warning */ - unsigned flags = TALLOC_MAGIC; - - if (unlikely(context == NULL)) { - context = null_context; - } - - if (unlikely(size >= MAX_TALLOC_SIZE)) { + if (unlikely(tc == NULL)) return NULL; - } - - if (likely(context)) { - parent = talloc_chunk_from_ptr(context); - if (unlikely(parent->flags & TALLOC_FLAG_EXT_ALLOC)) { - tc = tc_external_alloc(TC_PTR_FROM_CHUNK(parent), - TC_HDR_SIZE+size); - flags |= TALLOC_FLAG_EXT_ALLOC; - goto alloc_done; - } - } - - tc = (struct talloc_chunk *)malloc(TC_HDR_SIZE+size); -alloc_done: - if (unlikely(tc == NULL)) return NULL; tc->size = size; - tc->flags = flags; + tc->flags = TALLOC_MAGIC; + if (external) + tc->flags |= TALLOC_FLAG_EXT_ALLOC; tc->destructor = NULL; tc->child = NULL; tc->name = NULL; tc->refs = NULL; - if (likely(context)) { + if (likely(parent)) { if (parent->child) { parent->child->parent = NULL; tc->next = parent->child; @@ -238,6 +214,38 @@ alloc_done: return TC_PTR_FROM_CHUNK(tc); } +/* + Allocate a bit of memory as a child of an existing pointer +*/ +static inline void *__talloc(const void *context, size_t size) +{ + struct talloc_chunk *tc; + struct talloc_chunk *parent = NULL; + int external = 0; + + if (unlikely(context == NULL)) { + context = null_context; + } + + if (unlikely(size >= MAX_TALLOC_SIZE)) { + return NULL; + } + + if (likely(context)) { + parent = talloc_chunk_from_ptr(context); + if (unlikely(parent->flags & TALLOC_FLAG_EXT_ALLOC)) { + tc = tc_external_realloc(context, NULL, + TC_HDR_SIZE+size); + external = 1; + goto alloc_done; + } + } + + tc = (struct talloc_chunk *)malloc(TC_HDR_SIZE+size); +alloc_done: + return init_talloc(parent, tc, size, external); +} + /* setup a destructor to be called on free of a pointer the destructor should return 0 on success, or -1 on failure. @@ -419,7 +427,7 @@ static inline int _talloc_free(void *ptr) tc->flags |= TALLOC_FLAG_FREE; if (unlikely(tc->flags & TALLOC_FLAG_EXT_ALLOC)) - tc_external_free(tc, oldparent); + tc_external_realloc(oldparent, tc, 0); else free(tc); @@ -802,7 +810,7 @@ void *_talloc_realloc(const void *context, void *ptr, size_t size, const char *n /* need to get parent before setting free flag. */ void *parent = talloc_parent(ptr); tc->flags |= TALLOC_FLAG_FREE; - new_ptr = tc_external_realloc(tc, parent, size + TC_HDR_SIZE); + new_ptr = tc_external_realloc(parent, tc, size + TC_HDR_SIZE); } else { /* by resetting magic we catch users of the old memory */ tc->flags |= TALLOC_FLAG_FREE; @@ -1441,23 +1449,21 @@ int talloc_is_parent(const void *context, const void *ptr) return 0; } -void talloc_external_enable(void *(*alloc)(void *parent, size_t size), - void (*free)(void *ptr, void *parent), - void *(*realloc)(void *ptr, void *parent, size_t)) +void *talloc_add_external(const void *ctx, + void *(*realloc)(const void *, void *, size_t)) { - tc_external_alloc = alloc; - tc_external_free = free; - tc_external_realloc = realloc; -} + struct talloc_chunk *tc, *parent; -void talloc_mark_external(void *context) -{ - struct talloc_chunk *tc; + if (tc_external_realloc && tc_external_realloc != realloc) + TALLOC_ABORT("talloc_add_external realloc replaced"); + tc_external_realloc = realloc; - if (unlikely(context == NULL)) { - context = null_context; - } + if (unlikely(ctx == NULL)) { + ctx = null_context; + parent = NULL; + } else + parent = talloc_chunk_from_ptr(ctx); - tc = talloc_chunk_from_ptr(context); - tc->flags |= TALLOC_FLAG_EXT_ALLOC; + tc = tc_external_realloc(ctx, NULL, TC_HDR_SIZE); + return init_talloc(parent, tc, 0, 1); } diff --git a/ccan/talloc/talloc.h b/ccan/talloc/talloc.h index 8b0f8a38..e06f592b 100644 --- a/ccan/talloc/talloc.h +++ b/ccan/talloc/talloc.h @@ -929,30 +929,21 @@ size_t talloc_get_size(const void *ctx); void *talloc_find_parent_byname(const void *ctx, const char *name); /** - * talloc_external_enable - set external allocators for some nodes - * @alloc: the malloc() equivalent - * @free: the free() equivalent + * talloc_add_external - create an externally allocated node + * @ctx: the parent * @realloc: the realloc() equivalent * - * talloc_mark_external() can be used to mark nodes whose children should - * use separate allocators. Currently the set of allocators is global, not - * per-node, and is set with this function. + * talloc_add_external() creates a node which uses a separate allocator. All + * children allocated from that node will also use that allocator. * - * The parent pointers is the talloc pointer of the parent. - */ -void talloc_external_enable(void *(*alloc)(void *parent, size_t size), - void (*free)(void *ptr, void *parent), - void *(*realloc)(void *ptr, void *parent, size_t)); - -/** - * talloc_mark_external - children of this note must use external allocators - * @p: the talloc pointer + * Note: Currently there is only one external allocator, not per-node, + * and it is set with this function. * - * This function indicates that all children (and children's children etc) - * should use the allocators set up wth talloc_external_enable() rather than - * normal malloc/free. + * The parent pointers in realloc is the talloc pointer of the parent, if any. */ -void talloc_mark_external(void *ptr); +void *talloc_add_external(const void *ctx, + void *(*realloc)(const void *parent, + void *ptr, size_t)); /* The following definitions come from talloc.c */ void *_talloc(const void *context, size_t size); diff --git a/ccan/talloc/test/run-external-alloc.c b/ccan/talloc/test/run-external-alloc.c index 85b3b014..fb1e17e9 100644 --- a/ccan/talloc/test/run-external-alloc.c +++ b/ccan/talloc/test/run-external-alloc.c @@ -5,47 +5,37 @@ static int ext_alloc_count, ext_free_count, ext_realloc_count; static void *expected_parent; -static void *ext_alloc(void *parent, size_t size) +static void *ext_realloc(const void *parent, void *ptr, size_t size) { ok1(parent == expected_parent); - ext_alloc_count++; - return malloc(size); -} - -static void ext_free(void *ptr, void *parent) -{ - ok1(parent == expected_parent); - ext_free_count++; - free(ptr); -} - -static void *ext_realloc(void *ptr, void *parent, size_t size) -{ - ok1(parent == expected_parent); - ext_realloc_count++; + if (ptr == NULL) + ext_alloc_count++; + if (size == 0) + ext_free_count++; + if (ptr && size) + ext_realloc_count++; return realloc(ptr, size); } int main(void) { char *p, *p2, *head; - plan_tests(10); + plan_tests(12); - talloc_external_enable(ext_alloc, ext_free, ext_realloc); - head = talloc(NULL, char); + expected_parent = NULL; + head = talloc_add_external(NULL, ext_realloc); assert(head); - expected_parent = head; - - talloc_mark_external(head); + ok1(ext_alloc_count == 1); + expected_parent = head; p = talloc_array(head, char, 1); - ok1(ext_alloc_count == 1); + ok1(ext_alloc_count == 2); assert(p); /* Child is also externally allocated */ expected_parent = p; p2 = talloc(p, char); - ok1(ext_alloc_count == 2); + ok1(ext_alloc_count == 3); expected_parent = head; p = talloc_realloc(NULL, p, char, 1000);