From de1575f3ea9dd2ab66198537a0a3788fba0e06bb Mon Sep 17 00:00:00 2001 From: Felipe Oliveira Carvalho Date: Thu, 27 Mar 2014 23:35:27 -0300 Subject: [PATCH] xmalloc() that succeeds or gracefully aborts --- src/misc2.c | 97 +++++++++++++++++++++++++---------------------------- src/misc2.h | 2 ++ 2 files changed, 47 insertions(+), 52 deletions(-) diff --git a/src/misc2.c b/src/misc2.c index 21d942e370..5c07ada005 100644 --- a/src/misc2.c +++ b/src/misc2.c @@ -642,63 +642,56 @@ char_u *alloc_check(unsigned size) */ char_u *lalloc_clear(long_u size, int message) { - char_u *p; - - p = (lalloc(size, message)); - if (p != NULL) - (void)memset(p, 0, (size_t)size); + char_u *p = lalloc(size, message); + memset(p, 0, (size_t)size); return p; } -/* - * Low level memory allocation function. - * This is used often, KEEP IT FAST! - */ +/// When out of memory: try to release some memfile blocks and +/// if some blocks are released call malloc again. +void try_to_free_memory() +{ + static bool trying_to_free = false; + // avoid recursive calls + if (trying_to_free) + return; + trying_to_free = true; + + // free any scrollback text + clear_sb_text(); + // Try to save all buffers and release as many blocks as possible + mf_release_all(); + // cleanup recursive lists/dicts + garbage_collect(); + + trying_to_free = false; +} + +void *xmalloc(size_t size) +{ + void *ret = malloc(size); + + if (!ret && !size) + ret = malloc(1); + + if (!ret) { + try_to_free_memory(); + ret = malloc(size); + if (!ret && !size) + ret = malloc(1); + if (!ret) { + OUT_STR("Vim: Error: Out of memory.\n"); + preserve_exit(); + } + } + + return ret; +} + +/// Old low level memory allocation function. Prefer xmalloc() from now on. char_u *lalloc(long_u size, int message) { - char_u *p; /* pointer to new storage space */ - static int releasing = FALSE; /* don't do mf_release_all() recursive */ - int try_again; - - /* Safety check for allocating zero bytes */ - if (size == 0) { - /* Don't hide this message */ - emsg_silent = 0; - EMSGN(_("E341: Internal error: lalloc(%ld, )"), size); - return NULL; - } - - /* - * Loop when out of memory: Try to release some memfile blocks and - * if some blocks are released call malloc again. - */ - for (;; ) { - if ((p = (char_u *)malloc((size_t)size)) != NULL) { - /* No check for available memory: Just return. */ - goto theend; - } - /* - * Remember that mf_release_all() is being called to avoid an endless - * loop, because mf_release_all() may call alloc() recursively. - */ - if (releasing) - break; - releasing = TRUE; - - clear_sb_text(); /* free any scrollback text */ - try_again = mf_release_all(); /* release as many blocks as possible */ - try_again |= garbage_collect(); /* cleanup recursive lists/dicts */ - - releasing = FALSE; - if (!try_again) - break; - } - - if (message && p == NULL) - do_outofmem_msg(size); - -theend: - return p; + return (char_u *)xmalloc((size_t)size); } /* diff --git a/src/misc2.h b/src/misc2.h index d8f13d7640..0e52993412 100644 --- a/src/misc2.h +++ b/src/misc2.h @@ -27,6 +27,8 @@ char_u *alloc(unsigned size) FUNC_ATTR_MALLOC FUNC_ATTR_ALLOC_SIZE(1); char_u *alloc_clear(unsigned size) FUNC_ATTR_MALLOC FUNC_ATTR_ALLOC_SIZE(1); char_u *alloc_check(unsigned size) FUNC_ATTR_MALLOC FUNC_ATTR_ALLOC_SIZE(1); char_u *lalloc_clear(long_u size, int message) FUNC_ATTR_MALLOC FUNC_ATTR_ALLOC_SIZE(1); +void try_to_free_memory(); +void *xmalloc(size_t size) FUNC_ATTR_MALLOC FUNC_ATTR_ALLOC_SIZE(1); char_u *lalloc(long_u size, int message) FUNC_ATTR_MALLOC FUNC_ATTR_ALLOC_SIZE(1); void do_outofmem_msg(long_u size); void free_all_mem(void);