commsfwutils/commsbufs/version1/mbufmgr/src/MB_MAN.CPP
changeset 0 dfb7c4ff071f
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 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 // Buffer Manager for Protocols
       
    15 // 
       
    16 //
       
    17 
       
    18 /**
       
    19  @file
       
    20  @internalComponent
       
    21 */
       
    22 
       
    23 #include <comms-infras/cfperfmetrics.h>
       
    24 #include <es_mbman.h>
       
    25 #include <es_prot.h>	// for ESocketTimerPriority
       
    26 #include <e32hal.h>
       
    27 #include <comms-infras/cfmacro.h>
       
    28 #include "MBufPoolChain.h"
       
    29 #include "MBufTimer.h"
       
    30 #include "MBufPool.h"
       
    31 #include "MBufSizeAllocator.h"
       
    32 #include "MBufPoolManager.h"
       
    33 #include "MBufMemoryAllocator.h"
       
    34 #include <cflog.h>
       
    35 
       
    36 #ifdef __CFLOG_ACTIVE
       
    37 __CFLOG_STMT(_LIT8(KComponent, "Manager");)
       
    38 __CFLOG_STMT(_LIT8(KSubsysMBufMgr, "MBufMgr");) // subsystem name
       
    39 #endif
       
    40 
       
    41 /**
       
    42 MBuf Private Heap Limits
       
    43 
       
    44 @internalTechnology
       
    45 */
       
    46 static const TInt KMBufFreePriority = 20;
       
    47 
       
    48 // The asynchronous allocations have to be requested by the thread that created the MBufMgr
       
    49 // This we do by having a requester object in that thread which gets completed by the other
       
    50 // threads to trigger the request
       
    51 NONSHARABLE_CLASS(CRequestAsyncAlloc) : public CActive
       
    52 	{
       
    53 public:
       
    54 	static CRequestAsyncAlloc* NewL();
       
    55 	virtual ~CRequestAsyncAlloc();
       
    56 
       
    57 	void StartWaitForRequest();
       
    58 	void MakeRequest();
       
    59 private:
       
    60 	CRequestAsyncAlloc();
       
    61 	void ConstructL();
       
    62 
       
    63 	virtual void DoCancel();
       
    64 	virtual void RunL();
       
    65 	RCriticalSection iCritSec;
       
    66 	RThread iMBufMgrOwnerThread;
       
    67 	TBool iSignalled;
       
    68 	};
       
    69 
       
    70 CRequestAsyncAlloc::CRequestAsyncAlloc()
       
    71 : CActive(0)
       
    72 	{
       
    73 	}
       
    74 
       
    75 CRequestAsyncAlloc* CRequestAsyncAlloc::NewL()
       
    76 	{
       
    77 	CRequestAsyncAlloc* This = new(ELeave) CRequestAsyncAlloc;
       
    78 	CleanupStack::PushL(This);
       
    79 	This->ConstructL();
       
    80 	CleanupStack::Pop(This);
       
    81 	return This;
       
    82 	}
       
    83 
       
    84 void CRequestAsyncAlloc::ConstructL()
       
    85 	{
       
    86 	User::LeaveIfError(iCritSec.CreateLocal());
       
    87 	iMBufMgrOwnerThread.Duplicate(RThread());
       
    88 	CActiveScheduler::Add(this);
       
    89 	}
       
    90 
       
    91 CRequestAsyncAlloc::~CRequestAsyncAlloc()
       
    92 	{
       
    93 	Deque();
       
    94 	iCritSec.Close();
       
    95 	iMBufMgrOwnerThread.Close();
       
    96 	}
       
    97 
       
    98 void CRequestAsyncAlloc::StartWaitForRequest()
       
    99 	{
       
   100 	__ASSERT_DEBUG(!IsActive(), CMBufManager::Panic(EMBuf_AlreadyActive));
       
   101 	iStatus = KRequestPending;
       
   102 	SetActive();
       
   103 	}
       
   104 
       
   105 void CRequestAsyncAlloc::MakeRequest()
       
   106 	{
       
   107 	NETWORKING_ATOMIC(;) // Codepattern below may have SMP implications
       
   108 	// This is being most likely being called from the context of some thread other than the
       
   109 	// MBufMgr owner, and there's a distinct risk of more than one thread being OOB at the same
       
   110 	// time since it's a common pool. So here we have to guard against being completed multiple
       
   111 	// times, using a critical section because there's a tiny but real risk of a completion from
       
   112 	// another thread in between a test upon IsActive() and our completion of it, which could give
       
   113 	// a stray event panic
       
   114 	if(!iSignalled)
       
   115 		{
       
   116 		// We're almost certainly the only thread doing this; now check again inside the critsec to be sure
       
   117 		iCritSec.Wait();
       
   118 		if(!iSignalled)
       
   119 			{
       
   120 			iSignalled = ETrue;
       
   121 			TRequestStatus* pStatus = &iStatus;
       
   122 			iMBufMgrOwnerThread.RequestComplete(pStatus, KErrNone);
       
   123 			}
       
   124 		iCritSec.Signal();
       
   125 		}
       
   126 	}
       
   127 
       
   128 
       
   129 void CRequestAsyncAlloc::DoCancel()
       
   130 	{
       
   131 	NETWORKING_ATOMIC(;) // Codepattern below may have SMP implications
       
   132 	if(!iSignalled)
       
   133 		{
       
   134 		// We're almost certainly the only thread doing this; now check again inside the critsec to be sure
       
   135 		iCritSec.Wait();
       
   136 		if(!iSignalled)
       
   137 			{
       
   138 			iSignalled = ETrue;
       
   139 			TRequestStatus* pStatus = &iStatus;
       
   140 			User::RequestComplete(pStatus, KErrCancel);
       
   141 			}
       
   142 		iCritSec.Signal();
       
   143 		}
       
   144 	}
       
   145 
       
   146 void CRequestAsyncAlloc::RunL()
       
   147 	{
       
   148 	// Now that we're in the thread that owns the timer we can reset it
       
   149 	CMBufManager::Context()->WatchDogReset();
       
   150 	// Ready for the next cry of OOB distress
       
   151 	iStatus = KRequestPending;
       
   152 	iSignalled = EFalse;
       
   153 	SetActive();
       
   154 	}
       
   155 
       
   156 //
       
   157 // MBUF MANAGER
       
   158 //
       
   159 
       
   160 CMBufManager::CMBufManager()
       
   161 /**
       
   162 MBUF MANAGER
       
   163 */
       
   164 	: CBase()
       
   165 	{
       
   166 #ifdef __CFLOG_ACTIVE
       
   167 	__CFLOG_1(KSubsysMBufMgr, KComponent, _L8("CMBufManager %x:\tCMBufManager()"), this);
       
   168 #endif
       
   169 
       
   170 	iAllocsPending.SetOffset(_FOFF(RMBufAsyncRequest,iLink));
       
   171 #ifdef SYMBIAN_NETWORKING_PERFMETRICS
       
   172 	CommsFW::CPerfMetricStore::AddClient(this, AddToPerfLog);
       
   173 #endif
       
   174 	}
       
   175 
       
   176 
       
   177 EXPORT_C void CMBufManager::Panic(TMBufPanic aPanic)
       
   178 /**
       
   179 For use by mbuf related classes
       
   180 */
       
   181 	{
       
   182 	_LIT(mbuf,"MBuf");
       
   183 	User::Panic(mbuf, aPanic);
       
   184 	}
       
   185 
       
   186 
       
   187 EXPORT_C CMBufManager::~CMBufManager()
       
   188 //
       
   189 //
       
   190 //
       
   191 	{
       
   192 #ifdef SYMBIAN_NETWORKING_PERFMETRICS
       
   193 	CommsFW::CPerfMetricStore::RemoveClient(this);
       
   194 #endif
       
   195 	
       
   196 	if (iRequestAsyncAlloc)
       
   197 		{
       
   198 		iRequestAsyncAlloc->Cancel();
       
   199 		delete iRequestAsyncAlloc;
       
   200 		iRequestAsyncAlloc = NULL;
       
   201 		}
       
   202 
       
   203 	while (!iAllocsPending.IsEmpty())
       
   204 		{
       
   205         CancelRequest(*iAllocsPending.First());
       
   206         }
       
   207 
       
   208 	if (iFreeCB!=NULL)
       
   209 		{
       
   210         delete iFreeCB;
       
   211         }
       
   212 
       
   213 	iAsynAllocLock.Close();
       
   214 
       
   215 	delete iTimer;
       
   216 
       
   217 	if (iMBufPoolManager)
       
   218 		{
       
   219 		delete iMBufPoolManager;
       
   220 		}
       
   221 
       
   222 	Dll::SetTls(NULL);
       
   223 	}
       
   224 
       
   225 // overload
       
   226 // - aMBufSizeAllocator overload used to provide the caller (ie. the owner of the CMBufManager) restricted access to the pool manager
       
   227 EXPORT_C CMBufManager* CMBufManager::NewL(TInt aMaxHeapSize, MMBufSizeAllocator* &aMBufSizeAllocator)
       
   228 	{
       
   229 	__ASSERT_ALWAYS(Dll::Tls() == NULL, Panic(EMBuf_AlreadyInit));
       
   230 	CMBufManager* mgr = new(ELeave) CMBufManager;
       
   231 	Dll::SetTls(mgr);
       
   232 	CleanupStack::PushL(mgr);
       
   233 	mgr->ConstructL(aMaxHeapSize);
       
   234 	CleanupStack::Pop();
       
   235 
       
   236 	// the iMBufPoolManager object is owned by CNBufManager, and thus the aMBufSizeAllocator reference should not be destroyed by
       
   237 	// the caller code
       
   238 	aMBufSizeAllocator = mgr->iMBufPoolManager;
       
   239 
       
   240 	return mgr;
       
   241 	}
       
   242 
       
   243 void CMBufManager::ConstructL(TInt aMaxHeapSize)
       
   244 //
       
   245 //
       
   246 //
       
   247 	{
       
   248 	User::LeaveIfError(iAsynAllocLock.CreateLocal());
       
   249 
       
   250 	TCallBack c(FreeCallBack, this);
       
   251 
       
   252 	// create an instance of the mbuf pool manager
       
   253 	// - used to handle all pool allocation manipulation, also used as a concrete class for limited public interfaces exposed
       
   254 	//   to the client
       
   255 
       
   256 	iMBufPoolManager = CMBufPoolManager::NewL(aMaxHeapSize, *this);
       
   257 	CleanupStack::PushL(iMBufPoolManager);
       
   258 	
       
   259 	iFreeCB = new(ELeave) CAsyncCallBack(c, KMBufFreePriority);
       
   260 	CleanupStack::PushL(iFreeCB);
       
   261 	
       
   262 	iTimer=CDeltaTimer::NewL(EMBufMgrTimerPriority, KMbufManTimerGranularity);
       
   263 	CleanupStack::PushL(iTimer);
       
   264 	
       
   265 	iTimerThreadId = RThread().Id();
       
   266 
       
   267 	iRequestAsyncAlloc = CRequestAsyncAlloc::NewL();
       
   268 	
       
   269 	iRequestAsyncAlloc->StartWaitForRequest();
       
   270 	
       
   271 	CleanupStack::Pop(iTimer); 
       
   272 	CleanupStack::Pop(iFreeCB); 
       
   273 	CleanupStack::Pop(iMBufPoolManager); 
       
   274 	}
       
   275 
       
   276 EXPORT_C CMBufManager* CMBufManager::Context()
       
   277 	// There is a single system-wide MBuf manager.
       
   278 	{
       
   279 	CMBufManager* pMgr = STATIC_CAST(CMBufManager*, Dll::Tls());
       
   280 	__ASSERT_ALWAYS(pMgr != NULL, Panic(EMBuf_NoManager));
       
   281 	return pMgr;
       
   282 	}
       
   283 
       
   284 EXPORT_C void CMBufManager::SetContext()
       
   285 	// There is a single system-wide MBuf manager.
       
   286 	{
       
   287 	Dll::SetTls(this);
       
   288 	}
       
   289 
       
   290 TInt CMBufManager::BytesAvailable() const
       
   291     {
       
   292 	__ASSERT_DEBUG(iMBufPoolManager!=NULL, Panic(EMBuf_NoPoolManager));
       
   293 	return iMBufPoolManager->BytesAvailable();
       
   294     }
       
   295 
       
   296 TInt CMBufManager::BytesAvailable(TInt aSize) const
       
   297     {
       
   298     __ASSERT_DEBUG(iMBufPoolManager!=NULL, Panic(EMBuf_NoPoolManager));
       
   299 	return iMBufPoolManager->BytesAvailable(aSize);
       
   300     }
       
   301 
       
   302 
       
   303 #ifdef _MBUF_TEST
       
   304 // misc. sanity checks - all pool chains
       
   305 EXPORT_C void CMBufManager::__DbgCheckChain(RMBuf* aMBuf, TMBufType aType, TInt aLength, TInt aSize)
       
   306 //
       
   307 // Check that an MBuf chain if of the required length and that all bufs are
       
   308 // of the requred type.
       
   309 //
       
   310 	{
       
   311 	CMBufManager* mgr = CMBufManager::Context();
       
   312 
       
   313 	TInt siz=0, len=0;
       
   314 
       
   315 	RMBuf* m;
       
   316 	RMBuf* p = NULL;
       
   317 	TMBufIter iter(aMBuf);
       
   318 
       
   319 	while (m = iter++, m!=NULL)
       
   320 		{
       
   321 		mgr->__DbgCheckBuffer(m);
       
   322 
       
   323 		len += m->Length();
       
   324 		siz += m->Size();
       
   325 		if (m->Type()!=aType)
       
   326 			Panic(EMBuf_CheckFailType);
       
   327 		p = m; // so we know what the previous one was when it panics under the debugger
       
   328 		(void)p->Last();
       
   329 		}
       
   330 
       
   331 	if (aSize!=0 && siz!=aSize)
       
   332 		Panic(EMBuf_CheckFailSize);
       
   333 
       
   334 	if (aLength!=0 && len!=aLength)
       
   335 		Panic(EMBuf_CheckFailLength);
       
   336 	}
       
   337 
       
   338 
       
   339 EXPORT_C TInt CMBufManager::__DbgCheckBuffer(RMBuf* aBuf)
       
   340 //
       
   341 // For each pool within the corresponding chain, try to locate aBuf
       
   342 //
       
   343 	{
       
   344 	return iMBufPoolManager->__DbgCheckBuffer(aBuf);
       
   345 	}
       
   346 
       
   347 #else	//#ifdef _MBUF_TEST
       
   348 EXPORT_C void CMBufManager::__DbgCheckChain(RMBuf* /*aMBuf*/, TMBufType /*aType*/, TInt /*aLength*/, TInt /*aSize*/)
       
   349 {
       
   350    return;
       
   351 }
       
   352 
       
   353 EXPORT_C TInt CMBufManager::__DbgCheckBuffer(RMBuf* /*aBuf*/)
       
   354 {
       
   355    return KErrNone;
       
   356 }
       
   357 
       
   358 #endif
       
   359 
       
   360 
       
   361 void CMBufManager::WatchDogReset()
       
   362 	{
       
   363 	if (iWatchDogIsPending)
       
   364 		{
       
   365 		iWatchDogIsPending=EFalse;
       
   366 		MBufTimer::Remove(iWatchDog);
       
   367 		}
       
   368 	if(!iAllocsPending.IsEmpty())
       
   369 		{
       
   370 		TCallBack c(WatchDogExpire, this);
       
   371 		iWatchDogIsPending=ETrue;
       
   372 		iWatchDog.Set(c);
       
   373 		MBufTimer::Queue(KMBufWatchDogTime,iWatchDog);
       
   374 		}
       
   375 	}
       
   376 
       
   377 TInt CMBufManager::WatchDogExpire(TAny* aPtr)
       
   378 	{
       
   379 	((CMBufManager*)aPtr)->iWatchDogIsPending=EFalse;
       
   380 	((CMBufManager*)aPtr)->CompleteAsyncAllocs(EFalse);		// if required, do not allocate new pools
       
   381 	((CMBufManager*)aPtr)->CompleteAsyncAllocs(ETrue);		// if required, do allocate new pools
       
   382 	return 0;
       
   383 	}
       
   384 
       
   385 
       
   386 void CMBufManager::StartRequest(RMBufAsyncRequest& aRequest)
       
   387 //
       
   388 //
       
   389 //
       
   390 	{
       
   391 	iAsynAllocLock.Wait();
       
   392 	iAllocsPending.AddLast(aRequest);
       
   393 	iAsynAllocLock.Signal();
       
   394 	iRequestAsyncAlloc->MakeRequest();
       
   395 	}
       
   396 
       
   397 
       
   398 void CMBufManager::CancelRequest(RMBufAsyncRequest& aRequest)
       
   399 //
       
   400 //
       
   401 //
       
   402 	{
       
   403 	aRequest.iLink.Deque();
       
   404 	aRequest.Complete(KErrCancel);
       
   405 	
       
   406 	if (iRequestAsyncAlloc)
       
   407 	   {
       
   408 	   iRequestAsyncAlloc->MakeRequest();
       
   409 	   }
       
   410 	}
       
   411 
       
   412 // attempt to complete outstanding asynchronous allocation requests
       
   413 // - typically called after some mbufs have been freed
       
   414 void CMBufManager::CompleteAsyncAllocs(TBool aIsAllocPool)
       
   415 	{
       
   416 	TBool reset = ETrue;
       
   417 	RMBufAsyncRequest *req;
       
   418 
       
   419 #ifdef __CFLOG_ACTIVE
       
   420 	__CFLOG_1(KSubsysMBufMgr, KComponent, _L8("CMBufManager %x:\tCompleteAsyncAllocs() called"), this);
       
   421 #endif
       
   422 
       
   423 	// first lock the pending list
       
   424 	iAsynAllocLock.Wait();
       
   425 	TDblQueIter<RMBufAsyncRequest> iter(iAllocsPending);
       
   426 
       
   427 	// attempt to allocate each outstanding asynchronous allocation request
       
   428 	// - deliberately so, the request is attempted without extending the pool (as this is done from a watchdog timer as a last resort)
       
   429 	while (req = iter++, req != NULL)
       
   430 		{
       
   431 		// if null size specified, then allocate a default sized mbuf
       
   432 		// - to avoid a SC break, the default size is hard coded to K_MBufSmallSize for consumers that assume that this length will be returned
       
   433 		TInt reqSize = req->iLength;
       
   434 		if (reqSize == 0) 	// trs; does it make sense to request an allocation without specifying a length? kept as is to avoid a SC break
       
   435 			reqSize = KMBufSmallSize;
       
   436 
       
   437 
       
   438 		RMBuf* mBufs = Alloc(reqSize, 0, KMaxTInt, aIsAllocPool);
       
   439 		if (mBufs)
       
   440 			{
       
   441 			req->iMBufs = mBufs;
       
   442 			req->Complete(KErrNone);
       
   443 
       
   444 			if (aIsAllocPool)	// not done for pool allocation growth to ensure FC with the factored out implementation; CompleteLargeRequests()
       
   445 				reset = EFalse;
       
   446 			}
       
   447 		}
       
   448 
       
   449 	iAsynAllocLock.Signal();
       
   450 
       
   451 	// only reset the watch dog if there are no pending requests left or a request was completed, otherwise big pending requests might
       
   452 	// be stalled by a continual trickle of small allocs and frees.
       
   453 	if (iAllocsPending.IsEmpty() || reset)
       
   454 		WatchDogReset();
       
   455 	}
       
   456 
       
   457 // refer RMBufChain::AllocL notes regarding the deliberate decision not to provide an overloaded min/max mbuf size variant
       
   458 EXPORT_C RMBuf* CMBufManager::AllocL(TInt aSize)
       
   459 //
       
   460 // Allocate and initialise a chain of MBufs
       
   461 // Total data length is set to exact size.
       
   462 //
       
   463 	{
       
   464 	RMBuf* buf = Alloc(aSize);
       
   465 	if(!buf)
       
   466 		{
       
   467 		User::Leave(KErrNoMBufs);
       
   468 		}
       
   469 	return buf;
       
   470 	}
       
   471 
       
   472 TInt CMBufManager::LargestMBufSize() const
       
   473     /** Returns the size of the largest MBuf that the manager can provide.
       
   474         @return the size of the largest MBuf that the manager can provide.
       
   475     */
       
   476 	{
       
   477 	// iLargestMBufSize is needed for legacy functionallity when the MBufSize is not specified
       
   478 	// in RMBufChain::Align(TInt aSize).  It is updated in MBufPoolManager as new pools are created
       
   479 	__ASSERT_DEBUG(iMBufPoolManager!=NULL, Panic(EMBuf_NoPoolManager));
       
   480 	return iMBufPoolManager->LargestMBufSize();
       
   481 	}
       
   482 
       
   483 TInt CMBufManager::NextMBufSize(TInt aSize) const
       
   484     /** Used to obtains the sizes of the MBufs that the manager can provide.
       
   485         @param the size to start searching from.
       
   486         @return the size of the next MBuf that is greater than aSize, KErrNotFound if there is no MBuf bigger than aSize.
       
   487     */
       
   488 	{
       
   489 	__ASSERT_DEBUG(iMBufPoolManager!=NULL, Panic(EMBuf_NoPoolManager));
       
   490 	return iMBufPoolManager->NextMBufSize(aSize);
       
   491 	}
       
   492 
       
   493 // allocate and initialise a chain of MBufs
       
   494 // - total data length is set to exact size
       
   495 // - overloaded variants are deliberately not exported because;
       
   496 //   a. likely that this interface will be deprecated in the future and thus we don't want to unnecessarily extend it (ie. more maintenance)
       
   497 //   b. easy to export them down the track, but not so easy to go the other way
       
   498 RMBuf* CMBufManager::Alloc(TInt aSize, const RMBufChain& aMBufChain)
       
   499 	{
       
   500 	// select min/max mbuf size constraints based upon an existing mbuf
       
   501 	if (aMBufChain.First())
       
   502 		return Alloc(aSize, aMBufChain.First()->Size(), aMBufChain.First()->Size());
       
   503 	else
       
   504 		return Alloc(aSize);
       
   505 	}
       
   506 EXPORT_C RMBuf* CMBufManager::Alloc(TInt aSize)
       
   507 	{
       
   508 	return Alloc(aSize, 0, KMaxTInt);
       
   509 	}
       
   510 RMBuf* CMBufManager::Alloc(TInt aSize, TInt aMinMBufSize)
       
   511 	{
       
   512 	return Alloc(aSize, aMinMBufSize, KMaxTInt);
       
   513 	}
       
   514 RMBuf* CMBufManager::Alloc(TInt aSize, TInt aMinMBufSize, TInt aMaxMBufSize)
       
   515 	{
       
   516 	return Alloc(aSize, aMinMBufSize, aMaxMBufSize, ETrue);
       
   517 	}
       
   518 RMBuf* CMBufManager::Alloc(TInt aSize, TInt aMinMBufSize, TInt aMaxMBufSize, TBool aIsAllocPool)
       
   519 	{
       
   520 	// check args
       
   521 	// - regarding use of TInt instead of TUint, refer comments in CMBufPoolManager::AddL
       
   522 	__ASSERT_ALWAYS(aSize >= 0, Panic(EMBuf_SillyAlloc));
       
   523 	__ASSERT_DEBUG(aMinMBufSize >= 0, Panic(EMBuf_NegativeMinMBufSize));
       
   524 	__ASSERT_DEBUG(aMaxMBufSize >= 0, Panic(EMBuf_NegativeMaxMBufSize));
       
   525 	__ASSERT_DEBUG(aMaxMBufSize >= aMinMBufSize, Panic(EMBuf_MinExceedsMaxMBufSize));
       
   526 
       
   527 #ifdef SYMBIAN_NETWORKING_PERFMETRICS
       
   528 	TInt bucket = Min(aSize / KBucketSize, KNumBuckets - 1);
       
   529 #endif
       
   530 #ifdef _MBUF_TEST
       
   531 // Silly value here - the point is that the value won't be changed by this, so we can
       
   532 // emulate what happens if the system repeatedly fails to allocate the memory.
       
   533 	if (iDbgFailAfter != 0 && --iDbgFailAfter == 0)
       
   534 		{
       
   535 #ifdef SYMBIAN_NETWORKING_PERFMETRICS
       
   536 // REQ7862 fix up the iLock this might be free list lock from pool manager - perhaps all this goes to pool manager
       
   537 		iLock.Wait();
       
   538 		++iBuckets[bucket];
       
   539 		++iNumOOBs;
       
   540 // REQ7862 fix up the iLock this might be free list lock from pool manager - perhaps all this goes to pool manager
       
   541 		iLock.Signal();
       
   542 #endif
       
   543 		return NULL;
       
   544 		}
       
   545 #endif
       
   546 
       
   547 #ifdef SYMBIAN_NETWORKING_PERFMETRICS
       
   548 	++iBuckets[bucket];
       
   549 #endif
       
   550 
       
   551 
       
   552 
       
   553 	return iMBufPoolManager->Alloc(aSize, aMinMBufSize, aMaxMBufSize, aIsAllocPool);
       
   554 	}
       
   555 
       
   556 // return a chain of MBufs to the pool
       
   557 EXPORT_C void CMBufManager::Free(RMBuf* aMBuf)
       
   558 	{
       
   559 	aMBuf->Free();
       
   560 	}
       
   561 
       
   562 void CMBufManager::CallBackAfterFree()
       
   563 	{
       
   564 	if (!iAllocsPending.IsEmpty())
       
   565 		iFreeCB->CallBack();
       
   566 	}
       
   567 
       
   568 TInt CMBufManager::FreeCallBack(TAny* aPtr)
       
   569 	{
       
   570 	((CMBufManager*)aPtr)->CompleteAsyncAllocs(EFalse);	// attempt allocation without attempting to allocate any new pools
       
   571 	return 0;
       
   572 	}
       
   573 
       
   574 CDeltaTimer* CMBufManager::Timer()
       
   575 //
       
   576 // return context for the global timer.
       
   577 //
       
   578 	{
       
   579 	return Context()->iTimer;
       
   580 	}
       
   581 
       
   582 // retrieve free space for all pool chains
       
   583 EXPORT_C TUint CMBufManager::__DbgGetBufSpace()
       
   584     {
       
   585 #ifdef _MBUF_TEST
       
   586     return iMBufPoolManager->__DbgGetBufSpace();
       
   587 #else
       
   588     return 0;
       
   589 #endif
       
   590     }
       
   591 
       
   592 // get free space for pool chain with matching mbuf size
       
   593 EXPORT_C TUint CMBufManager::__DbgGetBufSpace(TUint aMBufSize)
       
   594     {
       
   595 #ifdef _MBUF_TEST
       
   596     return iMBufPoolManager->__DbgGetBufSpace(aMBufSize);
       
   597 #else
       
   598     aMBufSize = aMBufSize;
       
   599     return 0;
       
   600 #endif
       
   601     }
       
   602 
       
   603 // get used space for all pool chains
       
   604 EXPORT_C TUint CMBufManager::__DbgGetBufTotal()
       
   605     {
       
   606 #ifdef _MBUF_TEST
       
   607     return iMBufPoolManager->__DbgGetBufTotal();
       
   608 #else
       
   609     return 0;
       
   610 #endif
       
   611     }
       
   612 
       
   613 // get used space for pool chain with matching mbuf size
       
   614 EXPORT_C TUint CMBufManager::__DbgGetBufTotal(TUint aMBufSize)
       
   615     {
       
   616 #ifdef _MBUF_TEST
       
   617     return iMBufPoolManager->__DbgGetBufTotal(aMBufSize);
       
   618 #else
       
   619     aMBufSize = aMBufSize;
       
   620     return 0;
       
   621 #endif
       
   622     }
       
   623 
       
   624 // return the first mbuf in the free list belong to the first chain
       
   625 EXPORT_C RMBuf* CMBufManager::__DbgMBufChain()
       
   626     {
       
   627 #ifdef _MBUF_TEST
       
   628     return iMBufPoolManager->__DbgMBufChain();
       
   629 #else
       
   630     return NULL;
       
   631 #endif
       
   632     }
       
   633 // return the first mbuf in the free list belonging to the chain of the specified mbuf size
       
   634 EXPORT_C RMBuf* CMBufManager::__DbgMBufChain(TUint aMBufSize)
       
   635     {
       
   636 #ifdef _MBUF_TEST
       
   637     return iMBufPoolManager->__DbgMBufChain(aMBufSize);
       
   638 #else
       
   639     aMBufSize = aMBufSize;
       
   640     return NULL;
       
   641 #endif
       
   642     }
       
   643 
       
   644 // update the max pool limit (debug only) - use the first pool chain if none specified
       
   645 EXPORT_C void CMBufManager::__DbgSetPoolLimit(TInt aCount)
       
   646 	{
       
   647 #ifdef _MBUF_TEST
       
   648 	iMBufPoolManager->__DbgSetPoolLimit(aCount);
       
   649 #else
       
   650 	aCount = aCount;
       
   651 #endif
       
   652 	}
       
   653 
       
   654 // update the max pool limit (debug only) - for the specified mbuf size
       
   655 EXPORT_C void CMBufManager::__DbgSetPoolLimit(TInt aCount, TUint aMBufSize)
       
   656 	{
       
   657 #ifdef _MBUF_TEST
       
   658 	iMBufPoolManager->__DbgSetPoolLimit(aCount, aMBufSize);
       
   659 #else
       
   660 	aCount = aCount;
       
   661 	aMBufSize = aMBufSize;
       
   662 #endif
       
   663 	}
       
   664 
       
   665 // set a fail allocation count
       
   666 EXPORT_C void CMBufManager::__DbgSetFailAfter(TInt aCount)
       
   667 	{
       
   668 #ifdef _MBUF_TEST
       
   669 	iDbgFailAfter = aCount;
       
   670 #else
       
   671 	aCount = aCount;
       
   672 #endif
       
   673 	}
       
   674 
       
   675 // get the allocation size - note only valid if called from the CMBufManager owner thread
       
   676 EXPORT_C TInt CMBufManager::__DbgGetHeapSize()
       
   677 	{
       
   678 #ifdef _MBUF_TEST
       
   679 	if (iMBufPoolManager)
       
   680 		return iMBufPoolManager->BytesAllocated();
       
   681 	else
       
   682 		return 0;
       
   683 #else
       
   684     return 0;
       
   685 #endif
       
   686 	}
       
   687 
       
   688 
       
   689 #ifdef SYMBIAN_NETWORKING_PERFMETRICS
       
   690 
       
   691 TBool CMBufManager::AddToPerfLog(TAny* aSelf, TDes8& aBuffer, TDes8Overflow* aOverflowHandler)
       
   692 	{
       
   693 	CMBufManager* self = static_cast<CMBufManager*>(aSelf);
       
   694 	__ASSERT_COMPILE(KNumBuckets == 13);	// cross-check against below
       
   695 	_LIT8(KFormat, "MBuf OOB:%u, reqs:%u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u");
       
   696 	aBuffer.AppendFormat(KFormat, aOverflowHandler, self->iNumOOBs, self->iBuckets[0],
       
   697 		self->iBuckets[1], self->iBuckets[2], self->iBuckets[3], self->iBuckets[4], self->iBuckets[5], self->iBuckets[6],
       
   698 		self->iBuckets[7], self->iBuckets[8], self->iBuckets[9], self->iBuckets[10], self->iBuckets[11], self->iBuckets[12]);
       
   699 	return EFalse;
       
   700 	}
       
   701 
       
   702 #endif
       
   703 
       
   704 
       
   705 EXPORT_C RMBufAllocator::RMBufAllocator() 
       
   706 	: iManager(*CMBufManager::Context()) 
       
   707 		{}
       
   708 
       
   709 
       
   710 EXPORT_C TInt RMBufAllocator::BytesAvailable() const
       
   711 /**
       
   712 Obtains the total available bytes available in the mbuf system in it's entirety.
       
   713 @return the number of available bytes within all of the MBuf pools.
       
   714 */
       
   715     {
       
   716 	return iManager.BytesAvailable();
       
   717 	}
       
   718 
       
   719 EXPORT_C TInt RMBufAllocator::BytesAvailable(TInt aSize) const
       
   720 /**
       
   721 Obtains the total bytes available in the pool of the given sized MBuf.
       
   722 @param aSize one of the sizes returned by RMBufAllocator::NextMBufSize().
       
   723 @return the number of available bytes within the MBuf pool of MBufs given by the size aSize.
       
   724 */
       
   725     {
       
   726 	return iManager.BytesAvailable(aSize);
       
   727 	}
       
   728 
       
   729 EXPORT_C TInt RMBufAllocator::NextMBufSize(TInt aSize) const
       
   730 /**
       
   731 Returns the first MBuf size that is greater than aSize, returns KErrNotFound if there isn't an MBuf
       
   732 whose size is larger than aSize. Can be used to find the size of each of the MBuf pools by starting
       
   733 at 0 and repeatedly passing in the result of the previous call until KErrNotFound occurs.
       
   734 @param aSize a starting size to search upwards from.
       
   735 @return the size of the first MBuf whose size is greater than aSize.
       
   736 */
       
   737     {
       
   738 	return iManager.NextMBufSize(aSize);
       
   739 	}
       
   740 
       
   741 EXPORT_C TInt RMBufAllocator::LargestMBufSize() const
       
   742 /**
       
   743 @return the size of the largest MBuf that is registered with the sytem.
       
   744 */
       
   745     {
       
   746 	return iManager.LargestMBufSize();
       
   747 	}
       
   748 
       
   749 #ifndef __NOT_OWN_MBUFMGR_DLL  // Used by t_esock in the PPP testsuite
       
   750 
       
   751 #endif
       
   752