r2791: got rid of talloc_unreference() and instead created talloc_unlink(),
authorAndrew Tridgell <tridge@samba.org>
Sun, 3 Oct 2004 00:04:30 +0000 (00:04 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 17:59:34 +0000 (12:59 -0500)
which is much clearer and simpler to use. It removes a specific parent
from a pointer, no matter whether that parent is a "reference" or a
direct parent. This gives complete control over the free process.

source/include/talloc.h
source/lib/talloc.c
source/torture/local/talloc.c
talloc_guide.txt

index 2e0cca7070d347a1ffd819a8da27fdadbd15e684..5375bf5f84314a8688b4fbf30a7166d312434dd8 100644 (file)
@@ -59,7 +59,7 @@ void *_talloc(const void *context, size_t size);
 void talloc_set_destructor(const void *ptr, int (*destructor)(void *));
 void talloc_increase_ref_count(const void *ptr);
 void *talloc_reference(const void *context, const void *ptr);
-void *talloc_unreference(const void *context, const void *ptr);
+int talloc_unlink(const void *context, void *ptr);
 void talloc_set_name(const void *ptr, const char *fmt, ...) PRINTF_ATTRIBUTE(2,3);
 void talloc_set_name_const(const void *ptr, const char *name);
 void *talloc_named(const void *context, size_t size, 
index 403203914236ac11518d9b902d235ec71a37c4fc..fc655460638b75f310a4dda50dcf29cbb8928f38 100644 (file)
@@ -241,7 +241,7 @@ void *talloc_reference(const void *context, const void *ptr)
   talloc_reference() has done. The context and pointer arguments
   must match those given to a talloc_reference()
 */
-void *talloc_unreference(const void *context, const void *ptr)
+static int talloc_unreference(const void *context, const void *ptr)
 {
        struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
        struct talloc_reference_handle *h;
@@ -255,13 +255,58 @@ void *talloc_unreference(const void *context, const void *ptr)
                if ((p==NULL && context==NULL) || p+1 == context) break;
        }
        if (h == NULL) {
-               return NULL;
+               return -1;
        }
 
        talloc_set_destructor(h, NULL);
        _TLIST_REMOVE(tc->refs, h);
        talloc_free(h);
-       return discard_const_p(void, ptr);
+       return 0;
+}
+
+/*
+  remove a specific parent context from a pointer. This is a more
+  controlled varient of talloc_free()
+*/
+int talloc_unlink(const void *context, void *ptr)
+{
+       struct talloc_chunk *tc_p, *new_p;
+       void *new_parent;
+
+       if (talloc_unreference(context, ptr) == 0) {
+               return 0;
+       }
+
+       if (context == NULL) {
+               if (talloc_parent_chunk(ptr) != NULL) {
+                       return -1;
+               }
+       } else {
+               if (talloc_chunk_from_ptr(context) != talloc_parent_chunk(ptr)) {
+                       return -1;
+               }
+       }
+       
+       tc_p = talloc_chunk_from_ptr(ptr);
+
+       if (tc_p->refs == NULL) {
+               return talloc_free(ptr);
+       }
+
+       new_p = talloc_parent_chunk(tc_p->refs);
+       if (new_p) {
+               new_parent = new_p+1;
+       } else {
+               new_parent = NULL;
+       }
+
+       if (talloc_unreference(new_parent, ptr) != 0) {
+               return -1;
+       }
+
+       talloc_steal(new_parent, ptr);
+
+       return 0;
 }
 
 /*
index a3bfb45f54cd97fc8fcb4d3e954c066e77947eca..c9f9c60ea42418425df6897d6e1c91458ae20c9d 100644 (file)
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 
+#ifdef _STANDALONE_
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <sys/time.h>
+#include <time.h>
+#include "talloc.h"
+#else
 #include "includes.h"
+#endif
+
+/* the test suite can be built standalone, or as part of Samba */
+#ifdef _STANDALONE_
+typedef enum {False=0,True=1} BOOL;
+
+static struct timeval tp1,tp2;
+
+static void start_timer(void)
+{
+       gettimeofday(&tp1,NULL);
+}
+
+static double end_timer(void)
+{
+       gettimeofday(&tp2,NULL);
+       return((tp2.tv_sec - tp1.tv_sec) + 
+              (tp2.tv_usec - tp1.tv_usec)*1.0e-6);
+}
+#endif /* _STANDALONE_ */
 
-#define CHECK_BLOCKS(ptr, tblocks) do { \
-       if (talloc_total_blocks(ptr) != (tblocks)) { \
-               printf(__location__ " failed: wrong '%s' tree blocks: got %u  expected %u\n", \
-                      #ptr, \
-                      (unsigned)talloc_total_blocks(ptr), \
-                      (unsigned)tblocks); \
-               talloc_report_full(ptr, stdout); \
-               return False; \
-       } \
-} while (0)
 
 #define CHECK_SIZE(ptr, tsize) do { \
        if (talloc_total_size(ptr) != (tsize)) { \
        } \
 } while (0)
 
+#define CHECK_BLOCKS(ptr, tblocks) do { \
+       if (talloc_total_blocks(ptr) != (tblocks)) { \
+               printf(__location__ " failed: wrong '%s' tree blocks: got %u  expected %u\n", \
+                      #ptr, \
+                      (unsigned)talloc_total_blocks(ptr), \
+                      (unsigned)tblocks); \
+               talloc_report_full(ptr, stdout); \
+               return False; \
+       } \
+} while (0)
+
+
 /*
   test references 
 */
@@ -241,11 +272,11 @@ static BOOL test_ref4(void)
 /*
   test references 
 */
-static BOOL test_unref1(void)
+static BOOL test_unlink1(void)
 {
        void *root, *p1, *p2, *ref, *r1;
 
-       printf("TESTING UNREFERENCE\n");
+       printf("TESTING UNLINK\n");
 
        root = talloc_named_const(NULL, 0, "root");
        p1 = talloc_named_const(root, 1, "p1");
@@ -263,7 +294,7 @@ static BOOL test_unref1(void)
        CHECK_BLOCKS(r1, 2);
 
        printf("Unreferencing r1\n");
-       talloc_unreference(r1, p2);
+       talloc_unlink(r1, p2);
        talloc_report_full(root, stdout);
 
        CHECK_BLOCKS(p1, 6);
@@ -314,11 +345,16 @@ static BOOL test_misc(void)
        talloc_free(p1);
        CHECK_BLOCKS(p1, 1);
        CHECK_BLOCKS(root, 2);
-       talloc_unreference(NULL, p1);
+       talloc_unlink(NULL, p1);
        CHECK_BLOCKS(p1, 1);
        CHECK_BLOCKS(root, 2);
-       if (talloc_unreference(root, p1) != NULL) {
-               printf("failed: talloc_unreference() of non-reference context should return NULL\n");
+       p2 = talloc_strdup(p1, "foo");
+       if (talloc_unlink(root, p2) != -1) {
+               printf("failed: talloc_unlink() of non-reference context should return -1\n");
+               return False;
+       }
+       if (talloc_unlink(p1, p2) != 0) {
+               printf("failed: talloc_unlink() of parent should succeed\n");
                return False;
        }
        talloc_free(p1);
@@ -406,6 +442,44 @@ static BOOL test_misc(void)
        talloc_free(p1);
        CHECK_BLOCKS(root, 1);
 
+       p1 = talloc_named(root, 100, "%d bytes", 100);
+       CHECK_BLOCKS(p1, 2);
+       CHECK_BLOCKS(root, 3);
+       talloc_unlink(root, p1);
+
+       p1 = talloc_init("%d bytes", 200);
+       p2 = talloc_asprintf(p1, "my test '%s'", "string");
+       CHECK_BLOCKS(p1, 3);
+       CHECK_SIZE(p2, 17);
+       CHECK_BLOCKS(root, 1);
+       talloc_unlink(NULL, p1);
+
+       p1 = talloc_named_const(root, 10, "p1");
+       p2 = talloc_named_const(root, 20, "p2");
+       talloc_reference(p1, p2);
+       talloc_report_full(root, stdout);
+       talloc_unlink(root, p2);
+       talloc_report_full(root, stdout);
+       CHECK_BLOCKS(p2, 1);
+       CHECK_BLOCKS(p1, 2);
+       CHECK_BLOCKS(root, 3);
+       talloc_unlink(p1, p2);
+       talloc_unlink(root, p1);
+
+       p1 = talloc_named_const(root, 10, "p1");
+       p2 = talloc_named_const(root, 20, "p2");
+       talloc_reference(NULL, p2);
+       talloc_report_full(root, stdout);
+       talloc_unlink(root, p2);
+       talloc_report_full(root, stdout);
+       CHECK_BLOCKS(p2, 1);
+       CHECK_BLOCKS(p1, 1);
+       CHECK_BLOCKS(root, 2);
+       talloc_unlink(NULL, p2);
+       talloc_unlink(root, p1);
+
+       
+
        talloc_report(root, stdout);
        talloc_report(NULL, stdout);
 
@@ -567,7 +641,7 @@ static BOOL test_ldb(void)
 static BOOL test_speed(void)
 {
        void *ctx = talloc(NULL, 0);
-       uint_t count;
+       unsigned count;
 
        printf("MEASURING TALLOC VS MALLOC SPEED\n");
 
@@ -609,18 +683,32 @@ BOOL torture_local_talloc(int dummy)
 {
        BOOL ret = True;
 
-       init_iconv();
-
        ret &= test_ref1();
        ret &= test_ref2();
        ret &= test_ref3();
        ret &= test_ref4();
-       ret &= test_unref1();
+       ret &= test_unlink1();
        ret &= test_misc();
        ret &= test_realloc();
        ret &= test_steal();
        ret &= test_ldb();
-       ret &= test_speed();
+       if (ret) {
+               ret &= test_speed();
+       }
 
        return ret;
 }
+
+
+
+#ifdef _STANDALONE_
+int main(void)
+{
+       if (!torture_local_talloc(0)) {
+               printf("ERROR: TESTSUIE FAILED\n");
+               return -1;
+       }
+       return 0;
+}
+#endif
+
index b61e08e708012fd53ad62b8a68eaf12604f07160..7742ade62356bd66bb0db3d47489cc6cba87f85b 100644 (file)
@@ -33,10 +33,9 @@ n-ary tree, where you can free any part of the tree with
 talloc_free().
 
 If you find this confusing, then I suggest you run the LOCAL-TALLOC
-smbtorture test with the --leak-report-full option to watch talloc in
-action. You may also like to add your own tests to
-source/torture/local/talloc.c to clarify how some particular situation
-is handled.
+smbtorture test to watch talloc in action. You may also like to add
+your own tests to source/torture/local/talloc.c to clarify how some
+particular situation is handled.
 
 
 Performance
@@ -103,9 +102,11 @@ destructor returned -1. See talloc_set_destructor() for details on
 destructors.
 
 If this pointer has an additional reference when talloc_free() is
-called then the memory is not actually released, but instead the
-reference is destroyed. See talloc_reference() for details on
-establishing additional references.
+called then the memory is not actually released, but instead the most
+recently established reference is destroyed. See talloc_reference()
+for details on establishing additional references.
+
+For more control on which parent is removed, see talloc_unlink()
 
 talloc_free() operates recursively on its children.
 
@@ -137,21 +138,22 @@ ways:
     reference. That will destroy the reference, and leave the pointer
     where it is.
 
+For more control on which parent to remove, see talloc_unlink()
+
 
 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
-void *talloc_unreference(const void *context, const void *ptr);
+int talloc_unlink(const void *context, const void *ptr);
 
-The talloc_unreference() function removes a reference added by
-talloc_reference(). It must be called with exactly the same arguments
-as talloc_reference().
+The talloc_unlink() function removes a specific parent from ptr. The
+context passed must either be a context used in talloc_reference()
+with this pointer, or must be a direct parent of ptr. 
 
-Note that if the reference has already been removed using
-talloc_free() then this function will fail and will return NULL.
+Note that if the parent has already been removed using talloc_free()
+then this function will fail and will return -1.
 
-Usually you can just use talloc_free() instead of
-talloc_unreference(), but sometimes it is useful to have the
-additional control on who becomes the parent of the pointer given by
-talloc_unreference().
+Usually you can just use talloc_free() instead of talloc_unlink(), but
+sometimes it is useful to have the additional control on which parent
+is removed.
 
 
 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-