Fix for bug 2283 (RVCT 4.0 support is missing from PDK 3.0.h)
Have multiple extension sections in the bld.inf, one for each version
of the compiler. The RVCT version building the tools will build the
runtime libraries for its version, but make sure we extract all the other
versions from zip archives. Also add the archive for RVCT4.
// 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/epoc/flexible/mshbuf.cpp
// Shareable Data Buffers
#include <memmodel.h>
#include "mmu/mm.h"
#include "mmboot.h"
#include <kernel/smap.h>
_LIT(KLitDMemModelAlignedShPool,"DMMAlignedShPool"); // Must be no more than 16 characters!
struct TWait
{
void Link(TWait*& aList)
{
iSem.SetOwner(NULL);
iNext = aList;
aList = this;
};
void Wait()
{
NKern::FSWait(&iSem);
}
NFastSemaphore iSem;
TWait* iNext;
static void SignalAll(TWait* aList)
{
while (aList)
{
TWait* next = aList->iNext;
NKern::FSSignal(&aList->iSem);
aList = next;
}
}
};
class DShBufMapping : public DBase
{
public:
SDblQueLink iObjLink;
DMemoryMapping* iMapping;
TInt iOsAsid;
TWait* iTransitions; // Mapping and Unmapping operations
TBool iTransitioning;
};
DMemModelShPool::DMemModelShPool() : DShPool()
{
__KTRACE_OPT(KMMU, Kern::Printf(">DMemModelShPool::DMemModelShPool"));
}
DMemModelShPool::~DMemModelShPool()
{
__KTRACE_OPT(KMMU, Kern::Printf(">DMemModelShPool::~DMemModelShPool"));
}
void DMemModelShPool::DestroyClientResources(DProcess* aProcess)
{
__KTRACE_OPT(KMMU, Kern::Printf(">DMemModelShPool::DestroyClientResources"));
TInt r = DestroyAllMappingsAndReservedHandles(aProcess);
__NK_ASSERT_DEBUG((r == KErrNone) || (r == KErrDied));
(void)r; // Silence warnings
}
DMemModelAlignedShBuf::DMemModelAlignedShBuf(DShPool* aPool) : DShBuf(aPool)
{
__KTRACE_OPT(KMMU, Kern::Printf(">DMemModelAlignedShBuf::DMemModelAlignedShBuf()"));
}
TInt DMemModelAlignedShBuf::Construct()
{
__KTRACE_OPT(KMMU, Kern::Printf(">DMemModelAlignedShBuf::Construct()"));
TInt r = KErrNone;
r = DShBuf::Construct();
if (r == KErrNone)
r = Create();
return r;
}
TInt DMemModelAlignedShBuf::Close(TAny* aPtr)
{
__KTRACE_OPT(KMMU, Kern::Printf(">DMemModelAlignedShBuf::Close(0x%08x)", aPtr));
if (aPtr)
{
DProcess* pP = reinterpret_cast<DProcess*>(aPtr);
UnMap(pP);
iPool->CloseClient(pP);
}
return DShBuf::Close(aPtr);
}
TInt DMemModelAlignedShBuf::AddToProcess(DProcess* aProcess, TUint aAttr)
{
__KTRACE_OPT(KMMU,Kern::Printf("Adding DMemModelShBuf %O to process %O",this,aProcess));
TInt r;
TLinAddr base;
TUint flags;
r = iPool->OpenClient(aProcess, flags);
if (r == KErrNone)
{
if ((flags & EShPoolAutoMapBuf) && ((aAttr & EShPoolNoMapBuf) == 0))
{
// note we use the client's pool flags and not the buffer attributes
r = Map(flags, aProcess, base);
if (aProcess == K::TheKernelProcess)
iRelAddress = static_cast<TLinAddr>(base);
}
}
return r;
}
TInt DMemModelAlignedShBuf::Create()
{
__KTRACE_OPT(KMMU, Kern::Printf(">DMemModelAlignedShBuf::Create()"));
TInt r = KErrNone;
// calculate memory type...
TMemoryObjectType memoryType = EMemoryObjectUnpaged;
TMemoryAttributes attr = EMemoryAttributeStandard;
// calculate memory flags...
TMemoryCreateFlags flags = static_cast<TMemoryCreateFlags>((EMemoryCreateDefault|EMemoryCreateUseCustomWipeByte|(0xAA<<EMemoryCreateWipeByteShift)));
// note that any guard pages will be included in iBufGap, however the amount of memory committed
// will be iBufSize rounded up to a page
r = MM::MemoryNew(iMemoryObject, memoryType, MM::RoundToPageCount(iPool->iBufGap), flags, attr);
if(r!=KErrNone)
return r;
if (iPool->iPoolFlags & EShPoolContiguous)
{
TPhysAddr paddr;
r = MM::MemoryAllocContiguous(iMemoryObject, 0, MM::RoundToPageCount(iPool->iBufSize), 0, paddr);
}
else
{
r = MM::MemoryAlloc(iMemoryObject, 0, MM::RoundToPageCount(iPool->iBufSize));
}
return r;
}
DMemModelAlignedShBuf::~DMemModelAlignedShBuf()
{
__KTRACE_OPT(KMMU, Kern::Printf(">DMemModelAlignedShBuf::~DMemModelAlignedShBuf()"));
__NK_ASSERT_DEBUG(iMappings.IsEmpty());
MM::MemoryDestroy(iMemoryObject);
}
TInt DMemModelAlignedShBuf::Map(TUint aMapAttr, DProcess* aProcess, TLinAddr& aBase)
{
__KTRACE_OPT(KMMU, Kern::Printf(">DMemModelAlignedShBuf::Map()"));
TInt r = KErrNone;
DShBufMapping* m = NULL;
DMemoryMapping* mapping = NULL;
DMemModelProcess* pP = reinterpret_cast<DMemModelProcess*>(aProcess);
TBool write = (TBool)EFalse;
// User = ETrue, ReadOnlyWrite = ETrue, Execute = EFalse
if (aMapAttr & EShPoolWriteable)
write = (TBool)ETrue;
TMappingPermissions perm = MM::MappingPermissions(pP!=K::TheKernelProcess, write, (TBool)EFalse);
TWait wait;
for(;;)
{
iPool->LockPool();
r = FindMapping(m, pP);
if (r != KErrNone)
break;
if (m->iTransitioning)
{
wait.Link(m->iTransitions);
iPool->UnlockPool();
wait.Wait();
}
else
{
iPool->UnlockPool();
return KErrAlreadyExists;
}
}
DMemModelAlignedShPoolClient* client = reinterpret_cast<DMemModelAlignedShPoolClient*>(iPool->iClientMap->Find(reinterpret_cast<TUint>(aProcess)));
__NK_ASSERT_DEBUG(client);
DMemModelAlignedShPool* pool = reinterpret_cast<DMemModelAlignedShPool*>(iPool);
__NK_ASSERT_DEBUG(m == NULL);
r = pool->GetFreeMapping(m, client);
if (r == KErrNone)
{
iMappings.AddHead(&m->iObjLink);
m->iTransitioning = ETrue;
mapping = m->iMapping;
iPool->UnlockPool(); // have to release fast lock for MappingMap
r = MM::MappingMap(mapping, perm, iMemoryObject, 0, MM::RoundToPageCount(pool->iBufSize));
iPool->LockPool();
TWait* list = m->iTransitions;
m->iTransitions = NULL;
if (r != KErrNone)
pool->ReleaseMapping(m, client);
else
aBase = MM::MappingBase(mapping);
m->iTransitioning = EFalse;
iPool->UnlockPool();
TWait::SignalAll(list);
}
else
iPool->UnlockPool();
return r;
}
TInt DMemModelAlignedShBuf::FindMapping(DShBufMapping*& aMapping, DMemModelProcess* aProcess)
{
// Must be in critical section so we don't leak os asid references.
__ASSERT_CRITICAL;
__NK_ASSERT_DEBUG(iPool->iLock.HeldByCurrentThread());
TInt r = KErrNotFound;
aMapping = NULL;
// Open a reference on aProcess's os asid so that it can't be freed and
// reused while searching.
TInt osAsid = aProcess->TryOpenOsAsid();
if (osAsid < 0)
{// aProcess has died and freed its os asid.
return KErrDied;
}
SDblQueLink* pLink = iMappings.First();
SDblQueLink* end = reinterpret_cast<SDblQueLink*>(&iMappings);
DShBufMapping* m = NULL;
while (pLink != end)
{
m = _LOFF(pLink, DShBufMapping, iObjLink);
if (m->iOsAsid == osAsid)
{
aMapping = m;
r = KErrNone;
break;
}
pLink = pLink->iNext;
}
// Close the reference on the os asid as if we have a mapping then its lifetime will
// determine whether the process still owns an os asid.
aProcess->CloseOsAsid();
return r;
}
TInt DMemModelAlignedShBuf::UnMap(DProcess* aProcess)
{
__KTRACE_OPT(KMMU, Kern::Printf(">DMemModelAlignedShBuf::UnMap()"));
TInt r = KErrNone;
DMemModelProcess* pP = reinterpret_cast<DMemModelProcess*>(aProcess);
DShBufMapping* m = NULL;
TWait wait;
for(;;)
{
iPool->LockPool();
r = FindMapping(m, pP);
if (r != KErrNone)
{
iPool->UnlockPool();
return KErrNotFound;
}
if (m->iTransitioning)
{
wait.Link(m->iTransitions);
iPool->UnlockPool();
wait.Wait();
}
else
{
break;
}
}
m->iTransitioning = ETrue;
iPool->UnlockPool();
MM::MappingUnmap(m->iMapping);
iPool->LockPool();
DMemModelAlignedShPoolClient* client = reinterpret_cast<DMemModelAlignedShPoolClient*>(iPool->iClientMap->Find(reinterpret_cast<TUint>(aProcess)));
__NK_ASSERT_DEBUG(client);
TWait* list = m->iTransitions;
m->iTransitions = NULL;
m->iObjLink.Deque();
m->iTransitioning = EFalse;
DMemModelAlignedShPool* pool = reinterpret_cast<DMemModelAlignedShPool*>(iPool);
pool->ReleaseMapping(m, client);
if (aProcess == K::TheKernelProcess)
iRelAddress = NULL;
iPool->UnlockPool();
wait.SignalAll(list);
return KErrNone;
}
TUint8* DMemModelAlignedShBuf::Base(DProcess* aProcess)
{
__KTRACE_OPT(KMMU, Kern::Printf(">DMemModelAlignedShBuf::Base()"));
DMemModelProcess* pP = reinterpret_cast<DMemModelProcess*>(aProcess);
DShBufMapping* mapping = NULL;
iPool->LockPool();
TInt r = FindMapping(mapping, pP);
TUint8* base = NULL;
if (r == KErrNone)
base = reinterpret_cast<TUint8*>(MM::MappingBase(mapping->iMapping));
iPool->UnlockPool();
return base;
}
TUint8* DMemModelAlignedShBuf::Base()
{
return reinterpret_cast<TUint8*>(iRelAddress);
}
TInt DMemModelAlignedShBuf::Pin(TPhysicalPinObject* aPinObject, TBool aReadOnly, TPhysAddr& aAddress, TPhysAddr* aPages, TUint32& aMapAttr, TUint& aColour)
{
CHECK_PRECONDITIONS(MASK_THREAD_CRITICAL,"DMemModelAlignedShBuf::Pin");
TInt r = MM::PinPhysicalMemory(iMemoryObject, (DPhysicalPinMapping*)aPinObject, 0,
MM::RoundToPageCount(Size()),
aReadOnly, aAddress, aPages, aMapAttr, aColour);
return r;
}
TInt DMemModelAlignedShPool::GetFreeMapping(DShBufMapping*& aMapping, DMemModelAlignedShPoolClient* aClient)
{
__KTRACE_OPT(KMMU, Kern::Printf(">DMemModelAlignedShPool::GetFreeMapping()"));
__NK_ASSERT_DEBUG(iLock.HeldByCurrentThread());
TInt r = KErrNotFound;
aMapping = NULL;
if (aClient)
{
if (!aClient->iMappingFreeList.IsEmpty())
{
aMapping = _LOFF(aClient->iMappingFreeList.GetFirst(), DShBufMapping, iObjLink);
r = KErrNone;
}
else
{
r = KErrNoMemory;
}
}
__KTRACE_OPT(KMMU2, Kern::Printf("DMemModelAlignedShPool::GetFreeMapping(0x%08x, 0x%08x) returns %d", aMapping, aClient, r));
return r;
}
TInt DMemModelAlignedShPool::ReleaseMapping(DShBufMapping*& aMapping, DMemModelAlignedShPoolClient* aClient)
{
__KTRACE_OPT(KMMU2, Kern::Printf("DMemModelAlignedShPool::ReleaseMapping(0x%08x,0x%08x)",aMapping,aClient));
__NK_ASSERT_DEBUG(iLock.HeldByCurrentThread());
TInt r = KErrNone;
if (aClient)
{
aClient->iMappingFreeList.AddHead(&aMapping->iObjLink);
aMapping = NULL;
}
else
{
// pool has probably been closed delete mapping
r = KErrNotFound;
__KTRACE_OPT(KMMU2, Kern::Printf("DMemModelAlignedShPool::ReleaseMapping delete 0x%08x",aMapping));
UnlockPool(); // have to release fast lock for MappingDestroy
MM::MappingDestroy(aMapping->iMapping);
delete aMapping;
aMapping = NULL;
LockPool();
}
return r;
}
TInt DMemModelAlignedShPool::SetBufferWindow(DProcess* aProcess, TInt aWindowSize)
{
__KTRACE_OPT(KMMU, Kern::Printf(">DMemModelAlignedShPool::SetBufferWindow()"));
// Create and construct mappings but do not map
// also allocate reserved handles
TInt r = KErrNone;
TUint noOfBuffers = aWindowSize;
if (aWindowSize > static_cast<TInt>(iMaxBuffers))
return KErrArgument;
Kern::MutexWait(*iProcessLock);
LockPool();
DMemModelAlignedShPoolClient* client = reinterpret_cast<DMemModelAlignedShPoolClient*>(iClientMap->Find(reinterpret_cast<TUint>(aProcess)));
UnlockPool();
if (client)
{
if (client->iWindowSize != 0)
{
Kern::MutexSignal(*iProcessLock);
return KErrAlreadyExists;
}
if (aWindowSize < 0)
{
noOfBuffers = iTotalBuffers;
}
DMemModelProcess* pP = reinterpret_cast<DMemModelProcess*>(aProcess);
r = CreateMappings(client, noOfBuffers, pP);
if (r == KErrNone)
{
client->iWindowSize = aWindowSize;
}
else
{
DestroyMappings(client, noOfBuffers);
}
}
else
{
r = KErrNotFound;
}
Kern::MutexSignal(*iProcessLock);
return r;
}
TInt DMemModelAlignedShPool::MappingNew(DShBufMapping*& aMapping, DMemModelProcess* aProcess)
{
// Must be in critical section so we don't leak os asid references.
__ASSERT_CRITICAL;
TMappingCreateFlags flags=EMappingCreateDefault;
FlagSet(flags, EMappingCreateReserveAllResources);
// Open a reference to aProcess's os so it isn't freed and reused while
// we're creating this mapping.
TInt osAsid = aProcess->TryOpenOsAsid();
if (osAsid < 0)
{// The process has freed its os asid so can't create a new mapping.
return KErrDied;
}
DMemoryMapping* mapping = NULL;
DShBufMapping* m = NULL;
TInt r = MM::MappingNew(mapping, MM::RoundToPageCount(iBufGap), osAsid, flags);
if (r == KErrNone)
{
m = new DShBufMapping;
if (m)
{
m->iMapping = mapping;
m->iOsAsid = osAsid;
}
else
{
MM::MappingDestroy(mapping);
r = KErrNoMemory;
}
}
// Close the reference on the os asid as while aMapping is valid then the
// os asid must be also.
aProcess->CloseOsAsid();
aMapping = m;
__KTRACE_OPT(KMMU2, Kern::Printf("DMemModelAlignedShPool::MappingNew returns 0x%08x,%d",aMapping,r));
return r;
}
TInt DMemModelAlignedShPool::AddToProcess(DProcess* aProcess, TUint aAttr)
{
__KTRACE_OPT(KMMU,Kern::Printf("Adding DMemModelAlignedShPool %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 DMemModelAlignedShPoolClient;
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;
r = KErrNoMemory;
}
}
else
{
r = KErrNoMemory;
}
}
else
{
LockPool();
client->iAccessCount++;
UnlockPool();
}
Kern::MutexSignal(*iProcessLock);
return r;
}
DMemModelAlignedShPool::DMemModelAlignedShPool() : DMemModelShPool()
{
__KTRACE_OPT(KMMU, Kern::Printf(">DMemModelAlignedShPool::DMemModelAlignedShPool"));
}
void DMemModelAlignedShPool::Free(DShBuf* aBuf)
{
__KTRACE_OPT(KMMU, Kern::Printf(">DMemModelAlignedShPool::Free (aBuf = 0x%08x)", aBuf));
LockPool();
#ifdef _DEBUG
// Remove from allocated list
aBuf->iObjLink.Deque();
#endif
DMemModelAlignedShBuf* buf = reinterpret_cast<DMemModelAlignedShBuf*>(aBuf);
if (MM::MemoryIsNotMapped(buf->iMemoryObject))
{
UnlockPool(); // have to release fast mutex
MM::MemoryWipe(buf->iMemoryObject);
LockPool();
// 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
{
iFreeList.Add(&aBuf->iObjLink);
}
++iFreeBuffers;
#ifdef _DEBUG
--iAllocatedBuffers;
#endif
}
else
{
iPendingList.Add(&aBuf->iObjLink);
}
iPoolFlags &= ~EShPoolSuppressShrink; // Allow shrinking again, if it was blocked
UnlockPool();
// queue ManagementDfc which completes notifications as appropriate
if (HaveWorkToDo())
KickManagementDfc();
DShPool::Close(NULL); // decrement pool reference count
}
TInt DMemModelAlignedShPool::UpdateFreeList()
{
__KTRACE_OPT(KMMU, Kern::Printf(">DMemModelAlignedShPool::UpdateFreeList"));
LockPool();
SDblQueLink* pLink = iPendingList.First();
UnlockPool();
SDblQueLink* anchor = &iPendingList.iA;
while (pLink != anchor)
{
DMemModelAlignedShBuf* buf = _LOFF(pLink, DMemModelAlignedShBuf, iObjLink);
LockPool();
pLink = pLink->iNext;
UnlockPool();
if (MM::MemoryIsNotMapped(buf->iMemoryObject))
{
LockPool();
buf->iObjLink.Deque();
UnlockPool();
MM::MemoryWipe(buf->iMemoryObject);
LockPool();
if (buf >= iInitialBuffersArray && buf < (iInitialBuffersArray + iInitialBuffers))
{
iFreeList.AddHead(&buf->iObjLink);
}
else
{
iFreeList.Add(&buf->iObjLink);
}
++iFreeBuffers;
#ifdef _DEBUG
--iAllocatedBuffers;
#endif
UnlockPool();
}
}
__KTRACE_OPT(KMMU, Kern::Printf("<DMemModelAlignedShPool::UpdateFreeList"));
return KErrNone;
}
DMemModelAlignedShPool::~DMemModelAlignedShPool()
{
__KTRACE_OPT(KMMU, Kern::Printf(">DMemModelAlignedShPool::~DMemModelAlignedShPool"));
}
TInt DMemModelAlignedShPool::DoCreate(TShPoolCreateInfo& aInfo)
{
TUint64 maxSize64 = static_cast<TUint64>(aInfo.iInfo.iMaxBufs) * static_cast<TUint64>(iBufGap);
if (maxSize64 > static_cast<TUint64>(KMaxTInt) || maxSize64 <= static_cast<TUint64>(0))
return KErrArgument;
iMaxPages = MM::RoundToPageCount(static_cast<TInt>(maxSize64));
return KErrNone;
}
TInt DMemModelAlignedShPool::DestroyAllMappingsAndReservedHandles(DProcess* aProcess)
{
__KTRACE_OPT(KMMU, Kern::Printf(">DMemModelAlignedShPool::DestroyAllMappingsAndReservedHandles(0x%08x)", aProcess));
TInt r = KErrNone;
Kern::MutexWait(*iProcessLock);
DMemModelAlignedShPoolClient* client = reinterpret_cast<DMemModelAlignedShPoolClient*>(iClientMap->Remove(reinterpret_cast<TUint>(aProcess)));
__NK_ASSERT_DEBUG(client);
__NK_ASSERT_DEBUG(client->iAccessCount == 0);
DestroyMappings(client, KMaxTInt);
delete client;
if (aProcess != K::TheKernelProcess)
{
// Remove reserved handles
r = aProcess->iHandles.Reserve(-iTotalBuffers);
}
Kern::MutexSignal(*iProcessLock);
__KTRACE_OPT(KMMU, Kern::Printf("<DMemModelAlignedShPool::DestroyAllMappingsAndReservedHandles(0x%08x)", aProcess));
return r;
}
TInt DMemModelAlignedShPool::DestroyMappings(DMemModelAlignedShPoolClient* aClient, TInt aNoOfMappings)
{
__KTRACE_OPT(KMMU, Kern::Printf(">DMemModelAlignedShPool::DestroyMappings(0x%08x)", aClient));
TInt r = KErrNone;
TInt i = 0;
DShBufMapping* m = NULL;
SDblQueLink* pLink = NULL;
while (i < aNoOfMappings && !aClient->iMappingFreeList.IsEmpty())
{
LockPool();
pLink = aClient->iMappingFreeList.GetFirst();
UnlockPool();
if (pLink == NULL)
break;
m = _LOFF(pLink, DShBufMapping, iObjLink);
__KTRACE_OPT(KMMU2, Kern::Printf("DMemModelAlignedShPool::DestroyMappings delete 0x%08x",m));
MM::MappingClose(m->iMapping);
delete m;
++i;
}
__KTRACE_OPT(KMMU, Kern::Printf("<DMemModelAlignedShPool::DestroyMappings"));
return r;
}
TInt DMemModelAlignedShPool::CreateMappings(DMemModelAlignedShPoolClient* aClient, TInt aNoOfMappings, DMemModelProcess* aProcess)
{
__KTRACE_OPT(KMMU, Kern::Printf(">DMemModelAlignedShPool::CreateMappings"));
__ASSERT_MUTEX(iProcessLock);
TInt r = KErrNone;
for (TInt i = 0; i < aNoOfMappings; ++i)
{
DShBufMapping* mapping;
r = MappingNew(mapping, aProcess);
if (r == KErrNone)
{
LockPool();
aClient->iMappingFreeList.AddHead(&mapping->iObjLink);
UnlockPool();
}
else
{
r = KErrNoMemory;
break;
}
}
return r;
}
TInt DMemModelAlignedShPool::UpdateMappingsAndReservedHandles(TInt aNoOfBuffers)
{
__KTRACE_OPT(KMMU2, Kern::Printf(">DMemModelAlignedShPool::UpdateMappingsAndReservedHandles(0x%08x)", aNoOfBuffers));
SMap::TIterator iter(*iClientMap);
SMap::TEntry* entry;
SMap::TEntry* lastEntry = NULL;
DMemModelProcess* pP;
DMemModelAlignedShPoolClient* client;
TInt result = KErrNone;
Kern::MutexWait(*iProcessLock);
// First handle the case of increasing allocation
if (aNoOfBuffers > 0)
while ((entry = iter.Next()) != lastEntry)
{
// Try to update handle reservation; skip if process is null or has gone away
client = (DMemModelAlignedShPoolClient*)(entry->iObj);
pP = (DMemModelProcess*)(entry->iKey);
if (!pP)
continue;
TInt r = pP->iHandles.Reserve(aNoOfBuffers);
if (r)
__KTRACE_OPT(KMMU2, Kern::Printf("?DMemModelAlignedShPool::UpdateMappingsAndReservedHandles(0x%08x) Reserve failed %d", aNoOfBuffers, r));
if (r == KErrDied)
continue;
if (r == KErrNone && client->iWindowSize <= 0)
{
// A positive window size means the number of mappings is fixed, so we don't need to reserve more.
// But here zero or negative means a variable number, so we need to create extra mappings now.
r = CreateMappings(client, aNoOfBuffers, pP);
if (r != KErrNone)
{
__KTRACE_OPT(KMMU2, Kern::Printf("?DMemModelAlignedShPool::UpdateMappingsAndReservedHandles(0x%08x) CreateMappings failed %d", aNoOfBuffers, r));
pP->iHandles.Reserve(-aNoOfBuffers); // Creation failed, so release the handles reserved above
}
}
if (r != KErrNone)
{
// Some problem; cleanup as best we can by falling into the loop below to undo what we've done
result = r;
iter.Reset();
lastEntry = entry;
aNoOfBuffers = -aNoOfBuffers;
break;
}
}
// Now handle the case of decreasing allocation; also used for recovery from errors, in which case
// this loop iterates only over the elements that were *successfully* processed by the loop above
if (aNoOfBuffers < 0)
while ((entry = iter.Next()) != lastEntry)
{
// Try to update handle reservation; skip if process is null or has gone away
client = (DMemModelAlignedShPoolClient*)(entry->iObj);
pP = (DMemModelProcess*)(entry->iKey);
if (!pP)
continue;
TInt r = pP->iHandles.Reserve(aNoOfBuffers);
if (r == KErrDied)
continue;
if (r == KErrNone && client->iWindowSize <= 0)
r = DestroyMappings(client, -aNoOfBuffers);
// De-allocation by Reserve(-n) and/or DestroyMappings() should never fail
if (r != KErrNone)
Kern::PanicCurrentThread(KLitDMemModelAlignedShPool, r);
}
Kern::MutexSignal(*iProcessLock);
__KTRACE_OPT(KMMU2, Kern::Printf("<DMemModelAlignedShPool::UpdateMappingsAndReservedHandles(0x%08x) returning %d", aNoOfBuffers, result));
return result;
}
TInt DMemModelAlignedShPool::DeleteInitialBuffers()
{
__KTRACE_OPT(KMMU, Kern::Printf(">DMemModelAlignedShPool::DeleteInitialBuffers"));
if (iInitialBuffersArray != NULL)
{
for (TUint i = 0; i < iInitialBuffers; i++)
{
iInitialBuffersArray[i].iObjLink.Deque(); // remove from free list
iInitialBuffersArray[i].Dec();
iInitialBuffersArray[i].~DMemModelAlignedShBuf();
}
}
Kern::Free(iInitialBuffersArray);
iInitialBuffersArray = NULL;
return KErrNone;
}
TInt DMemModelAlignedShPool::Close(TAny* aPtr)
{
__KTRACE_OPT(KMMU, Kern::Printf(">DMemModelAlignedShPool::Close(0x%08x)", aPtr));
if (aPtr)
{
DProcess* pP = reinterpret_cast<DProcess*>(aPtr);
CloseClient(pP);
}
__KTRACE_OPT(KMMU, Kern::Printf("<DMemModelAlignedShPool::Close(0x%08x)", aPtr));
return DShPool::Close(aPtr);
}
TInt DMemModelAlignedShPool::CreateInitialBuffers()
{
__KTRACE_OPT(KMMU, Kern::Printf(">DMemModelAlignedShPool::CreateInitialBuffers"));
iInitialBuffersArray = reinterpret_cast<DMemModelAlignedShBuf*>(Kern::Alloc(iInitialBuffers * sizeof(DMemModelAlignedShBuf)));
if (iInitialBuffersArray == NULL)
return KErrNoMemory;
for (TUint i = 0; i < iInitialBuffers; i++)
{
// always use kernel linear address in DShBuf
DMemModelAlignedShBuf *buf = new (&iInitialBuffersArray[i]) DMemModelAlignedShBuf(this);
TInt r = buf->Construct();
if (r == KErrNone)
{
iFreeList.Add(&buf->iObjLink);
}
else
{
iInitialBuffers = i;
return KErrNoMemory;
}
}
iFreeBuffers = iInitialBuffers;
iTotalBuffers = iInitialBuffers;
return KErrNone;
}
TInt DMemModelAlignedShPool::GrowPool()
{
__KTRACE_OPT(KMMU, Kern::Printf(">DMemModelAlignedShPool::GrowPool()"));
TInt r = KErrNone;
SDblQue temp;
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;
TUint i;
for (i = 0; i < grow; ++i)
{
DMemModelAlignedShBuf *buf = new DMemModelAlignedShBuf(this);
if (buf == NULL)
{
r = KErrNoMemory;
break;
}
TInt r = buf->Construct();
if (r != KErrNone)
{
buf->DObject::Close(NULL);
break;
}
temp.Add(&buf->iObjLink);
}
r = UpdateMappingsAndReservedHandles(i);
if (r == KErrNone)
{
LockPool();
iFreeList.MoveFrom(&temp);
iFreeBuffers += i;
iTotalBuffers += i;
UnlockPool();
}
else
{
// couldn't create either the mappings or reserve handles so have no choice but to
// delete the buffers
SDblQueLink *pLink;
while ((pLink = temp.GetFirst()) != NULL)
{
DShBuf* buf = _LOFF(pLink, DShBuf, iObjLink);
buf->DObject::Close(NULL);
}
}
CalculateGrowShrinkTriggers();
Kern::MutexSignal(*iProcessLock);
__KTRACE_OPT(KMMU, Kern::Printf("<DMemModelAlignedShPool::GrowPool()"));
return r;
}
TInt DMemModelAlignedShPool::ShrinkPool()
{
__KTRACE_OPT(KMMU, Kern::Printf(">DMemModelAlignedShPool::ShrinkPool()"))
Kern::MutexWait(*iProcessLock);
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 as the grown buffers should be at the back
TUint i;
for (i = 0; i < shrink; i++)
{
LockPool();
if (iFreeList.IsEmpty())
{
UnlockPool();
break;
}
DShBuf* buf = _LOFF(iFreeList.Last(), DShBuf, iObjLink);
// can't delete initial buffers
if (buf >= iInitialBuffersArray && buf < (iInitialBuffersArray + iInitialBuffers))
{
UnlockPool();
break;
}
buf->iObjLink.Deque();
--iFreeBuffers;
--iTotalBuffers;
UnlockPool();
buf->DObject::Close(NULL);
}
TInt r = UpdateMappingsAndReservedHandles(-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("<DMemModelAlignedShPool::ShrinkPool()"));
return r;
}
// Kernel side API
TInt DMemModelAlignedShPool::Alloc(DShBuf*& aShBuf)
{
__KTRACE_OPT(KMMU, Kern::Printf(">DMemModelAlignedShPool::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;
}
UnlockPool();
if (HaveWorkToDo())
KickManagementDfc();
__KTRACE_OPT(KMMU, Kern::Printf("<DMemModelAlignedShPool::Alloc return buf = 0x%08x", aShBuf));
return r;
}
DMemModelNonAlignedShBuf::DMemModelNonAlignedShBuf(DShPool* aPool, TLinAddr aRelAddr) : DShBuf(aPool, aRelAddr)
{
__KTRACE_OPT(KMMU, Kern::Printf(">DMemModelNonAlignedShBuf::DMemModelNonAlignedShBuf()"));
}
DMemModelNonAlignedShBuf::~DMemModelNonAlignedShBuf()
{
__KTRACE_OPT(KMMU, Kern::Printf(">DMemModelNonAlignedShBuf::~DMemModelNonAlignedShBuf()"));
}
TInt DMemModelNonAlignedShBuf::Close(TAny* aPtr)
{
__KTRACE_OPT(KMMU, Kern::Printf(">DMemModelNonAlignedShBuf::Close(0x%08x)", aPtr));
if (aPtr)
{
DProcess* pP = reinterpret_cast<DProcess*>(aPtr);
// there no per buffer resources for kernel clients for non-aligned buffers
if (pP != K::TheKernelProcess)
iPool->CloseClient(pP);
}
return DShBuf::Close(aPtr);
}
TInt DMemModelNonAlignedShBuf::AddToProcess(DProcess* aProcess, TUint /* aAttr */)
{
__KTRACE_OPT(KMMU, Kern::Printf("Adding DMemModelShBuf %O to process %O", this, aProcess));
TUint flags;
return iPool->OpenClient(aProcess, flags);
}
TUint8* DMemModelNonAlignedShBuf::Base(DProcess* aProcess)
{
__KTRACE_OPT(KMMU, Kern::Printf(">DMemModelNonAlignedShBuf::Base(0x%x)", aProcess));
TUint8* base = reinterpret_cast<DMemModelNonAlignedShPool*>(iPool)->Base(aProcess) + (TUint)iRelAddress;
return base;
}
TUint8* DMemModelNonAlignedShBuf::Base()
{
__KTRACE_OPT(KMMU, Kern::Printf(">DMemModelNonAlignedShBuf::Base()"));
TUint8* base = reinterpret_cast<DMemModelNonAlignedShPool*>(iPool)->Base();
return base ? base + iRelAddress : NULL;
}
TInt DMemModelNonAlignedShBuf::Map(TUint /* aMapAttr */, DProcess* /* aProcess */, TLinAddr& /* aBase */)
{
__KTRACE_OPT(KMMU, Kern::Printf(">DMemModelNonAlignedShBuf::Map()"));
return KErrNotSupported;
}
TInt DMemModelNonAlignedShBuf::UnMap(DProcess* /* aProcess */)
{
__KTRACE_OPT(KMMU, Kern::Printf(">DMemModelNonAlignedShBuf::UnMap()"));
return KErrNotSupported;
}
TInt DMemModelNonAlignedShBuf::Pin(TPhysicalPinObject* aPinObject, TBool aReadOnly, TPhysAddr& aAddress, TPhysAddr* aPages, TUint32& aMapAttr, TUint& aColour)
{
CHECK_PRECONDITIONS(MASK_THREAD_CRITICAL,"DMemModelNonAlignedShBuf::Pin");
DMemModelNonAlignedShPool* pool = reinterpret_cast<DMemModelNonAlignedShPool*>(iPool);
NKern::ThreadEnterCS();
TInt startPage = iRelAddress >> KPageShift;
TInt lastPage = MM::RoundToPageCount(iRelAddress + Size());
TInt pages = lastPage - startPage;
if (!pages) pages++;
TInt r = MM::PinPhysicalMemory(pool->iMemoryObject, (DPhysicalPinMapping*)aPinObject,
startPage, pages, aReadOnly, aAddress, aPages, aMapAttr, aColour);
// adjust physical address to start of the buffer
if (r == KErrNone)
{
aAddress += (iRelAddress - (startPage << KPageShift));
}
NKern::ThreadLeaveCS();
return r;
}
DMemModelNonAlignedShPool::DMemModelNonAlignedShPool() : DMemModelShPool()
{
__KTRACE_OPT(KMMU, Kern::Printf(">DMemModelNonAlignedShPool::DMemModelNonAlignedShPool"));
}
DMemModelNonAlignedShPool::~DMemModelNonAlignedShPool()
{
__KTRACE_OPT(KMMU, Kern::Printf(">DMemModelNonAlignedShPool::~DMemModelNonAlignedShPool"));
MM::MemoryDestroy(iMemoryObject);
delete iPagesMap;
delete iBufMap;
}
TInt DMemModelNonAlignedShPool::DoCreate(TShPoolCreateInfo& aInfo)
{
__KTRACE_OPT(KMMU, Kern::Printf("DMemModelNonAlignedShPool::DoCreate(%d, %d, %d)", aInfo.iInfo.iMaxBufs, iBufGap, iBufSize));
TInt r;
TUint64 maxSize64 = static_cast<TUint64>(aInfo.iInfo.iMaxBufs) * static_cast<TUint64>(iBufGap);
if (maxSize64 > static_cast<TUint64>(KMaxTInt) || maxSize64 <= static_cast<TUint64>(0))
return KErrArgument;
TInt maxPages = MM::RoundToPageCount(static_cast<TInt>(maxSize64));
iBufMap = TBitMapAllocator::New(aInfo.iInfo.iMaxBufs, (TBool)ETrue);
if (iBufMap == NULL)
return KErrNoMemory;
iPagesMap = TBitMapAllocator::New(maxPages, (TBool)ETrue);
if (iPagesMap == NULL)
return KErrNoMemory;
// Memory attributes
TMemoryAttributes attr = EMemoryAttributeStandard;
// Memory type
TMemoryObjectType memoryType = (iPoolFlags & EShPoolPhysicalMemoryPool) ? EMemoryObjectHardware : EMemoryObjectUnpaged;
// Memory flags
TMemoryCreateFlags memoryFlags = EMemoryCreateDefault; // Don't leave previous contents of memory
// Now create the memory object
r = MM::MemoryNew(iMemoryObject, memoryType, maxPages, memoryFlags, attr);
if (r != KErrNone)
return r;
// Make sure we give the caller the number of buffers they were expecting
iCommittedPages = MM::RoundToPageCount(iInitialBuffers * iBufGap);
if (iPoolFlags & EShPoolPhysicalMemoryPool)
{
__KTRACE_OPT(KMMU, Kern::Printf("DMemModelNonAlignedShPool::DoCreate(iCommittedPages = 0x%08x, aInfo.iPhysAddr.iPhysAddrList = 0x%08x )", iCommittedPages, aInfo.iPhysAddr.iPhysAddrList));
if (iPoolFlags & EShPoolContiguous)
{
r = MM::MemoryAddContiguous(iMemoryObject, 0, iCommittedPages, aInfo.iPhysAddr.iPhysAddr);
}
else
{
r = MM::MemoryAddPages(iMemoryObject, 0, iCommittedPages, aInfo.iPhysAddr.iPhysAddrList);
}
iMaxPages = iCommittedPages;
}
else
{
__KTRACE_OPT(KMMU, Kern::Printf("DMemModelNonAlignedShPool::DoCreate(iCommittedPages = %d, contig = %d)", iCommittedPages, iPoolFlags & EShPoolContiguous));
if (iPoolFlags & EShPoolContiguous)
{
TPhysAddr paddr;
r = MM::MemoryAllocContiguous(iMemoryObject, 0, iCommittedPages, 0, paddr);
}
else
{
r = MM::MemoryAlloc(iMemoryObject, 0, iCommittedPages);
}
iMaxPages = maxPages;
}
iPagesMap->Alloc(0, iCommittedPages);
return r;
}
TUint8* DMemModelNonAlignedShPool::Base(DProcess* aProcess)
{
TUint8 *base = 0;
LockPool();
DMemModelNonAlignedShPoolClient* client = reinterpret_cast<DMemModelNonAlignedShPoolClient*>(iClientMap->Find(reinterpret_cast<TUint>(aProcess)));
__NK_ASSERT_DEBUG(client); // ASSERT because pool must be already opened in the clients address space
__NK_ASSERT_DEBUG(client->iMapping); // ASSERT because non-aligned buffers are mapped by default in user space
base = reinterpret_cast<TUint8*>(MM::MappingBase(client->iMapping));
UnlockPool();
return base;
}
TInt DMemModelNonAlignedShPool::CreateInitialBuffers()
{
__KTRACE_OPT(KMMU, Kern::Printf(">DMemModelNonAlignedShPool::CreateInitialBuffers"));
iInitialBuffersArray = reinterpret_cast<DMemModelNonAlignedShBuf*>(Kern::Alloc(iInitialBuffers * sizeof(DMemModelNonAlignedShBuf)));
if (iInitialBuffersArray == NULL)
return KErrNoMemory;
TLinAddr offset = 0;
for (TUint i = 0; i < iInitialBuffers; i++)
{
DMemModelNonAlignedShBuf *buf = new (&iInitialBuffersArray[i]) DMemModelNonAlignedShBuf(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;
}
TInt DMemModelNonAlignedShPool::AddToProcess(DProcess* aProcess, TUint aAttr)
{
// Must be in critical section so we don't leak os asid references.
__ASSERT_CRITICAL;
__KTRACE_OPT(KMMU, Kern::Printf("Adding DMemModelShPool %O to process %O", this, aProcess));
DMemoryMapping* mapping = NULL;
TBool write = (TBool)EFalse;
// User = ETrue, ReadOnlyWrite = ETrue, Execute = EFalse
if (aAttr & EShPoolWriteable)
write = (TBool)ETrue;
TMappingPermissions perm = MM::MappingPermissions(ETrue, // user
write, // writeable
EFalse); // execute
TMappingCreateFlags mappingFlags = EMappingCreateDefault;
DMemModelProcess* pP = reinterpret_cast<DMemModelProcess*>(aProcess);
Kern::MutexWait(*iProcessLock);
TInt r = KErrNone;
LockPool();
DMemModelNonAlignedShPoolClient* client = reinterpret_cast<DMemModelNonAlignedShPoolClient*>(iClientMap->Find(reinterpret_cast<TUint>(aProcess)));
UnlockPool();
if (!client)
{
client = new DMemModelNonAlignedShPoolClient;
if (client)
{
// map non aligned pools in userside processes by default
if (aAttr & EShPoolAutoMapBuf || pP != K::TheKernelProcess)
{
// Open a reference on the os asid so it doesn't get freed and reused.
TInt osAsid = pP->TryOpenOsAsid();
if (osAsid < 0)
{// The process freed its os asid so can't create a new mapping.
r = KErrDied;
}
else
{
r = MM::MappingNew(mapping, iMemoryObject, perm, osAsid, mappingFlags);
// Close the reference as the mapping will be destroyed if the process dies.
pP->CloseOsAsid();
}
if ((r == KErrNone) && (pP == K::TheKernelProcess))
{
iBaseAddress = MM::MappingBase(mapping);
}
}
if (r == KErrNone)
{
client->iMapping = mapping;
client->iFlags = aAttr;
r = iClientMap->Add(reinterpret_cast<TUint>(aProcess), client);
if (r == KErrNone)
{
if (pP != K::TheKernelProcess)
{
r = aProcess->iHandles.Reserve(iTotalBuffers);
if (r != KErrNone)
{
iClientMap->Remove(reinterpret_cast<TUint>(aProcess));
}
}
}
if (r != KErrNone)
{
delete client;
MM::MappingDestroy(mapping);
}
}
else
{
delete client;
}
}
else
{
r = KErrNoMemory;
}
}
else
{
LockPool();
client->iAccessCount++;
UnlockPool();
}
Kern::MutexSignal(*iProcessLock);
return r;
}
TInt DMemModelNonAlignedShPool::DeleteInitialBuffers()
{
__KTRACE_OPT(KMMU, Kern::Printf(">DMemModelNonAlignedShPool::DeleteInitialBuffers"));
if (iInitialBuffersArray != NULL)
{
for (TUint i = 0; i < iInitialBuffers; i++)
{
iInitialBuffersArray[i].iObjLink.Deque(); // remove from free list
iInitialBuffersArray[i].Dec();
iInitialBuffersArray[i].~DMemModelNonAlignedShBuf();
}
}
Kern::Free(iInitialBuffersArray);
iInitialBuffersArray = NULL;
return KErrNone;
}
TInt DMemModelNonAlignedShPool::DestroyAllMappingsAndReservedHandles(DProcess* aProcess)
{
__KTRACE_OPT(KMMU, Kern::Printf(">DMemModelNonAlignedShPool::DestroyAllMappingsAndReservedHandles(0x%08x)", aProcess));
TInt r = KErrNone;
Kern::MutexWait(*iProcessLock);
DMemModelNonAlignedShPoolClient* client = reinterpret_cast<DMemModelNonAlignedShPoolClient*>(iClientMap->Remove(reinterpret_cast<TUint>(aProcess)));
__NK_ASSERT_DEBUG(client);
__NK_ASSERT_DEBUG(client->iAccessCount == 0);
if (client->iMapping)
{
MM::MappingDestroy(client->iMapping);
}
delete client;
if (aProcess != K::TheKernelProcess)
{
// Remove reserved handles
r = aProcess->iHandles.Reserve(-(iTotalBuffers));
}
else
{
iBaseAddress = 0;
}
Kern::MutexSignal(*iProcessLock);
__KTRACE_OPT(KMMU, Kern::Printf("<DMemModelNonAlignedShPool::DestroyAllMappingsAndReservedHandles(0x%08x)", aProcess));
return r;
}
TInt DMemModelNonAlignedShPool::Close(TAny* aPtr)
{
__KTRACE_OPT(KMMU, Kern::Printf(">DMemModelNonAlignedShPool::Close(0x%08x)", aPtr));
if (aPtr)
{
DProcess* pP = reinterpret_cast<DProcess*>(aPtr);
CloseClient(pP);
}
return DShPool::Close(aPtr);
}
void DMemModelNonAlignedShPool::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>>KPageShift; // index of first page containing part of the buffer
TUint lastPage = lastByte>>KPageShift; // index of last page containing part of the buffer
TUint firstBuffer = (firstByte&~KPageMask)/iBufGap; // index of first buffer which lies in firstPage
TUint lastBuffer = (lastByte|KPageMask)/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::MemoryLock(iMemoryObject);
MM::MemoryFree(iMemoryObject, firstPage, numPages);
MM::MemoryUnlock(iMemoryObject);
iCommittedPages -= numPages;
}
}
TInt DMemModelNonAlignedShPool::GrowPool()
{
__KTRACE_OPT(KMMU, Kern::Printf(">DMemModelNonAlignedShPool::GrowPool()"));
// Don't do anything with physical memory pools
if (iPoolFlags & EShPoolPhysicalMemoryPool)
return KErrNone;
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) >> KPageShift;
// Allocate one page at a time.
for (TInt page = offset >> KPageShift; page <= lastPage; ++page)
{
// Is the page allocated?
if (iPagesMap->NotAllocated(page, 1))
{
MM::MemoryLock(iMemoryObject);
r = MM::MemoryAlloc(iMemoryObject, page, 1);
MM::MemoryUnlock(iMemoryObject);
if (r != KErrNone)
{
break;
}
++iCommittedPages;
iPagesMap->Alloc(page, 1);
}
}
if (r != KErrNone)
{
iBufMap->Free(offset / iBufGap);
FreeBufferPages(offset);
break;
}
DMemModelNonAlignedShBuf *buf = new DMemModelNonAlignedShBuf(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("<DMemModelNonAlignedShPool::GrowPool()"));
return r;
}
TInt DMemModelNonAlignedShPool::ShrinkPool()
{
__KTRACE_OPT(KMMU, Kern::Printf(">DMemModelNonAlignedShPool::ShrinkPool()"));
// Don't do anything with physical memory pools
if (iPoolFlags & EShPoolPhysicalMemoryPool)
return KErrNone;
Kern::MutexWait(*iProcessLock);
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("<DMemModelNonAlignedShPool::ShrinkPool()"));
return KErrNone;
}
TInt DMemModelNonAlignedShPool::UpdateFreeList()
{
__KTRACE_OPT(KMMU, Kern::Printf(">DMemModelNonAlignedShPool::UpdateFreeList"));
SDblQue temp;
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();
while (ETrue)
{
// 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* anchor = reinterpret_cast<SDblQueLink*>(&iFreeList);
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("<DMemModelNonAlignedShPool::UpdateFreeList"));
return KErrNone;
}
void DMemModelNonAlignedShPool::Free(DShBuf* aBuf)
{
__KTRACE_OPT(KMMU, Kern::Printf(">DMemModelNonAlignedShPool::Free (aBuf = 0x%08x, aBuf->Base() 0x%08x)", aBuf, aBuf->iRelAddress));
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();
DShPool::Close(NULL); // decrement pool reference count
}
// Kernel side API
TInt DMemModelNonAlignedShPool::Alloc(DShBuf*& aShBuf)
{
__KTRACE_OPT(KMMU, Kern::Printf(">DMemModelNonAlignedShPool::Alloc (DShBuf)"));
aShBuf = NULL;
LockPool();
if (!iFreeList.IsEmpty())
{
aShBuf = _LOFF(iFreeList.GetFirst(), DShBuf, iObjLink);
#ifdef _DEBUG
iAllocated.Add(&aShBuf->iObjLink);
iAllocatedBuffers++;
#endif
}
else
{
// try alternative free list
if (!iAltFreeList.IsEmpty())
{
aShBuf = _LOFF(iAltFreeList.GetFirst(), DShBuf, iObjLink);
#ifdef _DEBUG
iAllocated.Add(&aShBuf->iObjLink);
iAllocatedBuffers++;
#endif
}
else
{
UnlockPool();
KickManagementDfc(); // Try to grow
return KErrNoMemory;
}
}
--iFreeBuffers;
Open(); // increment pool reference count
UnlockPool();
if (HaveWorkToDo())
KickManagementDfc();
__KTRACE_OPT(KMMU, Kern::Printf("<DMemModelNonAlignedShPool::Alloc return buf = 0x%08x", aShBuf));
return KErrNone;
}