/* * heap_add_segment.c */ #include #include #include "private.h" #include "context.h" #include "lub/bintree.h" typedef struct { const lub_heap_segment_t *segment; } lub_heap_segment_key_t; /*--------------------------------------------------------- */ static int lub_heap_segment_compare(const void *clientnode, const void *clientkey) { const lub_heap_segment_t * segment = clientnode; const lub_heap_segment_key_t * key = clientkey; return ((long)segment - (long)key->segment); } /*--------------------------------------------------------- */ /* we simply use the segment address as the index */ static void lub_heap_segment_getkey(const void *clientnode, lub_bintree_key_t *key) { lub_heap_segment_key_t clientkey; clientkey.segment = clientnode; memcpy(key,&clientkey,sizeof(lub_heap_segment_key_t)); } /*--------------------------------------------------------- */ static void lub_heap_segment_meta_init() { static bool_t initialised = BOOL_FALSE; if(BOOL_FALSE == initialised) { lub_heap_leak_t *leak = lub_heap_leak_instance(); initialised = BOOL_TRUE; /* initialise the segment tree */ lub_bintree_init(&leak->m_segment_tree, offsetof(lub_heap_segment_t,bt_node), lub_heap_segment_compare, lub_heap_segment_getkey); lub_heap_leak_release(leak); } } /*--------------------------------------------------------- */ const lub_heap_segment_t * lub_heap_segment_findnext(const void *address) { lub_heap_segment_t *segment; lub_heap_segment_key_t key; lub_heap_leak_t *leak = lub_heap_leak_instance(); key.segment = address; segment = lub_bintree_findnext(&leak->m_segment_tree,&key); lub_heap_leak_release(leak); return segment; } /*--------------------------------------------------------- */ /* * as an optimisation this could be modified to merge * adjacent segments together */ void lub_heap_add_segment(lub_heap_t *this, void *start, size_t size) { lub_heap_segment_t *segment; /* check for simple adjacent segment as produced by sbrk() type behaviour */ if(this->first_segment.words) { lub_heap_tag_t *tail; char *ptr = (char*)&this[1]; ptr += (this->first_segment.words << 2); if(ptr == start) { /* simply extend the current first segment */ this->first_segment.words += (size >> 2); tail = &((lub_heap_tag_t*)start)[-1]; tail->segment = BOOL_FALSE; /* no longer last block in segment */ /* convert the new memory into a free block... */ lub_heap_init_free_block(this,start,size,BOOL_FALSE,BOOL_TRUE); /* try and merge with the previous block */ lub_heap_merge_with_previous(this,start); this->stats.segs_bytes += size; return; } } /* adjust the size which can be used */ size -= sizeof(lub_heap_segment_t); /* set up the linked list of segments */ segment = start; /* update the stats */ ++this->stats.segs; this->stats.segs_bytes += size; this->stats.segs_overhead += sizeof(lub_heap_segment_t); if(segment != &this->first_segment) { /* maintain the list of segments */ segment->next = this->first_segment.next; this->first_segment.next = segment; } segment->words = (size >> 2); lub_heap_init_free_block(this,&segment[1],size,BOOL_TRUE,BOOL_TRUE); /* add this segment to the tree */ lub_heap_segment_meta_init(); lub_bintree_node_init(&segment->bt_node); { lub_heap_leak_t *leak = lub_heap_leak_instance(); lub_bintree_insert(&leak->m_segment_tree,segment); lub_heap_leak_release(leak); } } /*--------------------------------------------------------- */