commsfwutils/commsbufs/mbufmgrimpl/src/MBufPoolManager.cpp
changeset 0 dfb7c4ff071f
child 14 8b5d60ce1e94
equal deleted inserted replaced
-1:000000000000 0:dfb7c4ff071f
       
     1 // Copyright (c) 1997-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 // Initial Contributors:
       
     8 // Nokia Corporation - initial contribution.
       
     9 // Contributors:
       
    10 //
       
    11 // Description:
       
    12 // CMBufPoolManager.cpp
       
    13 // Maintains one or more pool chains (CMBufPoolChain) on behalf of CMBufManager
       
    14 // 
       
    15 //
       
    16 
       
    17 /**
       
    18 @file
       
    19 
       
    20 Maintains one or more pool chains (CMBufPoolChain) on behalf of CMBufManager
       
    21 
       
    22 @internalComponent
       
    23 
       
    24 */
       
    25 
       
    26 #include "mbufmanager.h"
       
    27 #include <comms-infras/cfmacro.h>
       
    28 #include "MBufPoolManager.h"
       
    29 #include "MBufPoolChain.h"
       
    30 #include "MBufPool.h"
       
    31 #include "MBufMemoryAllocator.h"
       
    32 #include <cflog.h>
       
    33 
       
    34 static const TInt KMemoryAlignment = 8;
       
    35 const TInt KNoOutstandingRequests = -1;
       
    36 
       
    37 /** Patchable constant detailing the size of cache lines in the target architecture.
       
    38     The MBufMgr will align data to cache lines.
       
    39 */
       
    40 extern const TUint KMBufCacheLineSize = 32;
       
    41 
       
    42 #define ALIGN_CACHE_MASK    (KMBufCacheLineSize-1)
       
    43 #define ALIGN_CACHE_UP(n)   (((n)+(ALIGN_MASK)) & ~ALIGN_MASK)
       
    44 #define ALIGN_CACHE_DOWN(n) ((n) & ~ALIGN_MASK)
       
    45 #define IS_CACHE_ALIGNED(p) ((((TUint32)(p)) & ALIGN_MASK)==0)
       
    46 
       
    47 #ifdef __CFLOG_ACTIVE
       
    48 __CFLOG_STMT(_LIT8(KComponent, "PoolManager");)
       
    49 __CFLOG_STMT(_LIT8(KSubsysMBufMgr, "MBufMgr");) // subsystem name
       
    50 __CFLOG_STMT(_LIT8(KComponentPerformance, "performance");)	// component name - used for any sub-optimal performance behaviuor
       
    51 #endif
       
    52 
       
    53 CMBufPoolManager* CMBufPoolManager::NewL(TInt aMaxAllocSize, CMBufManager& aMBufManager)
       
    54 	{
       
    55 	CMBufPoolManager* This = new(ELeave) CMBufPoolManager(aMaxAllocSize, aMBufManager);
       
    56 	CleanupStack::PushL(This);
       
    57 	This->ConstructL(aMaxAllocSize);
       
    58 	CleanupStack::Pop(This);
       
    59 	return This;
       
    60 	}
       
    61 
       
    62 // ctor
       
    63 CMBufPoolManager::CMBufPoolManager(TInt aMaxAllocSize, CMBufManager& aMBufManager)
       
    64 	: CActive(EPriorityStandard),
       
    65 	  iMaxAllocSize(aMaxAllocSize),
       
    66 	  iMBufManager(aMBufManager)
       
    67 	{
       
    68 #ifdef __CFLOG_ACTIVE
       
    69 	__CFLOG_VAR((KSubsysMBufMgr, KComponent, _L8("CMBufPoolManager %x:\tCMBufPoolManager()"), this));
       
    70 #endif
       
    71 
       
    72 	iCommitted = EFalse;  
       
    73 	iNextMBufSize = KNoOutstandingRequests;
       
    74 	}
       
    75 
       
    76 void CMBufPoolManager::ConstructL(TInt aMaxAllocSize)
       
    77 	{
       
    78 	User::LeaveIfError(iPoolChainLock.CreateLocal());
       
    79 	iMBufMgrOwnerThread.Duplicate(RThread());
       
    80 
       
    81 	iMemoryAllocator = CMBufMemoryAllocator::NewL(aMaxAllocSize);
       
    82 
       
    83 	CActiveScheduler::Add(this);
       
    84 
       
    85 	WaitForNewPoolRequest();
       
    86 	}
       
    87 
       
    88 CMBufPoolManager::~CMBufPoolManager()
       
    89 	{
       
    90 	// Cancel any outstanding requests
       
    91 	Cancel();
       
    92 
       
    93 	iPoolChains.ResetAndDestroy();	
       
    94 	iPoolChains.Close();
       
    95 
       
    96 	delete iMemoryAllocator;
       
    97 
       
    98     iPoolChainLock.Close();
       
    99 	iMBufMgrOwnerThread.Close();
       
   100 	}
       
   101 
       
   102 CMBufMemoryAllocator& CMBufPoolManager::Memory()
       
   103 	{
       
   104 	return *iMemoryAllocator;
       
   105 	}
       
   106 
       
   107 CMBufManager& CMBufPoolManager::Manager()
       
   108 	{
       
   109 	return iMBufManager;		
       
   110 	}
       
   111 
       
   112 void CMBufPoolManager::WaitForNewPoolRequest()
       
   113 	{
       
   114 	__ASSERT_DEBUG(!IsActive(), CMBufManager::Panic(EMBuf_AlreadyActive));
       
   115 	iStatus = KRequestPending;
       
   116 	SetActive();
       
   117 	}
       
   118 
       
   119 void CMBufPoolManager::DoCancel()
       
   120 	{
       
   121 	NETWORKING_ATOMIC(;) // Codepattern below may have SMP implications
       
   122 	if(!iSignalled)
       
   123 		{
       
   124 		// We're almost certainly the only thread doing this; now check again inside the critsec to be sure
       
   125 		iPoolChainLock.Wait();
       
   126 		if(!iSignalled)
       
   127 			{
       
   128 			iSignalled = ETrue;
       
   129 			TRequestStatus* pStatus = &iStatus;
       
   130 			User::RequestComplete(pStatus, KErrCancel);
       
   131 			}
       
   132 		iPoolChainLock.Signal();
       
   133 		}
       
   134 	}
       
   135 
       
   136 TInt CMBufPoolManager::BackgroundAllocateNewPool(CMBufPoolChain& aPoolChain,
       
   137 					TInt aNumMBufs)
       
   138 	{
       
   139 
       
   140 	// Build a list of MBuf sizes and allow one request per MBuf pool size....
       
   141 	// Note its essential that at least one request is serviced, the allocation can
       
   142 	// then attempt to use the new MBufs created.  Its not essential that every 
       
   143 	// request is serviced, its more important to prevent this single new pool
       
   144 	// allocation routine from locking out processing on the many threads that use
       
   145 	// this routine for a long time
       
   146 
       
   147 	// The first attempted growth by aNumMBufs wins
       
   148 	NETWORKING_ATOMIC(;) // Codepattern below may have SMP implications
       
   149 	if (!aPoolChain.iSignalled)
       
   150 		{
       
   151 		
       
   152 		// This is being most likely being called from the context of some thread other than the
       
   153 		// MBufMgr owner, and there's a distinct risk of more than one thread being OOB at the same
       
   154 		// time since it's a common PoolChain. 	So we have to lock here to process this PoolChain
       
   155 		iPoolChainLock.Wait();
       
   156 		
       
   157 		// We're almost certainly the only thread doing this; now check again inside the critsec to be sure
       
   158 		if (!aPoolChain.iSignalled)
       
   159 			{
       
   160 			// First do a simple test to see if the new pool will be created
       
   161 			// Note in the future when CMBufPool deletion is implemented iNoMoreSpace
       
   162 			// should be cleared on all pools to allow growth again.
       
   163 			if (aPoolChain.iNoMoreSpace)
       
   164 				{
       
   165 				if (aPoolChain.iLastGrowth > aNumMBufs)
       
   166 					{
       
   167 					// Try this smaller allocation
       
   168 					aPoolChain.iNoMoreSpace = EFalse;
       
   169 					}
       
   170 				else
       
   171 					{
       
   172 					iPoolChainLock.Signal();
       
   173 					return KErrNoMBufs;
       
   174 					}
       
   175 				}
       
   176 			aPoolChain.iLastGrowth = aNumMBufs;
       
   177 			aPoolChain.iNumMBufsToAdd = aNumMBufs;
       
   178 			aPoolChain.iSignalled = ETrue;
       
   179 			}
       
   180 		
       
   181 		}
       
   182 	else
       
   183 		{
       
   184 		// Its possible that first time round we missed this growth attempt
       
   185 		if (iSignalled)
       
   186 			{
       
   187 			// already signalled so just return
       
   188 			return KErrNone;
       
   189 			}
       
   190 		// already signalled but the first time round the growth attempt was missed
       
   191 		// this is always possible because to stop the background thread slowing the
       
   192 		// these threads we dont lock in the RunL.  The RunL is always run in the same 
       
   193 		// thread so does not need a lock.
       
   194 		iPoolChainLock.Wait();
       
   195 		}
       
   196 
       
   197 	// Here we have to guard against being completed multiple times because more than
       
   198 	// one pool chain can be growing at the same time
       
   199 	if (!iSignalled)
       
   200 		{
       
   201 		iSignalled = ETrue;
       
   202 		
       
   203 		// iNextMBufSize is the first freepool for a growth attempt
       
   204 		iNextMBufSize = aPoolChain.iBufSize; 
       
   205 		
       
   206 		TRequestStatus* pStatus = &iStatus;
       
   207 		
       
   208 		// We dont need to hold onto the lock now since there is no chance
       
   209 		// that the RequestComplete can be called twice
       
   210 		iPoolChainLock.Signal();
       
   211 		
       
   212 		iMBufMgrOwnerThread.RequestComplete(pStatus, KErrNone);
       
   213 		return KErrNone;
       
   214 		}
       
   215 	
       
   216 	iPoolChainLock.Signal();
       
   217 	return KErrNone;
       
   218 	}
       
   219 
       
   220 void CMBufPoolManager::RunL()
       
   221 	{
       
   222 	// Now that we're in the thread that owns pools and ultimately the
       
   223 	// memory allocation so attempt to create the new pool
       
   224 
       
   225 	CMBufPoolChain* selectedPoolChain(NULL);
       
   226 	TInt growThisPoolChain = iNextMBufSize;
       
   227 	iNextMBufSize = KNoOutstandingRequests;
       
   228 
       
   229 	// There is a chance that there are other pools to grow as well
       
   230 	// looking for them now can save future locking and speed allocation.
       
   231 	
       
   232 	// Note we dont have to catch every growth attempt because background
       
   233 	// allocation should be triggered from an early threshold.  This allocation
       
   234 	// might satisfy the immediate growth requirement so no need to lock.
       
   235 	
       
   236 	// Ensure that each time RunL is called a different pool growth attempt
       
   237 	// by stepping through the available pools looking for the next request.
       
   238 	TInt poolChainCount = iPoolChains.Count();
       
   239 	TInt lowestRequest = KNoOutstandingRequests;
       
   240 	
       
   241 	for (TInt i = 0; i < poolChainCount; i++)
       
   242 		{
       
   243 		CMBufPoolChain* poolInfo = iPoolChains[i];
       
   244 		TInt thisMBufSize = poolInfo->BufSize();
       
   245 		
       
   246 		// locate this growth attempt
       
   247 		if (thisMBufSize == growThisPoolChain)
       
   248 			{
       
   249 			selectedPoolChain = poolInfo;
       
   250 			}
       
   251 		
       
   252 		if (poolInfo->iSignalled)
       
   253 			{
       
   254 			if (lowestRequest == KNoOutstandingRequests)
       
   255 				{
       
   256 				lowestRequest = thisMBufSize;
       
   257 				}
       
   258 			if ( (iNextMBufSize == KNoOutstandingRequests) &&
       
   259 					(thisMBufSize > growThisPoolChain) )
       
   260 				{
       
   261 				// found the next freepool to grow
       
   262 				iNextMBufSize = thisMBufSize;
       
   263 				break;
       
   264 				}
       
   265 			}
       
   266 		}
       
   267 
       
   268 	// Might have wrapped round all the PoolChains
       
   269 	if ( (iNextMBufSize == KNoOutstandingRequests)  
       
   270 			&& (lowestRequest != growThisPoolChain) )
       
   271 		{
       
   272 		iNextMBufSize = lowestRequest;
       
   273 		}
       
   274 	
       
   275 	// Now prepare for the next pool growth if any
       
   276 	if (iNextMBufSize != KNoOutstandingRequests)
       
   277 		{
       
   278 #ifdef __CFLOG_ACTIVE
       
   279 		__CFLOG_VAR((KSubsysMBufMgr, KComponent, _L8("CMBufPoolManager::RunL() - One of several pool growth attempts")));
       
   280 #endif
       
   281 
       
   282 		// Still more requests outstanding
       
   283 		// iSignalled = ETrue;
       
   284 		iStatus = KRequestPending;
       
   285 
       
   286 		SetActive();
       
   287 
       
   288 		// complete the request so we get called again
       
   289 		TRequestStatus* pStatus = &iStatus;
       
   290 		User::RequestComplete(pStatus, KErrNone);
       
   291 		}
       
   292 	else
       
   293 		{
       
   294 		// There are no more outstanding requests so prepare for next
       
   295 		// pool creation request
       
   296 		iStatus = KRequestPending;
       
   297 		
       
   298 		// open the door for more allocate requests on other pool chains
       
   299 		iSignalled = EFalse;
       
   300 		SetActive();
       
   301 		}
       
   302 
       
   303 	// No need to surround the pool creation with a lock
       
   304 	// allocate a pool & associate with the pool chain
       
   305 	CMBufPool* newpool = NULL;
       
   306 	CreatePool(newpool, *selectedPoolChain);
       
   307 	if (newpool == NULL)
       
   308     	{
       
   309     	// Pool create fails perhaps due to insufficient memory
       
   310 
       
   311 		// Each buffer size gets its own out of space indicator
       
   312     	selectedPoolChain->iNoMoreSpace = ETrue;
       
   313     	}
       
   314 	else
       
   315 		{
       
   316 		// add the pool to the pool list
       
   317 		// No need to lock if synchronous allocation is removed
       
   318 		iPoolChainLock.Wait();
       
   319 		selectedPoolChain->iPools.AddLast(*newpool);
       
   320 		iPoolChainLock.Signal();
       
   321 
       
   322    		// first grab the freelist lock
       
   323 		selectedPoolChain->iLockFreeList.Wait();
       
   324 		selectedPoolChain->ExtendFreeList(newpool);
       
   325 		selectedPoolChain->iLockFreeList.Signal();
       
   326 		}
       
   327 
       
   328 	// open the door for more allocate requests on this poolchain
       
   329 	selectedPoolChain->iSignalled = EFalse;
       
   330 
       
   331 	}
       
   332 
       
   333 
       
   334 TInt CMBufPoolManager::Commit()
       
   335 /**
       
   336 Ensures that no additional pool chains can be created (ie. via MMBufSizeAllocator::AddL())
       
   337 Calling this method is useful (but not mandated) to ensure that operations within MMBufSizeAllocator::AddL do not create any adverse affects
       
   338 
       
   339 @return KErrNone or KErrAlreadyExists if already called.
       
   340 */
       
   341 	{
       
   342 	TInt result = KErrAlreadyExists;
       
   343 	if (iCommitted == EFalse)
       
   344 		{
       
   345 		iCommitted = ETrue;
       
   346 		result = KErrNone;
       
   347 		}
       
   348 	return result;
       
   349 	}
       
   350 
       
   351 // create a pool chain with the specified values
       
   352 // - Deliberately have not exposed the concept of a pool or chain in the api, as these concepts are intended to be hidden within MBM
       
   353 //   as a private implementation detail.
       
   354 // - Mbuf size guidelines;
       
   355 //   1. 128 byte is mandatory for some (poorly writen) legacy code that assumes the existance of mbufs of this size.
       
   356 //   b. < 128 byte is acceptable, but could break some (poorly written) legacy code that assumes that minimum mbuf size is 128
       
   357 // - 128 byte guideline is due to K_MBufSmallSize definition having been made public;
       
   358 //   a. Externally - numerous instances within our codebase (and thus similar assumptions are likely within licensee code) that assume
       
   359 //		             mbufs of at least this size are available for allocation.
       
   360 //   b. Internally - When the allocation size is not specified, the value is defaulted to K_MBufSmallSize.  Refer ::AllocL notes.
       
   361 //                 - RMBufCells are assumed to be no larger than K_MBufSmallSize.
       
   362 //   Since the first point can't be fixed without a source break, there is little point in not creating a default pool chain of
       
   363 //   K_MBufSmallSize size in order to rectify the assumptions made within the other points.
       
   364 void CMBufPoolManager::AddL(TInt aMBufSize, TInt aInitialAllocation, TInt aMinGrowth, TInt aGrowthThreshold, TInt aPoolCeiling)
       
   365 /**
       
   366 Populate a free pool of specified size with RMBuf's.  Each RMBuf in this free pool will have the same size.  
       
   367 
       
   368 RMbuf size guidelines:
       
   369 At least one free pool with 128 byte RMBuf's is mandatory for some legacy code that assumes the existance of mbufs of this size.
       
   370 RMBuf size < 128 byte is acceptable, but could break some legacy code that assumes that minimum mbuf size is 128
       
   371 These 128 byte guideline are due to KMBufSmallSize definition having been made public.  Ideally, this constant should not be published.
       
   372 Instead, inspect the available sizes via RMBufAllocator::NextMBufSize() or the size of this RMBuf with RMBuf::Size().
       
   373 DO NOT ASSUME UNDER ANY CIRCUMSTANCES THAT ALL MBUFS ARE THE SAME SIZE!
       
   374 
       
   375 @param aMBufSize the size in bytes of the RMBuf's created.
       
   376 @param aInitialAllocation the number of RMBuf's in the initial free pool.
       
   377 @param aMinGrowth the number of RMBuf's added to the free pool.
       
   378 @param aGrowthThreshold when the free pool has less than this number of RMBuf's it will trigger allocation of more memory for more RMBuf's.
       
   379 */
       
   380 	{
       
   381 	// check args
       
   382 	// - on the surface it makes sense to declare the args as unsigned and rely on the compiler's type checking instead of writing code
       
   383 	//   to manually check (which has an inherit performance penalty), but as requested this was deliberately not done because;
       
   384 	//   a. concerns about strict compilers which warn/error arithmetic operations with literals that are not explicitly designeated as unsigned
       
   385 	//      eg. 1U versus 1
       
   386 	//   b. encourages type casting by user to avoid warnings, which circumvents useful compiler type checking & often leads to unexpected results
       
   387 	//	    eg. type casting -1 to unsigned using a 2's compliment compiler resulting in an unexpectedingly large allocation of 2GB
       
   388 	__ASSERT_ALWAYS(aMBufSize > 0, CMBufManager::Panic(EMBuf_PoolManager_NegativeMBufSize));
       
   389 	__ASSERT_ALWAYS(aInitialAllocation >= 0, CMBufManager::Panic(EMBuf_PoolManager_NegativePoolSize));
       
   390 	__ASSERT_ALWAYS(aMinGrowth >= 0, CMBufManager::Panic(EMBuf_PoolManager_NegativeMinGrowth));
       
   391 	__ASSERT_ALWAYS(aGrowthThreshold >= 0, CMBufManager::Panic(EMBuf_PoolManager_NegativeGrowthThreshold));
       
   392 
       
   393 	// ensure we are not already committed - refer CMBufPoolManager::Commit notes
       
   394 	if (iCommitted)
       
   395 		{
       
   396 		User::Leave(KErrNotReady);
       
   397 		}
       
   398 
       
   399 	TInt alignmentPadding = aMBufSize % KMemoryAlignment;
       
   400 	if (aMBufSize == 0)
       
   401 		{
       
   402 #ifdef __CFLOG_ACTIVE
       
   403 		__CFLOG_VAR((KSubsysMBufMgr, KComponent, _L8("CMBufPoolManager::AddAllocSizeL() - Warning! requested mbufSize=0 serves no useful purpose; accepted anyhow")));
       
   404 #endif
       
   405 		}
       
   406 	else if (alignmentPadding != 0)
       
   407 		{
       
   408 #ifdef __CFLOG_ACTIVE
       
   409 		__CFLOG_VAR((KSubsysMBufMgr, KComponent, _L8("CMBufPoolManager::AddAllocSizeL() - Warning! requested mbufSize=%d is not (armv5) dword aligned, size has been increased to %d"),
       
   410 			aMBufSize, aMBufSize + KMemoryAlignment - alignmentPadding));
       
   411 #endif
       
   412 		aMBufSize += KMemoryAlignment - alignmentPadding;
       
   413 		}
       
   414 	if ((aInitialAllocation * aMBufSize) > iMaxAllocSize)
       
   415 		{
       
   416 #ifdef __CFLOG_ACTIVE
       
   417 		__CFLOG_VAR((KSubsysMBufMgr, KComponent, _L8("CMBufPoolManager::AddAllocSizeL() - Warning! requested initialAllocation=%d exceeds the maxAllocSize=%d; accepted anyhow"),
       
   418 			(aInitialAllocation * aMBufSize), iMaxAllocSize));
       
   419 #endif
       
   420 		}
       
   421 	if (aMinGrowth == 0)
       
   422 		{
       
   423 #ifdef __CFLOG_ACTIVE
       
   424 		__CFLOG_VAR((KSubsysMBufMgr, KComponent, _L8("CMBufPoolManager::AddAllocSizeL() - Warning! requested minGrowth=0 increased to the minimum value of 1")));
       
   425 #endif
       
   426 		aMinGrowth = 1;
       
   427 		}
       
   428 	else if ((aMinGrowth * aMBufSize) > iMaxAllocSize)
       
   429 		{
       
   430 #ifdef __CFLOG_ACTIVE
       
   431 		__CFLOG_VAR((KSubsysMBufMgr, KComponent, _L8("CMBufPoolManager::AddAllocSizeL() - Warning! requested minGrowth=%d exceeds the maxAllocSize=%d; accepted anyhow"),
       
   432 			(aMinGrowth * aMBufSize), iMaxAllocSize));
       
   433 #endif
       
   434 		}
       
   435 	if (aGrowthThreshold > aMinGrowth)
       
   436 		{
       
   437 #ifdef __CFLOG_ACTIVE
       
   438 		__CFLOG_VAR((KSubsysMBufMgr, KComponent, _L8("CMBufPoolManager::AddAllocSizeL() - Warning! requested growthThreshold=%d exceeds minGrowth=%d, hence potentially requiring multiple/iterative growth allocation; accepted anyhow"),
       
   439 			aGrowthThreshold, aMinGrowth));
       
   440 #endif
       
   441 		}
       
   442 
       
   443 	// check pool chain already exists
       
   444 	TInt index = 0;
       
   445 	TInt found = KErrNone;
       
   446 	if (found == KErrNone)
       
   447 		{
       
   448 		CMBufPoolChain poolChain(aMBufSize, *this);
       
   449   		found = iPoolChains.FindInOrder(&poolChain, index, TLinearOrder<CMBufPoolChain>(CMBufPoolChain::Compare));		
       
   450 		}
       
   451 	if (found == KErrNotFound)
       
   452 		{
       
   453 		// create a new pool chain
       
   454 		CMBufPoolChain* chain = CMBufPoolChain::NewL(aMBufSize, aInitialAllocation, aMinGrowth, aGrowthThreshold, aPoolCeiling, *this);
       
   455 		CleanupStack::PushL(chain);
       
   456 		iPoolChains.InsertL(chain, index);
       
   457 		CleanupStack::Pop(); // chain
       
   458 		
       
   459 		// pre-allocate the initial pool
       
   460 		if (aInitialAllocation > 0)
       
   461 			{
       
   462 			// Lock the freelist so that the MBufs can be added to the freepool
       
   463 			chain->iLockFreeList.Wait();
       
   464 			
       
   465 			// Use synchronous allocate to ensure that the initial pool allocation gives immediate feedback
       
   466 			// to the rootserver or calling method.
       
   467 			// This can only be called from the owner thread for CMBufManager 
       
   468 			// Thus synchronous AllocPool is possible because no conflict with asynchronous 
       
   469 			// background AllocPool occurs because this also is run from the owner thread
       
   470 			// for the CMBufManager.  Synchronous AllocPool is not allowed from other threads
       
   471 
       
   472 			TInt res = AllocPool(*chain, aInitialAllocation, ETrue); 
       
   473 			chain->iLockFreeList.Signal();
       
   474 			User::LeaveIfError(res);
       
   475 			}
       
   476 		}
       
   477 	else
       
   478 		{
       
   479 		CMBufPoolChain* poolChain = iPoolChains[index];
       
   480 		// update existing chain's values - these will take affect the next time they are used (eg. next allocation)
       
   481 		poolChain->iMinGrowth = aMinGrowth;
       
   482 		poolChain->iGrowthThreshold = aGrowthThreshold;
       
   483 		}
       
   484 	
       
   485 	// maintain/update the largest mbuf size - for background allocation
       
   486     if (iLargestMBufSize < aMBufSize)
       
   487     	{
       
   488 		iLargestMBufSize = aMBufSize;
       
   489     	}
       
   490 	}
       
   491 
       
   492 void CMBufPoolManager::CreatePool(CMBufPool* &aNewpool, CMBufPoolChain& aMBufPoolChain)
       
   493 	{
       
   494 	aNewpool = CMBufPool::New(aMBufPoolChain.iBufSize
       
   495 							, aMBufPoolChain.iNumMBufsToAdd
       
   496 							, aMBufPoolChain
       
   497 							, *iMemoryAllocator);
       
   498 	}
       
   499 
       
   500 // Search algorithm to find the pool chain satisfying the request size
       
   501 // Algorithm first narrows down to pools chains with free mbufs to satisfy the request size
       
   502 // Then, searches through the remaining pool chains starting from the largest possible pool chain
       
   503 // towards the smallest pool chain until the whole request is satisfied
       
   504 void CMBufPoolManager::LinearSearchAlloc(RMBufQ& aList, TInt aSize
       
   505 					, TInt aMinMBufSize, TInt aMaxMBufSize, TBool aIsAllocPool)
       
   506 	{
       
   507 	// Check to see if an empty mbuf with zero length is requested
       
   508 	TBool zeroLengthMBuf = (aSize == 0);
       
   509 	
       
   510 	TInt poolChainMax = iPoolChains.Count() - 1;
       
   511 
       
   512 //	CMBufPoolChain* start = iPoolChains[0];
       
   513 //	CMBufPoolChain* chain = iPoolChains[poolChainMax];
       
   514 	CMBufPoolChain* chosen = NULL;
       
   515 	TInt chainIndex = poolChainMax;
       
   516 	// First narrow the pool chains to those that are acceptable
       
   517 	// Each pool chain represents a free list of mbufs of a particular size
       
   518 	// The mbuf size must be within aMinMBufSize - aMaxMBufSize range
       
   519 	// The free pool must have space
       
   520 	do
       
   521 		{
       
   522 		CMBufPoolChain* chain = iPoolChains[chainIndex];
       
   523 		// Look for the free pool with the largest mbufs
       
   524 		if ( (chain->iBufSize <= aMaxMBufSize) && 
       
   525 				(chain->iLenFree > 0) )
       
   526 			{
       
   527 			// Check that the chosen free pool is within the limits set
       
   528 			if (chain->iBufSize >= aMinMBufSize)
       
   529 				{
       
   530 				// This pool chain has space so found the largest mbufs
       
   531 				chosen = chain;
       
   532 				break;
       
   533 				}
       
   534 			// If reached this point: no pool chain to fulfil the request
       
   535 			return;
       
   536 			}
       
   537 		}
       
   538 	while (chainIndex-- != 0);
       
   539 
       
   540 	// Check to see a if there is a pool chain to fulfil the request
       
   541 	if (chosen == NULL)
       
   542 		{
       
   543 		return;
       
   544 		}
       
   545 	
       
   546 	TInt allocated = 0;
       
   547 	TInt extraMem = 0;
       
   548 	
       
   549 	// Now find the best free pool and allocate the memory
       
   550 	do
       
   551 		{
       
   552 		CMBufPoolChain* chain = iPoolChains[chainIndex];
       
   553 		// At first iteration, this check is false since chain == chosen
       
   554 		// and chosen is greater than aMinMBufSize
       
   555 		// Check if chain (iterator - smaller than chosen pool chain)
       
   556 		// is smaller than requested min size
       
   557 		if  (chain->iBufSize < aMinMBufSize)
       
   558 			{
       
   559 			break;
       
   560 			}
       
   561 		
       
   562 		// Test to see if more than one mbuf would be used to
       
   563 		// satisfy the request
       
   564 		if ( (chain->iBufSize < aSize) &&
       
   565 				(chain->iLenFree > 0) ) 
       
   566 			{
       
   567 			// Check if chosen is available, just to be secure
       
   568 			// Or we have a chosen chain which could complete in 1 mubuf, so choose it
       
   569 			if (chosen == NULL || chosen != chain)
       
   570 				{
       
   571 				break;
       
   572 				}
       
   573 			// Chosen is the next largest mbuf size so this allocation
       
   574 			// can be satisfied with the chosen free pool
       
   575 			allocated = chosen->Alloc(aList, aSize, aIsAllocPool);
       
   576 			
       
   577 			// Check if the allocation is complete
       
   578 			if (allocated >= aSize)
       
   579 				{
       
   580 				// Test if no smaller chains
       
   581 				// or no need to check for smaller
       
   582 				if ((chainIndex == 0) || (allocated == aSize))
       
   583 					{
       
   584 					// Allocation is complete
       
   585 					aSize = 0;
       
   586 					chosen = NULL;
       
   587 					break;
       
   588 					}
       
   589 				
       
   590 				// By swapping the first mbuf with a smaller mbuf it might
       
   591 				// be possible to fit the remainder into a smaller mbuf that
       
   592 				// wastes less memory
       
   593 				extraMem = chosen->iBufSize + aSize - allocated;
       
   594 				CMBufPoolChain* smallerChain = iPoolChains[chainIndex - 1];
       
   595 				// Check to see if the remainder can fit into a smaller mbuf
       
   596 				if ( extraMem <= smallerChain->iBufSize && smallerChain->iBufSize >= aMinMBufSize )
       
   597 					{
       
   598 					// It can fit
       
   599 					// Set request size to this remaining size so that the algorithm
       
   600 					// will continue searching for this remaining size
       
   601 					aSize = extraMem;
       
   602 					// Set chosen to null so that when the search cannot find a
       
   603 					// smaller mbuf for remaining size the algorithm will know this
       
   604 					chosen = NULL;
       
   605 					// No break - continue searching for remainder
       
   606 					}
       
   607 				else
       
   608 					{
       
   609 					// Remainder is large to fit in a smaller mbuf
       
   610 					// Allocation is complete
       
   611 					aSize = 0;
       
   612 					chosen = NULL;
       
   613 					break;
       
   614 					}
       
   615 				}
       
   616 			else
       
   617 				{
       
   618 				// No space left in the free pool so look for
       
   619 				// a smaller mbuf to satisfy the request
       
   620 				aSize -= allocated;
       
   621 				}
       
   622 			}
       
   623 		
       
   624 		// Best free pool not found yet
       
   625 		// Test to see if this free pool is a better choice
       
   626 		if ( (aSize <= chain->iBufSize) &&
       
   627 				(chain->iLenFree > 0) )
       
   628 			{
       
   629 			chosen = chain;
       
   630 			}
       
   631 		}
       
   632 	while (chainIndex-- != 0);
       
   633 	
       
   634 	// There is a chosen pool but the request is not satisfied yet due to:
       
   635 	// 1. Requested size is smaller than the smallest pool chain
       
   636 	// 2. Most suitable pool chain has no free space
       
   637 	// 3. An empty mbuf with zero length is requested
       
   638 	// 4. Request size was assigned with remaining size and a pool chain is found
       
   639 	//    for that remaining size
       
   640 	if ((chosen != NULL) && ((aSize > 0) || (zeroLengthMBuf)))
       
   641 		{
       
   642 		// This chosen free pool will have to do
       
   643 		RMBufQ bList;
       
   644 		TInt allocated = chosen->Alloc(bList, aSize, aIsAllocPool);
       
   645 		// Test for successful allocation
       
   646 		if (allocated >= aSize)
       
   647 			{
       
   648 			// If this allocation is for remaining size swap the extra mbuf with
       
   649 			// the allocated one
       
   650 			if (extraMem > 0)
       
   651 				{
       
   652 				// Allocation worked so swap this smaller mbuf thus saving space
       
   653 				RMBuf* first = aList.RemoveLast();
       
   654 				// Free the first mbuf
       
   655 				Free(first, ETrue);
       
   656 				}
       
   657 			aList.Append(bList);
       
   658 			aSize = 0;
       
   659 			}
       
   660 		}
       
   661 	
       
   662 	// If no chosen pool for remaining size but the allocation was successful
       
   663 	if (extraMem > 0)
       
   664 		{
       
   665 		// Allocation is complete
       
   666 		aSize = 0;
       
   667 		}
       
   668 	
       
   669 	// If allocated mbuf is insufficient to fulfill the req empty the list
       
   670 	if (aSize > 0)
       
   671 		{
       
   672 		Free(aList.First(), ETrue);
       
   673 		aList.Init();
       
   674 		}
       
   675 	}
       
   676 
       
   677 // Finds poolchains that will satisfy the request size using linear search,
       
   678 // and allocates and initialises a chain of MBufs 
       
   679 RMBuf* CMBufPoolManager::Alloc(TInt aSize, TInt aMinMBufSize, TInt aMaxMBufSize, TBool aIsAllocPool)
       
   680 	{
       
   681 	RMBufQ list;
       
   682 
       
   683 	TInt poolChainsCount = iPoolChains.Count();
       
   684 	__ASSERT_DEBUG(poolChainsCount != 0, CMBufManager::Panic(EMBuf_NoPoolChain));
       
   685 	
       
   686 #ifdef _DEBUG
       
   687 	if (poolChainsCount == 0)
       
   688 		{
       
   689 #ifdef __CFLOG_ACTIVE
       
   690 		__CFLOG_VAR((KSubsysMBufMgr, KComponent, _L8("CMBufPoolManager::Alloc() - Error! no mbuf pool chain exists")));
       
   691 #endif
       
   692 		}
       
   693 	else if (iLargestMBufSize < aSize)
       
   694 		{
       
   695 #ifdef __CFLOG_ACTIVE
       
   696 		__CFLOG_VAR((KSubsysMBufMgr, KComponentPerformance, _L8("CMBufPoolManager::Alloc() - Warning! sub-optimal performance; biggest chain doesn't satisfy the request with one mbuf, aSize=%d chainSize=%d"),
       
   697 			aSize, iLargestMBufSize));
       
   698 #endif
       
   699 		}
       
   700 #endif
       
   701 
       
   702 	// Do the allocation
       
   703 	LinearSearchAlloc(list, aSize, aMinMBufSize, aMaxMBufSize, aIsAllocPool);
       
   704 
       
   705 #ifdef _DEBUG
       
   706 	if (list.IsEmpty())
       
   707 		{
       
   708 #ifdef __CFLOG_ACTIVE
       
   709 		__CFLOG_VAR((KSubsysMBufMgr, KComponent, _L8("CMBufPoolManager::Alloc() - Warning! no matching poolChain found, aSize=%d aMinMBufSize=%d aMaxMBufSize=%d"),
       
   710 			aSize, aMinMBufSize, aMaxMBufSize));
       
   711 #endif
       
   712 		}
       
   713 #endif
       
   714 
       
   715 	// At this point, list should be a linked list of all the RMBufs necessary to satisfy the memory request.
       
   716 	// - mark each one to indicate that it's now being used for buffer data.
       
   717 	RMBuf* mBuf;
       
   718 	for (mBuf = list.First(); mBuf != NULL; mBuf = mBuf->Next())
       
   719 		{
       
   720 		__ASSERT_DEBUG(mBuf->Type() == EMBufFree, CMBufManager::Panic(EMBuf_AllreadyAlloc));
       
   721 		mBuf->SetType(EMBufData);
       
   722 #ifdef _MBUF_TEST
       
   723 		Mem::Fill(mBuf->Buffer(), mBuf->Size(), '#');
       
   724 #endif
       
   725 		}
       
   726 
       
   727 	return list.First();
       
   728 	}
       
   729 
       
   730 // return a chain of MBufs to the pool
       
   731 void CMBufPoolManager::Free(RMBuf* aMBuf, TBool aIsPreAlloc)
       
   732 	{
       
   733 	
       
   734 	TBool sameSize = EFalse;
       
   735 
       
   736 	while (aMBuf != NULL)
       
   737 		{
       
   738 		RMBuf* nextMBuf = aMBuf->Next();
       
   739 
       
   740 		// when aIsPreAlloc is true that means called from Alloc:
       
   741 		// total allocation for the request is unsuccessful so freeing the allocated MBufs
       
   742 		__ASSERT_DEBUG(aIsPreAlloc || aMBuf->Type() != EMBufFree, CMBufManager::Panic(EMBuf_AllreadyFree));
       
   743 
       
   744 		aMBuf->SetType(EMBufFree);
       
   745 		aMBuf->SetData(0, aMBuf->Size());	// reset length to the size of the mbuf, subsequent ::Alloc can update this if required
       
   746 
       
   747 		aMBuf->Unlink();
       
   748 
       
   749 		// update pool chain - eg. free list members
       
   750 		// placeholder for REQ7864 (de-allocation of mbufs), the return of mbufs to the free list should/could be more intelligent
       
   751 		// than merely pre-pending as is currently the case.  Eg. examine the pool and corresponding dchunk they belong too to
       
   752 		// determine if the mbufs should be given priority to be used or de-allocated in the future
       
   753 		// or alternatively leave marked mbuf's as orphans and mark the mbufs that need to be de-allocated in this way in the memory manager
       
   754 		CMBufPoolChain* poolChain = static_cast<CMBufPoolChain*>(aMBuf->Pool());
       
   755 		__ASSERT_DEBUG(poolChain->iBufSize > 0, User::Invariant());
       
   756 
       
   757 		if (!sameSize)
       
   758 			{
       
   759 			poolChain->iLockFreeList.Wait();
       
   760 			}
       
   761 		poolChain->iFreeMBufs.Prepend(aMBuf);	// prepends a single mbuf, ie. not any mbufs that may be pointed to by this mbuf
       
   762 		poolChain->iLenFree += aMBuf->Size();
       
   763 
       
   764 		if (nextMBuf)
       
   765 			{
       
   766 			sameSize = aMBuf->Size() == nextMBuf->Size();
       
   767 			}
       
   768 
       
   769 		aMBuf = nextMBuf;
       
   770 
       
   771 		// free mbufs within the chain
       
   772 		// - care taken to ensure correct handling of different sized mbufs
       
   773 		if (nextMBuf == NULL || !sameSize)
       
   774 			{
       
   775 			poolChain->iLockFreeList.Signal();
       
   776 			}
       
   777 		}
       
   778 
       
   779 	// when aIsPreAlloc is true that means called from Alloc:
       
   780 	// total allocation for the request is unsuccessful so freeing the allocated MBufs
       
   781 	if (!aIsPreAlloc)
       
   782 		{
       
   783 		iMBufManager.CallBackAfterFree();
       
   784 		}
       
   785 	}
       
   786 
       
   787 // allocate a memory pool & merge it into the pool chain
       
   788 TInt CMBufPoolManager::AllocPool(CMBufPoolChain& aPoolChain, TInt aSize, TBool aIsSynchronous)
       
   789 	{
       
   790 	// verify that the maximum size will not be exceeded ie; ceiling is not yet touched	
       
   791 	if(aPoolChain.HonourPoolCeiling())
       
   792 		{
       
   793 		if(aPoolChain.CanExtend())
       
   794 			{
       
   795 			// Alloate as much as we can
       
   796 			aSize = (aPoolChain.ExtendSize() < aSize) ? aPoolChain.ExtendSize() : aSize;
       
   797 			}
       
   798 		else
       
   799 			{
       
   800 			return KErrNoMBufs;	
       
   801 			}			
       
   802 		}
       
   803 	else
       
   804 		{
       
   805 		if ((iAllocSize + aSize * aPoolChain.iBufSize) > iMaxAllocSize)
       
   806 			{
       
   807 			return KErrNoMBufs;
       
   808 			}			
       
   809 		}
       
   810 		
       
   811 /*
       
   812 */	
       
   813 	if (aIsSynchronous)
       
   814 		{
       
   815 		// this is only valid if called from the thread that owns the CMBufManager
       
   816 		// the RHeap is created in that thread and its handle is only valid in that thread
       
   817 		CMBufPool* newpool = CMBufPool::New(aPoolChain.iBufSize,
       
   818 							aSize, aPoolChain, *iMemoryAllocator);
       
   819 		if (newpool != NULL)
       
   820 			{
       
   821 			iPoolChainLock.Wait();
       
   822 			aPoolChain.iPools.AddLast(*newpool);
       
   823 			iPoolChainLock.Signal();
       
   824 	
       
   825 			aPoolChain.ExtendFreeList(newpool);
       
   826 	
       
   827 			iAllocSize += aSize * aPoolChain.iBufSize;
       
   828 			return KErrNone;
       
   829 			}
       
   830 		return KErrNoMBufs;
       
   831 		}
       
   832 	return BackgroundAllocateNewPool(aPoolChain, aSize);
       
   833 	}
       
   834 
       
   835 TInt CMBufPoolManager::BytesAvailable()
       
   836 	// runtime metrics
       
   837 	// The total number of available bytes that MBufMgr has avaiable in it's free lists.
       
   838     {
       
   839     TInt bytes = 0;
       
   840     TUint poolChainsCount = iPoolChains.Count();
       
   841 	for (TUint i = 0; i < poolChainsCount; i++)
       
   842 		{
       
   843 		bytes += iPoolChains[i]->iLenFree;
       
   844 		}
       
   845     return bytes;
       
   846     }
       
   847 
       
   848 TInt CMBufPoolManager::BytesAvailable(TInt aSize)
       
   849 	// runtime metrics
       
   850 	// The total number of available bytes that MBufMgr has avaiable in a given free list.
       
   851     {
       
   852 	TInt index = iPoolChains.FindInOrder((TInt)aSize, CMBufPoolChain::Compare);
       
   853 	if (index != KErrNotFound)
       
   854 		{
       
   855 		return iPoolChains[index]->iLenFree;
       
   856 		}
       
   857 	return 0;
       
   858     }
       
   859 
       
   860 TInt CMBufPoolManager::NextMBufSize(TInt aSize)
       
   861 	// runtime metrics
       
   862     {
       
   863 	TInt index = 0;
       
   864     TUint poolChainsCount = iPoolChains.Count();
       
   865     while(index < poolChainsCount)
       
   866         {
       
   867 		if (iPoolChains[index]->iBufSize > aSize )
       
   868 		    {
       
   869 		    return iPoolChains[index]->iBufSize;
       
   870 			}
       
   871 		++index;
       
   872 		}
       
   873 	return KErrNotFound;
       
   874     }
       
   875 
       
   876 TInt CMBufPoolManager::BytesAllocated()
       
   877 	{
       
   878 	return iMemoryAllocator->AllocBytes();
       
   879 	}
       
   880 
       
   881 #ifdef _MBUF_TEST
       
   882 
       
   883 TInt CMBufPoolManager::__DbgCheckBuffer(RMBuf* aBuf)
       
   884 //
       
   885 // For each pool within the corresponding chain, try to locate aBuf
       
   886 //
       
   887 	{
       
   888 	if (aBuf==NULL)
       
   889 		{
       
   890 		return 0;
       
   891 		}
       
   892 
       
   893 	TInt n=-1;
       
   894 	CMBufPool* pool;
       
   895 
       
   896     TInt index = iPoolChains.FindInOrder((TInt)aBuf->Size(), CMBufPoolChain::Compare);
       
   897 	if (index != KErrNotFound)
       
   898         {
       
   899         CMBufPoolChain* poolChain = iPoolChains[index];
       
   900 
       
   901         TDblQueIter<CMBufPool> list(poolChain->iPools);
       
   902 
       
   903 		if (poolChain->iPools.IsEmpty())
       
   904 			{
       
   905 			return 0;
       
   906 			}
       
   907 
       
   908 		// iteratively invoke to locate the required mbuf
       
   909 		while (n==-1 && (pool = list++, pool!=NULL))
       
   910 			{
       
   911 			n = pool->__DbgCheckBuffer(aBuf);
       
   912 			}
       
   913 
       
   914 	    if (n<0)
       
   915 	    	{
       
   916 	    	CMBufManager::Panic(EMBuf_NotAnMBuf);
       
   917 	    	}
       
   918 		}
       
   919 	return n;
       
   920 	}
       
   921 
       
   922 // retrieve free space for all pool chains
       
   923 TUint CMBufPoolManager::__DbgGetBufSpace()
       
   924     {
       
   925     int len = 0;
       
   926     TUint poolChainsCount = iPoolChains.Count();
       
   927 	for (TUint i = 0; i < poolChainsCount; i++)
       
   928 		{
       
   929 		len += iPoolChains[i]->iLenFree;
       
   930 		}
       
   931     return len;
       
   932     }
       
   933 
       
   934 // get free space for pool chain with matching mbuf size
       
   935 TUint CMBufPoolManager::__DbgGetBufSpace(TUint aMBufSize)
       
   936     {
       
   937     TInt index = iPoolChains.FindInOrder((TInt)aMBufSize, CMBufPoolChain::Compare);
       
   938 	if (index != KErrNotFound)
       
   939         {
       
   940         return iPoolChains[index]->iLenFree;
       
   941 		}
       
   942 	return 0;
       
   943     }
       
   944 
       
   945 // get used space for all pool chains
       
   946 TUint CMBufPoolManager::__DbgGetBufTotal()
       
   947     {
       
   948     int len = 0;
       
   949     TUint poolChainsCount = iPoolChains.Count();
       
   950 	for (TUint i = 0; i < poolChainsCount; i++)
       
   951 		{
       
   952 		len += iPoolChains[i]->iLenTotal;
       
   953 		}
       
   954     return len;
       
   955     }
       
   956 
       
   957 // get used space for pool chain with matching mbuf size
       
   958 TUint CMBufPoolManager::__DbgGetBufTotal(TUint aMBufSize)
       
   959     {
       
   960     TInt index = iPoolChains.FindInOrder((TInt)aMBufSize, CMBufPoolChain::Compare);
       
   961 	if (index != KErrNotFound)
       
   962         {
       
   963         return iPoolChains[index]->iLenTotal;
       
   964 		}
       
   965 	return 0;
       
   966     }
       
   967 
       
   968 // return the first mbuf in the free list belong to the first chain
       
   969 RMBuf* CMBufPoolManager::__DbgMBufChain()
       
   970     {
       
   971     if (iPoolChains.Count() > 0)
       
   972 		{
       
   973 		return iPoolChains[0]->iFreeMBufs.First();
       
   974 		}
       
   975     return NULL;
       
   976     }
       
   977 // return the first mbuf in the free list belonging to the chain of the specified mbuf size
       
   978 RMBuf* CMBufPoolManager::__DbgMBufChain(TUint aMBufSize)
       
   979     {
       
   980     TInt index = iPoolChains.FindInOrder((TInt)aMBufSize, CMBufPoolChain::Compare);
       
   981 	if (index != KErrNotFound)
       
   982         {
       
   983         return iPoolChains[index]->iFreeMBufs.First();
       
   984 		}
       
   985 	return 0;
       
   986     }
       
   987 
       
   988 // update the max pool limit (debug only) - use the first pool chain
       
   989 void CMBufPoolManager::__DbgSetPoolLimit(TInt aCount)
       
   990 	{
       
   991 	if (iPoolChains.Count() > 0)
       
   992 		{
       
   993 		iPoolChains[0]->iDbgPoolLimit = aCount - (aCount % iPoolChains[0]->iBufSize);
       
   994 		}
       
   995 	}
       
   996 // update the max pool limit (debug only) - for the specified mbuf size
       
   997 void CMBufPoolManager::__DbgSetPoolLimit(TInt aCount, TUint aMBufSize)
       
   998 	{
       
   999     TInt index = iPoolChains.FindInOrder((TInt)aMBufSize, CMBufPoolChain::Compare);
       
  1000 	if (index != KErrNotFound)
       
  1001         {
       
  1002         CMBufPoolChain* poolChain = iPoolChains[index];
       
  1003     	poolChain->iDbgPoolLimit = aCount - (aCount % poolChain->iBufSize);
       
  1004     	}
       
  1005 	}
       
  1006 
       
  1007 #endif //#ifdef _MBUF_TEST
       
  1008 
       
  1009 //
       
  1010 // MBUF POOLS
       
  1011 //
       
  1012 
       
  1013 // overloaded new operator
       
  1014 // - allocates pools on the RHeap instead of the std thread heap
       
  1015 // - placeholder for substituting RHeap with RChunk for either/all;
       
  1016 //   a. creating
       
  1017 //   b. growing - req's handle to existing... handle likely stored within CMBM and accessed via a friend
       
  1018 TAny* CMBufPool::operator new(TUint aSize, TInt aExtra, CMBufMemoryAllocator& aMemoryAllocator) __NO_THROW
       
  1019 	{
       
  1020 	TAny* p = aMemoryAllocator.Alloc(aSize + aExtra);
       
  1021 	return p;
       
  1022 	}
       
  1023 
       
  1024 void CMBufPool::operator delete(TAny* aPtr) __NO_THROW
       
  1025 	{
       
  1026 	if (aPtr)
       
  1027 		{
       
  1028 		((CMBufPool* )aPtr)->iMemoryAllocator.Free(aPtr);
       
  1029 		}
       
  1030 	}
       
  1031 
       
  1032 /**
       
  1033  * extra delete operator for exception unwinding in Code Warrior
       
  1034  */
       
  1035 void CMBufPool::operator delete(TAny* aPtr, TInt /*aExtra*/, CMBufMemoryAllocator& /*aMemoryAllocator*/) __NO_THROW
       
  1036 	{
       
  1037 	CMBufPool::operator delete(aPtr);
       
  1038 	}
       
  1039 
       
  1040 CMBufPool::CMBufPool(TInt aMBufSize, TInt aNumMBufs, CMBufMemoryAllocator& aMemoryAllocator)
       
  1041 	: CBase()
       
  1042 	, iNumMBufs(aNumMBufs)
       
  1043 	, iMBufSize(aMBufSize)
       
  1044 	, iMemoryAllocator(aMemoryAllocator)
       
  1045 	{
       
  1046 	}
       
  1047 
       
  1048 // Create and return a new mbuf pool
       
  1049 CMBufPool* CMBufPool::New(TInt aMBufSize, TInt aNumMBufs, CMBufPoolChain& aMBufPoolChain, CMBufMemoryAllocator& aMemoryAllocator)
       
  1050 	{
       
  1051     // allocate pool on the RHeap via an overloaded ::new operator (not obvious here)
       
  1052 	TInt rmbufsize = ALIGN_CACHE_UP(sizeof(RMBuf));
       
  1053 	TInt mbufsize = ALIGN_CACHE_UP(aMBufSize);
       
  1054 	CMBufPool* pool = new(aNumMBufs * (rmbufsize + mbufsize), aMemoryAllocator) CMBufPool(mbufsize, aNumMBufs, aMemoryAllocator);
       
  1055 	if (pool != NULL)
       
  1056 		{
       
  1057 		TUint8* poolSize = ((TUint8*) pool) + sizeof(CMBufPool);
       
  1058 
       
  1059 		// buffers must be aligned so that MBUF_ALIGN() will work
       
  1060 	 	__ASSERT_DEBUG(IS_ALIGNED(poolSize), CMBufManager::Panic(EMBuf_NotAligned));
       
  1061 
       
  1062 		TInt rmbufsize = ALIGN_CACHE_UP(sizeof(RMBuf));
       
  1063 		TInt actualBufStart = (aNumMBufs * rmbufsize);
       
  1064 		for (TInt i=0; i<aNumMBufs; i++)
       
  1065 			{
       
  1066 			// overloaded new operator - in place allocation at the specified address
       
  1067 			TUint8* ptr = poolSize + i * rmbufsize;	
       
  1068 			TInt bufStart = (actualBufStart + (i * mbufsize)) - (i* rmbufsize);
       
  1069 			RCommsBuf* buf = new(ptr) RCommsBuf (bufStart, aMBufSize, aMBufPoolChain.Id()); 			
       
  1070 			pool->iList.Append(static_cast<RMBuf*>(buf));
       
  1071 			}
       
  1072 		}
       
  1073 	return pool;
       
  1074 	}
       
  1075 
       
  1076 CMBufPool::~CMBufPool()
       
  1077 //
       
  1078 //
       
  1079 //
       
  1080 	{
       
  1081 	iLink.Deque();
       
  1082 	}
       
  1083 
       
  1084 
       
  1085 void CMBufPool::Merge(RMBufQ &aFreeList)
       
  1086 //
       
  1087 //
       
  1088 //
       
  1089 	{
       
  1090 	aFreeList.Append(iList);
       
  1091 	}
       
  1092 
       
  1093 #ifdef _MBUF_TEST
       
  1094 TInt CMBufPool::__DbgCheckBuffer(RMBuf* aBuf)
       
  1095 //
       
  1096 // Given an mbuf ptr, returns its number in this pool
       
  1097 //
       
  1098 	{
       
  1099 	TUint8* p = (TUint8*)aBuf;
       
  1100 	TUint8* s = ((TUint8*) this) + sizeof(CMBufPool);
       
  1101 	TUint8* e = s + (iNumMBufs * sizeof(RMBuf));
       
  1102 
       
  1103 	if (p<s)
       
  1104 		{
       
  1105 		return -1;
       
  1106 		}
       
  1107 	else if (p<e)
       
  1108 		{
       
  1109 		return 1 + ((p-s) / sizeof(RMBuf));
       
  1110 		}
       
  1111 	s = e;
       
  1112 	e = s + (iNumMBufs * aBuf->Size());
       
  1113 	if (p>=e)
       
  1114 		{
       
  1115 		return -1;
       
  1116 		}
       
  1117 	else
       
  1118 		{
       
  1119 		CMBufManager::Panic(EMBuf_CorruptMBuf);
       
  1120 		}
       
  1121 
       
  1122 	return -2 - ((p-s) / aBuf->Size());
       
  1123 	}
       
  1124 #else
       
  1125 TInt CMBufPool::__DbgCheckBuffer(RMBuf* /*aBuf*/)
       
  1126 {
       
  1127    return KErrNone;
       
  1128 }
       
  1129 
       
  1130 #endif
       
  1131