Yet Another Malloc.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

166 lines
4.7 KiB

/*
* Yet Another Malloc
* yamalloc.c
*/
/*----------*/
/* Includes */
/*----------*/
#include "yamalloc.h"
#include "ya_debug.h"
#include "ya_block.h"
#include "ya_freelist.h"
/*----------------------*/
/* Function definitions */
/*----------------------*/
/* Splits block both at the block level and in the free list. */
void split(intptr_t *block, intptr_t size) {
fl_mend_split(block, block_split(block, size));
}
/* Coalesces block with neighbors if possible, both at the block level and in
* the free list. */
void join(intptr_t *block) {
fl_join(block);
block_join(block);
}
/* Allocates enough memory to store at least size bytes.
* Returns a dword-aligned pointer to the memory or NULL in case of failure. */
void *malloc(size_t n_bytes) {
if (n_bytes == 0) {
return NULL;
}
if (heap_start == NULL || heap_end == NULL) {
if (!heap_init()) {
return NULL;
}
}
intptr_t size = block_fit(n_bytes);
intptr_t *block = block_find(size);
if (!block) {
block = heap_extend(n_bytes);
}
split(block, size);
block_alloc(block);
fl_alloc(block);
return block;
}
/* Frees the memory block pointed to by ptr, which must have been allocated
* through a call to malloc, calloc or realloc before. Otherwise, undefined
* behavior occurs. */
void free(void *ptr) {
intptr_t *block = ptr;
if (block < heap_start || block > heap_end || !block_is_alloc(block)) {
return; // TODO: provoke segfault
}
block_free(block);
fl_free(block);
join(block);
}
/* Allocates enough memory to store an array of nmemb elements,
* each size bytes large, and clears the memory.
* Returns the pointer to the allocated memory or NULL in case of failure. */
void *calloc(size_t nmemb, size_t n_bytes) {
intptr_t *block = malloc(n_bytes * nmemb);
intptr_t size = block_size(block);
block_clear(block);
return block;
}
/* Resizes the previously allocated memory pointed to by ptr to size.
* If ptr is NULL, it is equivalent to malloc(size).
* If called with size 0, it is equivalent to free(ptr).
* If ptr does not point to memory previously allocated by malloc, calloc or
* realloc, undefined behavior occurs.
* */
void *realloc(void *ptr, size_t n_bytes) {
if (!ptr) {
return malloc(n_bytes);
}
if (n_bytes == 0) {
free(ptr);
return NULL;
}
intptr_t *block = ptr;
if (block < heap_start) {
return NULL; // TODO: provoke segfault
}
intptr_t new_size = block_fit(n_bytes);
intptr_t size = block_size(block); // segfault if ptr after heap end
if (new_size == size) {
return ptr; // don't change anything
}
if (new_size < size) {
intptr_t *next = block_split(block, new_size);
if (next) {
fl_free(next); // add the next from the free list
fl_join_next(next);
block_join_next(next); // coalesce the leftovers
}
block_alloc(block);
// no need to remove it from the free list, it wasn't in it
return block;
}
intptr_t *next = block + size;
if (next == heap_end || next == fl_get_end()) {
// grow the heap and extend block
next = heap_extend(n_bytes);
// then fall into next if clause which will use the newly extended
// heap to extend the block without moving it
}
// try to use next free block
if (next < heap_end) {
intptr_t next_size = block_size(next);
if (!block_is_alloc(next) && new_size <= size + next_size) {
// try to split the next block at the right size
split(next, new_size - size);
fl_alloc(next); // remove the next block from the free list
block_join_next(block); // coalesce
block_alloc(block); // mark block as allocated
return block;
}
}
// resizing failed, so allocate a whole new block and copy
intptr_t *new_block = malloc(n_bytes);
for (int i = 0; i < size; i++) {
new_block[i] = block[i];
}
free(block);
return new_block;
}
#ifdef YA_DEBUG
/* Print all blocks in the heap */
void ya_print_blocks() {
ya_debug("All blocks:\n");
block_print_range(heap_start, heap_end);
ya_debug("Free blocks:\n");
fl_debug_print();
}
/* Checks internal state for errors.
* Returns -1 on error, 0 otherwise. */
int ya_check() {
int heap_free = heap_check();
if (heap_free == -1) {
return -1;
}
int fl_free = fl_check();
if (fl_free == -1) {
return -1;
}
if (fl_free != heap_free) {
ya_debug("ya_check: heap_check reports %d free blocks, fl_check %d\n",
heap_free, fl_free);
return -1;
}
return 0;
}
#endif