svn commit: samba r2049 - branches/SAMBA_4_0/source/lib

tridge at samba.org tridge at samba.org
Wed Aug 25 06:40:59 GMT 2004


Author: tridge
Date: 2004-08-25 06:40:58 +0000 (Wed, 25 Aug 2004)
New Revision: 2049

WebSVN: http://websvn.samba.org/websvn/changeset.php?rep=samba&path=/&rev=2049&nolog=1

Log:
talloc now has destructors and reference counts

this means you can do:

  talloc_set_destructor(ptr, my_destructor);

and your destructor will be called with the pointer as an argument
when the pointer is about to be freed. The destructor can refuse the
free by returning -1.

You can also increase the reference count on a pointer like this:

  talloc_increase_ref_count(ptr);

and a talloc_free() will just reduce the reference count, only
actually freeing the memory when the count reaches zero.



Modified:
   branches/SAMBA_4_0/source/lib/talloc.c


Changeset:
Modified: branches/SAMBA_4_0/source/lib/talloc.c
===================================================================
--- branches/SAMBA_4_0/source/lib/talloc.c	2004-08-25 06:13:08 UTC (rev 2048)
+++ branches/SAMBA_4_0/source/lib/talloc.c	2004-08-25 06:40:58 UTC (rev 2049)
@@ -27,17 +27,32 @@
 #include "includes.h"
 
 #define MAX_TALLOC_SIZE 0x10000000
-#define TALLOC_MAGIC 0x14082004
-#define TALLOC_MAGIC_FREE 0x3421abcd
+#define TALLOC_MAGIC 0xe814ec4f
+#define TALLOC_MAGIC_FREE 0x7faebef3
 
 struct talloc_chunk {
 	struct talloc_chunk *next, *prev;
 	struct talloc_chunk *parent, *child;
 	size_t size;
 	uint_t magic;
+	uint_t ref_count;
+	int (*destructor)(void *);
 	char *name;
 };
 
+/* panic if we get a bad magic value */
+static struct talloc_chunk *talloc_chunk_from_ptr(void *ptr)
+{
+	struct talloc_chunk *tc = ((struct talloc_chunk *)ptr)-1;
+	if (tc->magic != TALLOC_MAGIC) {
+		if (tc->magic == TALLOC_MAGIC_FREE) {
+			smb_panic("Bad talloc magic value - double free\n");
+		} else {
+			smb_panic("Bad talloc magic value\n");
+		}
+	}
+	return tc;
+}
 
 /* 
    Allocate a bit of memory as a child of an existing pointer
@@ -57,19 +72,14 @@
 
 	tc->size = size;
 	tc->magic = TALLOC_MAGIC;
+	tc->ref_count = 1;
+	tc->destructor = NULL;
 	tc->child = NULL;
 	tc->name = NULL;
 
 	if (context) {
-		struct talloc_chunk *parent = ((struct talloc_chunk *)context)-1;
+		struct talloc_chunk *parent = talloc_chunk_from_ptr(context);
 
-		if (parent->magic != TALLOC_MAGIC) {
-			DEBUG(0,("Bad magic in context - 0x%08x\n", parent->magic));
-			free(tc);
-			smb_panic("Bad magic in talloc context");
-			return NULL;
-		}
-
 		tc->parent = parent;
 
 		if (parent->child) {
@@ -86,17 +96,35 @@
 
 
 /*
+  setup a destructor to be called on free of a pointer
+  the destructor should return 0 on success, or -1 on failure.
+  if the destructor fails then the free is failed, and the memory can
+  be continued to be used
+*/
+void talloc_set_destructor(void *ptr, int (*destructor)(void *))
+{
+	struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
+	tc->destructor = destructor;
+}
+
+/*
+  increase the reference count on a piece of memory. To decrease the 
+  reference count call talloc_free(), which will free the memory if 
+  the reference count reaches zero
+*/
+void talloc_increase_ref_count(void *ptr)
+{
+	struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
+	tc->ref_count++;
+}
+
+
+/*
   add a name to an existing pointer - va_list version
 */
 static void talloc_set_name_v(void *ptr, const char *fmt, va_list ap)
 {
-	struct talloc_chunk *tc;
-
-	tc = ((struct talloc_chunk *)ptr)-1;
-	if (tc->magic != TALLOC_MAGIC) {
-		return;
-	}
-
+	struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
 	vasprintf(&tc->name, fmt, ap);
 }
 
@@ -141,17 +169,14 @@
 {
 	va_list ap;
 	void *ptr;
-	struct talloc_chunk *tc;
 
 	ptr = talloc(NULL, 0);
 	if (ptr == NULL) {
 		return NULL;
 	}
 
-	tc = ((struct talloc_chunk *)ptr)-1;
-
 	va_start(ap, fmt);
-	vasprintf(&tc->name, fmt, ap);
+	talloc_set_name_v(ptr, fmt, ap);
 	va_end(ap);
 
 	return ptr;
@@ -162,23 +187,36 @@
 /* 
    free a talloc pointer. This also frees all child pointers of this 
    pointer recursively
+
+   return 0 if the memory is actually freed, otherwise -1. The memory
+   will not be freed if the ref_count is > 1 or the destructor (if
+   any) returns non-zero
 */
-void talloc_free(void *ptr)
+int talloc_free(void *ptr)
 {
 	struct talloc_chunk *tc;
 
-	if (ptr == NULL) return;
+	if (ptr == NULL) {
+		return -1;
+	}
 
-	tc = ((struct talloc_chunk *)ptr)-1;
+	tc = talloc_chunk_from_ptr(ptr);
 
-	if (tc->magic != TALLOC_MAGIC) {
-		DEBUG(0,("Bad talloc magic 0x%08x in talloc_free\n", tc->magic));
-		smb_panic("Bad talloc magic in talloc_realloc");
-		return;
+	tc->ref_count--;
+	if (tc->ref_count != 0) {
+		return -1;
 	}
 
+	if (tc->destructor && tc->destructor(ptr) == -1) {
+		tc->ref_count++;
+		return -1;
+	}
+
 	while (tc->child) {
-		talloc_free(tc->child + 1);
+		if (talloc_free(tc->child + 1) != 0) {
+			tc->child->parent = NULL;
+			break;
+		}
 	}
 
 	if (tc->parent) {
@@ -195,6 +233,7 @@
 	if (tc->name) free(tc->name);
 
 	free(tc);
+	return 0;
 }
 
 
@@ -218,19 +257,8 @@
 		return talloc(NULL, size);
 	}
 
-	tc = ((struct talloc_chunk *)ptr)-1;
+	tc = talloc_chunk_from_ptr(ptr);
 
-	if (tc->magic != TALLOC_MAGIC) {
-		if (tc->magic == TALLOC_MAGIC_FREE) {
-			
-			DEBUG(0,("Bad talloc magic - magic 0x%08x indicates double-free in talloc_realloc\n", tc->magic));
-			smb_panic("Bad talloc magic - double-free - in talloc_realloc");
-		} else {
-			DEBUG(0,("Bad talloc magic 0x%08x in talloc_realloc\n", tc->magic));
-			smb_panic("Bad talloc magic in talloc_realloc");
-		}
-	}
-
 	/* by resetting magic we catch users of the old memory */
 	tc->magic = TALLOC_MAGIC_FREE;
 
@@ -270,19 +298,12 @@
 		return NULL;
 	}
 
-	tc = ((struct talloc_chunk *)ptr)-1;
-	new_tc = ((struct talloc_chunk *)new_ctx)-1;
+	tc = talloc_chunk_from_ptr(ptr);
+	new_tc = talloc_chunk_from_ptr(new_ctx);
 
-	if (tc->magic != TALLOC_MAGIC) {
-		DEBUG(0,("Bad talloc magic 0x%08x in talloc_steal\n", tc->magic));
-		smb_panic("Bad talloc magic in talloc_steal");
-		return NULL;
+	if (tc == new_tc) {
+		return ptr;
 	}
-	if (new_tc->magic != TALLOC_MAGIC) {
-		DEBUG(0,("Bad new talloc magic 0x%08x in talloc_steal\n", new_tc->magic));
-		smb_panic("Bad new talloc magic in talloc_steal");
-		return NULL;
-	}
 
 	if (tc->parent) {
 		DLIST_REMOVE(tc->parent->child, tc);
@@ -304,13 +325,11 @@
 /*
   return the total size of a talloc pool (subtree)
 */
-off_t talloc_total_size(void *p)
+off_t talloc_total_size(void *ptr)
 {
 	off_t total = 0;
-	struct talloc_chunk *c, *tc;
+	struct talloc_chunk *c, *tc = talloc_chunk_from_ptr(ptr);
 
-	tc = ((struct talloc_chunk *)p)-1;
-
 	total = tc->size;
 	for (c=tc->child;c;c=c->next) {
 		total += talloc_total_size(c+1);



More information about the samba-cvs mailing list