From 5722f2d65cc4f1a1204f71edef311ce30cadda5c Mon Sep 17 00:00:00 2001 From: Panu Matilainen Date: Thu, 17 Sep 2009 11:36:10 +0300 Subject: [PATCH] Add runtime settable custom memory allocation failure callback routine - lets API users perform theirn own cleanup / exit through their own routines in case of allocation failure, or even try to free up some memory and retry allocation --- rpmio/rpmmalloc.c | 26 +++++++++++++++++++++++--- rpmio/rpmutil.h | 21 +++++++++++++++++++++ 2 files changed, 44 insertions(+), 3 deletions(-) diff --git a/rpmio/rpmmalloc.c b/rpmio/rpmmalloc.c index 80ad20c..f0e16ce 100644 --- a/rpmio/rpmmalloc.c +++ b/rpmio/rpmmalloc.c @@ -9,11 +9,31 @@ #define EXIT_FAILURE 1 #endif +static rpmMemFailFunc failfunc = NULL; +static void *failfunc_data = NULL; + +/* + * Give memfail callback a chance to try to give us memory or perform + * it's own cleanup. If we dont get memory we die anyway as rpm doesn't + * check for NULL returns from allocations. + */ static void *vmefail(size_t size) { - fprintf(stderr, _("memory alloc (%u bytes) returned NULL.\n"), (unsigned)size); - exit(EXIT_FAILURE); - return NULL; + void *val = failfunc ? (*failfunc)(size, failfunc_data) : NULL; + if (val == NULL) { + fprintf(stderr, _("memory alloc (%u bytes) returned NULL.\n"), + (unsigned)size); + exit(EXIT_FAILURE); + } + return val; +} + +void * rpmSetMemFail(rpmMemFailFunc func, void *data) +{ + void *ofunc = failfunc; + failfunc = func; + failfunc_data = data; + return ofunc; } void * rmalloc (size_t size) diff --git a/rpmio/rpmutil.h b/rpmio/rpmutil.h index dcc02bb..7f22f64 100644 --- a/rpmio/rpmutil.h +++ b/rpmio/rpmutil.h @@ -127,4 +127,25 @@ char * rstrdup(const char *str); /* Rpm specific free() which returns NULL */ void * rfree(void *ptr); +/** \ingroup rpmutil + * Memory allocation failure callback prototype. When registered through + * rpmSetMemFail(), this gets called if memory allocation through rmalloc() + * and friends fails. If the application can somehow recover memory here, + * it can return a newly allocated memory block of requested size, otherwise + * it must return NULL after performing it's own shutdown deeds or + * terminate itself. + * @param size Size of allocation request in bytes + * @param data User data (or NULL) + * @return Allocated memory block of requested size or NULL + */ +typedef void * (*rpmMemFailFunc) (size_t size, void *data); + +/** \ingroup rpmutil + * Set memory allocation failure callback. + * @param func Allocation failure callback function + * @param data User data (or NULL) + * @return Previous callback function + */ +void * rpmSetMemFail(rpmMemFailFunc func, void *data); + #endif /* _RPMUTIL_H */ -- 2.7.4