Example #1
0
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);
}
Example #2
0
/** 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);
}
Example #3
0
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;
}
Example #4
0
/** 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;
}
Example #5
0
/** 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;
}
Example #6
0
/** 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;
}