--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/commsfwutils/commsbufs/version1/mbufmgr/src/MBufPoolChain.cpp Thu Dec 17 09:22:25 2009 +0200
@@ -0,0 +1,184 @@
+// Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+// Maintains a free queue of single size RMBuf's on behalf of CMBufPoolManager
+//
+//
+
+/**
+ @file
+ @internalComponent
+*/
+
+#include "MBufPoolChain.h"
+#include "MBufPool.h"
+#include "MBufPoolManager.h"
+
+RMBufPoolChain::RMBufPoolChain(TInt aMBufSize, CMBufPoolManager& aMBufPoolManager)
+ : iMBufSize(aMBufSize), iInitialAllocation(0), iMBufPoolManager(aMBufPoolManager)
+ {
+ }
+
+RMBufPoolChain::RMBufPoolChain(TInt aMBufSize, TInt aInitialAllocation, TInt aMinGrowth, TInt aGrowthThreshold, CMBufPoolManager& aMBufPoolManager)
+ : iMBufSize(aMBufSize), iInitialAllocation(aInitialAllocation), iMinGrowth(aMinGrowth), iGrowthThreshold(aGrowthThreshold), iMBufPoolManager(aMBufPoolManager)
+ {
+ iLenFree = 0;
+ iLenTotal = 0;
+ iFreeMBufs.Init();
+ iPools.Reset();
+
+ iSignalled = EFalse;
+ iNumMBufsToAdd = 0;
+ iNoMoreSpace = 0;
+ iLastGrowth = 0;
+ iMaxGrowthAttempt = 0;
+
+ iDbgPoolLimit = 0;
+
+ iPools.SetOffset(_FOFF(CMBufPool, iLink));
+ }
+
+void RMBufPoolChain::OpenL()
+ {
+ User::LeaveIfError(iLockFreeList.CreateLocal());
+ iPools.Reset();
+ iPools.SetOffset(_FOFF(CMBufPool, iLink));
+ }
+
+void RMBufPoolChain::Close()
+ {
+ iLockFreeList.Close();
+ }
+
+// get the growth amount
+TInt RMBufPoolChain::GrowthSize(TInt aSize)
+{
+ // small request so grow by minimum size
+ if (aSize < iMinGrowth)
+ {
+ return iMinGrowth;
+ }
+
+ // Have we tried as big as this in the past?
+ if ( (iMaxGrowthAttempt > 0) && (aSize >= iMaxGrowthAttempt) )
+ {
+ // try smaller size again
+ aSize = iMaxGrowthAttempt;
+ }
+
+ // Attempt to grow the pool by requested amount
+ if (!iNoMoreSpace)
+ {
+ return aSize;
+ }
+
+ // Last growth attempt failed so check if its worth
+ // trying again
+ if ( iLastGrowth < (iMinGrowth + 2))
+ {
+ return 0;
+ }
+
+ // Last growth attempt failed so lets try a smaller
+ iMaxGrowthAttempt = iMinGrowth + (iLastGrowth - iMinGrowth) / 2;
+
+ return iMaxGrowthAttempt;
+}
+
+// merge new pool into the pool chain
+void RMBufPoolChain::ExtendFreeList(CMBufPool* aPool)
+ {
+ // The caller must already have acquired the freelist lock
+ // - justification;
+ // a. limitation in RWorkerLock's RFastLock which does not support nested requests by the same thread without hanging the thread
+ // b. performance is adversely affected by continuoulsy locking & releasing the lock by the caller, refer ::Alloc
+ // - assumption is checked for debug builds, but not for release builds as it is too expensive & indicates a serous coding error that
+ // could/should of been fixed within a debug build anyhow
+ __ASSERT_DEBUG(iLockFreeList.IsOwned(), CMBufManager::Panic(EMBuf_FreeLockNotOwned));
+
+ iFreeMBufs.Append(aPool->MBufQ());
+ iLenFree += aPool->Count() * iMBufSize;
+ iLenTotal += aPool->Count() * iMBufSize;
+ }
+
+// allocate a chain of MBufs from the pool chain
+TInt RMBufPoolChain::Alloc(RMBufQ& aList, TInt aSize, TBool aIsAllocPool)
+ {
+
+ // Lock the freelist so that the transfer of mbufs and statistics update is an atomic operation
+ iLockFreeList.Wait();
+
+ TInt transfered = iFreeMBufs.Transfer(aList, aSize);
+ iLenFree -= transfered;
+
+ // If necessary gather data from the poolChain within the freelist lock to ensure integrity of statistics used
+ TInt preAllocationLength = 0;
+ if (aIsAllocPool)
+ {
+ preAllocationLength = iGrowthThreshold - (iLenFree/iMBufSize); // determine in terms of number of mbufs.
+ }
+
+ // adjust the growth if necessary
+ TInt growth = 0;
+ if (preAllocationLength >= 0)
+ {
+ growth = GrowthSize(preAllocationLength); // determine in terms of number of mbufs.
+ }
+
+ // Now free the freelist lock
+ iLockFreeList.Signal();
+
+ // check if the growth threshold trigger has been exceeded, and if so perform a background pool (pre)allocation
+ if (aIsAllocPool)
+ {
+ if (preAllocationLength >= 0)
+ {
+ // a failed background (pre)allocation shall not error the user since they shouldn't know (and hence care), thus
+ // the return code is only used to avoid a perpetual loop
+ if (growth > 0)
+ {
+ if (KErrNoMBufs == iMBufPoolManager.AllocPool(*this, growth, EFalse))
+ {
+ iMaxGrowthAttempt = growth;
+ }
+ }
+ }
+ }
+ return transfered;
+ }
+
+// compare function to find the suitable pool chain
+TInt RMBufPoolChain::Compare(const TInt* aMBufSize, const RMBufPoolChain& aRHSPoolChain)
+ {
+ if (*aMBufSize < aRHSPoolChain.iMBufSize)
+ {
+ return -1;
+ }
+ else if (*aMBufSize > aRHSPoolChain.iMBufSize)
+ {
+ return 1;
+ }
+ return 0;
+ }
+
+TInt RMBufPoolChain::Compare(const RMBufPoolChain& aLHSPoolChain, const RMBufPoolChain& aRHSPoolChain)
+ {
+ return Compare((TInt*)&(aLHSPoolChain.iMBufSize), aRHSPoolChain);
+ }
+
+CMBufPoolManager& RMBufPoolChain::MBufPoolManager()
+ {
+ return iMBufPoolManager;
+ }
+
+