--- /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 <e32base.h>
+#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>(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 ();
+ }
+
+