diff -r 000000000000 -r dfb7c4ff071f commsfwutils/commsbufs/mbufmgr/src/mb_chn.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/commsfwutils/commsbufs/mbufmgr/src/mb_chn.cpp Thu Dec 17 09:22:25 2009 +0200 @@ -0,0 +1,636 @@ +// 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: +// Buffer Manager for Protocols (MBuf Chains) +// +// + +#include +#include +#include "commsbufpondintf.h" +#include "commsbufpool.h" +// +// MBUF CHAIN +// + +__IMPLEMENT_CLEANUP(RMBufChain, Free) + + +EXPORT_C void RMBufChain::AllocL(TInt aLen) +/** +Allocate sufficient mbufs to hold specfied amount of data + +- Overloaded min/max variants (eg. refer RMBufChain::Alloc) deliberately do not exist because; + a. Intention is to ultimately deprecate (or at least discourage) the leaving variants since their usage is not typically (but not always + the case) recommended because they the throw/catch mechanism can hinder performance if used in appopriately. + b. Intention is to ultimately deprecate (or at least discourage) this class as it will likely be superceded by a generic system wide + equivalent. + c. If they shown to useful for this API, they can easily be added in the future... but the same can not be said for removing them in the future! +@param aLen A length of the cell +*/ + { + RMBufAllocator allocator; + User::LeaveIfError(RCommsBufChain::Alloc(aLen, allocator)); + } + +EXPORT_C TInt RMBufChain::Alloc(TInt aLen) +/** +Allocate sufficient mbufs to hold specfied amount of data + +@param aLen A length of the cell +*/ + { + RMBufAllocator allocator; + return RCommsBufChain::Alloc(aLen, allocator); + } + +TInt RMBufChain::Alloc(TInt aLen, const RMBufChain &aMBufChain) +/** +Allocate sufficient mbufs to hold specfied amount of data + +@param aLen A length of the cell + +@return KErrNone if allocation is success +@return KErrNoMBufs if allocation is failed +*/ + { + if(aMBufChain.First()) + { + const RCommsBuf* commsBuf = static_cast(aMBufChain.First()); + iNext = commsBuf->Pool()->Pond().Alloc(aLen, commsBuf->RawSize(), commsBuf->RawSize()); + return iNext ? KErrNone : KErrNoMBufs; + } + RMBufAllocator allocator; + return RCommsBufChain::Alloc(aLen, allocator); + } + +EXPORT_C TInt RMBufChain::Alloc(TInt aLen, TInt aMinMBufSize) + { + RMBufAllocator allocator; + return RCommsBufChain::Alloc(aLen, aMinMBufSize, allocator); + } + +EXPORT_C TInt RMBufChain::Alloc(TInt aLen, TInt aMinMBufSize, TInt aMaxMBufSize) + { + RMBufAllocator allocator; + return RCommsBufChain::Alloc(aLen, aMinMBufSize, aMaxMBufSize, allocator); + } + + +// overloading for TLS +EXPORT_C void RMBufChain::AllocL(TInt aLen, RMBufAllocator& aRMBufAllocator) + { + User::LeaveIfError(RCommsBufChain::Alloc(aLen, aRMBufAllocator)); + } + +EXPORT_C TInt RMBufChain::Alloc(TInt aLen, RMBufAllocator& aRMBufAllocator) + { + return RCommsBufChain::Alloc(aLen, aRMBufAllocator); + } + +TInt RMBufChain::Alloc(TInt aLen, const RMBufChain& aMBufChain, RMBufAllocator& aRMBufAllocator) + { + if(aMBufChain.First()) + { + return RCommsBufChain::Alloc(aLen, aMBufChain.First ()->Size(), aMBufChain.First ()->Size(), aRMBufAllocator); + } + else + { + return RCommsBufChain::Alloc(aLen, aLen, aRMBufAllocator); + } + } + +EXPORT_C TInt RMBufChain::Alloc(TInt aLen, TInt aMinMBufSize, RMBufAllocator& aRMBufAllocator) + { + return RCommsBufChain::Alloc(aLen, aMinMBufSize, aRMBufAllocator); + } + +EXPORT_C TInt RMBufChain::Alloc(TInt aLen, TInt aMinMBufSize, TInt aMaxMBufSize, RMBufAllocator& aRMBufAllocator) + { + return RCommsBufChain::Alloc(aLen, aMinMBufSize, aMaxMBufSize, aRMBufAllocator); + } + +EXPORT_C TInt RMBufChain::ReAlloc(TInt aLen) +/** +Adjust the size of a chain, allocates a new memory for the chain +- refer RMBufChain::AllocL notes regarding the deliberate decision not to provide an overloaded min/max mbuf size variant +@param aLen A new length +*/ + { + __ASSERT_ALWAYS(aLen>=0, CommsBuf::Panic(EMBuf_NegativeLength)); + + TInt currLen = Length(); + if(aLen < currLen) + { + TrimEnd(aLen); + } + else if(aLen > currLen) + { + TInt extraReq = aLen - currLen; + if(currLen > 0) + { + // Extend the final buf to consume any idle space + RMBuf* pLast = static_cast(Last()); + TInt idleSpace = pLast->Size() - pLast->End(); + ASSERT(idleSpace >= 0); + if(idleSpace) + { + TInt useSpace = Min(idleSpace, extraReq); + pLast->AdjustEnd(useSpace); + extraReq -= useSpace; + // Did this yield enough? + if(!extraReq) + { + return KErrNone; + } + } + } + // Need additional allocation + RMBufChain extraChain; + TInt err = extraChain.Alloc(extraReq, *this); + if(err != KErrNone) + { + return err; + } + RCommsBufChain::Append(extraChain); + } + return KErrNone; + } + +EXPORT_C void RMBufChain::ReAllocL(TInt aLen) +/** +Adjust the size of a chain, allocates a new memory for the chain +@param aLen A new length +*/ + { + User::LeaveIfError(ReAlloc(aLen)); + } + + + +EXPORT_C TInt RMBufChain::Create(const TDesC8& aDes, TInt aHdrLen) +/** +Create an Mbuf chain from a descriptor optionally allowing room at front for a protocol header. +- refer RMBufChain::AllocL notes regarding the deliberate decision not to provide an overloaded min/max mbuf size variant +@param aDes +@param aHdrLen A header length +*/ + { + TInt err = Alloc(aDes.Length() + aHdrLen); + if(err == KErrNone) + { + CopyIn(aDes, aHdrLen); // NB! old version prepended explicit buf. wonder if that matters? + } + return err; + } + + +EXPORT_C void RMBufChain::CreateL(const TDesC8& aDes, TInt aHdrLen) +/** +Create an Mbuf chain from a descriptor optionally allowing room at front for a protocol header. +@param aDes +@param aHdrLen A header length +*/ + { + User::LeaveIfError(Create(aDes, aHdrLen)); + } + + + +EXPORT_C void RMBufChain::FillZ(TInt aLen) +/** +Zero fill the first aLen bytes of an mbuf chain +@param aLen the length (how many byte to be appended to the end) +*/ + { + __ASSERT_ALWAYS(iNext!=NULL, CommsBuf::Panic(EMBuf_EmptyChain)); + + TInt n; + RMBuf* m = static_cast(iNext); + + while(aLen>0 && m!=NULL) + { + n = aLen < m->Length() ? aLen : m->Length(); + Mem::FillZ(m->Ptr(), n); + aLen -= n; + m = m->Next(); + } + } + + +EXPORT_C void RMBufChain::CopyL(RMBufChain& newChain, TInt anOffset, TInt aLen) const +/** +Copy data into a new chain starting at a given offset +into this chain. +Allocate sufficient mbufs to hold specfied amount of data, +optionally zeroing the buffers. +@param aLen A length of the cell +*/ + { + User::LeaveIfError(Copy(newChain, anOffset, aLen, 0)); + } + +EXPORT_C TInt RMBufChain::Copy(RMBufChain &newChain, TInt aOffset, TInt aLen, TInt aHdrReserve) const +/** +Copy data into a new chain starting at a given offset +into this chain. +- refer RMBufChain::AllocL notes regarding the deliberate decision not to provide an overloaded min/max mbuf size variant +@param newChain A new chain, where the data is copied to +@param aOffset A offset, +@param aLen the length of the data to be copied +@param aHdrReserve Amount of space (bytes) to offset the start of data from the start of the first buffer, so allowing +subsequent prepending without further allocation (typically used for protocol headers) +*/ + { + __ASSERT_ALWAYS(iNext!=NULL, CommsBuf::Panic(EMBuf_EmptyChain)); + __ASSERT_ALWAYS(aLen>=0, CommsBuf::Panic(EMBuf_NegativeLength)); + __ASSERT_ALWAYS(aOffset>=0, CommsBuf::Panic(EMBuf_NegativeOffset)); + + TInt n, n1, n2; + TUint8* p1, *p2; + RMBuf* m1, *m2; + + TInt len = Length(); + if (aOffset>0) + { + __ASSERT_ALWAYS(aOffset0) + { + if ((m1 = static_cast(RCommsBufChain::Goto(aOffset, n, n1))) == NULL) + { + return KErrNone; + } + p1 = m1->Buffer()+n; + } + else + { + m1 = static_cast(iNext); + p1 = m1->Ptr(); + n1 = m1->Length(); + } + + if (aHdrReserve > 0) + { + m2 = static_cast(newChain.First()); + if(aHdrReserve >= m2->Length()) + { + // In principle we could have one or more buffers as header reserve, however it's not + // obvious whether a chain can contain wholly empty buffers in it, ie whether code + // walking the chain will have encountered such a situation. So we prevent this - in + // practice this shouldn't pose a problem as the expected use is reserving capacity + // within the copied buffer for subsequent pre-pending to avoid allocating another buf + newChain.Free(); + return KErrOverflow; + } + m2->SetData(aHdrReserve, m2->Length() - aHdrReserve); + p2 = m2->Ptr(); + n2 = m2->Length(); + } + else + { + m2 = static_cast(newChain.iNext); + p2 = m2->Ptr(); + n2 = m2->Length(); + } + + while (len>0) + { + __ASSERT_DEBUG(n1>0 && n2>0, CommsBuf::Panic(EMBuf_NegativeLength)); + + n = n1 < n2 ? n1 : n2; + + Mem::Copy(p2, p1, n); + + if (n1 -= n, n1 == 0) + { + if (m1 = m1->Next(), m1==NULL) + { + break; + } + + p1 = m1->Ptr(); + n1 = m1->Length(); + } + else + { + p1 += n; + } + + + if (n2 -= n, n2 == 0) + { + if (m2 = m2->Next(), m2==NULL) + { + break; + } + + p2 = m2->Ptr(); + n2 = m2->Length(); + } + else + { + p2 += n; + } + len -= n; + } + return KErrNone; + } + +EXPORT_C void RMBufChain::CopyIn(const TDesC8& aDes, TInt aOffset/*=0*/) + { + RCommsBufChain::Write(aDes, aOffset); + } + +EXPORT_C void RMBufChain::CopyOut(TDes8& aDes, TInt aOffset) const +/** +Copy data from an mbuf chain into linear buffer +starting at specified offset. +@param aDes the buffer to copy in to +@param aOffset the offset +*/ + { + RCommsBufChain::Read(aDes, aOffset); + } + + +EXPORT_C void RMBufChain::Assign(RMBufQ& aQueue) +/** +Take ownership of Mbuf from a queue +Previously allocated data (e.g. by a call to RMBufChain::AllocL) in the chain must be +emptied (e.g. by calling RMBufChain::Free) before the assignment +@param aQueue the queue +@see RMBufChain::IsEmpty() +@see RMBufChain::Free() +*/ + { + __ASSERT_ALWAYS(iNext==NULL, CommsBuf::Panic(EMBuf_NotEmptyChain)); + iNext = aQueue.First(); + aQueue.Init(); + } + +EXPORT_C void RMBufChain::Assign(RMBufChain& aChain) + { + RCommsBufChain::Assign(aChain); + } + +EXPORT_C void RMBufChain::Append(RMBufChain& aChain) + { + RCommsBufChain::Append(aChain); + } + +EXPORT_C void RMBufChain::AppendL(TInt aLen) +/** +Append space to the end of a MBuf chain +@param aLen the length (how many byte to be appended to the end) +*/ + { + User::LeaveIfError(Append(aLen)); + } + +EXPORT_C TInt RMBufChain::Append(TInt aLen) +/** +Append space to the end of a MBuf chain +- refer RMBufChain::AllocL notes regarding the deliberate decision not to provide an overloaded min/max mbuf size variant +@param aLen the length (how many byte to be appended to the end) +*/ + { + if(iNext == NULL) + { + RMBufAllocator allocator; + return Append(aLen, allocator); + } + return RCommsBufChain::Append(aLen); + } + +// overloading for TLS +EXPORT_C TInt RMBufChain::Append(TInt aLen, RMBufAllocator& aRMBufAllocator) + { + RMBuf* buf = static_cast(aRMBufAllocator.iPond.Alloc(aLen, 0, KMaxTInt)); + if(buf == NULL) + { + return KErrNoMBufs; + } + + RCommsBufChain::Append(buf); + return KErrNone; + } + + +EXPORT_C RMBuf* RMBufChain::Remove() +/** +Removes and returns the first RCommsBuf. The ownership of the returned RCommsBuf is with the caller +*/ + { + RMBuf* buf = static_cast(iNext); + if(buf) + { + iNext = buf->Next(); + buf->Unlink(); + } + + return buf; + } + + + +EXPORT_C void RMBufChain::PrependL(TInt aLen) +/** +Prepend space onto the front of a chain +@param aLen the length of the space +*/ + { + User::LeaveIfError(Prepend(aLen)); + } + +EXPORT_C TInt RMBufChain::Prepend(TInt aLen) +/** +Prepend space onto the front of a chain +- refer RMBufChain::AllocL notes regarding the deliberate decision not to provide an overloaded min/max mbuf size variant +@param aLen the length of the space +*/ + { + if(iNext) + { + return RCommsBufChain::Prepend(aLen); + } + RMBufAllocator allocator; + return Prepend(aLen, allocator); + } + +// overloading for TLS +EXPORT_C TInt RMBufChain::Prepend(TInt aLen, RMBufAllocator& aRMBufAllocator) + { + RMBuf* buf = static_cast(aRMBufAllocator.iPond.Alloc(aLen, 0, KMaxTInt)); + if(buf == NULL) + { + return KErrNoMBufs; + } + + RMBufChain chain(buf); + RCommsBufChain::Prepend(chain); + return KErrNone; + } + +EXPORT_C void RMBufChain::Prepend(RMBuf* aBuf) + { + RCommsBufChain::Prepend(aBuf); + } + +EXPORT_C void RMBufChain::Prepend(RMBufChain& aChain) + { + RCommsBufChain::Prepend(aChain); + } + + +EXPORT_C TInt RMBufChain::NumBufs() const +/** +Count the number of buffers in a chain +*/ + { + __ASSERT_ALWAYS(iNext!=NULL, CommsBuf::Panic(EMBuf_EmptyChain)); + + TInt len = 0; + RMBuf* m = static_cast(iNext); + for (; m!=NULL; m = m->Next()) + { + len++; + } + return len; + } + + +EXPORT_C void RMBufChain::SplitL(TInt anOffset, RMBufChain& newChain) +/** +Split a chain into two new chains +Original chain gets the 1st half +newChain gets the other half. +@param anOffset The offset +@param newChain The result chain +*/ + { + User::LeaveIfError(RCommsBufChain::Split(anOffset, newChain)); + } + +EXPORT_C TInt RMBufChain::Split(TInt anOffset, RMBufChain& newChain) +/** +Split a chain into two new chains Original chain gets the 1st half +newChain gets the other half. +- refer RMBufChain::AllocL notes regarding the deliberate decision not to provide an overloaded min/max mbuf size variant +@param anOffset The offset +@param newChain The result chain +*/ + { + return RCommsBufChain::Split(anOffset, newChain); + } + +// overloading for TLS +EXPORT_C TInt RMBufChain::Split(TInt anOffset, RMBufChain& newChain, RMBufAllocator& /* aRMBufAllocator */) + { + return RCommsBufChain::Split ( anOffset, newChain ); + } + + +EXPORT_C void RMBufChain::Free() +/** +Free an MBuf chain, returning it to the free Pool +A pointer to the first mbuf of the next packet is returned. +*/ + { + RCommsBufChain::Free (); + } + +EXPORT_C void RMBufChain::TrimStart(TInt nBytes) +/** +Trim chain upto offset +@param anOffset The offset +*/ + { + RCommsBufChain::TrimStart(nBytes); + } + +EXPORT_C void RMBufChain::TrimEnd(TInt anOffset) +/** +Trim chain after offset +@param anOffset The offset +*/ + { + RCommsBufChain::TrimEnd(anOffset); + } + +EXPORT_C TBool RMBufChain::Goto(TInt anOffset, RMBuf* &resBuf, TInt& resOffset, TInt& resLength, RMBuf* &resPrevBuf) const +/** +Goto specified byte offset into an Mbuf chain. Used as part of copyin/out, split etc to position +MBuf pointer and offset from start of iBuffer. +@param anOffset The offset +@param resBuf result buffer +@param resOffset result offset +@param resLength result length +@param resPrevBuf result previous Buf in the chain +@return ETrue if successful +*/ + { + RCommsBuf* commsResBuf; + RCommsBuf* commsResPrevBuf; + + commsResBuf = RCommsBufChain::Goto(anOffset, resOffset, resLength, commsResPrevBuf); + if(commsResBuf) + { + resBuf = static_cast(commsResBuf); + resPrevBuf = static_cast(commsResPrevBuf); + return ETrue; + } + return EFalse; + } + +EXPORT_C TInt RMBufChain::Length() const +/** +Return the number of bytes of actual data contained in an MBuf chain +*/ + { + return RCommsBufChain::Length (); + } + +EXPORT_C RMBuf* RMBufChain::Last() const +/** +Find the last MBuf in a chain +@return the last MBuf in the chain +*/ + { + return static_cast(RCommsBufChain::Last()); + } + + +EXPORT_C TInt RMBufChain::Align(TInt aSize) +/** +Ensure that the first aSize bytes can be safely cast +to a structure of size aSize. +@param aSize A size +@return the number of bytes actually aligned. This will be the min of aSize and chain length. +*/ + { + return RCommsBufChain::Align ( aSize ); + }