diff options
author | Jon Santmyer <jon@jonsantmyer.com> | 2024-04-19 16:11:24 -0400 |
---|---|---|
committer | Jon Santmyer <jon@jonsantmyer.com> | 2024-04-19 16:11:24 -0400 |
commit | 5b1b3bec3f25ea5fc1f48c269f300c4211a1bac7 (patch) | |
tree | d47b7693dd91a8dd08a5c7def418fd132a7032ac /free.c | |
download | heap-5b1b3bec3f25ea5fc1f48c269f300c4211a1bac7.tar.gz heap-5b1b3bec3f25ea5fc1f48c269f300c4211a1bac7.tar.bz2 heap-5b1b3bec3f25ea5fc1f48c269f300c4211a1bac7.zip |
initial commit; mostly documented.
Diffstat (limited to 'free.c')
-rw-r--r-- | free.c | 73 |
1 files changed, 73 insertions, 0 deletions
@@ -0,0 +1,73 @@ +#include "malloc.h" +#include <assert.h> + +bucket_t* +__bucket_from_obj(heap_cache_t *cache, bucket_obj_t *obj) +{ + assert(cache != NULL); + assert(cache->head != NULL); + /* Buckets are always aligned to the nearest page boundary, and that the + * metadata is always below the object. We use this fact to quickly find + * owning buckets.*/ + uintptr_t objptr = (uintptr_t)obj; + uintptr_t bktptr = objptr & ~0xFFF; + while(1) { + /* If the page boundary is below the head, we are below the heap memory + * region and can stop.*/ + if(bktptr < (uintptr_t)cache->head) return NULL; + + /* At each page boundary below the object, check for the heap checksum. + * If it is found, we can assume that we found a bucket.*/ + bucket_t *bucket = (bucket_t*)bktptr; + if(OBJ_VALID(bucket)) { + if(bucket->limit > objptr) return NULL; + return bucket; + } + + bktptr -= BUCKET_ALIGN; + } +} + +void +__free_impl(heap_cache_t *cache, void *ptr) +{ + DBGPRINT("free: asking to free ptr %p\n", ptr); + assert(cache != NULL); + /* free(NULL) does nothing.*/ + if(ptr == NULL) return; + + /* Make sure the pointer actually comes from the heap.*/ + assert((uintptr_t)ptr < (uintptr_t)cache->tail); + assert((uintptr_t)ptr > (uintptr_t)cache->head); + bucket_obj_t *obj = OBJ_FROM_PTR(ptr); + assert(OBJ_VALID(obj)); + + /* Mask the taken bit in the object to mark it free.*/ + DBGPRINT("free: masking taken bit in object %p (was %i, now ", + obj, obj->size_taken); + obj->size_taken &= ~1; + DBGPRINT("%i)\n", obj->size_taken); + + /* If the buckets' lastfree is greater than this new free object, this + * object will be the lastfree.*/ + bucket_t *bucket = __bucket_from_obj(cache, obj); + if(bucket != NULL && bucket->firstfree > obj) + bucket->firstfree = obj; + + /* Start trying to merge this free object with the next object. + * If the object after is taken, do nothing.*/ + bucket_obj_t *after = OBJ_AFTER(obj); + if((uintptr_t)after > bucket->limit) return; + assert(OBJ_VALID(after)); + if(OBJ_TAKEN(after)) return; + + /* Merge with the next object. + * from: + * [meta| -objw-][meta| -afterw-] + * to: + * [meta| ---------objw---------]*/ + DBGPRINT("free: obj %p merging with adjacent free object %p (was %i, now \n", + obj, after, obj->size_taken); + obj->size_taken += sizeof(bucket_obj_t) + after->size_taken; + DBGPRINT("%i)\n", obj->size_taken); +} |