예제 #1
0
/*convenient function that find the correct free list and insert that free block*/
void insertToFreeList(void* bp) {

    size_t size = GET_SIZE(HDRP(bp));
    int which = getWhichFreeList(size); //get the fit free list

    void* freeListHead = free_lists[which];
    void* next = getNextFreeBlock(freeListHead);
    if (next == NULL) {
        //if the list is empty just insert to head
        insertFreeBlock(bp, freeListHead, NULL);
        return;
    } else {
        //find the correct position to insert using ordered address policy
        void* last = NULL;

        while (next != NULL) {
            if (bp > next) {
                void* prev = getPrevFreeBlock(next);
                insertFreeBlock(bp, prev, next);
                return;
            }
            void* nextnext = getNextFreeBlock(next);
            if (nextnext == NULL) {
                last = next;
                break;
            }
            next = nextnext;
        }
        //insert at the end of the free list
        insertFreeBlock(bp, last, NULL);
        return;
    }
}
예제 #2
0
        VboBlock* Vbo::freeBlock(VboBlock& block) {
#ifdef _DEBUG_VBO
            checkBlockChain();
            checkFreeBlocks();
#endif

            VboBlock* previous = block.m_previous;
            VboBlock* next = block.m_next;
            
            m_freeCapacity += block.capacity();
            block.m_free = true;
            
            if (previous != NULL && previous->free() && next != NULL && next->free()) {
                resizeBlock(*previous, previous->capacity() + block.capacity() + next->capacity());
                if (m_last == next) m_last = previous;
                removeFreeBlock(*next);
                previous->insertBetween(previous->m_previous, next->m_next);
                delete █
                delete next;
                return previous;
            }
            
            if (previous != NULL && previous->free()) {
                resizeBlock(*previous, previous->capacity() + block.capacity());
                if (m_last == &block) m_last = previous;
                previous->insertBetween(previous->m_previous, next);
                delete █
                return previous;
            }
            
            if (next != NULL && next->free()) {
                if (m_last == next) m_last = █
                removeFreeBlock(*next);
                block.m_capacity += next->capacity();
                block.m_free = true;
                block.insertBetween(previous, next->m_next);
                insertFreeBlock(block);
                delete next;
                return █
            }
            
            insertFreeBlock(block);

#ifdef _DEBUG_VBO
            checkBlockChain();
            checkFreeBlocks();
#endif

            return █
        }
예제 #3
0
/* Free the block referenced by ptr. */
void mm_free (void *ptr) {
  size_t payloadSize;
  BlockInfo * blockInfo;
  BlockInfo * followingBlock;
  size_t bitMask;

  // Implement mm_free.  You can change or remove the declaraions
  // above.  They are included as minor hints.
 
  // set BlockInfo pointer to include header
  blockInfo = (BlockInfo*) POINTER_SUB(ptr, WORD_SIZE);
  payloadSize = SIZE(blockInfo->sizeAndTags) - WORD_SIZE;
  followingBlock = (BlockInfo*) POINTER_ADD(ptr, payloadSize + WORD_SIZE);
  
  // set header (first tags, then size)
  bitMask = ~0 << 1;
  blockInfo->sizeAndTags &= bitMask; /* preserves all bits, except sets lowest
				      to 0 (unsetting used tag)  */
  // copy header into footer
  *((size_t*) POINTER_ADD(blockInfo, payloadSize)) = blockInfo->sizeAndTags;
  
  // set preceding use tag for following block
  bitMask = (~0 << 2) | 1;
  followingBlock->sizeAndTags &= bitMask; /* preserves all bits except 2nd
						lowest bit */

  // insert into free list and coalesce
  insertFreeBlock(blockInfo);
  coalesceFreeBlock(blockInfo);
}
예제 #4
0
파일: mm.c 프로젝트: ndukweiko/mm
//set block allocates the chosen block by removing it from the free list/re-adding the remainder(from mem_sbrk) to the freelist
static void setBlock(BlockInfo * block, size_t reqSize, size_t precedingBlockUseTag ){
  BlockInfo * remainder;
  size_t size_allocated;
  size_allocated = (size_t)SIZE(block->sizeAndTags); //get the size of the block
  removeFreeBlock(block); //if we're allocating, we should remove from the free list
  if( (size_allocated - reqSize) > MIN_BLOCK_SIZE){ //calls to mem_sbrk allocate more memory than we need, let's put back what's left over after filling the request.
    block->sizeAndTags = reqSize | precedingBlockUseTag; //turn on the TAG_PRECEDING_USED for the else clause of mm_malloc
    remainder = (BlockInfo *)UNSCALED_POINTER_ADD(block, reqSize);//reqSize is the payload of the block we're trying to allocate, we move past that portion to access the remainder
    remainder->sizeAndTags = ((size_allocated - reqSize) | TAG_PRECEDING_USED);//the remainder is the block in the list immediately following the allocated. need to 
    //turn on the preceding block used flag
    *((size_t *)UNSCALED_POINTER_ADD(block, (reqSize - WORD_SIZE))) = reqSize;//boundary tag for allocated block
    *((size_t *)UNSCALED_POINTER_ADD(block, (size_allocated - WORD_SIZE))) = (size_allocated - reqSize); //size for the remainder is the size actually allocated - the desired size 
    insertFreeBlock(remainder);//re-insert remainder into the freeList
    
  }

  else{
    *((size_t* )UNSCALED_POINTER_ADD(block,(size_allocated - WORD_SIZE))) = size_allocated;
    remainder = (BlockInfo *)UNSCALED_POINTER_ADD(block, size_allocated);
    remainder->sizeAndTags = remainder->sizeAndTags | TAG_PRECEDING_USED;
  }

  block->sizeAndTags = block->sizeAndTags | TAG_USED;
  block->sizeAndTags = block->sizeAndTags | precedingBlockUseTag;
}
예제 #5
0
파일: mm.c 프로젝트: YurieCo/hsi
/* Free the block referenced by ptr. */
void mm_free (void *ptr) {
  size_t payloadSize;
  BlockInfo * blockInfo;
  BlockInfo * followingBlock;  
  
	// Implement mm_free.  You can change or remove the declaraions
  // above.  They are included as minor hints.
    
  // Casts void pointer into BlockInfo, subtracts pointer by Wsize
	blockInfo = (BlockInfo*)POINTER_SUB(ptr, WORD_SIZE);
	
	// Checks if block wasn't freed
	if(((blockInfo->sizeAndTags) & TAG_USED)==0){
		return;
	}
	
	// Marks it as free, adds to free list and coalesces the free blocks together.
	blockInfo->sizeAndTags = blockInfo->sizeAndTags & (~TAG_USED);
	insertFreeBlock(blockInfo);
	coalesceFreeBlock(blockInfo);
	
	// unmarks the next block's preced used tag
	payloadSize = SIZE(blockInfo->sizeAndTags);
	followingBlock = (BlockInfo*)POINTER_ADD(blockInfo, payloadSize);
	followingBlock->sizeAndTags = followingBlock->sizeAndTags &	(~TAG_PRECEDING_USED);

}
예제 #6
0
파일: mm.c 프로젝트: caweinshenker/CS304
/* Coalesce 'oldBlock' with any preceeding or following free blocks. */
static void coalesceFreeBlock(BlockInfo* oldBlock) {
  BlockInfo *blockCursor;
  BlockInfo *newBlock;
  BlockInfo *freeBlock;
  // size of old block
  size_t oldSize = SIZE(oldBlock->sizeAndTags);
  // running sum to be size of final coalesced block
  size_t newSize = oldSize;

  // Coalesce with any preceding free block
  blockCursor = oldBlock;
  while ((blockCursor->sizeAndTags & TAG_PRECEDING_USED)==0) {
    // While the block preceding this one in memory (not the
    // prev. block in the free list) is free:

    // Get the size of the previous block from its boundary tag.
    size_t size = SIZE(*((size_t*)UNSCALED_POINTER_SUB(blockCursor, WORD_SIZE)));
    // Use this size to find the block info for that block.
    freeBlock = (BlockInfo*)UNSCALED_POINTER_SUB(blockCursor, size);
    // Remove that block from free list.
    removeFreeBlock(freeBlock);
    // Count that block's size and update the current block pointer.
    newSize += size;
    blockCursor = freeBlock;
  }
  newBlock = blockCursor;

  // Coalesce with any following free block.
  // Start with the block following this one in memory
  blockCursor = (BlockInfo*)UNSCALED_POINTER_ADD(oldBlock, oldSize);
  while ((blockCursor->sizeAndTags & TAG_USED)==0) {
    // While the block is free:

    size_t size = SIZE(blockCursor->sizeAndTags);
    // Remove it from the free list.
    removeFreeBlock(blockCursor);
    // Count its size and step to the following block.
    newSize += size;
    blockCursor = (BlockInfo*)UNSCALED_POINTER_ADD(blockCursor, size);
  }

  // If the block actually grew, remove the old entry from the free
  // list and add the new entry.
  if (newSize != oldSize) {
    // Remove the original block from the free list
    removeFreeBlock(oldBlock);

    // Save the new size in the block info and in the boundary tag
    // and tag it to show the preceding block is used (otherwise, it
    // would have become part of this one!).
    newBlock->sizeAndTags = newSize | TAG_PRECEDING_USED;
    // The boundary tag of the preceding block is the word immediately
    // preceding block in memory where we left off advancing blockCursor.
    *(size_t*)UNSCALED_POINTER_SUB(blockCursor, WORD_SIZE) = newSize | TAG_PRECEDING_USED;

    // Put the new block in the free list.
    insertFreeBlock(newBlock);
  }
  return;
}
예제 #7
0
// Split a large block into two sub-blocks.
// spaceLeft and size are in words
void *splitFreeBlock(void* blockToSplit, uint64_t spaceLeft,
		uint32_t size, void* currentFreeBlock, 
		struct freeBlockLinks *currentBlockLinks) 
{
	// Reinitialise header of first sub-block.
	void* block = ADDRESS_MINUS_OFFSET(blockToSplit, blockHeader);
	struct blockHeader *allocatedBlock = INIT_STRUCT(blockHeader, block);
	allocatedBlock->attribute = size;

	// Create and initialise new node.
	uint32_t sizeNewNode = spaceLeft - BYTES_TO_WORDS(sizeof(blockHeader));
 
 	uint64_t sizeOffset =  WORDS_TO_BYTES(size);
	void* endUserRequestedBlock = blockToSplit + sizeOffset;
	// initialise new block.
	void* prevBlock = PREV_BLOCK(currentBlockLinks);

	totalFreeSpace -= WORDS_TO_BYTES(spaceLeft);
	totalFreeSpace -= WORDS_TO_BYTES(size); // Stats

	initialiseFreeBlock(endUserRequestedBlock, sizeNewNode, 
		prevBlock, currentFreeBlock, false, true);
	insertFreeBlock(endUserRequestedBlock, currentBlockLinks);

	return endUserRequestedBlock;
}
예제 #8
0
파일: mm.c 프로젝트: caweinshenker/CS304
/* Get more heap space of size at least reqSize. */
static void requestMoreSpace(size_t reqSize) {
  size_t pagesize = mem_pagesize();
  size_t numPages = (reqSize + pagesize - 1) / pagesize;
  BlockInfo *newBlock;
  size_t totalSize = numPages * pagesize;
  size_t prevLastWordMask;
  void* mem_sbrk_result = mem_sbrk(totalSize);
  if ((size_t)mem_sbrk_result == -1) {
    printf("ERROR: mem_sbrk failed in requestMoreSpace\n");
    exit(0);
  }
  newBlock = (BlockInfo*)UNSCALED_POINTER_SUB(mem_sbrk_result, WORD_SIZE);
  /* initialize header, inherit TAG_PRECEDING_USED status from the
     previously useless last word however, reset the fake TAG_USED
     bit */
  printf("newBlock: %p\n", (void *) newBlock);

  prevLastWordMask = newBlock->sizeAndTags & TAG_PRECEDING_USED;
  newBlock->sizeAndTags = totalSize | prevLastWordMask;
  // Initialize boundary tag.
  ((BlockInfo*)UNSCALED_POINTER_ADD(newBlock, totalSize - WORD_SIZE))->sizeAndTags =
    totalSize | prevLastWordMask;
  /* initialize "new" useless last word
     the previous block is free at this moment
     but this word is useless, so its use bit is set
     This trick lets us do the "normal" check even at the end of
     the heap and avoid a special check to see if the following
     block is the end of the heap... */
  *((size_t*)UNSCALED_POINTER_ADD(newBlock, totalSize)) = TAG_USED;

  // Add the new block to the free list and immediately coalesce newly
  // allocated memory space
  insertFreeBlock(newBlock);
  coalesceFreeBlock(newBlock);
}
/* Free the block referenced by ptr. */
void mm_free (void *ptr) {
  size_t payloadSize;
  BlockInfo * blockInfo;
  BlockInfo * followingBlock;

  // Implement mm_free.  You can change or remove the declaraions
  // above.  They are included as minor hints.
  blockInfo = (BlockInfo*)POINTER_SUB(ptr, WORD_SIZE);
  payloadSize = SIZE(blockInfo->sizeAndTags);
  followingBlock = (BlockInfo*)POINTER_ADD(blockInfo, payloadSize);

  // update the status in the current block: reset TAG_USED in both head and boundary tag
  size_t precedingBlockUseTag = blockInfo->sizeAndTags & TAG_PRECEDING_USED;
  blockInfo->sizeAndTags = payloadSize | precedingBlockUseTag;
  *((size_t*)POINTER_ADD(blockInfo, payloadSize - WORD_SIZE)) = payloadSize | precedingBlockUseTag;

  // update the status in the following block: reset TAG_PRECEDING_USED
  size_t followingBlockSize = SIZE(followingBlock->sizeAndTags);
  size_t followingBlockUsed = followingBlock->sizeAndTags & TAG_USED;
  followingBlock->sizeAndTags = followingBlockSize | followingBlockUsed;
  // if the following block is free, also update its boundary tag
  if ((followingBlock->sizeAndTags & TAG_USED) != TAG_USED) {
    *((size_t*)POINTER_ADD(followingBlock, followingBlockSize - WORD_SIZE)) = followingBlock->sizeAndTags;
  }

  insertFreeBlock(blockInfo);
  coalesceFreeBlock(blockInfo);
  
}
예제 #10
0
 void Vbo::resizeBlock(VboBlock& block, size_t newCapacity) {
     if (block.capacity() == newCapacity) return;
     if (block.free()) {
         removeFreeBlock(block);
         block.m_capacity = newCapacity;
         insertFreeBlock(block);
     }
 }
예제 #11
0
	Block & createBlock(char * ptr, size_t size, bool free)
	{
		assert(blocks.count(ptr) == 0);
		blocks[ptr] = Block(ptr, size, free);
		if(free)
			insertFreeBlock(blocks[ptr]);
		return blocks[ptr];
	}
예제 #12
0
	void resizeBlock(Block & block, size_t newSize)
	{
	    if(newSize != block.size)
	    {
	        if(block.free)
	            eraseFreeBlock(block);
	        block.size = newSize;
	        if(block.free)
	            insertFreeBlock(block);
	    }
	}
예제 #13
0
        VboBlock* Vbo::allocBlock(size_t capacity) {
            assert(capacity > 0);
            
#ifdef _DEBUG_VBO
            checkBlockChain();
            checkFreeBlocks();
#endif

            size_t index = findFreeBlock(0, capacity);
            if (index >= m_freeBlocks.size()) {
                SetVboState mapVbo(*this, VboMapped);
                pack();

                if (capacity > m_freeCapacity) {
                    const size_t usedCapacity = m_totalCapacity - m_freeCapacity;
                    size_t newCapacity = m_totalCapacity;
                    size_t newFreeCapacity = m_freeCapacity;
                    while (capacity > newFreeCapacity) {
                        newCapacity *= 2;
                        newFreeCapacity = newCapacity - usedCapacity;
                    }
                    resizeVbo(newCapacity);
                }
                
                index = findFreeBlock(0, capacity);
                assert(index < m_freeBlocks.size());
            }
            
            VboBlock* block = m_freeBlocks[index];
            std::vector<VboBlock*>::iterator it = m_freeBlocks.begin();
            std::advance(it, index);
            m_freeBlocks.erase(it);
            
            // split block
            if (capacity < block->capacity()) {
                VboBlock* remainder = new VboBlock(*this, block->address() + capacity, block->capacity() - capacity);
                remainder->insertBetween(block, block->m_next);
                block->m_capacity = capacity;
                insertFreeBlock(*remainder);
                if (m_last == block) m_last = remainder;
            }
            
            m_freeCapacity -= block->capacity();
            block->m_free = false;

#ifdef _DEBUG_VBO
            checkBlockChain();
            checkFreeBlocks();
#endif

            return block;
        }
예제 #14
0
파일: mm.c 프로젝트: ndukweiko/mm
/* Free the block referenced by ptr. */
void mm_free (void *ptr) {
  size_t payloadSize;
  BlockInfo * blockInfo;
  BlockInfo * followingBlock;
  
  blockInfo = (BlockInfo *)UNSCALED_POINTER_SUB(ptr, WORD_SIZE);//header of chosen block to free
  blockInfo->sizeAndTags = blockInfo->sizeAndTags & (~TAG_USED);//turn off the tag used tag
  
  payloadSize = SIZE(blockInfo->sizeAndTags);//get the payload of the block soon to be freed
  followingBlock = (BlockInfo *)UNSCALED_POINTER_ADD(blockInfo, payloadSize + WORD_SIZE);//move to the block that follows the block to be freed
  followingBlock->sizeAndTags = (followingBlock->sizeAndTags) & (~TAG_PRECEDING_USED);//turn off its preceding tag used flag
  insertFreeBlock(blockInfo);//insert block that was freed back to the list
  coalesceFreeBlock(blockInfo);//coalesce, if possible
  
}
예제 #15
0
/* Free the block referenced by ptr. */
void mm_free (void *ptr) {
  size_t payloadSize;
  BlockInfo * blockInfo;
  BlockInfo * nextBlock;
  
  // Implement mm_free.  You can change or remove the declaraions
  // above.  They are included as minor hints.
  blockInfo = (BlockInfo* )POINTER_SUB(ptr, WORD_SIZE);
  payloadSize = SIZE(blockInfo->sizeAndTags);
  blockInfo->sizeAndTags = blockInfo->sizeAndTags & ~TAG_USED;
  *((size_t*)POINTER_ADD(blockInfo, payloadSize- WORD_SIZE)) = blockInfo->sizeAndTags;
  nextBlock = (BlockInfo* )POINTER_ADD(blockInfo, payloadSize);
  nextBlock->sizeAndTags = nextBlock->sizeAndTags & ~TAG_PRECEDING_USED;
  insertFreeBlock(blockInfo);
  coalesceFreeBlock(blockInfo);
}
예제 #16
0
파일: mm.c 프로젝트: caweinshenker/CS304
/* Free the block referenced by ptr. */
void mm_free (void *ptr) {
  printf("Begin free\n");
  size_t payloadSize;
  BlockInfo * blockInfo;
  BlockInfo * footer;
  BlockInfo * nextBlock;
  size_t precedingBlockUseTag;
  blockInfo = (BlockInfo *) UNSCALED_POINTER_SUB(ptr, WORD_SIZE);
  payloadSize = SIZE(blockInfo->sizeAndTags);
  precedingBlockUseTag = blockInfo->sizeAndTags & TAG_PRECEDING_USED;
  blockInfo->sizeAndTags = (payloadSize & ~TAG_USED) | precedingBlockUseTag;
  footer = (BlockInfo *) UNSCALED_POINTER_ADD(blockInfo, payloadSize - WORD_SIZE);
  footer->sizeAndTags = blockInfo->sizeAndTags;
  nextBlock = (BlockInfo *) UNSCALED_POINTER_ADD(ptr, payloadSize);
  set_next_block(nextBlock, precedingBlockUseTag);
  insertFreeBlock(blockInfo);
  coalesceFreeBlock(blockInfo);
}
예제 #17
0
파일: mm.c 프로젝트: caweinshenker/CS304
void split_block(BlockInfo * ptrFreeBlock, size_t totalSize, size_t precedingBlockUseTag){
  printf("Splitting\n");
  BlockInfo * splitBlock = NULL;
  BlockInfo * splitBlockFooter = NULL;
  BlockInfo * nextBlock = NULL;
  size_t splitBlockSize;
  size_t ptrFreeBlockSize;
  ptrFreeBlockSize = SIZE(ptrFreeBlock->sizeAndTags);
  splitBlock = (BlockInfo *) UNSCALED_POINTER_ADD(ptrFreeBlock, ptrFreeBlockSize);
  splitBlockSize =  totalSize - ptrFreeBlockSize;
  splitBlock->sizeAndTags = splitBlockSize | TAG_PRECEDING_USED;
  splitBlockFooter = (BlockInfo *)  UNSCALED_POINTER_ADD((void*)splitBlock, splitBlockSize - WORD_SIZE);
  splitBlockFooter->sizeAndTags =  splitBlock->sizeAndTags;
  nextBlock = (BlockInfo *) UNSCALED_POINTER_ADD((void *) splitBlock, splitBlockSize);
  set_next_block(nextBlock,  0);
  insertFreeBlock(splitBlock);
  coalesceFreeBlock(splitBlock);
  examine_heap();
}
예제 #18
0
        VboBlock* Vbo::packBlock(VboBlock& block) {
            VboBlock* first = block.m_next;
            if (first == NULL)
                return NULL;
            
            VboBlock* previous = NULL;
            VboBlock* last = first;
            size_t size = 0;
            size_t address = first->address();
            
            do {
                last->m_address -= block.capacity();
                size += last->capacity();
                previous = last;
                last = last->m_next;
            } while (last != NULL && !last->free());
            
            memmove(m_buffer + block.address(), m_buffer + address, size);
            
            if (last != NULL) {
                last->m_address -= block.capacity();
                resizeBlock(*last, last->capacity() + block.capacity());
            } else {
                VboBlock* newBlock = new VboBlock(*this, previous->address() + previous->capacity(), block.capacity());
                insertFreeBlock(*newBlock);
                newBlock->insertBetween(previous, NULL);
                m_last = newBlock;
            }
            
            if (m_first == &block) m_first = block.m_next;
            
            removeFreeBlock(block);
            if (block.m_previous != NULL) block.m_previous->m_next = block.m_next;
            if (block.m_next != NULL) block.m_next->m_previous = block.m_previous;
            delete &block;

            return last;
        }
void ThreadCache::freeObject(void* ptr) {
    // Here you will return the object to the free list sorted by address
    // and you will coalesce it if possible.
    ObjHeader* obj = reinterpret_cast<ObjHeader*>((unsigned char*)ptr -
                     sizeof(ObjHeader));
    size_t totalSize = obj->_objectSize;

    _m.lock();
    // No space to put it into free-list (min: 48 bytes)
    if (totalSize < (sizeof(DualLnkNode) + 2 * sizeof(ObjHeader))) {
        _m.unlock();
        puts("Free without gettting back-------------");
        return;
    } else {
        obj->_flags = ObjFree;
        // "obj" now points to the Footer, set footer values
        obj = (ObjHeader*)((unsigned char*)obj+totalSize - sizeof(ObjHeader));
        obj->_flags = ObjFree;  // Set footer flag to freed
        // "obj" still points to the footer now
        assert(insertFreeBlock((DualLnkNode*)ptr, (totalSize / 8)));
        _m.unlock();
    }
}
예제 #20
0
// size free region in bytes
void initialiseFreeMmapRegion(void* beginningFreeRegion, uint64_t sizeFreeRegion) 
{
	uint32_t sizeFreeRegionInWords = BYTES_TO_WORDS(sizeFreeRegion); // headerMmapsize in words.
	if(!freeList) {
		freeList = beginningFreeRegion; // Initialise the free list.
		initialiseFreeBlock(beginningFreeRegion, sizeFreeRegionInWords, 
			beginningFreeRegion, beginningFreeRegion, false, true);
	} else {
		// Add to free list.
		void *currentBlock = freeList;
		void* links = ADDRESS_PLUS_OFFSET(currentBlock, blockHeader);
		struct freeBlockLinks *currentBlockLinks = INIT_STRUCT(freeBlockLinks, links);

		void* prevBlock = PREV_BLOCK(currentBlockLinks);
		initialiseFreeBlock(beginningFreeRegion, sizeFreeRegionInWords, 
			prevBlock, currentBlock, false, true); 

		// Tell next block that its previous one is NOW free. 
		uint64_t sizeOffset = WORDS_TO_BYTES(sizeFreeRegionInWords);
		updateNextBlockOnCoalescing(beginningFreeRegion, sizeFreeRegion);

		insertFreeBlock(beginningFreeRegion, currentBlockLinks);
	}
}
예제 #21
0
파일: mm.c 프로젝트: YurieCo/hsi
/*	places block for malloc function into free block
		basically changing last byte to 1 in header, so that
		block is marked as not empty, if free Block is >  tha what we need to allocate,
		also split free bloc, etc.
		*/
static void * placeBlock(BlockInfo * freeBlock, size_t reqSize, size_t precedingBlockUseTag)
{
	size_t sizeFree;
	BlockInfo * restOfFreeBlock;
	
	sizeFree = (size_t)SIZE( freeBlock->sizeAndTags ); //gives size without last 3 indicator bits
	removeFreeBlock(freeBlock);
	
	if( (sizeFree - reqSize) > MIN_BLOCK_SIZE )
	{
		freeBlock->sizeAndTags = reqSize | precedingBlockUseTag;
		//printf("Ex-Free block after allocation 0x%x %d 0x%x 0x%x\n", 
		//			(int*)freeBlock, (int)freeBlock->sizeAndTags, (int*)freeBlock->next, (int*)freeBlock->prev);
		restOfFreeBlock = POINTER_ADD( freeBlock, reqSize );
		restOfFreeBlock->sizeAndTags = ((sizeFree-reqSize) | TAG_PRECEDING_USED) & (~TAG_USED);
		
		//Updates the boundary tag
		*((int*)POINTER_ADD(freeBlock, (reqSize-WORD_SIZE))) = reqSize;
		*((int*)POINTER_ADD(freeBlock, (sizeFree-WORD_SIZE))) = sizeFree-reqSize;
		
		insertFreeBlock(restOfFreeBlock);		
		//printf("Rest of free block after allocation 0x%x %d 0x%x 0x%x\n", 
		//		(int*)restOfFreeBlock, (int)restOfFreeBlock->sizeAndTags, (int*)restOfFreeBlock->next, (int*)restOfFreeBlock->prev);
	}
	else
	{
		//freeBlock->sizeAndTags = sizeFree | TAG_USED;
		// Updates the following blocks preceding used and the boundary tag
		*((int*)POINTER_ADD(freeBlock, (sizeFree-WORD_SIZE))) = sizeFree;
		restOfFreeBlock = (BlockInfo*)POINTER_ADD(freeBlock, sizeFree);
		restOfFreeBlock->sizeAndTags = restOfFreeBlock->sizeAndTags | TAG_PRECEDING_USED;		
	}
	
	freeBlock->sizeAndTags |= TAG_USED;
	freeBlock->sizeAndTags |= precedingBlockUseTag;
}
예제 #22
0
/* Allocate a block of size size and return a pointer to it. */
void* mm_malloc (size_t size) {
  size_t reqSize;
  BlockInfo * ptrFreeBlock = NULL;
  size_t blockSize;
  size_t precedingBlockUseTag;
  BlockInfo * nextBlock = NULL;
  BlockInfo * newBlock = NULL;	
  // Zero-size requests get NULL.
  if (size == 0) {
    return NULL;
  }

  // Add one word for the initial size header.
  // Note that we don't need to boundary tag when the block is used!
  size += WORD_SIZE;
  if (size <= MIN_BLOCK_SIZE) {
    // Make sure we allocate enough space for a blockInfo in case we
    // free this block (when we free this block, we'll need to use the
    // next pointer, the prev pointer, and the boundary tag).
    reqSize = MIN_BLOCK_SIZE;
  } else {
    // Round up for correct alignment
    reqSize = ALIGNMENT * ((size + ALIGNMENT - 1) / ALIGNMENT);
  }

  // Implement mm_malloc.  You can change or remove any of the above
  // code.  It is included as a suggestion of where to start.
  // You will want to replace this return statement...
/*
  ptrFreeBlock = searchFreeList(reqSize);
  if( ptrFreeBlock != NULL) {
	  blockSize = SIZE(ptrFreeBlock->sizeAndTags);
	  nextBlock = (BlockInfo* )POINTER_ADD(ptrFreeBlock, blockSize);
	  nextBlock->sizeAndTags = nextBlock->sizeAndTags | TAG_PRECEDING_USED;
	  removeFreeBlock(ptrFreeBlock);
	  ptrFreeBlock->sizeAndTags =   ptrFreeBlock->sizeAndTags | TAG_USED;
	  return POINTER_ADD( ptrFreeBlock, WORD_SIZE);
  }
  
  requestMoreSpace(reqSize);
  ptrFreeBlock = searchFreeList(reqSize);
  if( ptrFreeBlock != NULL) {
	   blockSize = SIZE(ptrFreeBlock->sizeAndTags);
	  nextBlock = (BlockInfo* )POINTER_ADD(ptrFreeBlock, blockSize);
	  nextBlock->sizeAndTags = nextBlock->sizeAndTags | TAG_PRECEDING_USED;
	  removeFreeBlock(ptrFreeBlock);
	  ptrFreeBlock->sizeAndTags =   ptrFreeBlock->sizeAndTags | TAG_USED; 
	  return POINTER_ADD( ptrFreeBlock, WORD_SIZE);
  }
*/
 ptrFreeBlock = searchFreeList(reqSize);
 if( ptrFreeBlock == NULL){
	 requestMoreSpace(reqSize);
     ptrFreeBlock = searchFreeList(reqSize);
 }
 
 blockSize = SIZE(ptrFreeBlock->sizeAndTags);
 
 if( (blockSize - reqSize) >= MIN_BLOCK_SIZE ){
	precedingBlockUseTag = ptrFreeBlock->sizeAndTags & TAG_PRECEDING_USED;
	ptrFreeBlock->sizeAndTags = reqSize | precedingBlockUseTag | TAG_USED ;
    removeFreeBlock(ptrFreeBlock);
    
    newBlock = (BlockInfo* )POINTER_ADD(ptrFreeBlock, reqSize);
    newBlock->sizeAndTags = blockSize - reqSize;
    newBlock->sizeAndTags = newBlock->sizeAndTags | TAG_PRECEDING_USED;
    *((size_t*)POINTER_ADD(newBlock, blockSize - reqSize - WORD_SIZE ) ) = newBlock->sizeAndTags;

	insertFreeBlock(newBlock);
 }else{
    nextBlock = (BlockInfo* )POINTER_ADD(ptrFreeBlock, blockSize);
    nextBlock->sizeAndTags = nextBlock->sizeAndTags | TAG_PRECEDING_USED;
   
    ptrFreeBlock->sizeAndTags =   ptrFreeBlock->sizeAndTags | TAG_USED;
    removeFreeBlock(ptrFreeBlock);  
 }
 return POINTER_ADD( ptrFreeBlock, WORD_SIZE);
}
/* Allocate a block of size size and return a pointer to it. */
void* mm_malloc (size_t size) {
  size_t reqSize;
  BlockInfo * ptrFreeBlock = NULL;
  size_t blockSize;
  size_t precedingBlockUseTag;

  // Zero-size requests get NULL.
  if (size == 0) {
    return NULL;
  }

  // Add one word for the initial size header.
  // Note that we don't need to boundary tag when the block is used!
  size += WORD_SIZE;
  if (size <= MIN_BLOCK_SIZE) {
    // Make sure we allocate enough space for a blockInfo in case we
    // free this block (when we free this block, we'll need to use the
    // next pointer, the prev pointer, and the boundary tag).
    reqSize = MIN_BLOCK_SIZE;
  } else {
    // Round up for correct alignment
    reqSize = ALIGNMENT * ((size + ALIGNMENT - 1) / ALIGNMENT);
  }

  // Implement mm_malloc.  You can change or remove any of the above
  // code.  It is included as a suggestion of where to start.
  // You will want to replace this return statement...
 
  // Search the free list for a fit
  ptrFreeBlock = searchFreeList(reqSize);
 
  // No fit found. Get more memory
  if (ptrFreeBlock == NULL) {
    requestMoreSpace(reqSize);
    ptrFreeBlock = searchFreeList(reqSize);
  }

  // place the acquired block and split excessive part as needed
  removeFreeBlock(ptrFreeBlock);

  blockSize = SIZE(ptrFreeBlock->sizeAndTags);
  precedingBlockUseTag = ptrFreeBlock->sizeAndTags & TAG_PRECEDING_USED;

  if (blockSize - reqSize >= MIN_BLOCK_SIZE) {
    size_t newFreeBlockSize = blockSize - reqSize;

    BlockInfo *newPtrFreeBlock = (BlockInfo*)POINTER_ADD(ptrFreeBlock, reqSize);
    newPtrFreeBlock->sizeAndTags = newFreeBlockSize | TAG_PRECEDING_USED;	// !TAG_USED

    // update the boundary tag
    *((size_t*)POINTER_ADD(newPtrFreeBlock, newFreeBlockSize - WORD_SIZE)) = 
            newFreeBlockSize | TAG_PRECEDING_USED;	// !TAG_USED
    // insert the new free block into free list
    insertFreeBlock(newPtrFreeBlock);

    blockSize = reqSize;
  } else {
    // do not need to split the block, but need to update the status of following block
    BlockInfo *followingBlock = (BlockInfo*)POINTER_ADD(ptrFreeBlock, blockSize);
    size_t followingBlockSize = SIZE(followingBlock->sizeAndTags);
    size_t followingBlockUsed = followingBlock->sizeAndTags & TAG_USED;
    followingBlock->sizeAndTags = followingBlockSize | TAG_PRECEDING_USED | followingBlockUsed;
    if (followingBlockUsed != TAG_USED) {
      *((size_t*)POINTER_ADD(followingBlock, followingBlockSize - WORD_SIZE)) = followingBlock->sizeAndTags; 
    }
  }

  ptrFreeBlock->sizeAndTags = blockSize | precedingBlockUseTag | TAG_USED;
  // we do not care about the boundary tag of used block!

  return POINTER_ADD(ptrFreeBlock, WORD_SIZE); 
}
예제 #24
0
void coalescingAndFree(void* block) 
{
	struct blockHeader *header = INIT_STRUCT(blockHeader, block);
	uint32_t size = GET_SIZE(header->attribute); // in words
	uint32_t flag = GET_FLAG(header->attribute);

	NEIGHBOUR_BLOCKS state = NEIGHBOUR_BLOCKS_NOT_FREE; 

	struct freeBlockLinks *successorBlockLinks = NULL; // update only if necessary

	// Initialise addr and size for no change. 
	void* newAddr = block; 
	uint32_t newSize = size;
	uint64_t sizeOffset;
	// Is precedent block free? 
	if (flag == MSB_TO_ONE) {
		state = NEIGHBOUR_BLOCKS_PRECEDENT_FREE;
		// In this case it's just about updating the size of the prev free block 
		// and removing the successive one if free.
		void* footer = ADDRESS_MINUS_OFFSET(block, freeBlockFooter);
		struct freeBlockFooter *prevBlockFooter = INIT_STRUCT(freeBlockFooter, footer);
		sizeOffset = WORDS_TO_BYTES(prevBlockFooter->size); // Footer has no flag.
		newAddr = block - sizeOffset - sizeof(blockHeader);
		newSize = prevBlockFooter->size + BYTES_TO_WORDS(sizeof(blockHeader)) + size;
	}

	// Is successive block free? 
	sizeOffset = WORDS_TO_BYTES(size);
	void* nextBlock = ADDRESS_PLUS_OFFSET(block + sizeOffset, blockHeader);
	struct blockHeader *nextHeader = INIT_STRUCT(blockHeader, nextBlock);
	if (nextHeader->attribute != MSB_TO_ZERO) { // check if next block is mmap footer or not.
		uint32_t nextSize = GET_SIZE(nextHeader->attribute);
		sizeOffset = WORDS_TO_BYTES(nextSize);
		void* nextNextBlock =  ADDRESS_PLUS_OFFSET(nextBlock + sizeOffset, blockHeader);

		struct blockHeader *nextNextHeader = INIT_STRUCT(blockHeader, nextNextBlock);
		if (nextNextHeader->attribute != MSB_TO_ZERO) {
			flag = GET_FLAG(nextNextHeader->attribute);
			if (flag == MSB_TO_ONE) {
				if (!state) {
					state = NEIGHBOUR_BLOCKS_SUCCESSIVE_FREE;
					// Do not change address, but Increase size
					newSize = size + BYTES_TO_WORDS(sizeof(blockHeader)) + nextSize;
				} else {
					state = NEIGHBOUR_BLOCKS_BOTH_FREE;
					newSize = newSize + BYTES_TO_WORDS(sizeof(blockHeader)) + nextSize;
				}
				successorBlockLinks = nextBlock + sizeof(blockHeader);
				// IF NO PREV block is free:
				// Just update the pointers of the prev and next blocks 
				// relative to this block AND the size.
			}
		}
	} // Otherwise it's next block is the mmap footer.

	switch(state)
	{
		case NEIGHBOUR_BLOCKS_NOT_FREE: 
		{
			void *currentBlock = freeList;
			struct freeBlockLinks *currentBlockLinks = ADDRESS_PLUS_OFFSET(currentBlock, blockHeader);

			void* prevBlock = PREV_BLOCK(currentBlockLinks);
			initialiseFreeBlock(newAddr, newSize, 
				prevBlock, currentBlock, false, false);

			// Tell next block that its previous one is NOW free.
			sizeOffset = WORDS_TO_BYTES(size);
			updateNextBlockOnCoalescing(newAddr, sizeOffset);

			insertFreeBlock(newAddr, currentBlockLinks);
			numberFreeBlocks++;
			break;
		}
		case NEIGHBOUR_BLOCKS_PRECEDENT_FREE: 
		{
			coalesceWithPrevBlock(newAddr, newSize);
			break;
		}
		case NEIGHBOUR_BLOCKS_SUCCESSIVE_FREE: 
		{
			coalesceWithNextBlock(newAddr, newSize, successorBlockLinks);
			break;
		}
		case NEIGHBOUR_BLOCKS_BOTH_FREE: 
		{
			coalesceWithNeighbours(newAddr, newSize, successorBlockLinks);
			break;
		}
		default:
		{
			fprintf(stderr, "memoryManagement.coalescingAndFree - NEIGHBOUR_BLOCKS state unknown\n");
			exit(-1);
		}
	} // end switch

	// Update total free space
	// When state == 0, the totalFreeSpace is updated when the block is initialised.
	totalFreeSpace += WORDS_TO_BYTES(size); // Stats
	if (state != NEIGHBOUR_BLOCKS_NOT_FREE)
		totalFreeSpace += sizeof(blockHeader); 
	
	// Largest free region
	if (newSize > largestFreeBlock)
		largestFreeBlock = newSize;

	freeList = newAddr;
}
void* ThreadCache::allocateObject(size_t size) {
    //Make sure that allocator is initialized
    if (!_initialized) {
        if (__sync_bool_compare_and_swap(&_initialized, 0, 1))
            initialize();
    }

    // Add the ObjHeader and Footer to the size and round the total size
    // up to a multiple of 8 bytes for alignment.
    size_t totalSize = (size + (sizeof(ObjHeader) << 1) + 7) & ~7;
    // Min = 48, has to have space to fill in "DualLnkNode"
    totalSize = (totalSize < 48)? 48 : totalSize;

    // You should get memory from the OS only if the memory in the free
    // list could not satisfy the request.
    void* mem;
    size_t index = (totalSize / 8 > NUMOFSIZECLASSES -1)?
                   (NUMOFSIZECLASSES - 1) : (totalSize / 8);

    // Lock the shared doubly-linked-list-of-lists heap:
    _m.lock();

    if (freels_[index++] != NULL) {
        // if 0 <= index <= 63, "mem" won't be NULL, since
        // freels_[index] != NULL
        mem = static_cast<void*>(rmFromFreeLs(totalSize / 8, totalSize));
        if (mem != NULL) {  // suitable size free node found
            mem = (void*)((unsigned char*)mem - sizeof(ObjHeader));
        } else {  // requesting > 512 bytes, not suitable free node exist
            mem = getMemoryFromCentHeap(totalSize);
        }
        // If the actual size for 'mem' is larger than totalSize, reassign
        if (((ObjHeader*)mem)->_objectSize > totalSize) {
            totalSize = ((ObjHeader*)mem)->_objectSize;
        }
    } else {  // Search for larger free-lists in "freels_[]"
        while (index < NUMOFSIZECLASSES) {  // search for larger slots
            if (freels_[index] != NULL)
                break;
            ++index;
        }
        if (index == NUMOFSIZECLASSES) {
            mem = getMemoryFromCentHeap(totalSize);
            // If the actual size for 'mem' is larger than totalSize, reassign
            if (((ObjHeader*)mem)->_objectSize > totalSize) {
                totalSize = ((ObjHeader*)mem)->_objectSize;
            }
        } else {  // Split larger free slot
            DualLnkNode* toSplit = rmFromFreeLs(index, index * 8);
            size_t realSize = ((ObjHeader*)((unsigned char*)toSplit -
                                            sizeof(ObjHeader)))->_objectSize;
            if (realSize >= (totalSize + sizeof(DualLnkNode) +
                             2 * sizeof(ObjHeader))) {
                size_t newclass = (realSize - totalSize) / 8;
                // Set header and footer for new splitted object
                ObjHeader* splitobj = (ObjHeader*)((unsigned char*)toSplit +
                                                   totalSize - sizeof(ObjHeader));
                splitobj->_objectSize = realSize - totalSize;  // may > sizeclass
                splitobj->_flags = ObjFree;
                splitobj = (ObjHeader*)((unsigned char*)toSplit + realSize
                                        - 2 * sizeof(ObjHeader));  // Now, pointing to footer
                splitobj->_objectSize = realSize - totalSize;  // may > sizeclass
                splitobj->_flags = ObjFree;
                assert(insertFreeBlock((DualLnkNode*)((unsigned char*)toSplit +
                                                      totalSize), newclass));
                mem = (void*)((unsigned char*)toSplit - sizeof(ObjHeader));
            } else {  // Cannot split
                totalSize = realSize;  // Gave a larger free-node back
                mem = (void*)((unsigned char*)toSplit - sizeof(ObjHeader));
            }
        }
    }
    _m.unlock();

    // Get a pointer to the object header ????? didn't change footer
    ObjHeader* obj = static_cast<ObjHeader*>(mem);
    // Store the totalSize. We will need it in realloc() and in free()
    obj->_objectSize = totalSize;
    // Set object as allocated
    obj->_flags = ObjAllocated;
    // "obj" now points to the Footer, set footer values
    obj = (ObjHeader*)((unsigned char*)obj + totalSize - sizeof(ObjHeader));
    obj->_objectSize = totalSize;
    obj->_flags = ObjAllocated;
    // "obj" repoints to the header
    obj = (ObjHeader*)((unsigned char*)obj - totalSize + sizeof(ObjHeader));

    // Return the pointer after the object header.
    return static_cast<void*>(obj + 1);
}
예제 #26
0
	void markBlockFree(Block & block)
	{
		assert(block.free == false);
		block.free = true;
		insertFreeBlock(block);
	}
예제 #27
0
/* Allocate a block of size size and return a pointer to it. */
void* mm_malloc (size_t size) {
  size_t reqSize;
  BlockInfo * ptrFreeBlock = NULL;
  BlockInfo * splitBlock;
  size_t blockSize;
  size_t precedingBlockUseTag;

  // Zero-size requests get NULL.
  if (size == 0) {
    return NULL;
  }

  // Add one word for the initial size header.
  // Note that we don't need to boundary tag when the block is used!
  size += WORD_SIZE;
  if (size <= MIN_BLOCK_SIZE) {
    // Make sure we allocate enough space for a blockInfo in case we
    // free this block (when we free this block, we'll need to use the
    // next pointer, the prev pointer, and the boundary tag).
    reqSize = MIN_BLOCK_SIZE;
  } else {
    // Round up for correct alignment
    reqSize = ALIGNMENT * ((size + ALIGNMENT - 1) / ALIGNMENT);
  }

  // Implement mm_malloc.  You can change or remove any of the above
  // code.  It is included as a suggestion of where to start.
  // You will want to replace this return statement...

  // find free block of reqSize
  ptrFreeBlock = searchFreeList(reqSize);
  while ( ptrFreeBlock == NULL ) {
    requestMoreSpace(1 << 14);
    ptrFreeBlock = searchFreeList(reqSize);
  }
  // check free block size vs reqSize vs alignment requirements,
  // split if necessary. If split, reformat newly created free
  // block (add header, set bits, add footer).
  blockSize = SIZE(ptrFreeBlock->sizeAndTags);
  if ( blockSize - reqSize >= MIN_BLOCK_SIZE ) {
    // Split, set size and tags of new block
    splitBlock = (BlockInfo*) POINTER_ADD(ptrFreeBlock, reqSize);
    blockSize -= reqSize;
    splitBlock->sizeAndTags = blockSize | TAG_PRECEDING_USED;
    splitBlock->sizeAndTags &= ~0 << 1; // turn off use bit - preserve others
    
    // set footer equal to header. Current ptr + blockSize - one word = boundary
    // tag of current block (word prior to start of next block)
    *((size_t*) POINTER_ADD(splitBlock, blockSize- WORD_SIZE))= 
      splitBlock->sizeAndTags;
    insertFreeBlock(splitBlock);
    // set size of ptrFreeBlock to exclude size of newBlock
    blockSize = reqSize;
  } else { // if we didnt split, set the next block's preceding tag to 1
    *((size_t*) POINTER_ADD(ptrFreeBlock, SIZE(ptrFreeBlock->sizeAndTags))) |= 
			   TAG_PRECEDING_USED;
  }
  removeFreeBlock(ptrFreeBlock);

  precedingBlockUseTag = ptrFreeBlock->sizeAndTags & TAG_PRECEDING_USED;
  // if the preceding block is used as well, set lower two bits. Else, set only
  // used bit.
  if ( precedingBlockUseTag ) {
    ptrFreeBlock->sizeAndTags = blockSize | (TAG_PRECEDING_USED + TAG_USED);
  } else {
    ptrFreeBlock->sizeAndTags = blockSize | TAG_USED;
  }

  // return pointer to block (beginning of payload)
  // if null, return null. else return 8 after start of block (ie skip header,
  // return ptr to payload region)
  if ( ptrFreeBlock == NULL) { return NULL; }
  else { return (void*) POINTER_ADD(ptrFreeBlock, WORD_SIZE); }
 }
예제 #28
0
        void Vbo::resizeVbo(size_t newCapacity) {
            VboState oldState = m_state;
            
            unsigned char* temp = NULL;
            MemBlock::List memBlocks;
            if (m_vboId != 0 && m_freeCapacity < m_totalCapacity) {
                VboBlock* currentBlock = m_first;
                size_t totalLength = 0;
                
                while (currentBlock != NULL) {
                    while (currentBlock != NULL && currentBlock->free())
                        currentBlock = currentBlock->m_next;
                    if (currentBlock != NULL) {
                        size_t start = currentBlock->address();
                        size_t length = 0;
                        while (currentBlock != NULL && !currentBlock->free()) {
                            length += currentBlock->capacity();
                            currentBlock = currentBlock->m_next;
                        }
                        memBlocks.push_back(MemBlock(start, length));
                        totalLength += length;
                    }
                }
                
                if (m_state < VboActive)
                    activate();
                if (m_state < VboMapped)
                    map();

                temp = new unsigned char[totalLength];
                size_t offset = 0;
                MemBlock::List::const_iterator it, end;
                for (it = memBlocks.begin(), end = memBlocks.end(); it != end; ++it) {
                    const MemBlock& memBlock = *it;
                    memcpy(temp + offset, m_buffer + memBlock.start, memBlock.length);
                    offset += memBlock.length;
                }
            }
            
            size_t addedCapacity = newCapacity - m_totalCapacity;
            m_freeCapacity = newCapacity - (m_totalCapacity - m_freeCapacity);
            m_totalCapacity = newCapacity;
            
            if (m_last->free()) {
                resizeBlock(*m_last, m_last->capacity() + addedCapacity);
            } else {
                VboBlock* block = new VboBlock(*this, m_last->address() + m_last->capacity(), addedCapacity);
                block->insertBetween(m_last, NULL);
                insertFreeBlock(*block);
                m_last = block;
            }
            
            if (m_vboId != 0) {
                if (m_state == VboMapped)
                    unmap();
                if (m_state == VboActive)
                    deactivate();
                glDeleteBuffers(1, &m_vboId);
                m_vboId = 0;
            }
            
            if (temp != NULL) {
                assert(!memBlocks.empty());
                
                if (m_state < VboActive)
                    activate();
                if (m_state < VboMapped)
                    map();
                
                size_t offset = 0;
                MemBlock::List::const_iterator it, end;
                for (it = memBlocks.begin(), end = memBlocks.end(); it != end; ++it) {
                    const MemBlock& memBlock = *it;
                    memcpy(m_buffer + memBlock.start, temp + offset, memBlock.length);
                }
                
                delete [] temp;
                temp = NULL;
                memBlocks.clear();
                
                if (oldState < VboMapped)
                    unmap();
                if (oldState < VboActive)
                    deactivate();
            } else {
                if (oldState > VboInactive && m_state < VboActive)
                    activate();
                if (oldState > VboActive && m_state < VboMapped)
                    map();
            }
            
#ifdef _DEBUG_VBO
            checkBlockChain();
            checkFreeBlocks();
#endif
        }