servicediscoveryandcontrol/pnp/test/upnp/chunkmgr/src/cchunkmanager.cpp
changeset 0 f5a58ecadc66
equal deleted inserted replaced
-1:000000000000 0:f5a58ecadc66
       
     1 // Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 // @file
       
    15 // @internalComponent
       
    16 // 
       
    17 //
       
    18 
       
    19 #include <e32base.h>
       
    20 #include "cchunkmanager.h"
       
    21 #include "cchunkallocator.h"
       
    22 #include "cmemchunk.h"
       
    23 #include "rchunkpool.h"
       
    24 #include "rmemcell.h"
       
    25 
       
    26 EXPORT_C CChunkManager* CChunkManager::NewL ( TInt aHeapSize )
       
    27 	{
       
    28 	CChunkManager* self = new ( ELeave ) CChunkManager ( aHeapSize );
       
    29 	CleanupStack::PushL ( self );
       
    30 	self->ConstructL ();
       
    31 	CleanupStack::Pop ( self );
       
    32 	return self;
       
    33 	}
       
    34 
       
    35 CChunkManager::CChunkManager ( TInt aHeapSize )
       
    36 	:iHeapSize ( aHeapSize )
       
    37 	{
       
    38 	}
       
    39 	
       
    40 EXPORT_C CChunkManager::~CChunkManager ()
       
    41 	{
       
    42 	delete iChunkAllocator;
       
    43 	for ( TInt i = 0; i < iChunkPools.Count (); i++ )
       
    44 		{
       
    45 		iChunkPools[i].Close ();
       
    46 		}
       
    47 	iChunkPools.Close ();
       
    48 	iLock.Close ();
       
    49 	}
       
    50 	
       
    51 void CChunkManager::ConstructL ()
       
    52 	{
       
    53 	User::LeaveIfError ( iLock.CreateLocal () );
       
    54 	iChunkAllocator = CChunkAllocator::NewL ( iHeapSize );
       
    55 	}
       
    56 	
       
    57 CChunkAllocator& CChunkManager::Allocator ()
       
    58 	{
       
    59 	return *iChunkAllocator;
       
    60 	}
       
    61 	
       
    62 EXPORT_C void CChunkManager::AddPoolL ( TInt aBlockSize, TInt aNumBlocks, TInt aThresholdValue, TInt aMinGrowth )
       
    63 	{
       
    64 	__ASSERT_ALWAYS ( aBlockSize > 0, User::Invariant () ); // TODO
       
    65     __ASSERT_ALWAYS ( aNumBlocks > 0, User::Invariant () );
       
    66     __ASSERT_ALWAYS ( aThresholdValue >= 0, User::Invariant () );
       
    67    	__ASSERT_ALWAYS ( aMinGrowth >= 0, User::Invariant () );
       
    68    	    
       
    69     // aling the block size
       
    70    	const TUint8 KMemAlignment = 8;
       
    71    	TInt blockPadding = aBlockSize % KMemAlignment;
       
    72 	if ( blockPadding != 0 )
       
    73     	{
       
    74 	 	aBlockSize += KMemAlignment - blockPadding;
       
    75         }
       
    76     if ( aMinGrowth == 0 )
       
    77       	{
       
    78         aMinGrowth = 1;
       
    79         }
       
    80  	
       
    81  	
       
    82  	//maintains iChunkPools in blocks size order
       
    83     TInt found = KErrNotFound;
       
    84     TInt index = 0;
       
    85     RChunkPool tempPool ( *this, aBlockSize );
       
    86     found  = iChunkPools.FindInOrder ( tempPool, index, TLinearOrder<RChunkPool>(RChunkPool::Compare) );
       
    87     
       
    88     // create a new pool chain
       
    89     if ( found == KErrNotFound )
       
    90    		{
       
    91         RChunkPool pool ( aBlockSize, aThresholdValue, aMinGrowth, *this );
       
    92         //maintains iChunkPools in blocks size order
       
    93         User::LeaveIfError ( iChunkPools.Insert ( pool, index ) );
       
    94         
       
    95         RChunkPool* chunkPool = &iChunkPools[index];
       
    96 		chunkPool->OpenL ();
       
    97 		
       
    98         // Lock the freelist, inorder to add new blocks to the free list
       
    99         chunkPool->Wait ();
       
   100         TInt err = AllocChunk ( *chunkPool, aNumBlocks );
       
   101         chunkPool->Signal ();
       
   102 		
       
   103         User::LeaveIfError ( err );
       
   104     	}
       
   105 	else
       
   106     	{
       
   107         // update existing values
       
   108         iChunkPools[found].SetGrowth ( aMinGrowth );
       
   109         iChunkPools[found].SetThreshold ( aThresholdValue );
       
   110         }
       
   111 	}
       
   112 	
       
   113 TInt CChunkManager::AllocChunk ( RChunkPool& aChunkPool, TInt aNumBlocks )
       
   114 	{
       
   115     // verify if maximum size is exceeded
       
   116     if ( ( iUsedSpace + aNumBlocks * aChunkPool.BlockSize () ) > iHeapSize )
       
   117         {
       
   118         return KErrNoMemory;
       
   119         }
       
   120 	
       
   121     CMemChunk* newChunk = CMemChunk::New ( *iChunkAllocator, aChunkPool, aNumBlocks, aChunkPool.BlockSize () );
       
   122 	if ( newChunk != NULL )
       
   123         {
       
   124         iLock.Wait ();
       
   125         aChunkPool.Append ( newChunk );
       
   126         iLock.Signal ();
       
   127 		
       
   128 		// RChunkPool lock is already acquired
       
   129         aChunkPool.AppendToFreeList ( newChunk );
       
   130 		
       
   131         iUsedSpace += sizeof ( CMemChunk ) + ( aNumBlocks * aChunkPool.BlockSize () ) ;
       
   132         return KErrNone;
       
   133         }
       
   134 	
       
   135 	return KErrNoMemory;
       
   136 	}
       
   137 
       
   138 RMemCell* CChunkManager::Alloc ( TInt aSize )
       
   139 	{
       
   140 	TInt poolsCount = iChunkPools.Count ();
       
   141 	__ASSERT_DEBUG ( poolsCount != 0, User::Invariant () ); //TODO
       
   142 	
       
   143 	RMemCellList list;
       
   144 	// Search and get the avaliable memCell list
       
   145 	SearchAndAlloc ( list, aSize );
       
   146 	
       
   147 	return list.First ();
       
   148 	}
       
   149 	
       
   150 void CChunkManager::SearchAndAlloc ( RMemCellList& aList, TInt aSize )
       
   151 	{
       
   152 	if ( aSize == 0 ) 
       
   153 		{
       
   154 		__ASSERT_ALWAYS ( 0, User::Invariant () ); //TODO
       
   155 		}
       
   156 	
       
   157 	RChunkPool* poolChosen = NULL;
       
   158 	RChunkPool* startPool = &iChunkPools[0];
       
   159 	RChunkPool* pool = &iChunkPools[iChunkPools.Count () - 1];
       
   160 	
       
   161 	TInt minUnusedBytes = 0, minBlocks = 0;
       
   162 	
       
   163 	do
       
   164 		{
       
   165 		TInt blockSize = pool->BlockSize ();
       
   166 		
       
   167 		TInt unusedBytes = aSize % blockSize;
       
   168 		TInt neededBlocks = aSize / blockSize;
       
   169 		
       
   170 		if ( unusedBytes != 0 )
       
   171 			{
       
   172 			unusedBytes = blockSize - unusedBytes;
       
   173 			neededBlocks += 1;
       
   174 			}
       
   175 		
       
   176 		if ( poolChosen == NULL ) //for the first time this will be true
       
   177 			{
       
   178 			poolChosen = pool;
       
   179 			minUnusedBytes = unusedBytes;
       
   180 			minBlocks = neededBlocks;
       
   181 			}
       
   182 		else
       
   183 			{
       
   184 			if ( unusedBytes == minUnusedBytes )
       
   185 				{
       
   186 				if ( neededBlocks < minBlocks )
       
   187 					{
       
   188 					poolChosen = pool;
       
   189 					minUnusedBytes = unusedBytes;
       
   190 					minBlocks = neededBlocks;
       
   191 					}
       
   192 				}
       
   193 			else if ( unusedBytes < minUnusedBytes )
       
   194 				{
       
   195 				poolChosen = pool;
       
   196 				minUnusedBytes = unusedBytes;
       
   197 				minBlocks = neededBlocks;
       
   198 				}
       
   199 			}
       
   200 		} while ( pool-- != startPool );
       
   201 	
       
   202 	if ( poolChosen == NULL )
       
   203 		{
       
   204 		__ASSERT_DEBUG ( 0, User::Invariant () );
       
   205 		}
       
   206 	
       
   207 	TUint allocatedBytes = 0;
       
   208 	TBool growthFailed = EFalse;
       
   209 	if ( aSize <= poolChosen->FreeSpace () )
       
   210 		{
       
   211 		allocatedBytes = poolChosen->Alloc ( aList, aSize );
       
   212 		}
       
   213 	else
       
   214 		{
       
   215 		allocatedBytes = poolChosen->GrowAndAlloc ( aList, aSize, minBlocks );
       
   216 				
       
   217 		if ( allocatedBytes == 0 )
       
   218 			{
       
   219 			// need to search for the next best match and however, this time
       
   220 			// requesting pool to grow may not be worth :), as only error condition is KErrNoMemory
       
   221 			growthFailed = ETrue;
       
   222 			}
       
   223 		}
       
   224 	
       
   225 	if ( allocatedBytes >= aSize )
       
   226 		{
       
   227 		return;
       
   228 		}
       
   229 	else if ( growthFailed )
       
   230 		{
       
   231 		// just get the pool that can satisfy the request, no more best,good,worst match
       
   232 		for ( TInt i = 0; i < iChunkPools.Count (); i++ )
       
   233 			{			
       
   234 			if ( aSize <= iChunkPools[i].FreeSpace () )
       
   235 				{
       
   236 				allocatedBytes = iChunkPools[i].Alloc ( aList, aSize );
       
   237 				break;
       
   238 				}
       
   239 			}
       
   240 		}
       
   241 	}
       
   242 	
       
   243 TInt CChunkManager::BytesAvailable ()
       
   244 	{
       
   245 	TInt freeSpace = iHeapSize - iUsedSpace;
       
   246 	
       
   247 	freeSpace -= sizeof ( CMemChunk );
       
   248 	
       
   249 	return freeSpace <= 0 ? KErrNoMemory : freeSpace;
       
   250 	}
       
   251 	
       
   252 // return a chain of MBufs to the pool
       
   253 void CChunkManager::Free ( RMemCell* aPtr )
       
   254 	{
       
   255 	RChunkPool* pool ( aPtr->Pool () );
       
   256 	pool->Wait ();
       
   257 	
       
   258 	while ( aPtr != NULL )
       
   259 		{
       
   260 		RMemCell* nextPtr = aPtr->Next ();
       
   261 		
       
   262 		// reset length to the size of the block and break the link
       
   263 		aPtr->SetLength ( aPtr->Size () );
       
   264 		aPtr->Link ( NULL );
       
   265 		
       
   266 		// adds single block back to its free list and adjusts its free space
       
   267 		pool->FreeToPool ( aPtr );
       
   268 		
       
   269 		aPtr = nextPtr;
       
   270 		}
       
   271 	pool->Signal ();
       
   272 	}
       
   273 
       
   274