diff options
author | Gianni Tedesco <gianni.tedesco@citrix.com> | 2010-08-12 18:55:16 +0100 |
---|---|---|
committer | Gianni Tedesco <gianni.tedesco@citrix.com> | 2010-08-12 18:55:16 +0100 |
commit | 94413e51b0558f0b55137328d51ce8c26dd358a0 (patch) | |
tree | 1716442ff500684121d4da656788c812ce35606a /tools/libxl/libxl_internal.c | |
parent | db6b874fcd1430219176a4f86c2bf21dc4946388 (diff) | |
download | xen-94413e51b0558f0b55137328d51ce8c26dd358a0.tar.gz xen-94413e51b0558f0b55137328d51ce8c26dd358a0.tar.bz2 xen-94413e51b0558f0b55137328d51ce8c26dd358a0.zip |
xl: Implement per-API-call garbage-collection lifetime
Currently scratch variables allocated by libxl have the same lifetime as
the context. While this is suitable for one off invocations of xl. It is
not so great for a daemon process linking to libxl. In that case there
will be prolific leakage of heap memory.
My proposed solution involves create a new libxl_gc structure, which
contains a pointer to an owning context as well as the garbage
collection data. Top-level library functions which expect to do a lot of
scratch allocations put gc struct on the stack and initialize it with a
macro. Before returning they then call libxl_free_all on this struct.
This means that static helper functions called by such functions will
usually take a gc instead of a ctx as a first parameter.
The patch touches almost every code-path so a close review and testing
would be much appreciated. I have tested with valgrind all of the parts
I could which looked non-straightforward. Suffice to say that it seems
crash-free even if we have exposed a few real memory leaks. These are
for cases where we return eg. block list to an xl caller but there is no
appropriate block_list_free() function to call. Ian Campbells work in
this area should sew up all these loose ends.
Signed-off-by: Gianni Tedesco <gianni.tedesco@citrix.com>
committer: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
Diffstat (limited to 'tools/libxl/libxl_internal.c')
-rw-r--r-- | tools/libxl/libxl_internal.c | 65 |
1 files changed, 33 insertions, 32 deletions
diff --git a/tools/libxl/libxl_internal.c b/tools/libxl/libxl_internal.c index 22595f1578..2d5ad9a033 100644 --- a/tools/libxl/libxl_internal.c +++ b/tools/libxl/libxl_internal.c @@ -28,7 +28,7 @@ int libxl_error_set(libxl_ctx *ctx, int code) return 0; } -int libxl_ptr_add(libxl_ctx *ctx, void *ptr) +int libxl_ptr_add(libxl_gc *gc, void *ptr) { int i; void **re; @@ -37,29 +37,29 @@ int libxl_ptr_add(libxl_ctx *ctx, void *ptr) return 0; /* fast case: we have space in the array for storing the pointer */ - for (i = 0; i < ctx->alloc_maxsize; i++) { - if (!ctx->alloc_ptrs[i]) { - ctx->alloc_ptrs[i] = ptr; + for (i = 0; i < gc->alloc_maxsize; i++) { + if (!gc->alloc_ptrs[i]) { + gc->alloc_ptrs[i] = ptr; return 0; } } /* realloc alloc_ptrs manually with calloc/free/replace */ - re = calloc(ctx->alloc_maxsize + 25, sizeof(void *)); + re = calloc(gc->alloc_maxsize + 25, sizeof(void *)); if (!re) return -1; - for (i = 0; i < ctx->alloc_maxsize; i++) - re[i] = ctx->alloc_ptrs[i]; + for (i = 0; i < gc->alloc_maxsize; i++) + re[i] = gc->alloc_ptrs[i]; /* assign the next pointer */ re[i] = ptr; /* replace the old alloc_ptr */ - free(ctx->alloc_ptrs); - ctx->alloc_ptrs = re; - ctx->alloc_maxsize += 25; + free(gc->alloc_ptrs); + gc->alloc_ptrs = re; + gc->alloc_maxsize += 25; return 0; } -void libxl_free(libxl_ctx *ctx, void *ptr) +void libxl_free(libxl_gc *gc, void *ptr) { int i; @@ -67,9 +67,9 @@ void libxl_free(libxl_ctx *ctx, void *ptr) return; /* remove the pointer from the tracked ptrs */ - for (i = 0; i < ctx->alloc_maxsize; i++) { - if (ctx->alloc_ptrs[i] == ptr) { - ctx->alloc_ptrs[i] = NULL; + for (i = 0; i < gc->alloc_maxsize; i++) { + if (gc->alloc_ptrs[i] == ptr) { + gc->alloc_ptrs[i] = NULL; free(ptr); return; } @@ -78,43 +78,44 @@ void libxl_free(libxl_ctx *ctx, void *ptr) abort(); } -void libxl_free_all(libxl_ctx *ctx) +void libxl_free_all(libxl_gc *gc) { void *ptr; int i; - for (i = 0; i < ctx->alloc_maxsize; i++) { - ptr = ctx->alloc_ptrs[i]; - ctx->alloc_ptrs[i] = NULL; + for (i = 0; i < gc->alloc_maxsize; i++) { + ptr = gc->alloc_ptrs[i]; + gc->alloc_ptrs[i] = NULL; free(ptr); } + free(gc->alloc_ptrs); } -void *libxl_zalloc(libxl_ctx *ctx, int bytes) +void *libxl_zalloc(libxl_gc *gc, int bytes) { void *ptr = calloc(bytes, 1); if (!ptr) { - libxl_error_set(ctx, ENOMEM); + libxl_error_set(libxl_gc_owner(gc), ENOMEM); return NULL; } - libxl_ptr_add(ctx, ptr); + libxl_ptr_add(gc, ptr); return ptr; } -void *libxl_calloc(libxl_ctx *ctx, size_t nmemb, size_t size) +void *libxl_calloc(libxl_gc *gc, size_t nmemb, size_t size) { void *ptr = calloc(nmemb, size); if (!ptr) { - libxl_error_set(ctx, ENOMEM); + libxl_error_set(libxl_gc_owner(gc), ENOMEM); return NULL; } - libxl_ptr_add(ctx, ptr); + libxl_ptr_add(gc, ptr); return ptr; } -char *libxl_sprintf(libxl_ctx *ctx, const char *fmt, ...) +char *libxl_sprintf(libxl_gc *gc, const char *fmt, ...) { char *s; va_list ap; @@ -128,7 +129,7 @@ char *libxl_sprintf(libxl_ctx *ctx, const char *fmt, ...) return NULL; } - s = libxl_zalloc(ctx, ret + 1); + s = libxl_zalloc(gc, ret + 1); if (s) { va_start(ap, fmt); ret = vsnprintf(s, ret + 1, fmt, ap); @@ -137,20 +138,20 @@ char *libxl_sprintf(libxl_ctx *ctx, const char *fmt, ...) return s; } -char *libxl_strdup(libxl_ctx *ctx, const char *c) +char *libxl_strdup(libxl_gc *gc, const char *c) { char *s = strdup(c); if (s) - libxl_ptr_add(ctx, s); + libxl_ptr_add(gc, s); return s; } -char *libxl_dirname(libxl_ctx *ctx, const char *s) +char *libxl_dirname(libxl_gc *gc, const char *s) { char *c; - char *ptr = libxl_strdup(ctx, s); + char *ptr = libxl_strdup(gc, s); c = strrchr(ptr, '/'); if (!c) @@ -196,10 +197,10 @@ void xl_log(libxl_ctx *ctx, xentoollog_level msglevel, int errnoval, va_end(ap); } -char *libxl_abs_path(libxl_ctx *ctx, char *s, const char *path) +char *libxl_abs_path(libxl_gc *gc, char *s, const char *path) { if (!s || s[0] == '/') return s; - return libxl_sprintf(ctx, "%s/%s", path, s); + return libxl_sprintf(gc, "%s/%s", path, s); } |