void flower_check(Flower *flower) { eventTree_check(flower_getEventTree(flower)); Flower_GroupIterator *groupIterator = flower_getGroupIterator(flower); Group *group; while ((group = flower_getNextGroup(groupIterator)) != NULL) { group_check(group); } flower_destructGroupIterator(groupIterator); Flower_ChainIterator *chainIterator = flower_getChainIterator(flower); Chain *chain; while ((chain = flower_getNextChain(chainIterator)) != NULL) { chain_check(chain); } flower_destructCapIterator(chainIterator); //We check built trees in here. Flower_EndIterator *endIterator = flower_getEndIterator(flower); End *end; while ((end = flower_getNextEnd(endIterator)) != NULL) { end_check(end); end_check(end_getReverse(end)); //We will test everything backwards also. } flower_destructEndIterator(endIterator); if (flower_builtFaces(flower)) { Flower_FaceIterator *faceIterator = flower_getFaceIterator(flower); Face *face; while ((face = flower_getNextFace(faceIterator)) != NULL) { face_check(face); } flower_destructFaceIterator(faceIterator); face_checkFaces(flower); } else { cactusCheck(flower_getFaceNumber(flower) == 0); } if (flower_builtBlocks(flower)) { //Note that a flower for which the blocks are not yet built must be a leaf. Flower_BlockIterator *blockIterator = flower_getBlockIterator(flower); Block *block; while ((block = flower_getNextBlock(blockIterator)) != NULL) { block_check(block); block_check(block_getReverse(block)); //We will test everything backwards also. } flower_destructBlockIterator(blockIterator); } else { cactusCheck(flower_isLeaf(flower)); //Defensive cactusCheck(flower_isTerminal(flower)); //Checks that a flower without built blocks is a leaf and does not //contain any blocks. } Flower_SequenceIterator *sequenceIterator = flower_getSequenceIterator(flower); Sequence *sequence; while ((sequence = flower_getNextSequence(sequenceIterator)) != NULL) { sequence_check(sequence); } flower_destructSequenceIterator(sequenceIterator); }
/** Free a memory block * * @param addr The address of the block. * */ void free(const void *addr) { if (addr == NULL) return; futex_down(&malloc_futex); /* Calculate the position of the header. */ heap_block_head_t *head = (heap_block_head_t *) (addr - sizeof(heap_block_head_t)); block_check(head); malloc_assert(!head->free); heap_area_t *area = head->area; area_check(area); malloc_assert((void *) head >= (void *) AREA_FIRST_BLOCK_HEAD(area)); malloc_assert((void *) head < area->end); /* Mark the block itself as free. */ head->free = true; /* Look at the next block. If it is free, merge the two. */ heap_block_head_t *next_head = (heap_block_head_t *) (((void *) head) + head->size); if ((void *) next_head < area->end) { block_check(next_head); if (next_head->free) block_init(head, head->size + next_head->size, true, area); } /* Look at the previous block. If it is free, merge the two. */ if ((void *) head > (void *) AREA_FIRST_BLOCK_HEAD(area)) { heap_block_foot_t *prev_foot = (heap_block_foot_t *) (((void *) head) - sizeof(heap_block_foot_t)); heap_block_head_t *prev_head = (heap_block_head_t *) (((void *) head) - prev_foot->size); block_check(prev_head); if (prev_head->free) block_init(prev_head, prev_head->size + head->size, true, area); } heap_shrink(area); futex_up(&malloc_futex); }
static struct block *block_find(const void *ptr) { struct block *block; LOG(("block_find; ptr=0x%x\n", ptr)); assert(ptr); /* locate block based on pointer, then check whether it is valid */ block = (struct block *) page_round_down( (unsigned long) ((struct block *) __UNCONST(ptr) - 1)); block_check(block); LOG(("block_find; block=0x%x\n", block)); return block; }
/** Reallocate memory block * * @param addr Already allocated memory or NULL. * @param size New size of the memory block. * * @return Reallocated memory or NULL. * */ void *realloc(const void *addr, const size_t size) { if (addr == NULL) return malloc(size); futex_down(&malloc_futex); /* Calculate the position of the header. */ heap_block_head_t *head = (heap_block_head_t *) (addr - sizeof(heap_block_head_t)); block_check(head); malloc_assert(!head->free); heap_area_t *area = head->area; area_check(area); malloc_assert((void *) head >= (void *) AREA_FIRST_BLOCK_HEAD(area)); malloc_assert((void *) head < area->end); void *ptr = NULL; bool reloc = false; size_t real_size = GROSS_SIZE(ALIGN_UP(size, BASE_ALIGN)); size_t orig_size = head->size; if (orig_size > real_size) { /* Shrink */ if (orig_size - real_size >= STRUCT_OVERHEAD) { /* * Split the original block to a full block * and a trailing free block. */ block_init((void *) head, real_size, false, area); block_init((void *) head + real_size, orig_size - real_size, true, area); heap_shrink(area); } ptr = ((void *) head) + sizeof(heap_block_head_t); } else { /* * Look at the next block. If it is free and the size is * sufficient then merge the two. Otherwise just allocate * a new block, copy the original data into it and * free the original block. */ heap_block_head_t *next_head = (heap_block_head_t *) (((void *) head) + head->size); if (((void *) next_head < area->end) && (head->size + next_head->size >= real_size) && (next_head->free)) { block_check(next_head); block_init(head, head->size + next_head->size, false, area); split_mark(head, real_size); ptr = ((void *) head) + sizeof(heap_block_head_t); next_fit = NULL; } else reloc = true; } futex_up(&malloc_futex); if (reloc) { ptr = malloc(size); if (ptr != NULL) { memcpy(ptr, addr, NET_SIZE(orig_size)); free(addr); } } return ptr; }
/** Allocate memory from heap area starting from given block * * Should be called only inside the critical section. * As a side effect this function also sets the current * pointer on successful allocation. * * @param area Heap area where to allocate from. * @param first_block Starting heap block. * @param final_block Heap block where to finish the search * (may be NULL). * @param real_size Gross number of bytes to allocate. * @param falign Physical alignment of the block. * * @return Address of the allocated block or NULL on not enough memory. * */ static void *malloc_area(heap_area_t *area, heap_block_head_t *first_block, heap_block_head_t *final_block, size_t real_size, size_t falign) { area_check((void *) area); malloc_assert((void *) first_block >= (void *) AREA_FIRST_BLOCK_HEAD(area)); malloc_assert((void *) first_block < area->end); for (heap_block_head_t *cur = first_block; (void *) cur < area->end; cur = (heap_block_head_t *) (((void *) cur) + cur->size)) { block_check(cur); /* Finish searching on the final block */ if ((final_block != NULL) && (cur == final_block)) break; /* Try to find a block that is free and large enough. */ if ((cur->free) && (cur->size >= real_size)) { /* * We have found a suitable block. * Check for alignment properties. */ void *addr = (void *) ((uintptr_t) cur + sizeof(heap_block_head_t)); void *aligned = (void *) ALIGN_UP((uintptr_t) addr, falign); if (addr == aligned) { /* Exact block start including alignment. */ split_mark(cur, real_size); next_fit = cur; return addr; } else { /* Block start has to be aligned */ size_t excess = (size_t) (aligned - addr); if (cur->size >= real_size + excess) { /* * The current block is large enough to fit * data in (including alignment). */ if ((void *) cur > (void *) AREA_FIRST_BLOCK_HEAD(area)) { /* * There is a block before the current block. * This previous block can be enlarged to * compensate for the alignment excess. */ heap_block_foot_t *prev_foot = (heap_block_foot_t *) ((void *) cur - sizeof(heap_block_foot_t)); heap_block_head_t *prev_head = (heap_block_head_t *) ((void *) cur - prev_foot->size); block_check(prev_head); size_t reduced_size = cur->size - excess; heap_block_head_t *next_head = ((void *) cur) + excess; if ((!prev_head->free) && (excess >= STRUCT_OVERHEAD)) { /* * The previous block is not free and there * is enough free space left to fill in * a new free block between the previous * and current block. */ block_init(cur, excess, true, area); } else { /* * The previous block is free (thus there * is no need to induce additional * fragmentation to the heap) or the * excess is small. Therefore just enlarge * the previous block. */ block_init(prev_head, prev_head->size + excess, prev_head->free, area); } block_init(next_head, reduced_size, true, area); split_mark(next_head, real_size); next_fit = next_head; return aligned; } else { /* * The current block is the first block * in the heap area. We have to make sure * that the alignment excess is large enough * to fit a new free block just before the * current block. */ while (excess < STRUCT_OVERHEAD) { aligned += falign; excess += falign; } /* Check for current block size again */ if (cur->size >= real_size + excess) { size_t reduced_size = cur->size - excess; cur = (heap_block_head_t *) (AREA_FIRST_BLOCK_HEAD(area) + excess); block_init((void *) AREA_FIRST_BLOCK_HEAD(area), excess, true, area); block_init(cur, reduced_size, true, area); split_mark(cur, real_size); next_fit = cur; return aligned; } } } } } } return NULL; }
/** Try to shrink heap * * Should be called only inside the critical section. * In all cases the next pointer is reset. * * @param area Last modified heap area. * */ static void heap_shrink(heap_area_t *area) { area_check(area); heap_block_foot_t *last_foot = (heap_block_foot_t *) AREA_LAST_BLOCK_FOOT(area); heap_block_head_t *last_head = BLOCK_HEAD(last_foot); block_check((void *) last_head); malloc_assert(last_head->area == area); if (last_head->free) { /* * The last block of the heap area is * unused. The area might be potentially * shrunk. */ heap_block_head_t *first_head = (heap_block_head_t *) AREA_FIRST_BLOCK_HEAD(area); block_check((void *) first_head); malloc_assert(first_head->area == area); size_t shrink_size = ALIGN_DOWN(last_head->size, PAGE_SIZE); if (first_head == last_head) { /* * The entire heap area consists of a single * free heap block. This means we can get rid * of it entirely. */ heap_area_t *prev = area->prev; heap_area_t *next = area->next; if (prev != NULL) { area_check(prev); prev->next = next; } else first_heap_area = next; if (next != NULL) { area_check(next); next->prev = prev; } else last_heap_area = prev; as_area_destroy(area->start); } else if (shrink_size >= SHRINK_GRANULARITY) { /* * Make sure that we always shrink the area * by a multiple of page size and update * the block layout accordingly. */ size_t asize = (size_t) (area->end - area->start) - shrink_size; void *end = (void *) ((uintptr_t) area->start + asize); /* Resize the address space area */ int ret = as_area_resize(area->start, asize, 0); if (ret != EOK) abort(); /* Update heap area parameters */ area->end = end; size_t excess = ((size_t) area->end) - ((size_t) last_head); if (excess > 0) { if (excess >= STRUCT_OVERHEAD) { /* * The previous block cannot be free and there * is enough free space left in the area to * create a new free block. */ block_init((void *) last_head, excess, true, area); } else { /* * The excess is small. Therefore just enlarge * the previous block. */ heap_block_foot_t *prev_foot = (heap_block_foot_t *) (((uintptr_t) last_head) - sizeof(heap_block_foot_t)); heap_block_head_t *prev_head = BLOCK_HEAD(prev_foot); block_check((void *) prev_head); block_init(prev_head, prev_head->size + excess, prev_head->free, area); } } } } next_fit = NULL; }