X-Git-Url: https://git.ozlabs.org/?p=ccan;a=blobdiff_plain;f=ccan%2Ftalloc%2Ftalloc.c;h=59a981b48c8631dde962ee5326c1dcfde4d92a00;hp=d624b9174dde42b8e892fb5764cb9544bd249671;hb=f51dd128c16fd6c654bdfbdcb19204bf9a867fe5;hpb=650c775ff00cccd03fc84e7789a03c51d9839004 diff --git a/ccan/talloc/talloc.c b/ccan/talloc/talloc.c index d624b917..59a981b4 100644 --- a/ccan/talloc/talloc.c +++ b/ccan/talloc/talloc.c @@ -45,6 +45,7 @@ #define TALLOC_MAGIC 0xe814ec70 #define TALLOC_FLAG_FREE 0x01 #define TALLOC_FLAG_LOOP 0x02 +#define TALLOC_FLAG_EXT_ALLOC 0x04 #define TALLOC_MAGIC_REFERENCE ((const char *)1) /* by default we abort when given a bad pointer (such as when talloc_free() is called @@ -79,6 +80,10 @@ static void *null_context; static void *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); + struct talloc_reference_handle { struct talloc_reference_handle *next, *prev; void *ptr; @@ -181,6 +186,8 @@ const char *talloc_parent_name(const void *ptr) static inline void *__talloc(const void *context, size_t size) { struct talloc_chunk *tc; + struct talloc_chunk *parent = NULL; /* Prevent spurious gcc warning */ + unsigned flags = TALLOC_MAGIC; if (unlikely(context == NULL)) { context = null_context; @@ -190,19 +197,28 @@ static inline void *__talloc(const void *context, size_t size) 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->flags = TALLOC_MAGIC; + tc->flags = flags; tc->destructor = NULL; tc->child = NULL; tc->name = NULL; tc->refs = NULL; if (likely(context)) { - struct talloc_chunk *parent = talloc_chunk_from_ptr(context); - if (parent->child) { parent->child->parent = NULL; tc->next = parent->child; @@ -319,6 +335,7 @@ void *_talloc_reference(const void *context, const void *ptr) static inline int _talloc_free(void *ptr) { struct talloc_chunk *tc; + void *oldparent = NULL; if (unlikely(ptr == NULL)) { return -1; @@ -362,6 +379,7 @@ static inline int _talloc_free(void *ptr) } if (tc->parent) { + oldparent = TC_PTR_FROM_CHUNK(tc->parent); _TLIST_REMOVE(tc->parent->child, tc); if (tc->parent->child) { tc->parent->child->parent = tc->parent; @@ -395,7 +413,12 @@ static inline int _talloc_free(void *ptr) } tc->flags |= TALLOC_FLAG_FREE; - free(tc); + + if (unlikely(tc->flags & TALLOC_FLAG_EXT_ALLOC)) + tc_external_free(tc, oldparent); + else + free(tc); + return 0; } @@ -771,18 +794,26 @@ void *_talloc_realloc(const void *context, void *ptr, size_t size, const char *n return NULL; } - /* by resetting magic we catch users of the old memory */ - tc->flags |= TALLOC_FLAG_FREE; + if (unlikely(tc->flags & TALLOC_FLAG_EXT_ALLOC)) { + /* need to get parent before setting free flag. */ + void *parent = talloc_parent(ptr); + tc->flags |= TALLOC_FLAG_FREE; + new_ptr = tc_external_realloc(tc, parent, size + TC_HDR_SIZE); + } else { + /* by resetting magic we catch users of the old memory */ + tc->flags |= TALLOC_FLAG_FREE; #if ALWAYS_REALLOC - new_ptr = malloc(size + TC_HDR_SIZE); - if (new_ptr) { - memcpy(new_ptr, tc, tc->size + TC_HDR_SIZE); - free(tc); - } + new_ptr = malloc(size + TC_HDR_SIZE); + if (new_ptr) { + memcpy(new_ptr, tc, tc->size + TC_HDR_SIZE); + free(tc); + } #else - new_ptr = realloc(tc, size + TC_HDR_SIZE); + new_ptr = realloc(tc, size + TC_HDR_SIZE); #endif + } + if (unlikely(!new_ptr)) { tc->flags &= ~TALLOC_FLAG_FREE; return NULL; @@ -1401,3 +1432,24 @@ int talloc_is_parent(const void *context, const void *ptr) } 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)) +{ + tc_external_alloc = alloc; + tc_external_free = free; + tc_external_realloc = realloc; +} + +void talloc_mark_external(void *context) +{ + struct talloc_chunk *tc; + + if (unlikely(context == NULL)) { + context = null_context; + } + + tc = talloc_chunk_from_ptr(context); + tc->flags |= TALLOC_FLAG_EXT_ALLOC; +}