computing-systems-212 / Lab 2: Heap Allocation + Management / task5 / cpen212alloc.c
cpen212alloc.c
Raw
#include <stdlib.h>
#include <string.h>
#include "cpen212alloc.h"

typedef struct {
    void *end;   // end of heap
    void *free;  // next free address on heap
} alloc_state_t;

void *cpen212_init(void *heap_start, void *heap_end) {
    alloc_state_t *s = (alloc_state_t *) malloc(sizeof(alloc_state_t));
    s->end = heap_end;
    s->free = heap_start;
    return s;
}

void cpen212_deinit(void *s) {
    free(s);
}

void *cpen212_alloc(void *alloc_state, size_t nbytes) {
    alloc_state_t *s = (alloc_state_t *) alloc_state;
    size_t aligned_sz = (nbytes + 7) & ~7;

    void* p = s->free;

    if ((p >= s->end) || (p + aligned_sz > s->end)) {
        void* temp = s->free;
        while(temp < s->end) {
            size_t check_hdr = (size_t)(temp); 
            if (check_hdr % 2 == 0){  //sanity check
                check_hdr = aligned_sz++;
                return (void*) check_hdr + 8;
            }
        temp++;
        }
        return NULL;
    }

    size_t hdr = (size_t)s->free;
    s->free += aligned_sz;
    hdr = aligned_sz++;
    return p + 8;
}

void cpen212_free(void *alloc_state, void *p) {
    alloc_state_t *s = (alloc_state_t *) alloc_state;

    void *prev = p - 8;
    void *next = p + *(size_t *)p;

    void* start = s->free;
    void* end = s->end;

    if (p == NULL) {
        return;
    }

    // previous
    if (prev >= start && *(size_t *)prev % 2 == 0) {
        *(size_t *)prev += *(size_t *)p;
        p = prev;
    }
    
    // next
    if (next + 8 < end && *(size_t *)next % 2 == 0) {
        *(size_t *)p += *(size_t *)next;
    }

    if (p + *(size_t *)p == s->end) {
        s->free = p;
    }

    *(size_t *)p = *(size_t *)p | 1;

}

void *cpen212_realloc(void *alloc_state, void *prev, size_t nbytes) {
    alloc_state_t *s = (alloc_state_t *) alloc_state;
    
    if(prev == NULL){
        return cpen212_alloc(s, nbytes);
    }

    if(nbytes == 0){
        cpen212_free(s, prev);
        return NULL;
    }
    
    void *p = cpen212_alloc(s, nbytes);
    if (p != NULL && ((size_t)p % 2 == 0) && (!(p >= s->end) && !(p + ((nbytes + 7) & ~7) > s->end)) ) {
        memmove(p, prev, nbytes);
        cpen212_free(s, prev);
    }

    return p;
}

// WARNING: we don't know the prev block's size, so memmove just copies nbytes here.
//          this is safe only because in this dumb allocator we know that prev < p,
//          and p has at least nbytes usable. in your implementation,
//          you probably need to use the original allocation size.

bool cpen212_check_consistency(void *alloc_state) {
    alloc_state_t *s = (alloc_state_t *) alloc_state;
    return s->end > s->free;
}