Ejemplo n.º 1
0
bool FixedAllocator::Deallocate( void * p, Chunk * hint )
{
    assert(!chunks_.empty());
    assert(&chunks_.front() <= deallocChunk_);
    assert(&chunks_.back() >= deallocChunk_);
    assert( &chunks_.front() <= allocChunk_ );
    assert( &chunks_.back() >= allocChunk_ );
    assert( CountEmptyChunks() < 2 );

    Chunk * foundChunk = ( NULL == hint ) ? VicinityFind( p ) : hint;
    if ( NULL == foundChunk )
        return false;

    assert( foundChunk->HasBlock( p, numBlocks_ * blockSize_ ) );
#ifdef LOKI_CHECK_FOR_CORRUPTION
    if ( foundChunk->IsCorrupt( numBlocks_, blockSize_, true ) )
    {
        assert( false );
        return false;
    }
    if ( foundChunk->IsBlockAvailable( p, numBlocks_, blockSize_ ) )
    {
        assert( false );
        return false;
    }
#endif
    deallocChunk_ = foundChunk;
    DoDeallocate(p);
    assert( CountEmptyChunks() < 2 );

    return true;
}
Ejemplo n.º 2
0
	void * FixedAllocator::Allocate()
	{
		if (!last_alloc_ || last_alloc_->blocks_available_ == 0)
		{
			// no memory available in the cached chunk, try to find one.
			
			Chunks::iterator e = chunks_.end();
			Chunks::iterator i = chunks_.begin();
				
			for (; i!=e; ++i)
			{
				if (i->blocks_available_ > 0)
				{
					// found a chunk!
					last_alloc_ = &*i;
					break;
				}
			}
			if (i == e)
			{
				// no chunks have blocks available, add a new one.
				chunks_.reserve(chunks_.size()+1);
				MemChunk chunk;
				chunk.Init(block_size_, blocks_);
				chunks_.push_back(chunk);
				last_alloc_ = &chunks_.back();
				last_dealloc_ = &chunks_.back();
			}
		}
		
		// chunk pointer vaild check
		assert(last_alloc_ != NULL);
		assert(last_alloc_->blocks_available_ > 0);
		return last_alloc_->Allocate(block_size_);
	}
Ejemplo n.º 3
0
bool FixedAllocator::MakeNewChunk( void )
{
    bool allocated = false;
    try
    {
        std::size_t size = chunks_.size();
        // Calling chunks_.reserve *before* creating and initializing the new
        // Chunk means that nothing is leaked by this function in case an
        // exception is thrown from reserve.
        if ( chunks_.capacity() == size )
        {
            if ( 0 == size ) size = 4;
            chunks_.reserve( size * 2 );
        }
        Chunk newChunk;
        allocated = newChunk.Init( blockSize_, numBlocks_ );
        if ( allocated )
            chunks_.push_back( newChunk );
    }
    catch ( ... )
    {
        allocated = false;
    }
    if ( !allocated ) return false;

    allocChunk_ = &chunks_.back();
    deallocChunk_ = &chunks_.front();
    return true;
}
Ejemplo n.º 4
0
bool FixedAllocator::TrimEmptyChunk( void )
{
    // prove either emptyChunk_ points nowhere, or points to a truly empty Chunk.
    assert( ( NULL == emptyChunk_ ) || ( emptyChunk_->HasAvailable( numBlocks_ ) ) );
    if ( NULL == emptyChunk_ ) return false;

    // If emptyChunk_ points to valid Chunk, then chunk list is not empty.
    assert( !chunks_.empty() );
    // And there should be exactly 1 empty Chunk.
    assert( 1 == CountEmptyChunks() );

    Chunk * lastChunk = &chunks_.back();
    if ( lastChunk != emptyChunk_ )
        std::swap( *emptyChunk_, *lastChunk );
    assert( lastChunk->HasAvailable( numBlocks_ ) );
    lastChunk->Release();
    chunks_.pop_back();

    if ( chunks_.empty() )
    {
        allocChunk_ = NULL;
        deallocChunk_ = NULL;
    }
    else
    {
        if ( deallocChunk_ == emptyChunk_ )
        {
            deallocChunk_ = &chunks_.front();
            assert( deallocChunk_->blocksAvailable_ < numBlocks_ );
        }
        if ( allocChunk_ == emptyChunk_ )
        {
            allocChunk_ = &chunks_.back();
            assert( allocChunk_->blocksAvailable_ < numBlocks_ );
        }
    }

    emptyChunk_ = NULL;
    assert( 0 == CountEmptyChunks() );

    return true;
}
Ejemplo n.º 5
0
      void
      allocateChunk ()
      {
        chunks.push_back (new Chunk); // requires c++17 new with alignment

        for (Storage& storage : chunks.back ())
          {
            FreeListNode *node = reinterpret_cast<FreeListNode*> (&storage);
            new (node) FreeListNode;
            freeList.push_front (*node);
          }
      }
Ejemplo n.º 6
0
bool FixedAllocator::Deallocate( void * p, bool doChecks )
{
    if ( doChecks )
    {
        assert(!chunks_.empty());
        assert(&chunks_.front() <= deallocChunk_);
        assert(&chunks_.back() >= deallocChunk_);
        assert( &chunks_.front() <= allocChunk_ );
        assert( &chunks_.back() >= allocChunk_ );
    }

    Chunk * foundChunk = VicinityFind( p );
    if ( doChecks )
    {
        assert( NULL != foundChunk );
    }
    else if ( NULL == foundChunk )
        return false;

    deallocChunk_ = foundChunk;
    DoDeallocate(p);
    return true;
}
Ejemplo n.º 7
0
  char* allocate(size_t size)
  {
    assert(size <= chunk_size);

    if (chunks.empty() ||
        (next_free + size) > chunk_size)
    {
      char* chunk = new char[chunk_size];
      chunks.push_back(chunk);
      next_free = 0;
    }

    char* ptr = chunks.back() + next_free;
    next_free += size;
    return ptr;
  }
Ejemplo n.º 8
0
void FixedAllocator::DoDeallocate(void* p)
{
    // Show that deallocChunk_ really owns the block at address p.
    assert( deallocChunk_->HasBlock( p, numBlocks_ * blockSize_ ) );
    // Either of the next two assertions may fail if somebody tries to
    // delete the same block twice.
    assert( emptyChunk_ != deallocChunk_ );
    assert( !deallocChunk_->HasAvailable( numBlocks_ ) );
    // prove either emptyChunk_ points nowhere, or points to a truly empty Chunk.
    assert( ( NULL == emptyChunk_ ) || ( emptyChunk_->HasAvailable( numBlocks_ ) ) );

    // call into the chunk, will adjust the inner list but won't release memory
    deallocChunk_->Deallocate(p, blockSize_);

    if ( deallocChunk_->HasAvailable( numBlocks_ ) )
    {
        assert( emptyChunk_ != deallocChunk_ );
        // deallocChunk_ is empty, but a Chunk is only released if there are 2
        // empty chunks.  Since emptyChunk_ may only point to a previously
        // cleared Chunk, if it points to something else besides deallocChunk_,
        // then FixedAllocator currently has 2 empty Chunks.
        if ( NULL != emptyChunk_ )
        {
            // If last Chunk is empty, just change what deallocChunk_
            // points to, and release the last.  Otherwise, swap an empty
            // Chunk with the last, and then release it.
            Chunk * lastChunk = &chunks_.back();
            if ( lastChunk == deallocChunk_ )
                deallocChunk_ = emptyChunk_;
            else if ( lastChunk != emptyChunk_ )
                std::swap( *emptyChunk_, *lastChunk );
            assert( lastChunk->HasAvailable( numBlocks_ ) );
            lastChunk->Release();
            chunks_.pop_back();
            if ( ( allocChunk_ == lastChunk ) || allocChunk_->IsFilled() ) 
                allocChunk_ = deallocChunk_;
        }
        emptyChunk_ = deallocChunk_;
    }

    // prove either emptyChunk_ points nowhere, or points to a truly empty Chunk.
    assert( ( NULL == emptyChunk_ ) || ( emptyChunk_->HasAvailable( numBlocks_ ) ) );
}
Ejemplo n.º 9
0
	void FixedAllocator::Deallocate(void *p)
	{
		assert(last_dealloc_);
		assert(!chunks_.empty());
		
		// find the chunk that holds the pointer.
		last_dealloc_ = FindChunk(p);
		assert(last_dealloc_);
		
		// found the chunk, so forwards deallocation request to it.
		last_dealloc_->Deallocate(p, block_size_);
		
		// the chunk is empty, should we free it?
		if (last_dealloc_->blocks_available_ == blocks_)
		{
			MemChunk *last_chunk = &chunks_.back();
			
			if (last_chunk = last_dealloc_)
			{
				if (chunks_.size() > 1 && last_dealloc_[-1].blocks_available_ == blocks_)
				{
					// there are two free chunk, so free one.
					last_chunk->Free();
					chunks_.pop_back();
					last_alloc_ = last_dealloc_ = &chunks_.front();
				}
			}
			else if (last_chunk->blocks_available_ == blocks_)
			{
				// there are two free chunk, so free one.
				last_chunk->Free();
				chunks_.pop_back();
				last_alloc_ = last_dealloc_;
			}
			else
			{
				// move the empty chunk to the bottom.
				std::swap(*last_dealloc_, *last_chunk);
				last_alloc_ = last_dealloc_;
			}
		}
	}
Ejemplo n.º 10
0
FixedAllocator::Chunk * FixedAllocator::VicinityFind( void * p )
{
    if ( chunks_.empty() ) return NULL;
    assert(deallocChunk_);

    unsigned char * pc = static_cast< unsigned char * >( p );
    const std::size_t chunkLength = numBlocks_ * blockSize_;

    Chunk* lo = deallocChunk_;
    Chunk* hi = deallocChunk_ + 1;
    Chunk* loBound = &chunks_.front();
    Chunk* hiBound = &chunks_.back() + 1;

    // Special case: deallocChunk_ is the last in the array
    if (hi == hiBound) hi = NULL;

    for (;;)
    {
        if (lo)
        {
            if ( lo->HasBlock( pc, chunkLength ) ) return lo;
            if ( lo == loBound )
            {
                lo = NULL;
                if ( NULL == hi ) break;
            }
            else --lo;
        }

        if (hi)
        {
            if ( hi->HasBlock( pc, chunkLength ) ) return hi;
            if ( ++hi == hiBound )
            {
                hi = NULL;
                if ( NULL == lo ) break;
            }
        }
    }

    return NULL;
}
Ejemplo n.º 11
0
void FixedAllocator::DoDeallocate(void* p)
{
    assert( deallocChunk_->HasBlock( static_cast< unsigned char * >( p ),
                                     numBlocks_ * blockSize_ ) );
    // prove either emptyChunk_ points nowhere, or points to a truly empty Chunk.
    assert( ( NULL == emptyChunk_ ) || ( emptyChunk_->HasAvailable( numBlocks_ ) ) );

    // call into the chunk, will adjust the inner list but won't release memory
    deallocChunk_->Deallocate(p, blockSize_);

    if ( deallocChunk_->HasAvailable( numBlocks_ ) )
    {
        assert( emptyChunk_ != deallocChunk_ );
        // deallocChunk_ is empty, but a Chunk is only released if there are 2
        // empty chunks.  Since emptyChunk_ may only point to a previously
        // cleared Chunk, if it points to something else besides deallocChunk_,
        // then FixedAllocator currently has 2 empty Chunks.
        if ( NULL != emptyChunk_ )
        {
            // If last Chunk is empty, just change what deallocChunk_
            // points to, and release the last.  Otherwise, swap an empty
            // Chunk with the last, and then release it.
            Chunk * lastChunk = &chunks_.back();
            if ( lastChunk == deallocChunk_ )
                deallocChunk_ = emptyChunk_;
            else if ( lastChunk != emptyChunk_ )
                std::swap( *emptyChunk_, *lastChunk );
            assert( lastChunk->HasAvailable( numBlocks_ ) );
            lastChunk->Release();
            chunks_.pop_back();
            allocChunk_ = deallocChunk_;
        }
        emptyChunk_ = deallocChunk_;
    }

    // prove either emptyChunk_ points nowhere, or points to a truly empty Chunk.
    assert( ( NULL == emptyChunk_ ) || ( emptyChunk_->HasAvailable( numBlocks_ ) ) );
}
Ejemplo n.º 12
0
	MemChunk * FixedAllocator::FindChunk(void *p)
	{
		assert(last_dealloc_);
		assert(!chunks_.empty());

		MemChunk *lo_b = &chunks_.front();
		MemChunk *hi_b = &chunks_.back()+1;
		MemChunk *lo = last_dealloc_;
		MemChunk *hi = last_dealloc_+1;
		
		if (hi == hi_b) hi = NULL;
		
		for (;;)
		{
			if (lo)
			{
				if (InChunk(lo, p))
					return lo;
				if (lo == lo_b)
					lo = NULL;
				else
					--lo;
			}
			if (hi)
			{
				if (InChunk(hi, p))
					return hi;
				if (++hi == hi_b)
					hi = NULL;
			}
		}
		
		// Never gets here.
		assert(false);
		return NULL;
	} 
Ejemplo n.º 13
0
bool FixedAllocator::IsCorrupt( void ) const
{
    const bool isEmpty = chunks_.empty();
    ChunkCIter start( chunks_.begin() );
    ChunkCIter last( chunks_.end() );
    const size_t emptyChunkCount = CountEmptyChunks();

    if ( isEmpty )
    {
        if ( start != last )
        {
            assert( false );
            return true;
        }
        if ( 0 < emptyChunkCount )
        {
            assert( false );
            return true;
        }
        if ( NULL != deallocChunk_ )
        {
            assert( false );
            return true;
        }
        if ( NULL != allocChunk_ )
        {
            assert( false );
            return true;
        }
        if ( NULL != emptyChunk_ )
        {
            assert( false );
            return true;
        }
    }

    else
    {
        const Chunk * front = &chunks_.front();
        const Chunk * back  = &chunks_.back();
        if ( start >= last )
        {
            assert( false );
            return true;
        }
        if ( back < deallocChunk_ )
        {
            assert( false );
            return true;
        }
        if ( back < allocChunk_ )
        {
            assert( false );
            return true;
        }
        if ( front > deallocChunk_ )
        {
            assert( false );
            return true;
        }
        if ( front > allocChunk_ )
        {
            assert( false );
            return true;
        }

        switch ( emptyChunkCount )
        {
            case 0:
                if ( emptyChunk_ != NULL )
                {
                    assert( false );
                    return true;
                }
                break;
            case 1:
                if ( emptyChunk_ == NULL )
                {
                    assert( false );
                    return true;
                }
                if ( back < emptyChunk_ )
                {
                    assert( false );
                    return true;
                }
                if ( front > emptyChunk_ )
                {
                    assert( false );
                    return true;
                }
                if ( !emptyChunk_->HasAvailable( numBlocks_ ) )
                {
                    // This may imply somebody tried to delete a block twice.
                    assert( false );
                    return true;
                }
                break;
            default:
                assert( false );
                return true;
        }
        for ( ChunkCIter it( start ); it != last; ++it )
        {
            const Chunk & chunk = *it;
            if ( chunk.IsCorrupt( numBlocks_, blockSize_, true ) )
                return true;
        }
    }

    return false;
}