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