diff options
author | Sebastian Schmelzer | 2011-03-14 17:51:16 +0100 |
---|---|---|
committer | Sebastian Schmelzer | 2011-03-14 17:51:16 +0100 |
commit | 12e4b1c978975d8cb6f3e13f20b1dbb136166b41 (patch) | |
tree | 959f0e28343389f92313cc318af6de39a4e14c2b /contrib/syslinux/syslinux-4.03/com32/lib/realloc.c | |
download | usb-boot-stick-12e4b1c978975d8cb6f3e13f20b1dbb136166b41.tar.gz usb-boot-stick-12e4b1c978975d8cb6f3e13f20b1dbb136166b41.tar.xz usb-boot-stick-12e4b1c978975d8cb6f3e13f20b1dbb136166b41.zip |
initial commit
Diffstat (limited to 'contrib/syslinux/syslinux-4.03/com32/lib/realloc.c')
-rw-r--r-- | contrib/syslinux/syslinux-4.03/com32/lib/realloc.c | 98 |
1 files changed, 98 insertions, 0 deletions
diff --git a/contrib/syslinux/syslinux-4.03/com32/lib/realloc.c b/contrib/syslinux/syslinux-4.03/com32/lib/realloc.c new file mode 100644 index 0000000..2969e31 --- /dev/null +++ b/contrib/syslinux/syslinux-4.03/com32/lib/realloc.c @@ -0,0 +1,98 @@ +/* + * realloc.c + */ + +#include <stdlib.h> +#include <string.h> +#include <minmax.h> + +#include "malloc.h" + +void *realloc(void *ptr, size_t size) +{ + struct free_arena_header *ah, *nah; + void *newptr; + size_t newsize, oldsize, xsize; + + if (!ptr) + return malloc(size); + + if (size == 0) { + free(ptr); + return NULL; + } + + ah = (struct free_arena_header *) + ((struct arena_header *)ptr - 1); + + /* Actual size of the old block */ + oldsize = ah->a.size; + + /* Add the obligatory arena header, and round up */ + newsize = (size + 2 * sizeof(struct arena_header) - 1) & ARENA_SIZE_MASK; + + if (oldsize >= newsize && newsize >= (oldsize >> 2) && + oldsize - newsize < 4096) { + /* This allocation is close enough already. */ + return ptr; + } else { + xsize = oldsize; + + nah = ah->a.next; + if ((char *)nah == (char *)ah + ah->a.size && + nah->a.type == ARENA_TYPE_FREE && + oldsize + nah->a.size >= newsize) { + /* Merge in subsequent free block */ + ah->a.next = nah->a.next; + ah->a.next->a.prev = ah; + nah->next_free->prev_free = nah->prev_free; + nah->prev_free->next_free = nah->next_free; + xsize = (ah->a.size += nah->a.size); + } + + if (xsize >= newsize) { + /* We can reallocate in place */ + if (xsize >= newsize + 2 * sizeof(struct arena_header)) { + /* Residual free block at end */ + nah = (struct free_arena_header *)((char *)ah + newsize); + nah->a.type = ARENA_TYPE_FREE; + nah->a.size = xsize - newsize; + ah->a.size = newsize; + + /* Insert into block list */ + nah->a.next = ah->a.next; + ah->a.next = nah; + nah->a.next->a.prev = nah; + nah->a.prev = ah; + + /* Insert into free list */ + if (newsize > oldsize) { + /* Hack: this free block is in the path of a memory object + which has already been grown at least once. As such, put + it at the *end* of the freelist instead of the beginning; + trying to save it for future realloc()s of the same block. */ + nah->prev_free = __malloc_head.prev_free; + nah->next_free = &__malloc_head; + __malloc_head.prev_free = nah; + nah->prev_free->next_free = nah; + } else { + nah->next_free = __malloc_head.next_free; + nah->prev_free = &__malloc_head; + __malloc_head.next_free = nah; + nah->next_free->prev_free = nah; + } + } + /* otherwise, use up the whole block */ + return ptr; + } else { + /* Last resort: need to allocate a new block and copy */ + oldsize -= sizeof(struct arena_header); + newptr = malloc(size); + if (newptr) { + memcpy(newptr, ptr, min(size, oldsize)); + free(ptr); + } + return newptr; + } + } +} |