summaryrefslogtreecommitdiff
path: root/source4/lib/talloc.c
diff options
context:
space:
mode:
authorAndrew Tridgell <tridge@samba.org>2004-09-28 11:54:17 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 12:59:26 -0500
commit8ae2cd82caaf8762e73499a1744c63c42a5b9fe6 (patch)
treea3aedd4910cb254e9e6aa16b5a058cc3b0563a6c /source4/lib/talloc.c
parent0a93af206c723be75de55db5d4da2e8d31a17c54 (diff)
downloadsamba-8ae2cd82caaf8762e73499a1744c63c42a5b9fe6.tar.gz
samba-8ae2cd82caaf8762e73499a1744c63c42a5b9fe6.tar.bz2
samba-8ae2cd82caaf8762e73499a1744c63c42a5b9fe6.zip
r2718: - added a talloc_unreference() function as requested by metze.
- added documentation for talloc_unreference() - made the abandoned child logic in talloc_free() clearer and more consistent (This used to be commit a87584c8e3fb06cd3ff29a918f681b5c6c32b9ff)
Diffstat (limited to 'source4/lib/talloc.c')
-rw-r--r--source4/lib/talloc.c45
1 files changed, 43 insertions, 2 deletions
diff --git a/source4/lib/talloc.c b/source4/lib/talloc.c
index d0056d7b2a..bb2ed9449c 100644
--- a/source4/lib/talloc.c
+++ b/source4/lib/talloc.c
@@ -170,6 +170,34 @@ void *talloc_reference(const void *context, const void *ptr)
return handle->ptr;
}
+/*
+ remove a secondary reference to a pointer. This undo's what
+ 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)
+{
+ struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
+ struct talloc_reference_handle *h;
+
+ if (context == NULL) {
+ context = null_context;
+ }
+
+ for (h=tc->refs;h;h=h->next) {
+ struct talloc_chunk *tc2 = talloc_chunk_from_ptr(h);
+ const void *parent = tc2->parent?tc2->parent+1:null_context;
+ if (parent == context) break;
+ }
+ if (h == NULL) {
+ return NULL;
+ }
+
+ talloc_set_destructor(h, NULL);
+ DLIST_REMOVE(tc->refs, h);
+ talloc_free(h);
+ return discard_const(ptr);
+}
/*
add a name to an existing pointer - va_list version
@@ -318,8 +346,21 @@ int talloc_free(void *ptr)
}
while (tc->child) {
- talloc_free(talloc_steal(tc->parent?tc->parent+1:null_context,
- tc->child+1));
+ /* we need to work out who will own an abandoned child
+ if it cannot be freed. In priority order, the first
+ choice is owner of any remaining reference to this
+ pointer, the second choice is our parent, and the
+ final choice is the null context. */
+ void *child = tc->child+1;
+ const void *new_parent = null_context;
+ if (tc->child->refs) {
+ struct talloc_chunk *ref = talloc_chunk_from_ptr(tc->child->refs);
+ if (ref->parent) new_parent = ref->parent+1;
+ }
+ if (new_parent == null_context && tc->parent) {
+ new_parent = tc->parent+1;
+ }
+ talloc_free(talloc_steal(new_parent, child));
}
if (tc->parent) {