Commit 794a6678 authored by Rusty Russell's avatar Rusty Russell

Simplify external allocation (realloc only from Tridge)

parent 16b7eb13
- Remove talloc.h cruft
- Restore errno around (successful) talloc_free.
...@@ -82,9 +82,7 @@ ...@@ -82,9 +82,7 @@
static void *null_context; static void *null_context;
static pid_t *autofree_context; static pid_t *autofree_context;
static void *(*tc_external_alloc)(void *parent, size_t size); static void *(*tc_external_realloc)(const void *parent, void *ptr, size_t size);
static void (*tc_external_free)(void *ptr, void *parent);
static void *(*tc_external_realloc)(void *ptr, void *parent, size_t size);
struct talloc_reference_handle { struct talloc_reference_handle {
struct talloc_reference_handle *next, *prev; struct talloc_reference_handle *next, *prev;
...@@ -182,45 +180,23 @@ const char *talloc_parent_name(const void *ptr) ...@@ -182,45 +180,23 @@ const char *talloc_parent_name(const void *ptr)
return tc? tc->name : NULL; return tc? tc->name : NULL;
} }
/* static void *init_talloc(struct talloc_chunk *parent,
Allocate a bit of memory as a child of an existing pointer struct talloc_chunk *tc,
*/ size_t size, int external)
static inline void *__talloc(const void *context, size_t size)
{ {
struct talloc_chunk *tc; if (unlikely(tc == NULL))
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)) {
return 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->size = size;
tc->flags = flags; tc->flags = TALLOC_MAGIC;
if (external)
tc->flags |= TALLOC_FLAG_EXT_ALLOC;
tc->destructor = NULL; tc->destructor = NULL;
tc->child = NULL; tc->child = NULL;
tc->name = NULL; tc->name = NULL;
tc->refs = NULL; tc->refs = NULL;
if (likely(context)) { if (likely(parent)) {
if (parent->child) { if (parent->child) {
parent->child->parent = NULL; parent->child->parent = NULL;
tc->next = parent->child; tc->next = parent->child;
...@@ -238,6 +214,38 @@ alloc_done: ...@@ -238,6 +214,38 @@ alloc_done:
return TC_PTR_FROM_CHUNK(tc); 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 setup a destructor to be called on free of a pointer
the destructor should return 0 on success, or -1 on failure. the destructor should return 0 on success, or -1 on failure.
...@@ -419,7 +427,7 @@ static inline int _talloc_free(void *ptr) ...@@ -419,7 +427,7 @@ static inline int _talloc_free(void *ptr)
tc->flags |= TALLOC_FLAG_FREE; tc->flags |= TALLOC_FLAG_FREE;
if (unlikely(tc->flags & TALLOC_FLAG_EXT_ALLOC)) if (unlikely(tc->flags & TALLOC_FLAG_EXT_ALLOC))
tc_external_free(tc, oldparent); tc_external_realloc(oldparent, tc, 0);
else else
free(tc); free(tc);
...@@ -802,7 +810,7 @@ void *_talloc_realloc(const void *context, void *ptr, size_t size, const char *n ...@@ -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. */ /* need to get parent before setting free flag. */
void *parent = talloc_parent(ptr); void *parent = talloc_parent(ptr);
tc->flags |= TALLOC_FLAG_FREE; 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 { } else {
/* by resetting magic we catch users of the old memory */ /* by resetting magic we catch users of the old memory */
tc->flags |= TALLOC_FLAG_FREE; tc->flags |= TALLOC_FLAG_FREE;
...@@ -1441,23 +1449,21 @@ int talloc_is_parent(const void *context, const void *ptr) ...@@ -1441,23 +1449,21 @@ int talloc_is_parent(const void *context, const void *ptr)
return 0; return 0;
} }
void talloc_external_enable(void *(*alloc)(void *parent, size_t size), void *talloc_add_external(const void *ctx,
void (*free)(void *ptr, void *parent), void *(*realloc)(const void *, void *, size_t))
void *(*realloc)(void *ptr, void *parent, size_t))
{ {
tc_external_alloc = alloc; struct talloc_chunk *tc, *parent;
tc_external_free = free;
tc_external_realloc = realloc;
}
void talloc_mark_external(void *context) if (tc_external_realloc && tc_external_realloc != realloc)
{ TALLOC_ABORT("talloc_add_external realloc replaced");
struct talloc_chunk *tc; tc_external_realloc = realloc;
if (unlikely(context == NULL)) { if (unlikely(ctx == NULL)) {
context = null_context; ctx = null_context;
} parent = NULL;
} else
parent = talloc_chunk_from_ptr(ctx);
tc = talloc_chunk_from_ptr(context); tc = tc_external_realloc(ctx, NULL, TC_HDR_SIZE);
tc->flags |= TALLOC_FLAG_EXT_ALLOC; return init_talloc(parent, tc, 0, 1);
} }
...@@ -929,30 +929,21 @@ size_t talloc_get_size(const void *ctx); ...@@ -929,30 +929,21 @@ size_t talloc_get_size(const void *ctx);
void *talloc_find_parent_byname(const void *ctx, const char *name); void *talloc_find_parent_byname(const void *ctx, const char *name);
/** /**
* talloc_external_enable - set external allocators for some nodes * talloc_add_external - create an externally allocated node
* @alloc: the malloc() equivalent * @ctx: the parent
* @free: the free() equivalent
* @realloc: the realloc() equivalent * @realloc: the realloc() equivalent
* *
* talloc_mark_external() can be used to mark nodes whose children should * talloc_add_external() creates a node which uses a separate allocator. All
* use separate allocators. Currently the set of allocators is global, not * children allocated from that node will also use that allocator.
* per-node, and is set with this function.
* *
* The parent pointers is the talloc pointer of the parent. * Note: Currently there is only one external allocator, not per-node,
*/ * and it is set with this function.
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
* *
* This function indicates that all children (and children's children etc) * The parent pointers in realloc is the talloc pointer of the parent, if any.
* should use the allocators set up wth talloc_external_enable() rather than
* normal malloc/free.
*/ */
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 */ /* The following definitions come from talloc.c */
void *_talloc(const void *context, size_t size); void *_talloc(const void *context, size_t size);
......
...@@ -5,47 +5,37 @@ ...@@ -5,47 +5,37 @@
static int ext_alloc_count, ext_free_count, ext_realloc_count; static int ext_alloc_count, ext_free_count, ext_realloc_count;
static void *expected_parent; 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); ok1(parent == expected_parent);
ext_alloc_count++; if (ptr == NULL)
return malloc(size); ext_alloc_count++;
} if (size == 0)
ext_free_count++;
static void ext_free(void *ptr, void *parent) if (ptr && size)
{ ext_realloc_count++;
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++;
return realloc(ptr, size); return realloc(ptr, size);
} }
int main(void) int main(void)
{ {
char *p, *p2, *head; char *p, *p2, *head;
plan_tests(10); plan_tests(12);
talloc_external_enable(ext_alloc, ext_free, ext_realloc); expected_parent = NULL;
head = talloc(NULL, char); head = talloc_add_external(NULL, ext_realloc);
assert(head); assert(head);
expected_parent = head; ok1(ext_alloc_count == 1);
talloc_mark_external(head);
expected_parent = head;
p = talloc_array(head, char, 1); p = talloc_array(head, char, 1);
ok1(ext_alloc_count == 1); ok1(ext_alloc_count == 2);
assert(p); assert(p);
/* Child is also externally allocated */ /* Child is also externally allocated */
expected_parent = p; expected_parent = p;
p2 = talloc(p, char); p2 = talloc(p, char);
ok1(ext_alloc_count == 2); ok1(ext_alloc_count == 3);
expected_parent = head; expected_parent = head;
p = talloc_realloc(NULL, p, char, 1000); p = talloc_realloc(NULL, p, char, 1000);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment