summaryrefslogtreecommitdiff
path: root/source4
diff options
context:
space:
mode:
Diffstat (limited to 'source4')
-rw-r--r--source4/include/talloc.h2
-rw-r--r--source4/lib/talloc.c51
-rw-r--r--source4/torture/local/talloc.c130
3 files changed, 158 insertions, 25 deletions
diff --git a/source4/include/talloc.h b/source4/include/talloc.h
index 2e0cca7070..5375bf5f84 100644
--- a/source4/include/talloc.h
+++ b/source4/include/talloc.h
@@ -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,
diff --git a/source4/lib/talloc.c b/source4/lib/talloc.c
index 4032039142..fc65546063 100644
--- a/source4/lib/talloc.c
+++ b/source4/lib/talloc.c
@@ -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;
}
/*
diff --git a/source4/torture/local/talloc.c b/source4/torture/local/talloc.c
index a3bfb45f54..c9f9c60ea4 100644
--- a/source4/torture/local/talloc.c
+++ b/source4/torture/local/talloc.c
@@ -20,18 +20,37 @@
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)) { \
@@ -44,6 +63,18 @@
} \
} 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
+