Browse Source

Simplify external allocation (realloc only from Tridge)

Rusty Russell 17 years ago
parent
commit
794a6678aa
4 changed files with 80 additions and 95 deletions
  1. 0 2
      ccan/talloc/TODO
  2. 56 50
      ccan/talloc/talloc.c
  3. 10 19
      ccan/talloc/talloc.h
  4. 14 24
      ccan/talloc/test/run-external-alloc.c

+ 0 - 2
ccan/talloc/TODO

@@ -1,2 +0,0 @@
-- Remove talloc.h cruft
-- Restore errno around (successful) talloc_free.

+ 56 - 50
ccan/talloc/talloc.c

@@ -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_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 {
 	struct talloc_reference_handle *next, *prev;
 	struct talloc_reference_handle *next, *prev;
@@ -182,45 +180,23 @@ const char *talloc_parent_name(const void *ptr)
 	return tc? tc->name : NULL;
 	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;
 		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:
 	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)
 	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
 		/* 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)
 	return 0;
 	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);
 }
 }

+ 10 - 19
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);
 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
  * @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  */
 /* The following definitions come from talloc.c  */
 void *_talloc(const void *context, size_t size);
 void *_talloc(const void *context, size_t size);

+ 14 - 24
ccan/talloc/test/run-external-alloc.c

@@ -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++;
-	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);
 	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);
-	head = talloc(NULL, char);
+	expected_parent = NULL;
+	head = talloc_add_external(NULL, ext_realloc);
 	assert(head);
 	assert(head);
-	expected_parent = head;
-
-	talloc_mark_external(head);
+	ok1(ext_alloc_count == 1);
 
 
+	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);