diff --git a/src/jalloc.c b/src/jalloc.c index 30308a0..d771493 100644 --- a/src/jalloc.c +++ b/src/jalloc.c @@ -1,16 +1,15 @@ +#include #include #include #include #include +#include #define HEAP_SIZE (1024 * 1024 * 2) #define ALIGNMENT 16 #define HEADER_SIZE 32 #define FOOTER_SIZE 16 -static uint8_t heap[HEAP_SIZE]; -static uint8_t *heap_ptr = heap; - struct Header { size_t size; bool is_free; @@ -21,38 +20,156 @@ struct Footer { struct Header *header; }; +struct Block { + struct Header *header; + struct Block *next; +}; + +static uint8_t heap[HEAP_SIZE]; +static struct Block *free_stack; +static bool initialized = false; + + + +struct Footer *footer(struct Header *hdr) { + return (struct Footer *)((uint8_t *)hdr + hdr->size); +} + +struct Block *pop_first_fit(size_t size) { + struct Block *head = free_stack; + if (head->header->size >= size) { + free_stack = head->next; // remove from free stack + return head; + } + while (head != NULL) { + struct Block *next = head->next; + if (next == NULL) return NULL; + if (next->header->size >= size) { + head->next = next->next; // remove from free stack + return next; + } + head = next; + } + return NULL; +} + +struct Block *pop(struct Block *ptr) { + struct Block *head = free_stack; + if (head == ptr) { + free_stack = head->next; + return head; + } + while (head != NULL) { + struct Block *next = head->next; + if (next == NULL) break; // if next is NULL, deref below will fault + if (next == ptr) { + head->next = next->next; + return next; + } + } + return NULL; +} + +struct Block *push_header(struct Header *hdr) { + struct Block *blk = malloc(sizeof(struct Block)); + blk->header = hdr; + blk->next = free_stack; + free_stack = blk; +} + +struct Block *pop_header(struct Header *ptr) { + return NULL; +} + size_t next_multiple_of_align(size_t size) { return ((size + (ALIGNMENT - 1)) >> 4) << 4; } +void initialize() { + // initialize the free list to be a single element containing the entire block + size_t initial_block_size = HEAP_SIZE - (HEADER_SIZE + FOOTER_SIZE); + free_stack = malloc(sizeof(struct Block)); + // write a header + struct Header *hdr = (struct Header *) heap; // first two alignment slots taken by initial header + push_header(hdr); + free_stack->header->is_free = true; + free_stack->header->size = initial_block_size; + free_stack->header->next = NULL; + free_stack->next = NULL; + // write a footer to heap + struct Footer *ftr = (struct Footer *) (heap + initial_block_size - ALIGNMENT); + ftr->header = hdr; + initialized = true; +} + +struct Block *shrink(struct Block *ptr, size_t size) { + // given a size, shrink a block down to the appropriate alignment. + // if align(size) + ALIGNMENT*3 is equal to current size, just return initial ptr with noop + // otherwise, shrink it down so that we have two blocks. + // Push the right block to the free stack + // Return left block + size = next_multiple_of_align(size); // align if not already so + struct Header *hdr = ptr->header; + size_t other_size = hdr->size-size-(HEADER_SIZE + FOOTER_SIZE); + // if we have space for a full alignment, then a single block of 16 bytes can be allocated there + if (other_size >= ALIGNMENT) { + hdr->size = size; // resize left block + // create our footer + struct Footer *ftr = footer(hdr); + ftr->header = hdr; + // create next header + struct Header *next_hdr = (struct Header *)((uint8_t *)ftr + FOOTER_SIZE); + next_hdr->size = other_size; + next_hdr->is_free = true; + next_hdr->next = hdr->next; + hdr->next = next_hdr; + // create next footer + struct Footer *next_ftr = footer(next_hdr); + next_ftr->header = next_hdr; + + // push new block to stack + push_header(next_hdr); + } + return ptr; +} + /** * Allocate memory via bump allocation */ void *jalloc(size_t size) { + if (!initialized) initialize(); // Total size of allocation = HEADER(padded to ALIGNMENT) + size(padded to ALIGNMENT) + FOOTER(padded to ALIGNMENT) size_t aligned_size = next_multiple_of_align(size); - void *ptr = heap_ptr + HEADER_SIZE; - struct Header *hdr = (struct Header *)heap_ptr; - struct Footer *ftr = (struct Footer *)(ptr + aligned_size); - if ((uint8_t *)ftr + FOOTER_SIZE > (uint8_t *)heap + sizeof(heap)) return NULL; - heap_ptr = (void *) ftr + FOOTER_SIZE; // set next ptr + struct Block *blk = pop_first_fit(aligned_size); + if (blk == NULL) return NULL; + + blk = shrink(blk, aligned_size); + + struct Header *hdr = blk->header; + struct Footer *ftr = footer(hdr); + uint8_t* heap_ptr = (void *) ftr + FOOTER_SIZE; // set next ptr if ((uint8_t *)heap_ptr > (heap + HEAP_SIZE)) heap_ptr = NULL; hdr->size = aligned_size; hdr->next = (struct Header *)heap_ptr; hdr->is_free = false; ftr->header = hdr; - return ptr; + return (void*)hdr + HEADER_SIZE; } void jfree(void *ptr) { + printf("freeing\n\n"); struct Header *hdr = (struct Header *)(ptr-HEADER_SIZE); struct Footer *ftr = (struct Footer *)((uint8_t *)hdr+hdr->size); hdr->is_free = true; if ((uint8_t *)hdr > heap) { // if this is greater, then there ought to be a foot to the left + printf("checking coalescing left\n\n"); struct Footer *prev_ftr = (struct Footer *)((uint8_t *)hdr-FOOTER_SIZE); struct Header *prev_hdr = prev_ftr->header; if (prev_hdr->is_free) { + printf("coalescing left\n\n"); + pop_header(prev_hdr); + printf("header popped\n\n"); prev_hdr->size += hdr->size + HEADER_SIZE + FOOTER_SIZE; prev_hdr->next=hdr->next; ftr->header=prev_hdr; @@ -60,13 +177,24 @@ void jfree(void *ptr) { } } if (hdr->next != NULL) { + printf("checking coalescing right\n\n"); struct Header *next_hdr = hdr->next; - struct Footer *next_ftr = (struct Footer *) ((uint8_t *)next_hdr + next_hdr->size); + struct Footer *next_ftr = footer(next_hdr); + assert(next_ftr != NULL); + assert(next_ftr->header != NULL); if (next_hdr->is_free) { + printf("coalescing right\n\n"); + pop_header(next_hdr); + printf("header popped\n\n"); hdr->size += next_hdr->size + HEADER_SIZE + FOOTER_SIZE; hdr->next = (struct Header *) ((uint8_t*)next_ftr + FOOTER_SIZE); + if ((uint8_t *)hdr->next > (heap + HEAP_SIZE)) hdr->next = NULL; + printf("set next\n\n"); + printf("next ftr?: %s\n\n", (uint8_t*)next_ftr); next_ftr->header = hdr; ftr = next_ftr; } } + printf("pushing free header\n\n"); + push_header(hdr); }