summaryrefslogtreecommitdiffstats
path: root/contrib/syslinux-4.02/com32/lib/realloc.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/syslinux-4.02/com32/lib/realloc.c')
-rw-r--r--contrib/syslinux-4.02/com32/lib/realloc.c98
1 files changed, 98 insertions, 0 deletions
diff --git a/contrib/syslinux-4.02/com32/lib/realloc.c b/contrib/syslinux-4.02/com32/lib/realloc.c
new file mode 100644
index 0000000..2969e31
--- /dev/null
+++ b/contrib/syslinux-4.02/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;
+ }
+ }
+}