commsfwutils/commsbufs/mbufmgr/src/mb_chn.cpp
changeset 40 34fc115b8742
parent 0 dfb7c4ff071f
child 48 07656293a99c
--- a/commsfwutils/commsbufs/mbufmgr/src/mb_chn.cpp	Thu May 27 14:07:49 2010 +0300
+++ b/commsfwutils/commsbufs/mbufmgr/src/mb_chn.cpp	Fri Jun 11 14:52:21 2010 +0300
@@ -272,7 +272,23 @@
 		len = Min(aLen, len);	
 		}		
 
-	TInt err = newChain.Alloc(len + aHdrReserve, *this);
+// Suppress the "follow-the-leader" behaviour of preserving the buffer sizing of the
+// existing chain. The goal of preserving buffer characteristics remains desirable but
+// not at the cost of having TCP use unnecessarily small buffers - this area needs 
+// rework once the Comms stack really adopts buffer pools and zero copy  	
+//	TInt err = newChain.Alloc(len + aHdrReserve, *this);
+	TInt err;
+    if(First())
+        {
+        newChain.iNext = First()->Pool()->Pond().Alloc(len + aHdrReserve, 0, KMaxTInt);
+        err = iNext ? KErrNone : KErrNoMBufs;      
+        }
+    else
+        {
+        RMBufAllocator allocator;
+        err = newChain.Alloc(aLen + aHdrReserve, allocator);  
+        }
+	
 	if(err != KErrNone)
 		{
 		return err;
@@ -532,10 +548,10 @@
 @param newChain The result chain
 */
 	{
-	User::LeaveIfError(RCommsBufChain::Split(anOffset, newChain));
+	User::LeaveIfError(Split(anOffset, newChain));
 	}
 
-EXPORT_C TInt RMBufChain::Split(TInt anOffset, RMBufChain& newChain)
+EXPORT_C TInt RMBufChain::Split(TInt aOffset, RMBufChain& aNewChain)
 /** 	  	 
 Split a chain into two new chains Original chain gets the 1st half 	  	 
 newChain gets the other half. 	  	 
@@ -544,8 +560,63 @@
 @param newChain The result chain 	  	 
 */
 	{
-	return RCommsBufChain::Split(anOffset, newChain);		
-	}
+    // RCommsBuf::Split() will not allocate a smaller buffer size than the current, as part of its approach of (trying to)
+    // support zero-copy transfer by respecting the buffer pool in use. This work is incomplete (needs support throughout
+    // the stack and probably a cleverer idea of what constitutes an acceptable buffer than simply size), so in the meantime
+    // having MBufMgr reflect this behaviour by refusing to Split() a big buf into smaller bufs is unnecessarily purist.
+    // Hence the functionality is implemented directly here
+    
+    __ASSERT_ALWAYS(iNext!=NULL, CommsBuf::Panic(EMBuf_EmptyChain));
+    __ASSERT_ALWAYS(aOffset>=0, CommsBuf::Panic(EMBuf_NegativeOffset));
+    
+    // For testing post-conditions
+#ifdef _DEBUG
+    TInt origLen = Length();
+#endif
+    TInt splitBufOffset;
+    TInt splitBufRemainder;
+    RMBuf* splitBuf;
+    RMBuf* splitBufPrev;
+    
+    if(!Goto(aOffset, splitBuf, splitBufOffset, splitBufRemainder, splitBufPrev))
+        {
+        aNewChain.Init();
+        return KErrNone;
+        }
+    
+    if(splitBufOffset != splitBuf->Offset()) // Not on an mbuf boundary
+        {
+        // Copy tail of splitBuf out to a new chain (hopefully a single buf, but needn't be)
+        TInt splitDataOffset = splitBufOffset - splitBuf->Offset();
+        TInt err = RMBufChain(splitBuf).Copy(aNewChain, splitDataOffset, splitBufRemainder);
+        if(err != KErrNone)
+            {
+            return err;
+            }
+        splitBuf->AdjustDataEnd(-splitBufRemainder);
+        RMBufChain splitTail(splitBuf->Next());
+        aNewChain.Append(splitTail);
+        splitBuf->SetNext(NULL);
+        }
+    else
+        {
+        // Split cleaves chain between bufs
+        aNewChain = splitBuf;
+        if(splitBufPrev)
+            {
+            splitBufPrev->Unlink();
+            }
+        }
+    
+    // Check post-conditions
+#ifdef _DEBUG
+    TInt frag1Len = Length(); 
+    TInt frag2Len = aNewChain.Length();
+    ASSERT(origLen == frag1Len + frag2Len);
+    ASSERT(frag1Len == aOffset);
+#endif
+    return KErrNone;
+	}           
 
 // overloading for TLS
 EXPORT_C TInt RMBufChain::Split(TInt anOffset, RMBufChain& newChain, RMBufAllocator& /* aRMBufAllocator */)