kernel/eka/memmodel/emul/win32/mshbuf.cpp
changeset 0 a41df078684a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/eka/memmodel/emul/win32/mshbuf.cpp	Mon Oct 19 15:55:17 2009 +0100
@@ -0,0 +1,1087 @@
+// 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 the License "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:
+// e32/memmodel/emul/win32/mshbuf.cpp
+// Shareable Data Buffers
+
+#include "memmodel.h"
+#include <kernel/smap.h>
+
+_LIT(KLitDWin32ShPool,"DWin32ShPool");
+_LIT(KLitDWin32AlignedShPool,"DWin32AlignedShPool");
+_LIT(KLitDWin32NonAlignedShPool,"DWin32NonAlignedShPool");
+
+
+DWin32ShBuf::DWin32ShBuf(DShPool* aPool, TLinAddr aRelAddr) : DShBuf(aPool, aRelAddr)
+	{
+	__KTRACE_OPT(KMMU, Kern::Printf(">DWin32ShBuf::DWin32ShBuf()"));
+	}
+
+DWin32ShBuf::~DWin32ShBuf()
+	{
+	__KTRACE_OPT(KMMU, Kern::Printf(">DWin32ShBuf::~DWin32ShBuf()"));
+	}
+
+TUint8* DWin32ShBuf::Base(DProcess* aProcess)
+	{
+	__KTRACE_OPT(KMMU, Kern::Printf(">DWin32ShBuf::Base(0x%x)", aProcess));
+
+	TUint8* base = reinterpret_cast<DWin32ShPool*>(iPool)->Base(aProcess) + (TUint)iRelAddress;
+
+	return base;
+	}
+
+TUint8* DWin32ShBuf::Base()
+	{
+	__KTRACE_OPT(KMMU, Kern::Printf(">DWin32ShBuf::Base()"));
+
+	TUint8* base = reinterpret_cast<DWin32ShPool*>(iPool)->Base() + (TUint)iRelAddress;
+
+	return base;
+	}
+
+TInt DWin32ShBuf::Map(TUint /* aMapAttr */, DProcess* /* aProcess */, TLinAddr& aBase)
+	{
+	__KTRACE_OPT(KMMU, Kern::Printf(">DWin32ShBuf::Map()"));
+
+	TInt r = KErrNotSupported;
+
+	if (iPool->iPoolFlags & EShPoolPageAlignedBuffer)
+		{
+		if(iMapped)
+			{
+			r = KErrAlreadyExists;
+			}
+		else
+			{
+			aBase = reinterpret_cast<TUint>(reinterpret_cast<DWin32ShPool*>(iPool)->Base() + (TUint)iRelAddress);
+			iMapped = ETrue;
+			r = KErrNone;
+			}
+		}
+
+	return r;
+	}
+
+TInt DWin32ShBuf::UnMap(DProcess* /* aProcess */)
+	{
+	__KTRACE_OPT(KMMU, Kern::Printf(">DWin32ShBuf::UnMap()"));
+
+	TInt r = KErrNotSupported;
+
+	if (iPool->iPoolFlags & EShPoolPageAlignedBuffer)
+		{
+		if(iMapped)
+			{
+			iMapped = EFalse;
+			r = KErrNone;
+			}
+		else
+			{
+			r = KErrNotFound;
+			}
+		}
+
+	return r;
+	}
+
+TInt DWin32ShBuf::AddToProcess(DProcess* aProcess, TUint /* aAttr */)
+	{
+	__KTRACE_OPT(KMMU, Kern::Printf("Adding DWin32ShBuf %O to process %O", this, aProcess));
+	TUint flags;
+	TInt r = KErrNone;
+
+	if (aProcess != K::TheKernelProcess)
+	    r = iPool->OpenClient(aProcess, flags);
+
+	return r;
+	}
+
+TInt DWin32ShBuf::Close(TAny* aPtr)
+	{
+	__KTRACE_OPT(KMMU, Kern::Printf(">DWin32ShBuf::Close(0x%08x)", aPtr));
+
+	if (aPtr)
+		{
+		DProcess* pP = reinterpret_cast<DProcess*>(aPtr);
+
+		if (pP != K::TheKernelProcess)
+		    iPool->CloseClient(pP);
+		}
+
+	return DShBuf::Close(aPtr);
+	}
+
+DWin32ShPool::DWin32ShPool()
+  : DShPool()
+	{
+	__KTRACE_OPT(KMMU, Kern::Printf(">DWin32ShPool::DWin32ShPool"));
+	}
+
+
+DWin32ShPool::~DWin32ShPool()
+	{
+	__KTRACE_OPT(KMMU, Kern::Printf(">DWin32ShPool::~DWin32ShPool"));
+
+	if (iWin32MemoryBase)
+		{
+		TUint64 maxSize = static_cast<TUint64>(iMaxBuffers) * static_cast<TUint64>(iBufGap);
+
+		// We know that maxSize is less than KMaxTInt as we tested for this in DoCreate().
+		VirtualFree(LPVOID(iWin32MemoryBase), (SIZE_T)maxSize, MEM_DECOMMIT);
+		VirtualFree(LPVOID(iWin32MemoryBase), 0, MEM_RELEASE);
+		MM::Wait();
+		MM::FreeMemory += iWin32MemorySize;
+		MM::Signal();
+		}
+
+	delete iBufMap;
+	}
+
+void DWin32ShPool::DestroyClientResources(DProcess* aProcess)
+	{
+	__KTRACE_OPT(KMMU, Kern::Printf(">DWin32ShPool::DestroyClientResources"));
+
+	TInt r = DestroyHandles(aProcess);
+	__NK_ASSERT_DEBUG((r == KErrNone) || (r == KErrDied));
+	(void)r;		// Silence warnings
+	}
+
+TInt DWin32ShPool::DeleteInitialBuffers()
+	{
+	__KTRACE_OPT(KMMU, Kern::Printf(">DWin32ShPool::DeleteInitialBuffers"));
+
+	if (iInitialBuffersArray != NULL)
+		{
+		for (TUint i = 0; i < iInitialBuffers; i++)
+			{
+			iInitialBuffersArray[i].iObjLink.Deque(); // remove from free list
+			iInitialBuffersArray[i].Dec();
+			iInitialBuffersArray[i].~DWin32ShBuf();
+			}
+
+		Kern::Free(iInitialBuffersArray);
+		iInitialBuffersArray = NULL;
+		}
+
+	return KErrNone;
+	}
+
+TInt DWin32ShPool::DestroyHandles(DProcess* aProcess)
+	{
+	__KTRACE_OPT(KMMU, Kern::Printf(">DWin32ShPool::DestroyHandles(0x%08x)", aProcess));
+
+	TInt r = KErrNone;
+	Kern::MutexWait(*iProcessLock);
+	DShPoolClient* client = reinterpret_cast<DShPoolClient*>(iClientMap->Remove(reinterpret_cast<TUint>(aProcess)));
+
+	__NK_ASSERT_DEBUG(client);
+	__NK_ASSERT_DEBUG(client->iAccessCount == 0);
+
+	delete client;
+
+	if (aProcess != K::TheKernelProcess)
+		{
+		// Remove reserved handles
+		r = aProcess->iHandles.Reserve(-TInt(iTotalBuffers));
+		}
+
+	Kern::MutexSignal(*iProcessLock);
+
+	return r;
+	}
+
+
+TInt DWin32ShPool::Close(TAny* aPtr)
+	{
+	__KTRACE_OPT(KMMU, Kern::Printf(">DWin32ShPool::Close(0x%08x)", aPtr));
+
+	if (aPtr) // not NULL must be user side
+		{
+		DProcess* pP = reinterpret_cast<DProcess*>(aPtr);
+
+		CloseClient(pP);
+		}
+
+	return DShPool::Close(aPtr);
+	}
+
+
+TInt DWin32ShPool::CreateInitialBuffers()
+	{
+	__KTRACE_OPT(KMMU,Kern::Printf(">DWin32ShPool::CreateInitialBuffers"));
+
+	iInitialBuffersArray = reinterpret_cast<DWin32ShBuf*>(Kern::Alloc(iInitialBuffers * sizeof(DWin32ShBuf)));
+
+	if (iInitialBuffersArray == NULL)
+		return KErrNoMemory;
+
+	TLinAddr offset = 0;
+	for (TUint i = 0; i < iInitialBuffers; i++)
+		{
+		DWin32ShBuf *buf = new (&iInitialBuffersArray[i]) DWin32ShBuf(this, offset);
+		TInt r = buf->Construct();
+
+		if (r == KErrNone)
+			{
+			iFreeList.Add(&buf->iObjLink);
+			}
+		else
+			{
+			iInitialBuffers = i;
+			return KErrNoMemory;
+			}
+
+		offset += iBufGap;
+		}
+
+	iFreeBuffers = iInitialBuffers;
+	iTotalBuffers = iInitialBuffers;
+
+	iBufMap->Alloc(0, iInitialBuffers);
+
+	return KErrNone;
+	}
+
+
+TUint8* DWin32ShPool::Base()
+	{
+	return iWin32MemoryBase;
+	}
+
+
+TUint8* DWin32ShPool::Base(DProcess* /*aProcess*/)
+	{
+	return iWin32MemoryBase;
+	}
+
+
+TInt DWin32ShPool::AddToProcess(DProcess* aProcess, TUint aAttr)
+	{
+	__KTRACE_OPT(KEXEC, Kern::Printf("Adding DWin32ShPool %O to process %O", this, aProcess));
+
+	TInt r = KErrNone;
+
+	Kern::MutexWait(*iProcessLock);
+	LockPool();
+	DShPoolClient* client = reinterpret_cast<DShPoolClient*>(iClientMap->Find(reinterpret_cast<TUint>(aProcess)));
+	UnlockPool();
+
+	if (!client)
+		{
+		client = new DShPoolClient;
+
+		if (client)
+			{
+			client->iFlags = aAttr;
+			r = iClientMap->Add(reinterpret_cast<TUint>(aProcess), client);
+
+			if (r == KErrNone)
+				{
+				if (aProcess != K::TheKernelProcess)
+					{
+					r = aProcess->iHandles.Reserve(iTotalBuffers);
+
+					if (r != KErrNone)
+						{
+						iClientMap->Remove(reinterpret_cast<TUint>(aProcess));
+						}
+					}
+				}
+
+			if (r != KErrNone)
+				{
+				delete client;
+				}
+			}
+		else
+			{
+			r = KErrNoMemory;
+			}
+		}
+	else
+		{
+		LockPool();
+		client->iAccessCount++;
+		UnlockPool();
+		}
+
+	Kern::MutexSignal(*iProcessLock);
+
+	return r;
+	}
+
+
+TInt DWin32ShPool::DoCreate(TShPoolCreateInfo& aInfo)
+	{
+	TUint64 maxSize = static_cast<TUint64>(aInfo.iInfo.iMaxBufs) * static_cast<TUint64>(iBufGap);
+
+	if (maxSize > static_cast<TUint64>(KMaxTInt))
+		{
+		return KErrArgument;
+		}
+
+	__KTRACE_OPT(KMMU,Kern::Printf("DWin32ShPool::DoCreate (maxSize = 0x%08x, iBufGap = 0x%08x)",
+		static_cast<TInt>(maxSize), iBufGap));
+
+	iWin32MemoryBase = (TUint8*) VirtualAlloc(NULL, (SIZE_T)maxSize, MEM_RESERVE, PAGE_READWRITE);
+	if (iWin32MemoryBase == NULL)
+		{
+		return KErrNoMemory;
+		}
+
+	__KTRACE_OPT(KMMU,Kern::Printf("DWin32ShPool::DoCreate (iWin32MemoryBase = 0x%08x)", iWin32MemoryBase));
+
+	iBufMap = TBitMapAllocator::New(aInfo.iInfo.iMaxBufs, (TBool)ETrue);
+	if (iBufMap == NULL)
+		{
+		return KErrNoMemory;
+		}
+
+	return KErrNone;
+	}
+
+
+TBool DWin32ShPool::IsOpen(DProcess* /*aProcess*/)
+	{
+	// could do we some kind of check here?
+	return (TBool)ETrue;
+	}
+
+
+TInt DWin32ShPool::UpdateFreeList()
+	{
+	__KTRACE_OPT(KMMU, Kern::Printf(">DWin32ShPool::UpdateFreeList"));
+
+	SDblQue temp;
+	SDblQueLink* anchor = reinterpret_cast<SDblQueLink*>(&iFreeList);
+
+	LockPool();
+	while(!iAltFreeList.IsEmpty())
+		{
+		// sort a temporary list of 'n' object with the lowest index first
+		for (TInt n = 0; n < 8 && !iAltFreeList.IsEmpty(); ++n)
+			{
+			// bit of an assumption, lets assume that the lower indexes will be allocated and freed first
+			// and therefore will be nearer the front of the list
+			DShBuf* buf = _LOFF(iAltFreeList.GetFirst(), DShBuf, iObjLink);
+
+			SDblQueLink* anchor = reinterpret_cast<SDblQueLink*>(&temp);
+			SDblQueLink* pLink = temp.Last();
+
+			for (;;)
+				{
+				// traverse the list starting at the back
+				if ((pLink != anchor) && (_LOFF(pLink, DShBuf, iObjLink)->iRelAddress > buf->iRelAddress))
+					{
+					pLink = pLink->iPrev;
+					}
+				else
+					{
+					buf->iObjLink.InsertAfter(pLink);
+					break;
+					}
+				}
+			}
+
+		// now merge with the free list
+		while(!temp.IsEmpty())
+			{
+			if (iFreeList.IsEmpty())
+				{
+				iFreeList.MoveFrom(&temp);
+				break;
+				}
+
+			// working backwards with the highest index
+			DShBuf* buf = _LOFF(temp.Last(), DShBuf, iObjLink);
+			SDblQueLink* pLink = iFreeList.Last();
+
+			while (!NKern::FMFlash(&iLock))
+				{
+				if ((pLink != anchor) && (_LOFF(pLink, DShBuf, iObjLink)->iRelAddress > buf->iRelAddress))
+					{
+					pLink = pLink->iPrev;
+					}
+				else
+					{
+					buf->iObjLink.Deque();
+					buf->iObjLink.InsertAfter(pLink);
+					// next buffer
+					if (temp.IsEmpty())
+						break;
+					buf = _LOFF(temp.Last(), DShBuf, iObjLink);
+					}
+				}
+			}
+		NKern::FMFlash(&iLock);
+		}
+	UnlockPool();
+
+	__KTRACE_OPT(KMMU, Kern::Printf("<DWin32ShPool::UpdateFreeList"));
+	return KErrNone;
+	}
+
+
+void DWin32ShPool::Free(DShBuf* aBuf)
+	{
+	__KTRACE_OPT(KMMU, Kern::Printf(">DWin32ShPool::Free (aBuf = 0x%08x, aBuf->Base() 0x%08x)", aBuf, aBuf->Base()));
+
+	TLinAddr newAddr = (TLinAddr)aBuf->Base();
+#ifdef _DEBUG
+	memset((TAny*)newAddr,0xde,aBuf->Size());
+#else
+	memclr((TAny*)newAddr,aBuf->Size());
+#endif
+
+	LockPool();
+#ifdef _DEBUG
+	// Remove from allocated list
+	aBuf->iObjLink.Deque();
+#endif
+	// we want to put the initial buffers at the head of the free list
+	// and the grown buffers at the tail as this makes shrinking more efficient
+	if (aBuf >= iInitialBuffersArray && aBuf < (iInitialBuffersArray + iInitialBuffers))
+		{
+		iFreeList.AddHead(&aBuf->iObjLink);
+		}
+	else
+		{
+		iAltFreeList.Add(&aBuf->iObjLink);
+		}
+
+	++iFreeBuffers;
+#ifdef _DEBUG
+	--iAllocatedBuffers;
+#endif
+	iPoolFlags &= ~EShPoolSuppressShrink;		// Allow shrinking again, if it was blocked
+	UnlockPool();
+
+	// queue ManagementDfc which completes notifications as appropriate
+	if (HaveWorkToDo())
+		KickManagementDfc();
+
+	Close(NULL); // decrement pool reference count
+	}
+
+// Kernel side API
+TInt DWin32ShPool::Alloc(DShBuf*& aShBuf)
+	{
+	__KTRACE_OPT(KMMU, Kern::Printf(">DWin32ShPool::Alloc (DShBuf)"));
+
+	TInt r = KErrNoMemory;
+	aShBuf = NULL;
+
+	LockPool();
+
+	if (!iFreeList.IsEmpty())
+		{
+		aShBuf = _LOFF(iFreeList.GetFirst(), DShBuf, iObjLink);
+#ifdef _DEBUG
+		iAllocated.Add(&aShBuf->iObjLink);
+		iAllocatedBuffers++;
+#endif
+		--iFreeBuffers;
+		Open(); // increment pool reference count
+		r = KErrNone;
+		}
+	else
+		{
+		// try alternative free list
+		if (!iAltFreeList.IsEmpty())
+			{
+			aShBuf = _LOFF(iAltFreeList.GetFirst(), DShBuf, iObjLink);
+#ifdef _DEBUG
+			iAllocated.Add(&aShBuf->iObjLink);
+			iAllocatedBuffers++;
+#endif
+			--iFreeBuffers;
+			Open(); // increment pool reference count
+			r = KErrNone;
+			}
+		}
+
+	UnlockPool();
+
+	if (HaveWorkToDo())
+		KickManagementDfc();
+
+	__KTRACE_OPT(KMMU, Kern::Printf("<DWin32ShPool::Alloc return buf = 0x%08x", aShBuf));
+	return r;
+	}
+
+
+DWin32AlignedShPool::DWin32AlignedShPool()
+  : DWin32ShPool()
+	{
+	__KTRACE_OPT(KMMU, Kern::Printf(">DWin32AlignedShPool::DWin32AlignedShPool"));
+	}
+
+
+DWin32AlignedShPool::~DWin32AlignedShPool()
+	{
+	__KTRACE_OPT(KMMU, Kern::Printf(">DWin32AlignedShPool::~DWin32AlignedShPool"));
+	}
+
+
+TInt DWin32AlignedShPool::DoCreate(TShPoolCreateInfo& aInfo)
+	{
+	TInt r;
+	// Create Chunk
+	r = DWin32ShPool::DoCreate(aInfo);
+	if (r != KErrNone)
+		{
+		return r;
+		}
+
+	if (iPoolFlags & EShPoolGuardPages)
+		{
+		TUint numOfBytes = iBufGap - MM::RamPageSize;
+		iCommittedPages = MM::RoundToPageSize(iInitialBuffers * numOfBytes) >> MM::RamPageShift;
+
+		for (TUint i = 0; i < iInitialBuffers; ++i)
+			{
+			TUint offset = iBufGap * i;
+
+			MM::Wait();
+			if (MM::Commit(reinterpret_cast<TLinAddr>(iWin32MemoryBase+offset), numOfBytes, 0xFF, EFalse) != KErrNone)
+				{
+				MM::Signal();
+				return KErrNoMemory;
+				}
+			iWin32MemorySize += numOfBytes;
+
+			MM::Signal();
+			}
+
+		iMaxPages = MM::RoundToPageSize(aInfo.iInfo.iMaxBufs * numOfBytes) >> MM::RamPageShift;
+		}
+	else
+		{
+		// Make sure we give the caller the number of buffers they were expecting
+		iCommittedPages = MM::RoundToPageSize(iInitialBuffers * iBufGap) >> MM::RamPageShift;
+		MM::Wait();
+		if (MM::Commit(reinterpret_cast<TLinAddr>(iWin32MemoryBase), iCommittedPages << MM::RamPageShift, 0xFF, EFalse) != KErrNone)
+			{
+			MM::Signal();
+			return KErrNoMemory;
+			}
+		iWin32MemorySize = iCommittedPages << MM::RamPageShift;
+
+		MM::Signal();
+
+		iMaxPages = MM::RoundToPageSize(aInfo.iInfo.iMaxBufs * iBufGap) >> MM::RamPageShift;
+		}
+
+	return r;
+	}
+
+
+TInt DWin32AlignedShPool::SetBufferWindow(DProcess* /*aProcess*/, TInt /*aWindowSize*/ )
+	{
+	return KErrNone;
+	}
+
+
+TInt DWin32AlignedShPool::GrowPool()
+	{
+	__KTRACE_OPT(KMMU, Kern::Printf(">DWin32AlignedShPool::GrowPool()"));
+
+	Kern::MutexWait(*iProcessLock);
+
+	// How many bytes to commit for each new buffer (must be whole number of pages)
+	TUint bytes = (iPoolFlags & EShPoolGuardPages) ? iBufGap - MM::RamPageSize : iBufGap;
+
+	__ASSERT_DEBUG(!(bytes % MM::RamPageSize), Kern::PanicCurrentThread(KLitDWin32AlignedShPool, __LINE__));
+
+	TInt pages = bytes >> MM::RamPageShift;
+
+	TUint32 headroom = iMaxBuffers - iTotalBuffers;
+
+	// How many buffers to grow by?
+	TUint32 grow = mult_fx248(iTotalBuffers, iGrowByRatio);
+	if (grow == 0)			// Handle round-to-zero
+		grow = 1;
+	if (grow > headroom)
+		grow = headroom;
+
+	TInt r = KErrNone;
+	SDblQue temp;
+
+	TUint i;
+	for (i = 0; i < grow; ++i)
+		{
+		TInt offset = iBufMap->Alloc();
+
+		if (offset < 0)
+			{
+			r = KErrNoMemory;
+			break;
+			}
+
+		offset *= iBufGap;
+
+		MM::Wait();
+		if (MM::Commit(reinterpret_cast<TLinAddr>(iWin32MemoryBase+offset), bytes, 0xFF, EFalse) != KErrNone)
+			{
+			r = KErrNoMemory;
+			}
+		iWin32MemorySize += bytes;
+		MM::Signal();
+
+		if (r != KErrNone)
+			{
+			iBufMap->Free(offset / iBufGap);
+			break;
+			}
+
+		DWin32ShBuf *buf = new DWin32ShBuf(this, offset);
+
+		if (buf == NULL)
+			{
+			MM::Wait();
+			MM::Decommit(reinterpret_cast<TLinAddr>(iWin32MemoryBase+offset), bytes);
+			iWin32MemorySize -= bytes;
+			MM::Signal();
+			iBufMap->Free(offset / iBufGap);
+			r = KErrNoMemory;
+			break;
+			}
+
+		TInt r = buf->Construct();
+
+		if (r != KErrNone)
+			{
+			MM::Wait();
+			MM::Decommit(reinterpret_cast<TLinAddr>(iWin32MemoryBase+offset), bytes);
+			iWin32MemorySize -= bytes;
+			MM::Signal();
+			iBufMap->Free(offset / iBufGap);
+			buf->DObject::Close(NULL);
+			break;
+			}
+
+		iCommittedPages += pages;
+
+		temp.Add(&buf->iObjLink);
+		}
+
+	r = UpdateReservedHandles(i);
+
+	if (r == KErrNone)
+		{
+		LockPool();
+		iFreeList.MoveFrom(&temp);
+		iFreeBuffers += i;
+		iTotalBuffers += i;
+		UnlockPool();
+		}
+	else
+		{
+		// else delete buffers
+		SDblQueLink *pLink;
+		while ((pLink = temp.GetFirst()) != NULL)
+			{
+			DShBuf* buf = _LOFF(pLink, DShBuf, iObjLink);
+			TLinAddr offset = buf->iRelAddress;
+			iBufMap->Free(offset / iBufGap);
+			MM::Wait();
+			MM::Decommit(reinterpret_cast<TLinAddr>(iWin32MemoryBase+offset), bytes);
+			iWin32MemorySize -= bytes;
+			MM::Signal();
+			iCommittedPages -= pages;
+			buf->DObject::Close(NULL);
+			}
+		}
+
+	CalculateGrowShrinkTriggers();
+
+	Kern::MutexSignal(*iProcessLock);
+
+	__KTRACE_OPT(KMMU, Kern::Printf("<DWin32AlignedShPool::GrowPool()"));
+	return r;
+	} // DWin32AlignedShPool::GrowPool
+
+
+TInt DWin32AlignedShPool::ShrinkPool()
+	{
+	__KTRACE_OPT(KMMU, Kern::Printf(">DWin32AlignedShPool::ShrinkPool()"));
+
+	Kern::MutexWait(*iProcessLock);
+
+	// How many bytes to commit for each new buffer (must be whole number of pages)
+	TUint bytes = (iPoolFlags & EShPoolGuardPages) ? iBufGap - MM::RamPageSize : iBufGap;
+
+	__ASSERT_DEBUG(!(bytes % MM::RamPageSize), Kern::PanicCurrentThread(KLitDWin32AlignedShPool, __LINE__));
+
+	TInt pages = bytes >> MM::RamPageShift;
+
+	// Grab pool stats
+	TUint32 grownBy = iTotalBuffers - iInitialBuffers;
+
+	// How many buffers to shrink by?
+	TUint32 shrink = mult_fx248(iTotalBuffers, iShrinkByRatio);
+	if (shrink == 0)		// Handle round-to-zero
+		shrink = 1;
+	if (shrink > grownBy)
+		shrink = grownBy;
+	if (shrink > iFreeBuffers)
+		shrink = iFreeBuffers;
+
+	// work backwards
+	TUint i;
+	for (i = 0; i < shrink; ++i)
+		{
+		LockPool();
+		if (iFreeList.IsEmpty())
+			{
+			UnlockPool();
+			break;
+			}
+		// work from the back of the queue
+		SDblQueLink *pLink = iFreeList.Last();
+
+		DShBuf* pBuf = _LOFF(pLink, DShBuf, iObjLink);
+
+		if (pBuf >= iInitialBuffersArray && pBuf < (iInitialBuffersArray + iInitialBuffers))
+			{
+			UnlockPool();
+			break;
+			}
+
+		--iFreeBuffers;
+		--iTotalBuffers;
+		pLink->Deque();
+		iCommittedPages -= pages;
+		UnlockPool();
+
+		TLinAddr offset = pBuf->iRelAddress;
+
+		iBufMap->Free(offset / iBufGap);
+
+		MM::Wait();
+		MM::Decommit(reinterpret_cast<TLinAddr>(iWin32MemoryBase+offset), iBufSize);
+		iWin32MemorySize -= iBufSize;
+		MM::Signal();
+		pBuf->DObject::Close(NULL);
+		}
+
+	TInt r = UpdateReservedHandles(-(TInt)i);
+
+	// If we couldn't shrink the pool by this many buffers, wait until we Free() another
+	// buffer before trying to shrink again.
+	if (i < shrink)
+		iPoolFlags |= EShPoolSuppressShrink;
+
+	CalculateGrowShrinkTriggers();
+
+	Kern::MutexSignal(*iProcessLock);
+
+	__KTRACE_OPT(KMMU, Kern::Printf("<DWin32AlignedShPool::ShrinkPool()"));
+	return r;
+	} // DWin32AlignedShPool::ShrinkPool
+
+
+DWin32NonAlignedShPool::DWin32NonAlignedShPool()
+  : DWin32ShPool()
+	{
+	__KTRACE_OPT(KMMU, Kern::Printf(">DWin32NonAlignedShPool::DWin32NonAlignedShPool"));
+	}
+
+
+DWin32NonAlignedShPool::~DWin32NonAlignedShPool()
+	{
+	__KTRACE_OPT(KMMU, Kern::Printf(">DWin32NonAlignedShPool::~DWin32NonAlignedShPool"));
+
+	delete iPagesMap;
+	}
+
+
+TInt DWin32NonAlignedShPool::DoCreate(TShPoolCreateInfo& aInfo)
+	{
+	// Create Chunk
+	TInt r;
+
+	r = DWin32ShPool::DoCreate(aInfo);
+
+	if (r != KErrNone)
+		{
+		return r;
+		}
+
+	if (iPoolFlags & EShPoolPhysicalMemoryPool)
+		{
+		return KErrNotSupported;
+		}
+	else
+		{
+		// Make sure we give the caller the number of buffers they were expecting
+		iCommittedPages = MM::RoundToPageSize(iInitialBuffers * iBufGap) >> MM::RamPageShift;
+
+		MM::Wait();
+		if (MM::Commit(reinterpret_cast<TLinAddr>(iWin32MemoryBase), iCommittedPages << MM::RamPageShift, 0xFF, EFalse) != KErrNone)
+			{
+			MM::Signal();
+			return KErrNoMemory;
+			}
+		iWin32MemorySize = iCommittedPages << MM::RamPageShift;
+
+		MM::Signal();
+		iMaxPages = MM::RoundToPageSize(aInfo.iInfo.iMaxBufs * iBufGap) >> MM::RamPageShift;
+		}
+
+	iPagesMap = TBitMapAllocator::New(iMaxPages, (TBool)ETrue);
+
+	if(!iPagesMap)
+		{
+		return KErrNoMemory;
+		}
+
+	iPagesMap->Alloc(0, iCommittedPages);
+	return r;
+	}
+
+
+void DWin32NonAlignedShPool::FreeBufferPages(TUint aOffset)
+	{
+	TLinAddr firstByte = aOffset;	// offset of first byte in buffer
+	TLinAddr lastByte = firstByte+iBufGap-1;	// offset of last byte in buffer
+	TUint firstPage = firstByte>>MM::RamPageShift;	// index of first page containing part of the buffer
+	TUint lastPage = lastByte>>MM::RamPageShift;		// index of last page containing part of the buffer
+
+	TUint firstBuffer = (firstByte&~(MM::RamPageSize - 1))/iBufGap; // index of first buffer which lies in firstPage
+	TUint lastBuffer = (lastByte|(MM::RamPageSize - 1))/iBufGap;    // index of last buffer which lies in lastPage
+	TUint thisBuffer = firstByte/iBufGap;				// index of the buffer to be freed
+
+	// Ensure lastBuffer is within bounds (there may be room in the last
+	// page for more buffers than we have allocated).
+	if (lastBuffer >= iMaxBuffers)
+		lastBuffer = iMaxBuffers-1;
+
+	if(firstBuffer!=thisBuffer && iBufMap->NotFree(firstBuffer,thisBuffer-firstBuffer))
+		{
+		// first page has other allocated buffers in it,
+		// so we can't free it and must move on to next one...
+		if (firstPage >= lastPage)
+			return;
+		++firstPage;
+		}
+
+	if(lastBuffer!=thisBuffer && iBufMap->NotFree(thisBuffer+1,lastBuffer-thisBuffer))
+		{
+		// last page has other allocated buffers in it,
+		// so we can't free it and must step back to previous one...
+		if (lastPage <= firstPage)
+			return;
+		--lastPage;
+		}
+
+	if(firstPage<=lastPage)
+		{
+		// we can free pages firstPage trough to lastPage...
+		TUint numPages = lastPage-firstPage+1;
+		iPagesMap->SelectiveFree(firstPage,numPages);
+		MM::Wait();
+		MM::Decommit(reinterpret_cast<TLinAddr>(iWin32MemoryBase+(firstPage << MM::RamPageShift)), (numPages << MM::RamPageShift));
+		iWin32MemorySize -= (numPages << MM::RamPageShift);
+		MM::Signal();
+		iCommittedPages -= numPages;
+		}
+	}
+
+
+TInt DWin32NonAlignedShPool::GrowPool()
+	{
+	__KTRACE_OPT(KMMU, Kern::Printf(">DWin32NonAlignedShPool::GrowPool()"));
+
+	Kern::MutexWait(*iProcessLock);
+
+	TUint32 headroom = iMaxBuffers - iTotalBuffers;
+
+	// How many buffers to grow by?
+	TUint32 grow = mult_fx248(iTotalBuffers, iGrowByRatio);
+	if (grow == 0)			// Handle round-to-zero
+		grow = 1;
+	if (grow > headroom)
+		grow = headroom;
+
+	TInt r = KErrNone;
+	SDblQue temp;
+
+	TUint i;
+	for (i = 0; i < grow; ++i)
+		{
+		TInt offset = iBufMap->Alloc();
+
+		if (offset < 0)
+			{
+			r = KErrNoMemory;
+			break;
+			}
+
+		offset *= iBufGap;
+
+		TInt lastPage = (offset + iBufSize - 1) >> MM::RamPageShift;
+
+		// Allocate one page at a time.
+		for (TInt page = offset >> MM::RamPageShift; page <= lastPage; ++page)
+			{
+			// Is the page allocated?
+			if (iPagesMap->NotAllocated(page, 1))
+				{
+				MM::Wait();
+				if (MM::Commit(reinterpret_cast<TLinAddr>(iWin32MemoryBase+(page << MM::RamPageShift)), MM::RamPageSize, 0xFF, EFalse) != KErrNone)
+					{
+					MM::Signal();
+					r = KErrNoMemory;
+					break;
+					}
+				iWin32MemorySize += MM::RamPageSize;
+
+				MM::Signal();
+				++iCommittedPages;
+				iPagesMap->Alloc(page, 1);
+				}
+			}
+
+		if (r != KErrNone)
+			{
+			iBufMap->Free(offset / iBufGap);
+			FreeBufferPages(offset);
+			break;
+			}
+
+		DWin32ShBuf *buf = new DWin32ShBuf(this, offset);
+
+		if (buf == NULL)
+			{
+			iBufMap->Free(offset / iBufGap);
+			FreeBufferPages(offset);
+			r = KErrNoMemory;
+			break;
+			}
+
+		r = buf->Construct();
+
+		if (r != KErrNone)
+			{
+			iBufMap->Free(offset / iBufGap);
+			FreeBufferPages(offset);
+			buf->DObject::Close(NULL);
+			break;
+			}
+
+		temp.Add(&buf->iObjLink);
+		}
+
+	r = UpdateReservedHandles(i);
+
+	if (r == KErrNone)
+		{
+		LockPool();
+		iFreeList.MoveFrom(&temp);
+		iFreeBuffers += i;
+		iTotalBuffers += i;
+		UnlockPool();
+		}
+	else
+		{
+		// couldn't reserve handles so have no choice but to
+		// delete the buffers
+		__KTRACE_OPT(KMMU, Kern::Printf("GrowPool failed with %d, deleting buffers", r));
+		SDblQueLink *pLink;
+		while ((pLink = temp.GetFirst()) != NULL)
+			{
+			DShBuf* buf = _LOFF(pLink, DShBuf, iObjLink);
+			TLinAddr offset = buf->iRelAddress;
+			iBufMap->Free(offset / iBufGap);
+			FreeBufferPages(offset);
+			buf->DObject::Close(NULL);
+			}
+		__KTRACE_OPT(KMMU, Kern::Printf("Buffers deleted"));
+		}
+
+	CalculateGrowShrinkTriggers();
+
+	Kern::MutexSignal(*iProcessLock);
+
+	__KTRACE_OPT(KMMU, Kern::Printf("<DWin32NonAlignedShPool::GrowPool()"));
+	return r;
+	} // DWin32NonAlignedShPool::GrowPool
+
+
+TInt DWin32NonAlignedShPool::ShrinkPool()
+	{
+	__KTRACE_OPT(KMMU, Kern::Printf(">DWin32NonAlignedShPool::ShrinkPool()"));
+
+	Kern::MutexWait(*iProcessLock);
+
+	// Grab pool stats
+	TUint32 grownBy = iTotalBuffers - iInitialBuffers;
+
+	// How many buffers to shrink by?
+	TUint32 shrink = mult_fx248(iTotalBuffers, iShrinkByRatio);
+	if (shrink == 0)		// Handle round-to-zero
+		shrink = 1;
+	if (shrink > grownBy)
+		shrink = grownBy;
+	if (shrink > iFreeBuffers)
+		shrink = iFreeBuffers;
+
+	TUint i;
+	for (i = 0; i < shrink; ++i)
+		{
+		LockPool();
+		if (iFreeList.IsEmpty())
+			{
+			UnlockPool();
+			break;
+			}
+		// work from the back of the queue
+		SDblQueLink *pLink = iFreeList.Last();
+
+		DShBuf* pBuf = _LOFF(pLink, DShBuf, iObjLink);
+
+		if (pBuf >= iInitialBuffersArray && pBuf < (iInitialBuffersArray + iInitialBuffers))
+			{
+			UnlockPool();
+			break;
+			}
+
+		--iFreeBuffers;
+		--iTotalBuffers;
+		pLink->Deque();
+		UnlockPool();
+
+		TLinAddr offset = pBuf->iRelAddress;
+
+		iBufMap->Free(offset / iBufGap);
+		FreeBufferPages(offset);
+		pBuf->DObject::Close(NULL);
+		}
+
+	UpdateReservedHandles(-(TInt)i);
+
+	// If we couldn't shrink the pool by this many buffers, wait until we Free() another
+	// buffer before trying to shrink again.
+	if (i < shrink)
+		iPoolFlags |= EShPoolSuppressShrink;
+
+	CalculateGrowShrinkTriggers();
+
+	Kern::MutexSignal(*iProcessLock);
+
+	__KTRACE_OPT(KMMU, Kern::Printf("<DWin32NonAlignedShPool::ShrinkPool()"));
+
+	return KErrNone;
+	} // DWin32NonAlignedShPool::ShrinkPool