summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libc/stdlib/malloc/alloc.c139
1 files changed, 132 insertions, 7 deletions
diff --git a/libc/stdlib/malloc/alloc.c b/libc/stdlib/malloc/alloc.c
index 5282c140a..5e508f9c1 100644
--- a/libc/stdlib/malloc/alloc.c
+++ b/libc/stdlib/malloc/alloc.c
@@ -3,6 +3,28 @@
#include <stdio.h>
#include <stdlib.h>
+struct chunkControl {
+ size_t nodeCount;
+ size_t chunkSize;
+};
+
+struct nodeControl {
+ struct chunkControl *chunk;
+ size_t nodeSize;
+};
+
+#define ROUND_UP_LENGTH(len) ((len+7) & ~0x07)
+
+extern struct nodeControl *mallocNextNode;
+
+#ifdef L_malloc
+/* This variable is a pointer to the next place to allocate from.
+ * Note: This variable makes the code NOT thread save. */
+struct nodeControl *mallocNextNode = 0;
+static size_t PageSize = 0;
+
+#endif
+
#ifdef L_calloc_dbg
void *
@@ -61,12 +83,64 @@ calloc(size_t num, size_t size)
void *
malloc(size_t len)
{
- void * result = mmap((void *)0, len, PROT_READ | PROT_WRITE,
- MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
- if (result == (void*)-1)
- return 0;
-
- return result;
+ void *result;
+ struct chunkControl *chunk;
+ struct nodeControl *next;
+ size_t size;
+
+ /* round len up to keep things on even boundaries */
+ len = ROUND_UP_LENGTH(len);
+
+ if (len == 0)
+ return 0;
+
+TryAgain:
+ if (mallocNextNode != 0) {
+ /* first see if this request will fit on this chunk */
+ next = mallocNextNode;
+ chunk = next->chunk;
+ if (((char *)next + sizeof(struct nodeControl)*2 + len) <
+ ((char *)chunk + chunk->chunkSize))
+ {
+ /* this request will fit, so simply move the next
+ * pointer ahead and update chunk node count */
+ next->nodeSize = len;
+ result = (char *)next + sizeof(struct nodeControl);
+ chunk->nodeCount++;
+ next = (struct nodeControl *)
+ ((char *)next + (sizeof(struct nodeControl) + len));
+ next->chunk = chunk;
+ next->nodeSize = 0;
+ mallocNextNode = next;
+
+ return result; /* normal return path */
+ }
+
+ }
+
+ /* the request will not fit on this chunk, so get another chunk */
+ if (PageSize == 0) {
+ PageSize = getpagesize();
+ }
+ size = len + (sizeof(struct chunkControl) + (sizeof(struct nodeControl) * 2));
+ if (size < PageSize * 2) {
+ size = PageSize * 2;
+ }
+ size = (size + (PageSize-1)) & ~(PageSize-1);
+
+ chunk = mmap((void *)0, size, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
+ if (chunk == (void*)-1)
+ return 0;
+
+ chunk->chunkSize = size;
+ chunk->nodeCount = 0;
+ next = (struct nodeControl *)
+ ((char *)chunk + sizeof(struct chunkControl));
+ next->chunk = chunk;
+ mallocNextNode = next;
+
+ goto TryAgain;
}
#endif
@@ -76,7 +150,58 @@ malloc(size_t len)
void
free(void * ptr)
{
- munmap(ptr, 0);
+ struct chunkControl *chunk;
+ struct nodeControl *node;
+
+ if (ptr == 0) {
+ return;
+ }
+ /* get a pointer to the control information for this memory node
+ * and the chunk it belongs to */
+ node = (struct nodeControl *)ptr - 1;
+ chunk = node->chunk;
+ /* decrement the node count and if it is zero free the chunk */
+ chunk->nodeCount--;
+ if (chunk->nodeCount == 0) {
+ if ((void *)mallocNextNode >= (void *)chunk &&
+ ((void *)mallocNextNode < (void *)((char *)chunk + chunk->chunkSize)))
+ {
+ mallocNextNode = 0;
+ }
+ munmap(chunk, chunk->chunkSize);
+ }
}
#endif
+
+#ifdef L_realloc
+
+void *
+realloc(void *ptr, size_t len)
+{
+ struct nodeControl *node;
+ size_t oldSize;
+ void *new;
+
+
+ if (ptr == 0) {
+ return malloc(len);
+ }
+ if (len == 0) {
+ free(ptr);
+ return 0;
+ }
+ node = (struct nodeControl *)ptr - 1;
+ oldSize = node->nodeSize;
+ if (oldSize >= len) {
+ return ptr;
+ }
+
+ new = malloc(len);
+ memcpy(new, ptr, len);
+ free(ptr);
+ return new;
+}
+
+#endif
+