Browse Source

realloc

master
Mathieu Serandour 1 year ago
parent
commit
a03f95d288
  1. 99
      kernel/memory/heap.c
  2. 1
      kernel/memory/heap.h

99
kernel/memory/heap.c

@ -7,6 +7,7 @@
#include "../memory/paging.h"
#include "../lib/logging.h"
#include "../lib/assert.h"
#include "../lib/string.h"
#define MIN_EXPAND_SIZE 1024
@ -151,6 +152,20 @@ static void defragment(void) {
}
}
// return the node preceding the argument
// in the linked list
// O(n) sequential research
static seg_header* find_pred(seg_header* node) {
for(seg_header* seg = current_segment;
seg != NULL;
seg = seg->next) {
if(seg->next == node)
return node;
}
assert(0);
__builtin_unreachable();
}
// try to merge the node with the next one
// we suppose that the argument is free
static inline void try_merge(seg_header* free_node) {
@ -191,28 +206,17 @@ static inline void try_merge(seg_header* free_node) {
// if not, we must find the preceding
// node in the linked list
seg_header* seg = find_pred(free_node);
for(seg_header* seg = current_segment;
seg != NULL;
seg = seg->next) {
if(seg->next == free_node) {
// we found it!
// now make it point on the
// new merged node which is
// the 'next' node
seg->next = next;
// we are done merging!
return;
}
}
// oh no! wtf
// the argument wasn't in the list
assert(0);
// now make it point on the
// new merged node which is
// the 'next' node
seg->next = next;
}
}
/*
* insert a new segment between to_split and pred
* return the new segment
@ -253,7 +257,7 @@ void heap_init(void) {
}
void* __attribute__((noinline)) malloc(size_t size) {
void* malloc(size_t size) {
// align the size to assure that
// the whole structure is alligned
size = ((size + 7 ) / 8) * 8;
@ -324,6 +328,63 @@ void* __attribute__((noinline)) malloc(size_t size) {
return malloc(size);
}
static void realloc_shrink(seg_header* header, size_t size) {
// check if we can actually free some memory
if(header->size - size >= sizeof(seg_header) + MIN_SEGMENT_SIZE) {
split_segment(
find_pred(header), // we need to find the preceding
// node in order to split it
header,
size
);
}
else {
// the difference is not big enough
// to actually free anything
// let's not even change the size
// in the structure
// so that if we do:
// realloc(ptr, size-X);
// realloc(ptr, size);
// no reallocation will be done
}
}
// O(n) in case of freeing (size < oldsize)
void* realloc(void* ptr, size_t size) {
if(ptr == NULL)
return malloc(size);
seg_header* header = ptr - sizeof(seg_header);
if(size <= header->size) {// no need to move
realloc_shrink(header, size);
}
else {
// maybe need reallocation
// mark the node free
header->free = 1;
unsigned old_size = header->size;
// hope for the node to merge with another
defragment();
// check the size again
if(header->size >= size) {
// we have enough space now!
header->free = 0;
realloc_shrink(header, size);
}
else {
// still not enough space
// we have to copy the whole thing
void* new_ptr = malloc(size);
memcpy(new_ptr, ptr, old_size);
}
}
}
// O(1) free
void free(void *ptr) {

1
kernel/memory/heap.h

@ -6,6 +6,7 @@
// free memory
void* malloc(size_t size);
void free(void* p);
void* realloc(void* ptr, size_t size);
void heap_init(void);
#ifndef NDEBUG

Loading…
Cancel
Save