From: Arran Cudbard-Bell Date: Wed, 20 May 2020 20:56:27 +0000 (-0500) Subject: talloc: Extend link_ctx functionality so that we can run custom destructors X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=effd1fe5825cc30ef7eebcb3b38efb514a9aab07;p=thirdparty%2Ffreeradius-server.git talloc: Extend link_ctx functionality so that we can run custom destructors --- diff --git a/src/lib/util/talloc.c b/src/lib/util/talloc.c index b7b8c4bfc09..3042beefb09 100644 --- a/src/lib/util/talloc.c +++ b/src/lib/util/talloc.c @@ -31,13 +31,6 @@ RCSID("$Id$") #include #include -typedef struct fr_talloc_link fr_talloc_link_t; - -struct fr_talloc_link { //!< Allocated in the context of the parent. - fr_talloc_link_t **self; //!< Allocated in the context of the child. - TALLOC_CTX *child; //!< Allocated in the context of the child. -}; - /** Retrieve the current talloc NULL ctx * * Talloc doesn't provide a function to retrieve the top level memory tracking context. @@ -57,50 +50,91 @@ void *talloc_null_ctx(void) return null_ctx; } -/** Called when the parent CTX is freed +/** Called with the fire_ctx is freed * */ -static int _link_ctx_link_free(fr_talloc_link_t *link) +static int _talloc_destructor_fire(fr_talloc_destructor_t *d) { - /* - * This hasn't been freed yet. Mark it as "about to be - * freed", and then free it. - */ - if (link->self) { - fr_talloc_link_t **self = link->self; - - link->self = NULL; - talloc_free(self); + if (d->ds) { + talloc_set_destructor(d->ds, NULL); /* Disarm the disarmer */ + TALLOC_FREE(d->ds); /* Free the disarm trigger ctx */ } - talloc_free(link->child); - /* link is freed by talloc when this function returns */ - return 0; + return d->func(d->fire, d->uctx); } -/** Called when the child CTX is freed +/** Called when the disarm_ctx ctx is freed * */ -static int _link_ctx_self_free(fr_talloc_link_t **link_p) +static int _talloc_destructor_disarm(fr_talloc_destructor_disarm_t *ds) { - fr_talloc_link_t *link = *link_p; + talloc_set_destructor(ds->d, NULL); /* Disarm the destructor */ + return talloc_free(ds->d); /* Free memory allocated to the destructor */ +} - /* - * link->child is freed by talloc at some other point, - * which results in this destructor being called. - */ +/** Add an additional destructor to a talloc chunk + * + * @param[in] fire_ctx When this ctx is freed the destructor function + * will be called. + * @param[in] disarm_ctx When this ctx is freed the destructor will be + * disarmed. May be NULL. #talloc_destructor_disarm + * may be used to disarm the destructor too. + * @param[in] func to call when the fire_ctx is freed. + * @param[in] uctx data to pass to the above function. + * @return + * - A handle to access the destructor on success. + * - NULL on failure. + */ +fr_talloc_destructor_t *talloc_destructor_add(TALLOC_CTX *fire_ctx, TALLOC_CTX *disarm_ctx, + fr_talloc_free_func_t func, void const *uctx) +{ + fr_talloc_destructor_t *d; - /* link->self is freed by talloc when this function returns */ + if (!fire_ctx) return NULL; - /* - * If link->self is still pointing to us, the link is - * still valid. Mark it as "about to be freed", and free the link. - */ - if (link->self) { - link->self = NULL; - talloc_free(link); + d = talloc(fire_ctx, fr_talloc_destructor_t); + if (!d) return NULL; + + d->fire = fire_ctx; + d->func = func; + memcpy(&d->uctx, &uctx, sizeof(d->uctx)); + + if (disarm_ctx) { + fr_talloc_destructor_disarm_t *ds; + + ds = talloc(disarm_ctx, fr_talloc_destructor_disarm_t); + if (!ds) { + talloc_free(d); + return NULL; + } + ds->d = d; + d->ds = ds; + talloc_set_destructor(ds, _talloc_destructor_disarm); + } + + talloc_set_destructor(d, _talloc_destructor_fire); + + return d; +} + +/** Disarm a destructor and free all memory allocated in the trigger ctxs + * + */ +void talloc_destructor_disarm(fr_talloc_destructor_t *d) +{ + if (d->ds) { + talloc_set_destructor(d->ds, NULL); /* Disarm the disarmer */ + TALLOC_FREE(d->ds); /* Free the disarmer ctx */ } + talloc_set_destructor(d, NULL); /* Disarm the destructor */ + talloc_free(d); /* Free the destructor ctx */ +} + +static int _talloc_link_ctx_free(UNUSED void *parent, void *child) +{ + talloc_free(child); + return 0; } @@ -117,41 +151,7 @@ static int _link_ctx_self_free(fr_talloc_link_t **link_p) */ int talloc_link_ctx(TALLOC_CTX *parent, TALLOC_CTX *child) { - fr_talloc_link_t *link; - - /* - * Don't link to a NULL context. - */ - if (!parent) return 0; - -#if 0 - /* - * Commented out for debugging. - */ - { - TALLOC_CTX *check; - - check = talloc_parent(child); - if (fr_cond_assert(parent != check)) { - return -1; - } - } -#endif - - link = talloc(parent, fr_talloc_link_t); - if (!link) return -1; - - link->self = talloc(child, fr_talloc_link_t *); - if (!link->self) { - talloc_free(link); - return -1; - } - - link->child = child; - *(link->self) = link; - - talloc_set_destructor(link, _link_ctx_link_free); - talloc_set_destructor(link->self, _link_ctx_self_free); + if (!talloc_destructor_add(parent, child, _talloc_link_ctx_free, child)) return -1; return 0; } diff --git a/src/lib/util/talloc.h b/src/lib/util/talloc.h index 4946a4723bd..11310c564db 100644 --- a/src/lib/util/talloc.h +++ b/src/lib/util/talloc.h @@ -36,6 +36,31 @@ extern "C" { #include #include +typedef int(* fr_talloc_free_func_t)(void *fire_ctx, void *uctx); + +typedef struct fr_talloc_destructor_s fr_talloc_destructor_t; +typedef struct fr_talloc_destructor_disarm_s fr_talloc_destructor_disarm_t; + +/** Structure to record a destructor operation on a specific talloc chunk + * + * Provided here so that additional memory can be allocated with talloc pool. + */ +struct fr_talloc_destructor_s { + void *fire; //!< Parent chunk. + + fr_talloc_free_func_t func; //!< Free function. + void *uctx; //!< uctx to pass to free function. + fr_talloc_destructor_disarm_t *ds; //!< Chunk to free. +}; + +/** Structure to record a destructor to disarm if a child talloc chunk is freed + * + * Provided here so that additional memory can be allocated with talloc pool. + */ +struct fr_talloc_destructor_disarm_s { + fr_talloc_destructor_t *d; //!< Destructor to disarm. +}; + /** Allocate a top level chunk with a constant name * * @param[in] name Must be a string literal. @@ -57,8 +82,17 @@ static inline TALLOC_CTX *talloc_init_const(char const *name) void *talloc_null_ctx(void); +fr_talloc_destructor_t *talloc_destructor_add(TALLOC_CTX *fire_ctx, TALLOC_CTX *disarm_ctx, + fr_talloc_free_func_t func, void const *uctx); + +void talloc_destructor_disarm(fr_talloc_destructor_t *d); + int talloc_link_ctx(TALLOC_CTX *parent, TALLOC_CTX *child); +fr_talloc_destructor_t *talloc_add_destructor(TALLOC_CTX *chunk, fr_talloc_free_func_t func, void const *uctx); + +void talloc_disarm_destructor(fr_talloc_destructor_t *d); + TALLOC_CTX *talloc_page_aligned_pool(TALLOC_CTX *ctx, void **start, void **end, size_t size); /*