BarryServer : Git

All the code for all my projects
// BarryServer : Git / OrionLibC / commit / 03048a95d88cc7a78171393371f5c22a0250a014 / stdlib / malloc.c

// Related

OrionLibC

Barry Importing existing Orion LibC 03048a9 (2 years, 2 months ago)
diff --git a/stdlib/malloc.c b/stdlib/malloc.c
new file mode 100644
index 0000000..cd19760
--- /dev/null
+++ b/stdlib/malloc.c
@@ -0,0 +1,157 @@
+#include <stdint.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <errno.h>
+
+#define BLOCK_SIZE 16
+
+typedef struct Header Header;
+typedef struct Arena Arena;
+
+extern char _end[];
+
+/* Structure for a Memory Header */
+struct Header {
+	Header *prev, *next;
+	size_t size;
+	char magic[4];
+};
+
+/* Structure for a Memory Arena */
+struct Arena {
+	Arena *next;
+	void *start, *end;
+	size_t size;
+};
+
+Arena primaryArena = {
+	.next = NULL,
+	.start = NULL,
+	.end = NULL,
+	.size = 0
+};
+
+/* Allocate a region of memory in an arena */
+static void *
+arena_malloc(Arena *arena, size_t size)
+{
+	size_t blockSize, gapSize;
+	intptr_t blockEnd;
+	Header *prev, *head, *next;
+	head = prev = arena->start;
+	next = NULL;
+
+	/* Minimum allocation */
+	if (size % BLOCK_SIZE)
+		size += BLOCK_SIZE - (size % BLOCK_SIZE);
+
+	/* Block does not exist, create heap */
+	if (head->prev != head || memcmp(head->magic, "HEAP", 4)) {
+		head->prev = head;
+		head->next = NULL;
+		head->size = size;
+		memcpy(head->magic, "HEAP", 4);
+		memset((void *) (head + 1), 0, size);
+		return (void *) (head + 1);
+	}
+
+	/* Find gap */
+	while (head->next) {
+		next = head->next;
+		blockSize = sizeof(Header) + head->size;
+		blockEnd = (uintptr_t) head + blockSize;
+		gapSize = (size_t) next - blockEnd;
+		prev = head;
+
+		/* Fit in gap */
+		if (gapSize >= size + sizeof(Header)) {
+			head = (void *) blockEnd;
+			head->next = next;
+			head->prev = prev;
+			prev->next = head;
+			next->prev = head;
+			head->size = size;
+			memcpy(head->magic, "HEAP", 4);
+			memset((void *) (head + 1), 0, size);
+			return (void *) (head + 1);
+		}
+
+		head = head->next;
+	}
+
+	/* Add to end */
+	blockSize = sizeof(Header) + head->size;
+	blockEnd = (uintptr_t) head + blockSize;
+	/* Ensure more arenas can be allocated */
+	gapSize = (size_t) arena->end - blockEnd - sizeof(Arena);
+	/* Fit in gap */
+	if (gapSize >= size + sizeof(Header)) {
+		prev = head;
+		head = (void *) blockEnd;
+		head->next = NULL;
+		head->prev = prev;
+		prev->next = head;
+		head->size = size;
+		memcpy(head->magic, "HEAP", 4);
+		memset((void *) (head + 1), 0, size);
+		return (void *) (head + 1);
+	}
+
+	return NULL;
+}
+
+/* Allocate a region of memory */
+void *
+malloc(size_t size)
+{
+	void *addr = NULL;
+	Arena *arena;
+	size_t arenaSize = 64 * 1024;
+	while (arenaSize < size + sizeof(Arena))
+		arenaSize += 64 * 1024;
+
+	for (arena = &primaryArena; !addr; arena = arena->next) {
+		/* Allocate a new arena */
+		if (!arena->size) {
+			arena->size = arenaSize;
+			arena->start = mmap(NULL, arena->size,
+			                    PROT_READ | PROT_WRITE,
+			                    MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
+			if (arena->start == MAP_FAILED) {
+				errno = ENOMEM;
+				return NULL;
+			}
+			arena->end = arena->start + arena->size;
+		}
+
+		/* Attempt to use arena */
+		addr = arena_malloc(arena, size);
+		if (!addr && !arena->next)
+			arena->next = arena_malloc(arena, sizeof(Arena));
+	}
+
+	return addr;
+}
+
+/* Free an allocated region of memory */
+void
+free(void *addr)
+{
+	Header *prev, *head, *next;
+	head = (Header *) addr - 1;
+	if (memcmp(head->magic, "HEAP", 4)) {
+		printf("free(): invalid pointer\n");
+		abort();
+	}
+	prev = head->prev;
+	next = head->next;
+	memset(head, 0, sizeof(Header));
+
+	if (prev != head)
+		prev->next = next;
+	if (next)
+		next->prev = prev;
+}