Replace attach/detach in isc_mem with refcount implementation

The isc_mem API is one of the most commonly used APIs that didn't
used ISC_REFCOUNT_DECL and ISC_REFCOUNT_IMPL macros.  Replace the
implementation of isc_mem_attach(), isc_mem_detach() and
isc_mem_destroy() with the respective macros.

This also removes the legacy isc_mem_destroy() functionality that would
check whether all references had been detached from the memory context
as it doesn't work reliably when using the call_rcu() API.  Instead of
doing this individually, call isc_mem_checkdestroyed(stderr) from the
isc_mem_destroy() macro to keep the extra check that all contexts were
freed when the program is exiting.
This commit is contained in:
Ondřej Surý
2024-09-09 12:14:05 +02:00
parent 552cf64a70
commit eab9fc22e7
2 changed files with 28 additions and 53 deletions

View File

@@ -21,9 +21,12 @@
#include <isc/attributes.h>
#include <isc/mutex.h>
#include <isc/overflow.h>
#include <isc/refcount.h>
#include <isc/types.h>
#include <isc/urcu.h>
/* Add -DISC_MEM_TRACE=1 to CFLAGS for detailed reference tracing */
/*%
* Define ISC_MEM_TRACKLINES=1 to turn on detailed tracing of memory
* allocation and freeing by file and line number.
@@ -249,28 +252,16 @@ isc_mem_arena_set_dirty_decay_ms(isc_mem_t *mctx, const ssize_t decay_ms);
*/
/*@}*/
void
isc_mem_attach(isc_mem_t *, isc_mem_t **);
/*@{*/
void
isc_mem_attach(isc_mem_t *, isc_mem_t **);
#define isc_mem_detach(cp) isc__mem_detach((cp)_ISC_MEM_FILELINE)
void
isc__mem_detach(isc_mem_t **_ISC_MEM_FLARG);
/*!<
* \brief Attach to / detach from a memory context.
*
* This is intended for applications that use multiple memory contexts
* in such a way that it is not obvious when the last allocations from
* a given context has been freed and destroying the context is safe.
*
* Most applications do not need to call these functions as they can
* simply create a single memory context at the beginning of main()
* and destroy it at the end of main(), thereby guaranteeing that it
* is not destroyed while there are outstanding allocations.
*/
/*@}*/
#if ISC_MEM_TRACE
#define isc_mem_ref(ptr) isc_mem__ref(ptr, __func__, __FILE__, __LINE__)
#define isc_mem_unref(ptr) isc_mem__unref(ptr, __func__, __FILE__, __LINE__)
#define isc_mem_attach(ptr, ptrp) \
isc_mem__attach(ptr, ptrp, __func__, __FILE__, __LINE__)
#define isc_mem_detach(ptrp) isc_mem__detach(ptrp, __func__, __FILE__, __LINE__)
ISC_REFCOUNT_TRACE_DECL(isc_mem);
#else
ISC_REFCOUNT_DECL(isc_mem);
#endif
void
isc_mem_stats(isc_mem_t *mctx, FILE *out);

View File

@@ -427,6 +427,8 @@ void
isc__mem_shutdown(void) {
bool empty;
rcu_barrier();
isc__mem_checkdestroyed();
LOCK(&contextslock);
@@ -495,8 +497,11 @@ mem_create(isc_mem_t **ctxp, unsigned int debugging, unsigned int flags,
*/
static void
destroy(isc_mem_t *ctx) {
mem_destroy(isc_mem_t *ctx) {
unsigned int arena_no;
isc_refcount_destroy(&ctx->references);
LOCK(&contextslock);
ISC_LIST_UNLINK(contexts, ctx, link);
UNLOCK(&contextslock);
@@ -543,36 +548,11 @@ destroy(isc_mem_t *ctx) {
}
}
void
isc_mem_attach(isc_mem_t *source, isc_mem_t **targetp) {
REQUIRE(VALID_CONTEXT(source));
REQUIRE(targetp != NULL && *targetp == NULL);
isc_refcount_increment(&source->references);
*targetp = source;
}
void
isc__mem_detach(isc_mem_t **ctxp FLARG) {
isc_mem_t *ctx = NULL;
REQUIRE(ctxp != NULL && VALID_CONTEXT(*ctxp));
ctx = *ctxp;
*ctxp = NULL;
if (isc_refcount_decrement(&ctx->references) == 1) {
isc_refcount_destroy(&ctx->references);
#if ISC_MEM_TRACKLINES
if ((ctx->debugging & ISC_MEM_DEBUGTRACE) != 0) {
fprintf(stderr, "destroy mctx %p file %s line %u\n",
ctx, file, line);
}
#if ISC_MEM_TRACE
ISC_REFCOUNT_TRACE_IMPL(isc_mem, mem_destroy);
#else
ISC_REFCOUNT_IMPL(isc_mem, mem_destroy);
#endif
destroy(ctx);
}
}
/*
* isc_mem_putanddetach() is the equivalent of:
@@ -595,7 +575,11 @@ isc__mem_putanddetach(isc_mem_t **ctxp, void *ptr, size_t size,
*ctxp = NULL;
isc__mem_put(ctx, ptr, size, flags FLARG_PASS);
isc__mem_detach(&ctx FLARG_PASS);
#if ISC_MEM_TRACE
isc_mem__detach(&ctx, __func__, file, line);
#else
isc_mem_detach(&ctx);
#endif
}
void *