diff options
author | Anton Kling <anton@kling.gg> | 2023-10-22 19:50:38 +0200 |
---|---|---|
committer | Anton Kling <anton@kling.gg> | 2023-10-22 19:50:38 +0200 |
commit | 4e09bca9e34c226b6d7e34b4fa11248405fd988e (patch) | |
tree | 80f156b7940d9d19971395f335530170c69516c7 /userland/libc/malloc/oldmalloc.c |
Move everything into a new repo.
Diffstat (limited to 'userland/libc/malloc/oldmalloc.c')
-rw-r--r-- | userland/libc/malloc/oldmalloc.c | 136 |
1 files changed, 136 insertions, 0 deletions
diff --git a/userland/libc/malloc/oldmalloc.c b/userland/libc/malloc/oldmalloc.c new file mode 100644 index 0000000..042049d --- /dev/null +++ b/userland/libc/malloc/oldmalloc.c @@ -0,0 +1,136 @@ +#include "stdio.h" +#include "stdlib.h" +#include "../errno.h" +#include <stdint.h> +#include <stddef.h> +#include <string.h> + +#define NEW_ALLOC_SIZE 0x1000 + +#define IS_FREE (1 << 0) +#define IS_FINAL (1 << 1) + +typedef struct MallocHeader { + uint32_t size; + uint8_t flags; +} MallocHeader; + +MallocHeader *head = NULL; +MallocHeader *final = NULL; +uint32_t total_heap_size = 0; + +int init_heap(void) { + head = sbrk(NEW_ALLOC_SIZE); + if ((void *)-1 == head) { + // perror("sbrk"); + return 0; + } + total_heap_size += NEW_ALLOC_SIZE; + head->size = NEW_ALLOC_SIZE; + head->flags = IS_FREE | IS_FINAL; + final = head; + return 1; +} + +int add_heap_memory(void) { + if ((void *)-1 == sbrk(NEW_ALLOC_SIZE)) { + // perror("sbrk"); + return 0; + } + total_heap_size += NEW_ALLOC_SIZE; + final->size += NEW_ALLOC_SIZE; + return 1; +} + +MallocHeader *next_header(MallocHeader *a) { + if (a->flags & IS_FINAL) + return NULL; + return ((void *)a) + a->size; +} + +MallocHeader *find_free_entry(uint32_t s) { + // A new header is required as well as the newly allocated chunk + s += sizeof(MallocHeader); + if (!head) + init_heap(); + MallocHeader *p = head; + for (; p; p = next_header(p)) { + if (!(p->flags & IS_FREE)) + continue; + if (p->size < s) + continue; + return p; + } + return NULL; +} + +void merge_headers(MallocHeader *b) { + if (!(b->flags & IS_FREE)) + return; + + MallocHeader *n = next_header(b); + if (!n) + return; + + if (!(n->flags & IS_FREE)) + return; + + // Remove the next header and just increase the newly freed header + b->size += n->size; + b->flags |= n->flags & IS_FINAL; + if (b->flags & IS_FINAL) + final = b; +} + +extern int errno; +// https://pubs.opengroup.org/onlinepubs/9699919799/ +void *malloc(size_t s) { + if(s == 0) + s = 1; + + MallocHeader *free_entry = find_free_entry(s); + if (!free_entry) { + if (!add_heap_memory()) { + errno = ENOMEM; + return NULL; + } + return malloc(s); + } + + // Create a new header + MallocHeader *new_entry = ((void *)free_entry) + s; + new_entry->flags |= IS_FREE; + new_entry->size = free_entry->size - s - sizeof(MallocHeader); + new_entry->flags |= free_entry->flags & IS_FINAL; + if (new_entry->flags & IS_FINAL) + final = new_entry; + merge_headers(new_entry); + + // Modify the free entry + free_entry->size = s; + free_entry->flags = 0; + + return ((void *)free_entry) + sizeof(MallocHeader); +} + +// https://pubs.opengroup.org/onlinepubs/9699919799/ +void *calloc(size_t nelem, size_t elsize) { + // The calloc() function shall allocate unused space for an array of + // nelem elements each of whose size in bytes is elsize. + size_t alloc_size = nelem*elsize; + void *rc = malloc(alloc_size); + // The space shall be initialized to all bits 0. + memset(rc, 0, alloc_size); + return rc; +} + +void free(void *p) { + // FIXME: This assumes that p is at the start of a allocated area. + // Is this a assumption that can be made? + MallocHeader *h = p - sizeof(MallocHeader); + if (h->flags & IS_FREE) + return; + + h->flags |= IS_FREE; + merge_headers(h); +} |