--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/commsfwutils/commsbufs/inc/systemsharedbufs.h Thu Dec 17 09:22:25 2009 +0200
@@ -0,0 +1,267 @@
+// Copyright (c) 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: Implementation of system shared buffer allocation and buffer
+// management.
+//
+
+#ifndef __SYSTEMSHAREDBUFS_H__
+#define __SYSTEMSHAREDBUFS_H__
+
+#include "commsbufpondintf.h"
+#include "commsbufponddbg.h"
+#include "commsbufpool.h"
+#include "systemsharedasyncalloc.h"
+#include "commsbufq.h"
+#include "commsbufponddbg.h"
+#include <e32shbuf.h>
+
+class TCommsBufPoolCreateInfo;
+class RCommsBuf;
+class RShPool;
+class MCommsBufPondIntf;
+/**
+
+Representation of a single system shared pool.Allocates/free from the system shared pool or from
+the freelist if enabled)
+
+@internalTechnology
+
+*/
+NONSHARABLE_CLASS(CSystemSharedBufPool) : public CCommsBufPool
+ {
+ public:
+ static CSystemSharedBufPool* New(MCommsBufPondIntf& aPondIntf, const TCommsBufPoolCreateInfo& aCreateInfo);
+
+#ifdef SYMBIAN_ZEROCOPY_BUF_FREELIST
+ TInt FreeListCount();
+#endif // SYMBIAN_ZEROCOPY_BUF_FREELIST
+
+ ~CSystemSharedBufPool();
+
+ TInt AllocUnderflow(RCommsBufQ& aBufQ, TInt aSize);
+ TInt AllocOverflow(RCommsBufQ& aBufQ, TInt aSize);
+
+ RCommsBuf* Alloc();
+ void Free(RCommsBuf* aBuf);
+ inline RShPool Pool() const;
+
+ static TInt Compare(const CSystemSharedBufPool& aLhs, const CSystemSharedBufPool& aRhs);
+
+ private:
+ inline CSystemSharedBufPool(MCommsBufPondIntf& aPondIntf, TInt aSize);
+ TInt Construct(const TCommsBufPoolCreateInfo& aCreateInfo);
+
+#ifdef SYMBIAN_ZEROCOPY_BUF_FREELIST
+ inline CSystemSharedBufPool(MCommsBufPondIntf& aPondIntf, TInt aSize, TInt aFreeListCount);
+ TInt AllocFromFreeList(RCommsBufQ& BufQ, TInt aSize);
+ TBool ReleaseToFreeList(RCommsBuf* aBuf);
+#endif // SYMBIAN_ZEROCOPY_BUF_FREELIST
+
+ private:
+ RShPool iPool;
+#ifdef SYMBIAN_ZEROCOPY_BUF_FREELIST
+ RWorkerLock iFreeListLock;
+ RCommsBufQ iFreeList;
+ TInt iMaxFreeListCount;
+ TInt iFreeListCount;
+#endif // SYMBIAN_ZEROCOPY_BUF_FREELIST
+ };
+
+/**
+Implements the 3 stage buffer allocation algorithm using the system wide shared buffer APIs or
+from the freelist (if enabled)
+
+Description of the 3 stage allocator.
+
+Requirements:
+1/ The algorithm MUST try to allocate from the pool that has bigger or equal size buffers in
+preference to the pools that has smaller size buffers ie;
+2/ The algorithm MUST return fewest bytes of memory that satisfy the request and doesn't conflict
+with 1/
+3/ More than one buffer may be allocated and linked, if the requested buffer size doesn't directly
+satisfy with the configured buffer sizes.
+
+Input parameters:
+Size - Requested total size
+Minimum Size - The size that the allocated buffer(s) must atleast have
+Maximum Size - The size that the allocated buffer(s) must not exceed
+
+
+Working Model:
+The algorithm relies on the big to small order. If the order is not obeyed/adhered the algorithm will
+fail to allocate the buffers from the right pools and more buffers maybe allocated than needed.The
+pools are sorted during initialization time.
+
+The first step in the algorithm is to clip the pool array position based on the given min and max size.
+Clipping is done to ensure that allocation happens from the pools that satisfies the given min and
+max condition, and no further checking is needed on the pools to see whether the pool buffer size
+satisfies the min and max values. Once the clipping is done the algorithm works in 4 stages.
+
+The following terms are used in the description of the algorithm. The terms should be read as:
+biggest pool --- The pool that has the bigger buffer size, relative to the given max value
+smallest pool --- The pool that has the smallest buffer size, relative to the given min value
+
+The reader should note that there is no gurantee that the requested allocation size will be exactly or
+nearly matching to the pool sizes and this applies to each stage that operatea on the allocation size.
+
+The first stage execution depends on the input parameters and lower and upper index. Subsequent stages
+exectuion depend on the outcome of the prior stage.
+
+The 4 stages are:
+1/ Traverse the pool array forward from the biggest pool index till the traversal reaches the smallest
+pool index. When the requested size is greater than the buffer size of the "next" pool allocate as much
+as possible from the "current" pool and decrement the requested size if there is an allocation. If there
+is no allocation happens from the "current" pool mark the "current" pool index and exit the stage.
+ At this point,
+ a/ We allocated completely as requested or
+ b/ We would have been passed through and didn't allocate from the bigger pools that may have buffer for
+ allocation in order to satisfy the Credo 2/. But we MUST satisfy the Credo 1/ and in order to satisfy the
+ Credo 1/ we need to traverse back from the point where we stopped the traversal, hence need to mark the
+ "current" pool index.
+2/ If the first stage allocation cannot complete due to the non-availability of buffer in the pools or with
+1.b/ traverse the array backward starting from the marked pool index till the traversal reaches the biggest
+pool index. Allocate from any pool where buffers are available by satisfying Credo 1/.
+3/ If the second stage allocation cannot complete due to the non-availability of buffers then we have to
+increment the marked pool index by 1 as the marked pool has been checked for buffer availability on the 2nd
+stage. We have the following scenario:
+ a/ The pending allocation size (maybe partial or the size "actually" requested)is greater than the marked
+ pool index buffer size
+ b/ Allocation MUST satisfy the Credo 1/
+
+Traverse the array forward from the marked pool index till the traversal reaches the smallest pool index.
+Allocate from any pool where buffers are available.
+
+Special condition:
+If the requested size is 0 we will allocate from the pool that has the smallest buffer size, provided the
+availability of buffers in the pool. The zero sized allocation takes a different path (using ZeroSizedAlloc Fn.)
+and does not run through the stages as described above.
+
+Reasoning:
+
+We MUST satisfy the requirement 1 and we SHOULD try to achieve the requirement 2 then we have the following
+that we encounter during allocation
+
+1/ No gurantee that we get buffers from the pool that has the best size for the allocation.
+2/ We might skip a pool to identify the more best size and we may not be able to allocate from that pool
+due to the non-availablity of the buffers. We would be needing to traverse back on the pool array.
+3/ No gurantee that we can allocate we traverse back because some other threads woule have been executed inbetween
+and allocate the buffers and the pool might became empty. and vice versa.
+
+Drawbacks:
+
+1/ More looping happens with the algorithm on certain cases when the bigger size pools became empty.
+
+Conclusion:
+1/ Couple of more loops on certain cases does not add much problems as the total no. of elements in the pools
+are expected to be ~10 hence does not cause much problems in terms of performance.
+2/ All depends on how the pool buffer sizes are configured. It is expected that the smaller size buffer numbers
+in the pool will be lesser than bigger sizes. So most time we get good allocation.
+3/ More problems are on the allocation of system shared buffer from the Kernal as the algorithm has to allocate
+one by one and ask the pool each time. If there is no buffers available on the requested pool there will be more
+system calls
+
+Based on the above arguments the conclusion is that algorithm (and the couple of more loops) doesn't cause much
+problems
+
+
+Future & suggestions:
+It maybe possible to fine tune the algorithm. But any futuer enhancements should consider
+1/ the min and max conditions
+2/ Non-deterministic configured pool sizes
+
+One of the thing that would definitly improve the algorithm is to request the kernel to allocate a series of
+RShBuf's. This would reduce the no. of system calls that is currently happening on the system. The current freelist
+implementation tries to address this issue to an extent.
+
+@internalTechnology
+*/
+
+class T3StageAllocator
+ {
+ public:
+ T3StageAllocator(RPointerArray<CSystemSharedBufPool>& aPools, TInt aSize, TInt aMinSize, TInt aMaxSize);
+ RCommsBuf* Do();
+
+ private:
+
+ void Init(TInt aMinSize, TInt aMaxSize);
+
+ void ForwardAlloc1stStage();
+ void BackwardAlloc2ndStage();
+ void ForwardAlloc3rdStage();
+
+ void ZeroSizedAlloc();
+
+ private:
+ RPointerArray<CSystemSharedBufPool>& iPools;
+ TInt iSize;
+ TInt iBiggestPoolIndex;
+ TInt iSmallestPoolIndex;
+ TInt iMarkedPoolIndex;
+ RCommsBufQ iBufQ;
+ TBool iZeroBufSize;
+ };
+
+/**
+Implements the buffer management using the system wide shared buffers
+
+@internalTechnology
+*/
+NONSHARABLE_CLASS(CSystemSharedBufPond) : public CBase, public MCommsBufPondIntf, public MCommsBufPondDbg
+ {
+ friend class RCommsBufPond;
+
+ public:
+ static MCommsBufPondIntf* New(RArray <TCommsBufPoolCreateInfo>& aPoolInfo);
+ ~CSystemSharedBufPond();
+
+ private:
+
+ TInt Construct(RArray <TCommsBufPoolCreateInfo>& aPoolInfo);
+
+ // From MCommsBufPondIntf
+ virtual RCommsBuf* Alloc(TInt aSize, TInt aMinBufSize, TInt aMaxBufSize);
+ virtual RCommsBuf* FromHandle(TInt aHandle);
+ virtual TInt Store(TDes8& aStore) const;
+ virtual void Free(RCommsBuf* aBuf);
+ virtual TInt BytesAvailable() const;
+ virtual TInt BytesAvailable(TInt aSize) const;
+ virtual TInt NextBufSize(TInt aSize) const;
+ virtual TInt LargestBufSize() const;
+ virtual void StartRequest(CCommsBufAsyncRequest& aRequest);
+ virtual void CancelRequest(CCommsBufAsyncRequest& aRequest);
+ virtual void SetContext();
+ virtual void Release(RLibrary& aLib);
+ virtual MCommsBufPondDbg& CommsBufPondDbg();
+
+ // From MCommsBufPondDbg
+ virtual RCommsBuf* __DbgBufChain();
+ virtual RCommsBuf* __DbgBufChain(TUint aBufSize);
+ virtual void __DbgSetPoolLimit(TInt aCount);
+ virtual void __DbgSetPoolLimit(TInt aCount, TUint aBufSize);
+ virtual void __DbgSetFailAfter(TInt aCount=0);
+ virtual TUint __DbgGetBufSpace();
+ virtual TUint __DbgGetBufSpace(TUint aBufSize);
+ virtual TUint __DbgGetBufTotal();
+ virtual TUint __DbgGetBufTotal(TUint aMufSize);
+ virtual TInt __DbgGetHeapSize();
+
+ private:
+ RPointerArray<CSystemSharedBufPool> iPools;
+ CSystemSharedAsyncAlloc* iAsyncAlloc;
+ };
+
+#include "systemsharedbufs.inl"
+#endif // __SYSTEMSHAREDBUFS_H__
+
+