]> git.corax.cc Git - corax/commitdiff
Add heap implementation for use in drivers and system services
authorMatthias Kruk <m@m10k.eu>
Wed, 18 Dec 2019 06:38:18 +0000 (15:38 +0900)
committerMatthias Kruk <m@m10k.eu>
Wed, 18 Dec 2019 06:38:18 +0000 (15:38 +0900)
kernel/include/kheap.h [new file with mode: 0644]
kernel/klibc/Makefile
kernel/klibc/heap.c [new file with mode: 0644]

diff --git a/kernel/include/kheap.h b/kernel/include/kheap.h
new file mode 100644 (file)
index 0000000..d91bbb8
--- /dev/null
@@ -0,0 +1,22 @@
+#ifndef __KHEAP_H
+#define __KHEAP_H
+
+#include <config.h>
+#include <corax/types.h>
+#include <sys/types.h>
+#include <spinlock.h>
+
+typedef struct {
+       spinlock_t h_lock;
+       void       *h_base;
+       void       *h_brk;
+       size_t     h_size;
+       size_t     h_free;
+} kheap_t;
+
+int kheap_init(kheap_t*, size_t);
+int kheap_alloc(kheap_t*, size_t, void**);
+int kheap_free(kheap_t*, void*);
+
+
+#endif /* __KHEAP_H */
index f4f88a05bdc7b38bf28e698b81a7cf361b1d786e..f2bb415e06df8172043109ee223ee23848cf1495 100644 (file)
@@ -1,5 +1,5 @@
 OUTPUT = klibc.a
-OBJECTS = string.o spinlock.o mutex.o posixcall.o coraxcall.o
+OBJECTS = string.o spinlock.o mutex.o posixcall.o coraxcall.o heap.o
 PHONY = clean
 INCLUDES = -I../include -I../../include -I../..
 CFLAGS = -m32 -Wall -nostdlib -nodefaultlibs -nostartfiles -ffreestanding $(INCLUDES)
diff --git a/kernel/klibc/heap.c b/kernel/klibc/heap.c
new file mode 100644 (file)
index 0000000..6c06c95
--- /dev/null
@@ -0,0 +1,168 @@
+#include <config.h>
+#include <corax/types.h>
+#include <corax/errno.h>
+#include <mutex.h>
+#include <unistd.h>
+#include <kheap.h>
+#include <string.h>
+
+#define FLAG_USED (1 << 0)
+
+struct heap_node {
+       struct heap_node *next;
+       size_t size;
+       size_t flags;
+};
+
+int kheap_init(kheap_t *heap, size_t size)
+{
+       struct heap_node *obj;
+       int ret_val;
+
+       ret_val = -EINVAL;
+
+       if(heap) {
+               heap->h_base = sbrk(0);
+               heap->h_brk = sbrk((ssize_t)size);
+
+               if(heap->h_base != (void*)-1 && heap->h_brk != (void*)-1) {
+                       heap->h_size = (size_t)heap->h_brk - (size_t)heap->h_base;
+                       heap->h_lock = 0;
+
+                       obj = (struct heap_node*)heap->h_base;
+                       obj->next = NULL;
+                       obj->size = heap->h_size - sizeof(*obj);
+                       obj->flags = 0;
+
+                       heap->h_free = heap->h_size - sizeof(*obj);
+
+                       ret_val = 0;
+               } else {
+                       ret_val = -ENOMEM;
+               }
+       }
+
+       return(ret_val);
+}
+
+static int _kheap_grow(kheap_t *heap, const size_t size)
+{
+       struct heap_node *last;
+       struct heap_node *new;
+       int ret_val;
+       size_t new_size;
+
+       ret_val = -ENOMEM;
+
+       /* old brk is the start of the new heap object */
+       new = (struct heap_node*)heap->h_brk;
+       /* attempt to grow the heap */
+       heap->h_brk = sbrk((ssize_t)size);
+
+       new_size = (size_t)heap->h_brk - (size_t)new;
+
+       if(new_size > sizeof(*new)) {
+               /* find the last node */
+               for(last = (struct heap_node*)heap->h_base;
+                       last->next; last = last->next);
+
+               new->next = NULL;
+               new->size = new_size - sizeof(*new);
+               new->flags = 0;
+
+               last->next = new;
+               heap->h_size += new_size;
+               heap->h_free += new->size;
+               ret_val = 0;
+       }
+
+       return(ret_val);
+}
+
+void* heap_alloc(kheap_t *heap, size_t size)
+{
+       struct heap_node *cur;
+       void *ret_val;
+       int err;
+
+       ret_val = NULL;
+       err = 0;
+
+       spinlock_lock(&(heap->h_lock));
+
+       if(heap->h_free < size) {
+               err = _kheap_grow(heap, size);
+       }
+
+       if(!err) {
+               for(cur = (struct heap_node*)heap->h_base;
+                       cur; cur = cur->next) {
+                       if(cur->flags & FLAG_USED) {
+                               continue;
+                       }
+
+                       if(cur->size < size) {
+                               continue;
+                       }
+
+                       /* get a pointer to the available memory */
+                       ret_val = (void*)(cur + 1);
+
+                       cur->flags |= FLAG_USED;
+
+                       /* split the heap node, if possible */
+                       if(cur->size > (size + sizeof(struct heap_node))) {
+                               struct heap_node *new;
+
+                               new = (struct heap_node*)(ret_val + size);
+                               new->size = cur->size - size - sizeof(*new);
+                               new->next = cur->next;
+                               new->flags = 0;
+
+                               cur->size = size;
+                               cur->next = new;
+
+                               heap->h_free -= sizeof(*new);
+                       }
+
+                       memset(ret_val, 0, size);
+                       heap->h_free -= size;
+
+                       break;
+               }
+       }
+
+       spinlock_unlock(&(heap->h_lock));
+
+       return(ret_val);
+}
+
+void heap_free(kheap_t *heap, void *ptr)
+{
+       struct heap_node *cur;
+
+       spinlock_lock(&(heap->h_lock));
+
+       for(cur = (struct heap_node*)heap->h_base;
+               cur;
+               cur = cur->next) {
+               void *base;
+
+               base = (void*)(cur + 1);
+
+               if(base <= ptr && (base + cur->size) > ptr) {
+                       if(!(cur->flags & FLAG_USED)) {
+                               /* double free */
+                       } else {
+                               cur->flags ^= FLAG_USED;
+                               heap->h_free += cur->size;
+                       }
+
+                       break;
+               }
+       }
+
+       spinlock_unlock(&(heap->h_lock));
+
+       return;
+}