diff -r 000000000000 -r f5a58ecadc66 servicediscoveryandcontrol/pnp/test/upnp/chunkmgr/src/cchunkmanager.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/servicediscoveryandcontrol/pnp/test/upnp/chunkmgr/src/cchunkmanager.cpp Tue Feb 02 01:12:20 2010 +0200 @@ -0,0 +1,274 @@ +// Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// @file +// @internalComponent +// +// + +#include +#include "cchunkmanager.h" +#include "cchunkallocator.h" +#include "cmemchunk.h" +#include "rchunkpool.h" +#include "rmemcell.h" + +EXPORT_C CChunkManager* CChunkManager::NewL ( TInt aHeapSize ) + { + CChunkManager* self = new ( ELeave ) CChunkManager ( aHeapSize ); + CleanupStack::PushL ( self ); + self->ConstructL (); + CleanupStack::Pop ( self ); + return self; + } + +CChunkManager::CChunkManager ( TInt aHeapSize ) + :iHeapSize ( aHeapSize ) + { + } + +EXPORT_C CChunkManager::~CChunkManager () + { + delete iChunkAllocator; + for ( TInt i = 0; i < iChunkPools.Count (); i++ ) + { + iChunkPools[i].Close (); + } + iChunkPools.Close (); + iLock.Close (); + } + +void CChunkManager::ConstructL () + { + User::LeaveIfError ( iLock.CreateLocal () ); + iChunkAllocator = CChunkAllocator::NewL ( iHeapSize ); + } + +CChunkAllocator& CChunkManager::Allocator () + { + return *iChunkAllocator; + } + +EXPORT_C void CChunkManager::AddPoolL ( TInt aBlockSize, TInt aNumBlocks, TInt aThresholdValue, TInt aMinGrowth ) + { + __ASSERT_ALWAYS ( aBlockSize > 0, User::Invariant () ); // TODO + __ASSERT_ALWAYS ( aNumBlocks > 0, User::Invariant () ); + __ASSERT_ALWAYS ( aThresholdValue >= 0, User::Invariant () ); + __ASSERT_ALWAYS ( aMinGrowth >= 0, User::Invariant () ); + + // aling the block size + const TUint8 KMemAlignment = 8; + TInt blockPadding = aBlockSize % KMemAlignment; + if ( blockPadding != 0 ) + { + aBlockSize += KMemAlignment - blockPadding; + } + if ( aMinGrowth == 0 ) + { + aMinGrowth = 1; + } + + + //maintains iChunkPools in blocks size order + TInt found = KErrNotFound; + TInt index = 0; + RChunkPool tempPool ( *this, aBlockSize ); + found = iChunkPools.FindInOrder ( tempPool, index, TLinearOrder(RChunkPool::Compare) ); + + // create a new pool chain + if ( found == KErrNotFound ) + { + RChunkPool pool ( aBlockSize, aThresholdValue, aMinGrowth, *this ); + //maintains iChunkPools in blocks size order + User::LeaveIfError ( iChunkPools.Insert ( pool, index ) ); + + RChunkPool* chunkPool = &iChunkPools[index]; + chunkPool->OpenL (); + + // Lock the freelist, inorder to add new blocks to the free list + chunkPool->Wait (); + TInt err = AllocChunk ( *chunkPool, aNumBlocks ); + chunkPool->Signal (); + + User::LeaveIfError ( err ); + } + else + { + // update existing values + iChunkPools[found].SetGrowth ( aMinGrowth ); + iChunkPools[found].SetThreshold ( aThresholdValue ); + } + } + +TInt CChunkManager::AllocChunk ( RChunkPool& aChunkPool, TInt aNumBlocks ) + { + // verify if maximum size is exceeded + if ( ( iUsedSpace + aNumBlocks * aChunkPool.BlockSize () ) > iHeapSize ) + { + return KErrNoMemory; + } + + CMemChunk* newChunk = CMemChunk::New ( *iChunkAllocator, aChunkPool, aNumBlocks, aChunkPool.BlockSize () ); + if ( newChunk != NULL ) + { + iLock.Wait (); + aChunkPool.Append ( newChunk ); + iLock.Signal (); + + // RChunkPool lock is already acquired + aChunkPool.AppendToFreeList ( newChunk ); + + iUsedSpace += sizeof ( CMemChunk ) + ( aNumBlocks * aChunkPool.BlockSize () ) ; + return KErrNone; + } + + return KErrNoMemory; + } + +RMemCell* CChunkManager::Alloc ( TInt aSize ) + { + TInt poolsCount = iChunkPools.Count (); + __ASSERT_DEBUG ( poolsCount != 0, User::Invariant () ); //TODO + + RMemCellList list; + // Search and get the avaliable memCell list + SearchAndAlloc ( list, aSize ); + + return list.First (); + } + +void CChunkManager::SearchAndAlloc ( RMemCellList& aList, TInt aSize ) + { + if ( aSize == 0 ) + { + __ASSERT_ALWAYS ( 0, User::Invariant () ); //TODO + } + + RChunkPool* poolChosen = NULL; + RChunkPool* startPool = &iChunkPools[0]; + RChunkPool* pool = &iChunkPools[iChunkPools.Count () - 1]; + + TInt minUnusedBytes = 0, minBlocks = 0; + + do + { + TInt blockSize = pool->BlockSize (); + + TInt unusedBytes = aSize % blockSize; + TInt neededBlocks = aSize / blockSize; + + if ( unusedBytes != 0 ) + { + unusedBytes = blockSize - unusedBytes; + neededBlocks += 1; + } + + if ( poolChosen == NULL ) //for the first time this will be true + { + poolChosen = pool; + minUnusedBytes = unusedBytes; + minBlocks = neededBlocks; + } + else + { + if ( unusedBytes == minUnusedBytes ) + { + if ( neededBlocks < minBlocks ) + { + poolChosen = pool; + minUnusedBytes = unusedBytes; + minBlocks = neededBlocks; + } + } + else if ( unusedBytes < minUnusedBytes ) + { + poolChosen = pool; + minUnusedBytes = unusedBytes; + minBlocks = neededBlocks; + } + } + } while ( pool-- != startPool ); + + if ( poolChosen == NULL ) + { + __ASSERT_DEBUG ( 0, User::Invariant () ); + } + + TUint allocatedBytes = 0; + TBool growthFailed = EFalse; + if ( aSize <= poolChosen->FreeSpace () ) + { + allocatedBytes = poolChosen->Alloc ( aList, aSize ); + } + else + { + allocatedBytes = poolChosen->GrowAndAlloc ( aList, aSize, minBlocks ); + + if ( allocatedBytes == 0 ) + { + // need to search for the next best match and however, this time + // requesting pool to grow may not be worth :), as only error condition is KErrNoMemory + growthFailed = ETrue; + } + } + + if ( allocatedBytes >= aSize ) + { + return; + } + else if ( growthFailed ) + { + // just get the pool that can satisfy the request, no more best,good,worst match + for ( TInt i = 0; i < iChunkPools.Count (); i++ ) + { + if ( aSize <= iChunkPools[i].FreeSpace () ) + { + allocatedBytes = iChunkPools[i].Alloc ( aList, aSize ); + break; + } + } + } + } + +TInt CChunkManager::BytesAvailable () + { + TInt freeSpace = iHeapSize - iUsedSpace; + + freeSpace -= sizeof ( CMemChunk ); + + return freeSpace <= 0 ? KErrNoMemory : freeSpace; + } + +// return a chain of MBufs to the pool +void CChunkManager::Free ( RMemCell* aPtr ) + { + RChunkPool* pool ( aPtr->Pool () ); + pool->Wait (); + + while ( aPtr != NULL ) + { + RMemCell* nextPtr = aPtr->Next (); + + // reset length to the size of the block and break the link + aPtr->SetLength ( aPtr->Size () ); + aPtr->Link ( NULL ); + + // adds single block back to its free list and adjusts its free space + pool->FreeToPool ( aPtr ); + + aPtr = nextPtr; + } + pool->Signal (); + } + +