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;
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;
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.
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);
/* 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;
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);
}
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);
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);