commsfwutils/commsbufs/version1/mbufmgr/src/MB_CHN.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 (MBuf Chains)
       
    15 // 
       
    16 //
       
    17 
       
    18 /**
       
    19  @file
       
    20  @internalComponent
       
    21 */
       
    22 
       
    23 #include <es_mbman.h>
       
    24 #include "MBufPoolChain.h"
       
    25 #include "MBufPoolManager.h"
       
    26 #include <cflog.h>
       
    27 
       
    28 
       
    29 //
       
    30 // MBUF CHAIN
       
    31 //
       
    32 
       
    33 #ifdef __CFLOG_ACTIVE
       
    34 __CFLOG_STMT(_LIT8(KSubsysMBufMgr, "MBufMgr");) // subsystem name
       
    35 __CFLOG_STMT(_LIT8(KComponentPerformance, "performance");)	// component name - used for any sub-optimal performance behaviuor
       
    36 #endif
       
    37 
       
    38 __IMPLEMENT_CLEANUP(RMBufChain, Free)
       
    39 
       
    40 
       
    41 EXPORT_C void RMBufChain::AllocL(TInt aLen)
       
    42 /**
       
    43 Allocate sufficient mbufs to hold specfied amount of data,
       
    44 optionally zeroing the buffers.
       
    45 - Overloaded min/max variants (eg. refer RMBufChain::Alloc) deliberately do not exist because;
       
    46   a. Intention is to ultimately deprecate (or at least discourage) the leaving variants since their usage is not typically (but not always
       
    47      the case) recommended because they the throw/catch mechanism can hinder performance if used in appopriately.
       
    48   b. Intention is to ultimately deprecate (or at least discourage) this class as it will likely be superceded by a generic system wide
       
    49      equivalent.
       
    50   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!
       
    51 @param aLen A length of the cell
       
    52 */
       
    53 	{
       
    54 	RMBufAllocator allocator;
       
    55 	return AllocL(aLen, allocator);
       
    56 	}
       
    57 
       
    58 EXPORT_C TInt RMBufChain::Alloc(TInt aLen)
       
    59 /**
       
    60 Allocate sufficient mbufs to hold specfied amount of data,
       
    61 optionally zeroing the buffers.
       
    62 @param aLen A length of the cell
       
    63 */
       
    64 	{
       
    65 	RMBufAllocator allocator;
       
    66 	return Alloc(aLen, allocator);
       
    67 	}
       
    68 TInt RMBufChain::Alloc(TInt aLen, const RMBufChain &aMBufChain)
       
    69 	{
       
    70 	RMBufAllocator allocator;
       
    71 	return Alloc(aLen, aMBufChain, allocator);
       
    72 	}
       
    73 EXPORT_C TInt RMBufChain::Alloc(TInt aLen, TInt aMinMBufSize)
       
    74 	{
       
    75 	RMBufAllocator allocator;
       
    76 	return Alloc(aLen, aMinMBufSize, allocator);
       
    77 	}
       
    78 EXPORT_C TInt RMBufChain::Alloc(TInt aLen, TInt aMinMBufSize, TInt aMaxMBufSize)
       
    79 	{
       
    80 	RMBufAllocator allocator;
       
    81 	return Alloc(aLen, aMinMBufSize, aMaxMBufSize, allocator);
       
    82 	}
       
    83 
       
    84 
       
    85 // overloading for TLS
       
    86 EXPORT_C void RMBufChain::AllocL(TInt aLen, RMBufAllocator& aRMBufAllocator)
       
    87 	{
       
    88 	__ASSERT_ALWAYS(iNext==NULL, CMBufManager::Panic(EMBuf_NotEmptyChain));
       
    89 
       
    90 	iNext = aRMBufAllocator.MBufManager().AllocL(aLen);
       
    91 	}
       
    92 EXPORT_C TInt RMBufChain::Alloc(TInt aLen, RMBufAllocator& aRMBufAllocator)
       
    93 	{
       
    94 	__ASSERT_ALWAYS(iNext==NULL, CMBufManager::Panic(EMBuf_NotEmptyChain));
       
    95 
       
    96 	iNext = aRMBufAllocator.MBufManager().Alloc(aLen);
       
    97 	return iNext? KErrNone: KErrNoMBufs;
       
    98 	}
       
    99 TInt RMBufChain::Alloc(TInt aLen, const RMBufChain& aMBufChain, RMBufAllocator& aRMBufAllocator)
       
   100 	{
       
   101 	__ASSERT_ALWAYS(iNext==NULL, CMBufManager::Panic(EMBuf_NotEmptyChain));
       
   102 
       
   103 	iNext = aRMBufAllocator.MBufManager().Alloc(aLen, aMBufChain);
       
   104 	return iNext? KErrNone: KErrNoMBufs;
       
   105 	}
       
   106 EXPORT_C TInt RMBufChain::Alloc(TInt aLen, TInt aMinMBufSize, RMBufAllocator& aRMBufAllocator)
       
   107 	{
       
   108 	__ASSERT_ALWAYS(iNext==NULL, CMBufManager::Panic(EMBuf_NotEmptyChain));
       
   109 
       
   110 	iNext = aRMBufAllocator.MBufManager().Alloc(aLen, aMinMBufSize);
       
   111 	return iNext? KErrNone: KErrNoMBufs;
       
   112 	}
       
   113 EXPORT_C TInt RMBufChain::Alloc(TInt aLen, TInt aMinMBufSize, TInt aMaxMBufSize, RMBufAllocator& aRMBufAllocator)
       
   114 	{
       
   115 	__ASSERT_ALWAYS(iNext==NULL, CMBufManager::Panic(EMBuf_NotEmptyChain));
       
   116 
       
   117 	iNext = aRMBufAllocator.MBufManager().Alloc(aLen, aMinMBufSize, aMaxMBufSize);
       
   118 	return iNext? KErrNone: KErrNoMBufs;
       
   119 	}
       
   120 
       
   121 EXPORT_C TInt RMBufChain::ReAlloc(TInt aLen)
       
   122 /**
       
   123 Adjust the size of a chain, allocates a new memory for the chain
       
   124 - refer RMBufChain::AllocL notes regarding the deliberate decision not to provide an overloaded min/max mbuf size variant
       
   125 @param aLen A new length
       
   126 */
       
   127 	{
       
   128 	__ASSERT_ALWAYS(aLen>=0, CMBufManager::Panic(EMBuf_NegativeLength));
       
   129 
       
   130 	TInt currLen = Length();
       
   131 	if(aLen < currLen)
       
   132 		TrimEnd(aLen);
       
   133 	else if(aLen > currLen)
       
   134 		{
       
   135 		TInt extraReq = aLen - currLen;
       
   136 		if(currLen > 0)
       
   137 			{
       
   138 			// Extend the final buf to consume any idle space
       
   139 			RMBuf* pLast = Last();
       
   140 			TInt idleSpace = pLast->Size() - pLast->End();
       
   141 			ASSERT(idleSpace >= 0);
       
   142 			if(idleSpace)
       
   143 				{
       
   144 				TInt useSpace = Min(idleSpace, extraReq);
       
   145 				pLast->AdjustEnd(useSpace);
       
   146 				extraReq -= useSpace;
       
   147 				// Did this yield enough?
       
   148 				if(!extraReq)
       
   149 					return KErrNone;
       
   150 				}
       
   151 			}
       
   152 		// Need additional allocation
       
   153 		RMBufChain extraChain;
       
   154 		TInt err = extraChain.Alloc(extraReq, *this);
       
   155 		if(err != KErrNone)
       
   156 			{
       
   157 			return err;
       
   158 			}
       
   159 		Append(extraChain);
       
   160 		}
       
   161 	return KErrNone;
       
   162 	}
       
   163 
       
   164 EXPORT_C void RMBufChain::ReAllocL(TInt aLen)
       
   165 /**
       
   166 Adjust the size of a chain, allocates a new memory for the chain
       
   167 @param aLen A new length
       
   168 */
       
   169 	{
       
   170 	User::LeaveIfError(ReAlloc(aLen));
       
   171 	}
       
   172 
       
   173 
       
   174 
       
   175 EXPORT_C TInt RMBufChain::Create(const TDesC8& aDes, TInt aHdrLen)
       
   176 /**
       
   177 Create an Mbuf chain from a descriptor optionally allowing room at front for a protocol header.
       
   178 - refer RMBufChain::AllocL notes regarding the deliberate decision not to provide an overloaded min/max mbuf size variant
       
   179 @param aDes
       
   180 @param aHdrLen A header length
       
   181 */
       
   182 	{
       
   183 	TInt err = Alloc(aDes.Length() + aHdrLen);
       
   184 	if(err == KErrNone)
       
   185 		{
       
   186 		CopyIn(aDes, aHdrLen);	// NB! old version prepended explicit buf. wonder if that matters?
       
   187 		}
       
   188 	return err;
       
   189 	}
       
   190 
       
   191 
       
   192 EXPORT_C void RMBufChain::CreateL(const TDesC8& aDes, TInt aHdrLen)
       
   193 /**
       
   194 Create an Mbuf chain from a descriptor optionally allowing room at front for a protocol header.
       
   195 @param aDes
       
   196 @param aHdrLen A header length
       
   197 */
       
   198 	{
       
   199 	User::LeaveIfError(Create(aDes, aHdrLen));
       
   200 	}
       
   201 
       
   202 
       
   203 EXPORT_C void RMBufChain::Free()
       
   204 /**
       
   205 Free an MBuf chain, returning it to the free Pool
       
   206 A pointer to the first mbuf of the next packet is returned.
       
   207 */
       
   208 	{
       
   209 	if (iNext!=NULL)
       
   210 		iNext->Free();
       
   211 	Init();
       
   212 	}
       
   213 
       
   214 
       
   215 EXPORT_C void RMBufChain::FillZ(TInt aLen)
       
   216 /**
       
   217 Zero fill the first aLen bytes of an mbuf chain
       
   218 @param aLen the length (how many byte to be appended to the end)
       
   219 */
       
   220 	{
       
   221 	__ASSERT_ALWAYS(iNext!=NULL, CMBufManager::Panic(EMBuf_EmptyChain));
       
   222 
       
   223 	TInt n;
       
   224 	RMBuf* m = iNext;
       
   225 
       
   226 	while (aLen>0 && m!=NULL)
       
   227 		{
       
   228 			n = aLen < m->Length() ? aLen : m->Length();
       
   229 			Mem::FillZ(m->Ptr(), n);
       
   230 			aLen -= n;
       
   231 			m = m->Next();
       
   232 		}
       
   233 	}
       
   234 
       
   235 
       
   236 EXPORT_C void RMBufChain::CopyL(RMBufChain& newChain, TInt anOffset, TInt aLen) const
       
   237 /**
       
   238 Copy data into a new chain starting at a given offset
       
   239 into this chain.
       
   240 Allocate sufficient mbufs to hold specfied amount of data,
       
   241 optionally zeroing the buffers.
       
   242 @param aLen A length of the cell
       
   243 */
       
   244 	{
       
   245 	User::LeaveIfError(Copy(newChain, anOffset, aLen));
       
   246 	}
       
   247 
       
   248 EXPORT_C TInt RMBufChain::Copy(RMBufChain &newChain, TInt anOffset, TInt aLen) const
       
   249 /**
       
   250 Copy data into a new chain starting at a given offset
       
   251 into this chain.
       
   252 - refer RMBufChain::AllocL notes regarding the deliberate decision not to provide an overloaded min/max mbuf size variant
       
   253 @param newChain A new chain, where the data is copied to
       
   254 @param anOffset A offset,
       
   255 @param aLen the length of the data to be copied
       
   256 */
       
   257 	{
       
   258 	__ASSERT_ALWAYS(iNext!=NULL, CMBufManager::Panic(EMBuf_EmptyChain));
       
   259 	__ASSERT_ALWAYS(aLen>=0, CMBufManager::Panic(EMBuf_NegativeLength));
       
   260 	__ASSERT_ALWAYS(anOffset>=0, CMBufManager::Panic(EMBuf_NegativeOffset));
       
   261 
       
   262 	TInt n, n1, n2;
       
   263 	TUint8* p1, *p2;
       
   264 	RMBuf* m1, *m2;
       
   265 
       
   266 	TInt len = Length();
       
   267 	if (anOffset>0)
       
   268 		{
       
   269 		__ASSERT_ALWAYS(anOffset<len, CMBufManager::Panic(EMBuf_BadOffset));
       
   270 		n = len - anOffset;
       
   271 		len = Min(aLen, n);
       
   272 		}
       
   273 	else
       
   274 		len = Min(aLen, len);
       
   275 
       
   276 	TInt err = newChain.Alloc(len, *this);
       
   277 	if(err != KErrNone)
       
   278 		{
       
   279 		return err;
       
   280 		}
       
   281 
       
   282 	if (anOffset>0)
       
   283 		{
       
   284 		if (!Goto(anOffset, m1, n, n1))
       
   285 			return KErrNone;
       
   286 		p1 = m1->Buffer()+n;
       
   287 		}
       
   288 	else
       
   289 		{
       
   290 		m1 = iNext;
       
   291 		p1 = m1->Ptr();
       
   292 		n1 = m1->Length();
       
   293 		}
       
   294 
       
   295 	m2 = newChain.iNext;
       
   296 	p2 = m2->Ptr();
       
   297 	n2 = m2->Length();
       
   298 
       
   299 	while (len>0)
       
   300 		{
       
   301 		__ASSERT_DEBUG(n1>0 && n2>0, CMBufManager::Panic(EMBuf_NegativeLength));
       
   302 
       
   303 		n = n1 < n2 ? n1 : n2;
       
   304 
       
   305 		Mem::Copy(p2, p1, n);
       
   306 
       
   307 		if (n1 -= n, n1 == 0)
       
   308 			{
       
   309 			if (m1 = m1->Next(), m1==NULL)
       
   310 				break;
       
   311 			p1 = m1->Ptr();
       
   312 			n1 = m1->Length();
       
   313 			}
       
   314 		else
       
   315 			p1 += n;
       
   316 
       
   317 		if (n2 -= n, n2 == 0)
       
   318 			{
       
   319 			if (m2 = m2->Next(), m2==NULL)
       
   320 				break;
       
   321 			p2 = m2->Ptr();
       
   322 			n2 = m2->Length();
       
   323 			}
       
   324 		else
       
   325 			p2 += n;
       
   326 
       
   327 		len -= n;
       
   328 		}
       
   329 	return KErrNone;
       
   330 	}
       
   331 
       
   332 
       
   333 EXPORT_C void RMBufChain::CopyIn(const TDesC8& aDes, TInt aOffset)
       
   334 /**
       
   335 Copy data into an mbuf chain from a linear buffer
       
   336 starting at specified offset.
       
   337 @param aDes The buffer from where data is copied to the chain
       
   338 @param aOffset The offset
       
   339 */
       
   340 	{
       
   341 	__ASSERT_ALWAYS(iNext!=NULL, CMBufManager::Panic(EMBuf_EmptyChain));
       
   342 	__ASSERT_ALWAYS(aOffset>=0, CMBufManager::Panic(EMBuf_NegativeOffset));
       
   343 
       
   344 	TUint8* ptr = (TUint8*)aDes.Ptr();
       
   345 	TInt len = aDes.Length();
       
   346 
       
   347 	TInt n;
       
   348 	RMBuf* m;
       
   349 
       
   350 	if (aOffset>0)
       
   351 		{
       
   352 		TInt o;
       
   353 
       
   354 		if (!Goto(aOffset, m, o, n))
       
   355 			return;
       
   356 
       
   357 		if (n>len)
       
   358 			n = len;
       
   359 
       
   360 		Mem::Copy(m->Buffer()+o, ptr, n);
       
   361 		ptr += n;
       
   362 		len -= n;
       
   363 		m = m->Next();
       
   364 		}
       
   365 	else
       
   366 		m = iNext;
       
   367 
       
   368 	while (len>0 && m!=NULL)
       
   369 		{
       
   370 		n = len > m->Length() ? m->Length() : len;
       
   371 		Mem::Copy(m->Ptr(), ptr, n);
       
   372 		ptr += n;
       
   373 		len -= n;
       
   374 		m = m->Next();
       
   375 		}
       
   376 	}
       
   377 
       
   378 
       
   379 EXPORT_C void RMBufChain::CopyOut(TDes8& aDes, TInt aOffset) const
       
   380 /**
       
   381 Copy data from an mbuf chain into linear buffer
       
   382 starting at specified offset.
       
   383 @param aDes the buffer to copy in to
       
   384 @param aOffset the offset
       
   385 */
       
   386 	{
       
   387 //removed after internal discussion; generally unhelpful as empty == zero length is ok concept
       
   388 //	__ASSERT_ALWAYS(iNext!=NULL, CMBufManager::Panic(EMBuf_EmptyChain));
       
   389 	__ASSERT_ALWAYS(aOffset>=0, CMBufManager::Panic(EMBuf_NegativeOffset));
       
   390 
       
   391 	TUint8* ptr = (TUint8*)aDes.Ptr();
       
   392 	TInt len = aDes.Length();
       
   393 
       
   394 	TInt n;
       
   395 	RMBuf* m;
       
   396 
       
   397 	if (aOffset>0)
       
   398 		{
       
   399 		TInt o;
       
   400 
       
   401 		if (!Goto(aOffset, m, o, n))
       
   402 			{
       
   403 			aDes.SetLength(0);
       
   404 			return;
       
   405 			}
       
   406 
       
   407 		if (n>len)
       
   408 			n = len;
       
   409 
       
   410 		Mem::Copy(ptr, m->Buffer()+o, n);
       
   411 		ptr += n;
       
   412 		len -= n;
       
   413 		m = m->Next();
       
   414 		}
       
   415 	else
       
   416 		m = iNext;
       
   417 
       
   418 	while (len>0 && m!=NULL)
       
   419 		{
       
   420 		n = len > m->Length() ? m->Length() : len;
       
   421 		Mem::Copy(ptr, m->Ptr(), n);
       
   422 		ptr += n;
       
   423 		len -= n;
       
   424 		m = m->Next();
       
   425 		}
       
   426 	aDes.SetLength(ptr-aDes.Ptr());
       
   427 	}
       
   428 
       
   429 
       
   430 EXPORT_C void RMBufChain::Assign(RMBufQ& aQueue)
       
   431 /**
       
   432 Take ownership of Mbuf from a queue
       
   433 Previously allocated data (e.g. by a call to RMBufChain::AllocL) in the chain must be
       
   434 emptied (e.g. by calling RMBufChain::Free) before the assignment
       
   435 @param aQueue the queue
       
   436 @see RMBufChain::IsEmpty()
       
   437 @see RMBufChain::Free()
       
   438 */
       
   439 	{
       
   440 	__ASSERT_ALWAYS(iNext==NULL, CMBufManager::Panic(EMBuf_NotEmptyChain));
       
   441 	iNext = aQueue.First();
       
   442 	aQueue.Init();
       
   443 	}
       
   444 
       
   445 
       
   446 EXPORT_C void RMBufChain::Assign(RMBufChain& aChain)
       
   447 /**
       
   448 Take ownership of Mbuf from another chain
       
   449 Previously allocated data (e.g. by a call to RMBufChain::AllocL) in the chain must be
       
   450 emptied (e.g. by calling RMBufChain::Free) before the assignment
       
   451 @param aChain the chain
       
   452 @see RMBufChain::IsEmpty()
       
   453 @see RMBufChain::Free()
       
   454 */
       
   455 	{
       
   456 	__ASSERT_ALWAYS(iNext==NULL, CMBufManager::Panic(EMBuf_NotEmptyChain));
       
   457 	iNext = aChain.iNext;
       
   458 	aChain.Init();
       
   459 	}
       
   460 
       
   461 
       
   462 EXPORT_C void RMBufChain::Append(RMBufChain& aChain)
       
   463 /**
       
   464 Append an MBuf chain, taking ownership of the MBufs
       
   465 @param aChain the chain to be appended
       
   466 */
       
   467 	{
       
   468 	__ASSERT_ALWAYS(iNext!=aChain.iNext, CMBufManager::Panic(EMBuf_CircularRef));
       
   469 
       
   470 	if (iNext!=NULL)
       
   471 		{
       
   472 		RMBuf* last	= Last();
       
   473 		last->Link(aChain.iNext);
       
   474 		}
       
   475 	else
       
   476 		iNext = aChain.iNext;
       
   477 
       
   478 	aChain.Init();
       
   479 	}
       
   480 
       
   481 
       
   482 EXPORT_C void RMBufChain::AppendL(TInt aLen)
       
   483 /**
       
   484 Append space to the end of a MBuf chain
       
   485 @param aLen the length (how many byte to be appended to the end)
       
   486 */
       
   487 	{
       
   488 	User::LeaveIfError(Append(aLen));
       
   489 	}
       
   490 
       
   491 EXPORT_C TInt RMBufChain::Append(TInt aLen)
       
   492 /**
       
   493 Append space to the end of a MBuf chain
       
   494 - refer RMBufChain::AllocL notes regarding the deliberate decision not to provide an overloaded min/max mbuf size variant
       
   495 @param aLen the length (how many byte to be appended to the end)
       
   496 */
       
   497 	{
       
   498 	RMBufAllocator allocator;
       
   499 	return Append(aLen, allocator);
       
   500 	}
       
   501 
       
   502 // overloading for TLS
       
   503 EXPORT_C TInt RMBufChain::Append(TInt aLen, RMBufAllocator& aRMBufAllocator)
       
   504 	{
       
   505 	if (iNext==NULL)
       
   506 		{
       
   507 		return Alloc(aLen, *this, aRMBufAllocator);
       
   508 		}
       
   509 
       
   510 	RMBuf* last = Last();
       
   511 	// Amount of space available on end of last Mbuf
       
   512 	TInt n = Min(last->Size()-(last->Offset()+last->Length()), aLen);
       
   513 	// Amount of space that needs to be Allocated in new buffers
       
   514 	TInt m = aLen-n;
       
   515 
       
   516 	if (m>0)
       
   517 		{
       
   518 		RMBufChain chn;
       
   519 		TInt err = chn.Alloc(m, *this, aRMBufAllocator);
       
   520 		if(err != KErrNone)
       
   521 			{
       
   522 			return err;
       
   523 			}
       
   524 		last->Link(chn.iNext);
       
   525 		}
       
   526 	// Left to last to avoid modifying the chain unless the extension suceeds
       
   527 	last->AdjustEnd(n);
       
   528 	return KErrNone;
       
   529 	}
       
   530 
       
   531 
       
   532 EXPORT_C RMBuf* RMBufChain::Remove()
       
   533 /**
       
   534 Remove 1st mbuf from chain
       
   535 @param aChain the chain to be prepended
       
   536 */
       
   537 	{
       
   538 	if (IsEmpty())
       
   539 		return NULL;
       
   540 	else
       
   541 		{
       
   542 		RMBuf* m = iNext;
       
   543 		iNext = iNext->Next();
       
   544 		m->Unlink();
       
   545 		return m;
       
   546 		}
       
   547 	}
       
   548 
       
   549 
       
   550 EXPORT_C void RMBufChain::Prepend(RMBufChain& aChain)
       
   551 /**
       
   552 Prepend an MBuf chain, taking ownership of the MBufs
       
   553 @param aChain the chain to be prepended
       
   554 */
       
   555 	{
       
   556 	if (iNext!=NULL)
       
   557 		{
       
   558 		RMBuf* last = aChain.Last();
       
   559 		last->Link(iNext);
       
   560 		}
       
   561 	iNext = aChain.iNext;
       
   562 	aChain.Init();
       
   563 	}
       
   564 
       
   565 
       
   566 EXPORT_C void RMBufChain::Prepend(RMBuf* aBuf)
       
   567 /**
       
   568 Prepend an MBuf to a chain, taking ownership of the MBuf
       
   569 @param aBuf the buffer to be prepended
       
   570 */
       
   571 	{
       
   572 	aBuf->Link(iNext);
       
   573 	iNext = aBuf;
       
   574 	}
       
   575 
       
   576 
       
   577 EXPORT_C void RMBufChain::PrependL(TInt aLen)
       
   578 /**
       
   579 Prepend space onto the front of a chain
       
   580 @param aLen the length of the space
       
   581 */
       
   582 	{
       
   583 	User::LeaveIfError(Prepend(aLen));
       
   584 	}
       
   585 
       
   586 EXPORT_C TInt RMBufChain::Prepend(TInt aLen)
       
   587 /**
       
   588 Prepend space onto the front of a chain
       
   589 - refer RMBufChain::AllocL notes regarding the deliberate decision not to provide an overloaded min/max mbuf size variant
       
   590 @param aLen the length of the space
       
   591 */
       
   592 	{
       
   593 	RMBufAllocator allocator;
       
   594 	return Prepend(aLen, allocator);
       
   595 	}
       
   596 
       
   597 // overloading for TLS
       
   598 EXPORT_C TInt RMBufChain::Prepend(TInt aLen, RMBufAllocator& aRMBufAllocator)
       
   599 	{
       
   600 	__ASSERT_ALWAYS(aLen>=0, CMBufManager::Panic(EMBuf_NegativeLength));
       
   601 
       
   602 	// If can fit and the start would remain aligned
       
   603 	// then prepend by moving offset and length
       
   604  	// if (iNext->Offset()>=aLen && IS_ALIGNED(iNext->Offset()-aLen))
       
   605 	if (iNext && iNext->Offset()>=aLen)
       
   606 		{
       
   607 		iNext->AdjustStart(-aLen);
       
   608 		return KErrNone;
       
   609 		}
       
   610 
       
   611 	// else allocation required
       
   612 #ifdef __CFLOG_ACTIVE
       
   613 	__CFLOG_VAR((KSubsysMBufMgr, KComponentPerformance, _L8("RMBufChain::Prepend() - Warning! sub-optimal performance; prepend required to alloc a new mbuf/chain, iOffset=%d reqLen=%d"),
       
   614 		iNext?iNext->Offset():0, aLen));
       
   615 #endif
       
   616 	RMBuf* m=NULL;
       
   617 
       
   618 	m = aRMBufAllocator.MBufManager().Alloc(aLen);
       
   619 	if(!m)
       
   620 		{
       
   621 		return KErrNoMBufs;
       
   622 		}
       
   623 
       
   624     // Iterate along the mbuf chain to determine the size and find the last in the chain.
       
   625     RMBuf* next = m;
       
   626 	RMBuf* last;
       
   627 	do
       
   628 	{
       
   629 		last = next;
       
   630 		aLen -= last->Length();
       
   631 	    next = last->Next();
       
   632 	}
       
   633 	while(next);
       
   634 
       
   635 	// Performance enhancement - most of these prepends are 20 byes or so
       
   636 	// This allows the next one to use this MBuf
       
   637 	if (aLen<0)
       
   638 		{
       
   639 		m->SetData(-aLen, m->Length()+aLen);
       
   640 		}
       
   641 
       
   642 	last->Link(iNext);
       
   643 	iNext = m;
       
   644 	return KErrNone;
       
   645 	}
       
   646 
       
   647 EXPORT_C TInt RMBufChain::NumBufs() const
       
   648 /**
       
   649 Count the number of buffers in a chain
       
   650 */
       
   651 	{
       
   652 	__ASSERT_ALWAYS(iNext!=NULL, CMBufManager::Panic(EMBuf_EmptyChain));
       
   653 
       
   654 	TInt len = 0;
       
   655 	RMBuf* m;
       
   656 	for (m = iNext; m!=NULL; m = m->Next())
       
   657 		len++;
       
   658 
       
   659 	return len;
       
   660 	}
       
   661 
       
   662 
       
   663 EXPORT_C TInt RMBufChain::Length() const
       
   664 /**
       
   665 Return the number of bytes of actual data contained
       
   666 in an MBuf chain
       
   667 */
       
   668 	{
       
   669 //removed after internal & 3rd party discussion; generally unhelpful as empty == zero length is ok concept
       
   670 //	__ASSERT_ALWAYS(iNext!=NULL, CMBufManager::Panic(EMBuf_EmptyChain));
       
   671 
       
   672 	TInt len = 0;
       
   673 	RMBuf* m;
       
   674 	for (m = iNext; m!=NULL; m = m->Next())
       
   675 		len += m->Length();
       
   676 
       
   677 	return len;
       
   678 	}
       
   679 
       
   680 
       
   681 EXPORT_C void RMBufChain::SplitL(TInt anOffset, RMBufChain& newChain)
       
   682 /**
       
   683 Split a chain into two new chains
       
   684 Original chain gets the 1st half
       
   685 newChain gets the other half.
       
   686 @param anOffset The offset
       
   687 @param newChain The result chain
       
   688 */
       
   689 	{
       
   690 	User::LeaveIfError(Split(anOffset, newChain));
       
   691 	}
       
   692 
       
   693 EXPORT_C TInt RMBufChain::Split(TInt anOffset, RMBufChain& newChain)
       
   694 /**
       
   695 Split a chain into two new chains
       
   696 Original chain gets the 1st half
       
   697 newChain gets the other half.
       
   698 - refer RMBufChain::AllocL notes regarding the deliberate decision not to provide an overloaded min/max mbuf size variant
       
   699 @param anOffset The offset
       
   700 @param newChain The result chain
       
   701 */
       
   702 	{
       
   703 	RMBufAllocator allocator;
       
   704 	return Split(anOffset, newChain, allocator);
       
   705 	}
       
   706 
       
   707 // overloading for TLS
       
   708 EXPORT_C TInt RMBufChain::Split(TInt anOffset, RMBufChain& newChain, RMBufAllocator& aRMBufAllocator)
       
   709 	{
       
   710 	__ASSERT_ALWAYS(iNext!=NULL, CMBufManager::Panic(EMBuf_EmptyChain));
       
   711 	__ASSERT_ALWAYS(anOffset>=0, CMBufManager::Panic(EMBuf_NegativeOffset));
       
   712 
       
   713 	if (anOffset==0)
       
   714 		{
       
   715 		newChain.iNext = NULL;
       
   716 		return KErrNone;
       
   717 		}
       
   718 
       
   719 	TInt o, n;
       
   720 	RMBuf* m, *p;
       
   721 
       
   722 	if (!Goto(anOffset, m, o, n, p))
       
   723 		return KErrNone;
       
   724 
       
   725 	if (o!=m->Offset()) // Not on an mbuf boundary
       
   726 		{
       
   727 		// get another mbuf and copy extra data
       
   728 		RMBuf* m2;
       
   729 		m2 = aRMBufAllocator.MBufManager().Alloc(n, n);
       
   730 		if(!m2)
       
   731 			{
       
   732 			return KErrNoMBufs;
       
   733 			}
       
   734 
       
   735 		__ASSERT_DEBUG(m2->Size() >= n, CMBufManager::Panic(EMBuf_TooSmall));
       
   736 		Mem::Copy(m2->Ptr(), m->Buffer()+o, n);		// trs; possible future enhancement to optionally not split the mbuf unless requested, thus avoiding the copy, but kept as is to avoid a functional break
       
   737 		m2->SetLength(n);
       
   738 		m2->Link(m->Next());
       
   739 		m->AdjustEnd(-n);
       
   740 		m->Unlink();
       
   741 		newChain = m2;
       
   742 		}
       
   743 	else
       
   744 		{
       
   745 		p->Unlink();
       
   746 		newChain = m;
       
   747 		}
       
   748 	return KErrNone;
       
   749 	}
       
   750 
       
   751 EXPORT_C void RMBufChain::TrimStart(TInt anOffset)
       
   752 /**
       
   753 Trim chain upto offset
       
   754 @param anOffset The offset
       
   755 */
       
   756 	{
       
   757 	__ASSERT_ALWAYS(iNext!=NULL, CMBufManager::Panic(EMBuf_EmptyChain));
       
   758 	__ASSERT_ALWAYS(anOffset>=0, CMBufManager::Panic(EMBuf_NegativeOffset));
       
   759 
       
   760 	if (anOffset==0)
       
   761 		return;
       
   762 
       
   763 	RMBuf* m, *p;
       
   764 	TInt o, n;
       
   765 	if (!Goto(anOffset, m, o, n, p))
       
   766 		{
       
   767 		Free();
       
   768 		return;
       
   769 		}
       
   770 
       
   771 	if (p!=NULL) // m not first mbuf?
       
   772 		{
       
   773 		p->Unlink();
       
   774 		iNext->Free();
       
   775 
       
   776 		iNext = m;
       
   777 		}
       
   778 
       
   779 	if (o!=m->Offset()) // not at mbuf boundary?
       
   780 		m->SetData(o, n);
       
   781 	}
       
   782 
       
   783 EXPORT_C void RMBufChain::TrimEnd(TInt anOffset)
       
   784 /**
       
   785 Trim chain after offset
       
   786 @param anOffset The offset
       
   787 */
       
   788 	{
       
   789 	__ASSERT_ALWAYS(iNext!=NULL, CMBufManager::Panic(EMBuf_EmptyChain));
       
   790 	__ASSERT_ALWAYS(anOffset>=0, CMBufManager::Panic(EMBuf_NegativeOffset));
       
   791 
       
   792 	if(anOffset==0)
       
   793 		{
       
   794 		Free();
       
   795 		return;
       
   796 		}
       
   797 
       
   798 	RMBuf* m, *p;
       
   799 	TInt o, n;
       
   800 	if (!Goto(anOffset, m, o, n, p))
       
   801 		return;
       
   802 
       
   803 	if (o!=m->Offset()) // not at mbuf boundary?
       
   804 		{
       
   805 		m->AdjustEnd(-n);
       
   806 		if (p = m->Next(), p!=NULL)
       
   807 			{
       
   808 			m->Unlink();
       
   809 			p->Free();
       
   810 			}
       
   811 		}
       
   812 	else
       
   813 		{
       
   814 		if (p!=NULL)
       
   815 			p->Unlink();
       
   816 			m->Free();
       
   817 		}
       
   818 	}
       
   819 
       
   820 
       
   821 EXPORT_C TBool RMBufChain::Goto(TInt anOffset, RMBuf* &resBuf, TInt& resOffset, TInt& resLength, RMBuf* &resPrevBuf) const
       
   822 /**
       
   823 Goto specified byte offset into an Mbuf chain
       
   824 Used as part of copyin/out, split etc to position
       
   825 MBuf pointer and offset from start of iBuffer.
       
   826 @param anOffset The offset
       
   827 @param resBuf result buffer
       
   828 @param resOffset result offset
       
   829 @param resLength result length
       
   830 @param resPrevBuf result previous Buf in the chain
       
   831 @return ETrue if successful
       
   832 */
       
   833 	{
       
   834 	__ASSERT_ALWAYS(iNext!=NULL, CMBufManager::Panic(EMBuf_EmptyChain));
       
   835 	__ASSERT_ALWAYS(anOffset>=0, CMBufManager::Panic(EMBuf_NegativeOffset));
       
   836 
       
   837 	TInt o = 0;
       
   838 	RMBuf* p = NULL, *m = iNext;
       
   839 
       
   840 	while (m!=NULL)
       
   841 		{
       
   842 		if (o + m->Length() > anOffset)
       
   843 			{
       
   844 			resBuf = m;
       
   845 			resOffset = (anOffset - o) + m->Offset();
       
   846 			resLength = m->Length() - (anOffset - o);
       
   847 			resPrevBuf = p;
       
   848 			return ETrue;
       
   849 			}
       
   850 		o += m->Length();
       
   851 		p = m;
       
   852 		m = m->Next();
       
   853 		}
       
   854 
       
   855 	// Attempt to goto beyond end of chain
       
   856 	__ASSERT_ALWAYS(o==anOffset, CMBufManager::Panic(EMBuf_BadOffset));
       
   857 	return EFalse;
       
   858 	}
       
   859 
       
   860 EXPORT_C RMBuf* RMBufChain::Last() const
       
   861 /**
       
   862 Find the last MBuf in a chain
       
   863 @return the last MBuf in the chain
       
   864 */
       
   865 	{
       
   866 	__ASSERT_ALWAYS(iNext!=NULL, CMBufManager::Panic(EMBuf_EmptyChain));
       
   867 
       
   868 	return iNext->Last();
       
   869 	}
       
   870 
       
   871 
       
   872 EXPORT_C TInt RMBufChain::Align(TInt aSize)
       
   873 /**
       
   874 Ensure that the first aSize bytes can be safely cast
       
   875 to a structure of size aSize.
       
   876 @param aSize A size
       
   877 @return the number of bytes actually aligned. This will be the min of aSize and chain length.
       
   878 */
       
   879 	{
       
   880 	__ASSERT_ALWAYS(iNext!=NULL, CMBufManager::Panic(EMBuf_EmptyChain));
       
   881 	__ASSERT_ALWAYS(aSize>=0, CMBufManager::Panic(EMBuf_NegativeLength));
       
   882 
       
   883 	// update length to the largest sized mbuf possible
       
   884 	if (aSize == KMBufAll)	// trs; does the KMBufAll concept (ie. 'largest sized' mbuf) really make sense? code kept as is to avoid a functional break
       
   885 		{
       
   886 		aSize = ((RMBufPoolChain*)iNext->MBufPoolChain())->MBufPoolManager().LargestMBufSize();
       
   887 		}
       
   888 
       
   889 	// All data required is already in the first MBuf
       
   890 	if (aSize <= iNext->Length())
       
   891 		{
       
   892 		// Case 1 - allready aligned
       
   893 		// Case 2 - it needs to be aligned
       
   894 		if (!IS_ALIGNED(iNext->Offset()))
       
   895 			{
       
   896 			Mem::Copy(iNext->Buffer(), iNext->Ptr(), iNext->Length());
       
   897 			iNext->SetOffset(0);
       
   898 			}
       
   899 		return aSize; // already as required
       
   900 		}
       
   901 
       
   902 	// Get existing data at start
       
   903 	if (iNext->Offset()!=0)
       
   904 		{
       
   905 		Mem::Copy(iNext->Buffer(), iNext->Ptr(), iNext->Length());
       
   906 		iNext->SetOffset(0);
       
   907 		}
       
   908 
       
   909 	RMBuf* m = iNext->Next();
       
   910 	TInt len = iNext->Length();
       
   911 	while (len<aSize && m!=NULL)
       
   912 		{
       
   913 		TInt n = aSize-len;
       
   914 		if (n>m->Length())
       
   915 			n = m->Length();
       
   916 		Mem::Copy(iNext->EndPtr(), m->Ptr(), n);
       
   917 		iNext->AdjustEnd(n);
       
   918 		m->AdjustStart(n);
       
   919 		len += n;
       
   920 
       
   921 		// MBuf might now be empty so free it
       
   922 		if (m->Length()==0)
       
   923 			{
       
   924 			iNext->Link(m->Next());
       
   925 			m->Unlink();
       
   926 			m->Free();
       
   927 			m = iNext->Next();
       
   928 			}
       
   929 		}
       
   930 	return len;
       
   931 	}