// Copyright (c) 2008-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:
//
#include <plat_priv.h>
#include "mm.h"
#include "mmu.h"
#include "mmanager.h"
#include "mobject.h"
#include "mmapping.h"
#include "mpager.h"
#include "mswap.h"
/**
Manages the swap via the data paging device.
*/
class DSwapManager
{
public:
enum TSwapFlags
{
EAllocated = 1 << 0,
EUninitialised = 1 << 1,
ESaved = 1 << 2,
ESwapFlagsMask = 0x7,
ESwapIndexShift = 3,
ESwapIndexMask = 0xffffffff << ESwapIndexShift,
};
TInt Create(DPagingDevice* aDevice);
TInt ReserveSwap(DMemoryObject* aMemory, TUint aStartIndex, TUint aPageCount);
TInt UnreserveSwap(DMemoryObject* aMemory, TUint aStartIndex, TUint aPageCount);
TBool IsReserved(DMemoryObject* aMemory, TUint aStartIndex, TUint aPageCount);
TInt ReadSwapPages(DMemoryObject* aMemory, TUint aIndex, TUint aCount, TLinAddr aLinAddr, DPageReadRequest* aRequest, TPhysAddr* aPhysAddrs);
TInt WriteSwapPages(DMemoryObject* aMemory, TUint aIndex, TUint aCount, TLinAddr aLinAddr, DPageWriteRequest* aRequest);
void DoDeleteNotify(TUint aSwapData);
void GetSwapInfo(SVMSwapInfo& aInfoOut);
TInt SetSwapThresholds(const SVMSwapThresholds& aThresholds);
void CheckSwapThresholds(TUint aInitial, TUint aFinal);
protected:
DPagingDevice* iDevice;
TBitMapAllocator* iBitMap;
TUint iBitMapFree;
TUint iAllocOffset;
TUint iSwapThesholdLow;
TUint iSwapThesholdGood;
TThreadMessage iDelNotifyMsg;
};
/**
Manager for demand paged memory objects which contain writeable data.
The contents of the memory are written to a backing store whenever its
pages are 'paged out'.
@see DSwapManager
*/
class DDataPagedMemoryManager : public DPagedMemoryManager
{
private:
// from DMemoryManager...
virtual TInt Alloc(DMemoryObject* aMemory, TUint aIndex, TUint aCount);
virtual void Free(DMemoryObject* aMemory, TUint aIndex, TUint aCount);
virtual TInt Wipe(DMemoryObject* aMemory);
virtual TInt CleanPage(DMemoryObject* aMemory, SPageInfo* aPageInfo, TPhysAddr*& aPageArrayEntry);
// Methods inherited from DPagedMemoryManager
virtual void Init3();
virtual TInt InstallPagingDevice(DPagingDevice* aDevice);
virtual TInt AcquirePageReadRequest(DPageReadRequest*& aRequest, DMemoryObject* aMemory, TUint aIndex, TUint aCount);
virtual TInt AcquirePageWriteRequest(DPageWriteRequest*& aRequest, DMemoryObject* aMemory, TUint aIndex, TUint aCount);
virtual TInt ReadPages(DMemoryObject* aMemory, TUint aIndex, TUint aCount, TPhysAddr* aPages, DPageReadRequest* aRequest);
virtual TInt WritePages(DMemoryObject* aMemory, TUint aIndex, TUint aCount, TPhysAddr* aPages, DPageWriteRequest* aRequest);
virtual TBool IsAllocated(DMemoryObject* aMemory, TUint aIndex, TUint aCount);
public:
void GetSwapInfo(SVMSwapInfo& aInfoOut);
TInt SetSwapThresholds(const SVMSwapThresholds& aThresholds);
private:
/**
The paging device used for accessing the backing store.
This is set by #InstallPagingDevice.
*/
DPagingDevice* iDevice;
/**
The instance of #DSwapManager being used by this manager.
*/
DSwapManager* iSwapManager;
public:
/**
The single instance of this manager class.
*/
static DDataPagedMemoryManager TheManager;
};
DDataPagedMemoryManager DDataPagedMemoryManager::TheManager;
DPagedMemoryManager* TheDataPagedMemoryManager = &DDataPagedMemoryManager::TheManager;
/**
Create a swap manager.
@param aDevice The demand paging device for access to the swap.
*/
TInt DSwapManager::Create(DPagingDevice* aDevice)
{
__ASSERT_COMPILE(!(ESwapIndexMask & ESwapFlagsMask));
__NK_ASSERT_DEBUG(iDevice == NULL);
iDevice = aDevice;
// Create the structures required to track the swap usage.
TUint swapPages = (iDevice->iSwapSize << iDevice->iReadUnitShift) >> KPageShift;
// Can't have more swap pages than we can map.
__NK_ASSERT_DEBUG(swapPages<=DMemoryObject::KMaxPagingManagerData);
__NK_ASSERT_DEBUG(swapPages<=(KMaxTUint>>ESwapIndexShift));
if ((TheMmu.TotalPhysicalRamPages() << 2) < swapPages)
{// The swap is limited to a maximum of 4 times the amount of RAM.
return KErrTooBig;
}
iBitMap = TBitMapAllocator::New(swapPages, ETrue);
if (iBitMap == NULL)
{// Not enough RAM to keep track of the swap.
return KErrNoMemory;
}
iBitMapFree = swapPages;
iAllocOffset = 0;
return KErrNone;
}
/**
Reserve some swap pages for the requested region of the memory object
@param aMemory The memory object to reserve pages for.
@param aStartIndex The page index in the memory object of the start of the region.
@param aPageCount The number of pages to reserve.
@return KErrNone on success, KErrNoMemory if not enough swap space available.
@pre aMemory's lock is held.
@post aMemory's lock is held.
*/
TInt DSwapManager::ReserveSwap(DMemoryObject* aMemory, TUint aStartIndex, TUint aPageCount)
{
__NK_ASSERT_DEBUG(MemoryObjectLock::IsHeld(aMemory));
__NK_ASSERT_DEBUG(RamAllocLock::IsHeld());
const TUint indexEnd = aStartIndex + aPageCount;
TUint index = aStartIndex;
#ifdef _DEBUG
for (; index < indexEnd; index++)
{// This page shouldn't already be in use.
MmuLock::Lock();
__NK_ASSERT_DEBUG(!(aMemory->PagingManagerData(index) & ESwapFlagsMask));
MmuLock::Unlock();
}
#endif
if (iBitMapFree < aPageCount)
{
Kern::AsyncNotifyChanges(EChangesOutOfMemory);
return KErrNoMemory;
}
// Reserve the required swap space and mark each page as allocated and uninitialised.
TUint initFree = iBitMapFree;
iBitMapFree -= aPageCount;
for (index = aStartIndex; index < indexEnd; index++)
{
// Grab MmuLock to stop manager data being accessed.
MmuLock::Lock();
TUint swapData = aMemory->PagingManagerData(index);
__NK_ASSERT_DEBUG(!(swapData & EAllocated));
swapData = EAllocated | EUninitialised;
aMemory->SetPagingManagerData(index, swapData);
MmuLock::Unlock();
}
CheckSwapThresholds(initFree, iBitMapFree);
return KErrNone;
}
/**
Unreserve swap pages for the requested region of the memory object.
@param aMemory The memory object to unreserve pages for.
@param aStartIndex The page index in the memory object of the start of the region.
@param aPageCount The number of pages to unreserve.
@return The number of pages freed.
@pre aMemory's lock is held.
@post aMemory's lock is held.
*/
TInt DSwapManager::UnreserveSwap(DMemoryObject* aMemory, TUint aStartIndex, TUint aPageCount)
{
__NK_ASSERT_DEBUG(MemoryObjectLock::IsHeld(aMemory));
__NK_ASSERT_DEBUG(RamAllocLock::IsHeld());
TUint initFree = iBitMapFree;
TUint freedPages = 0;
const TUint indexEnd = aStartIndex + aPageCount;
for (TUint index = aStartIndex; index < indexEnd; index++)
{
// Grab MmuLock to stop manager data being accessed.
MmuLock::Lock();
TUint swapData = aMemory->PagingManagerData(index);
TUint swapIndex = swapData >> ESwapIndexShift;
TBool notifyDelete = EFalse;
if (swapData & EAllocated)
{
if (swapData & ESaved)
{
notifyDelete = ETrue;
iBitMap->Free(swapIndex);
}
freedPages++;
aMemory->SetPagingManagerData(index, 0);
}
#ifdef _DEBUG
else
__NK_ASSERT_DEBUG(swapData == 0);
#endif
MmuLock::Unlock();
if (notifyDelete)
DoDeleteNotify(swapIndex);
}
iBitMapFree += freedPages;
CheckSwapThresholds(initFree, iBitMapFree);
return freedPages;
}
/**
Determine whether the specified pages in the memory object have swap reserved for them.
@param aMemory The memory object that owns the pages.
@param aStartIndex The first index of the pages to check.
@param aPageCount The number of pages to check.
@return ETrue if swap is reserved for all the pages, EFalse otherwise.
*/
TBool DSwapManager::IsReserved(DMemoryObject* aMemory, TUint aStartIndex, TUint aPageCount)
{// MmuLock required to protect manager data.
__NK_ASSERT_DEBUG(MmuLock::IsHeld());
__NK_ASSERT_DEBUG(aStartIndex < aMemory->iSizeInPages);
__NK_ASSERT_DEBUG(aStartIndex + aPageCount <= aMemory->iSizeInPages);
const TUint indexEnd = aStartIndex + aPageCount;
for (TUint index = aStartIndex; index < indexEnd; index++)
{
if (!(aMemory->PagingManagerData(index) & DSwapManager::EAllocated))
{// This page is not allocated by swap manager.
return EFalse;
}
}
return ETrue;
}
/**
Read from the swap the specified pages associated with the memory object.
@param aMemory The memory object to read the pages for
@param aIndex The index of the first page within the memory object.
@param aCount The number of pages to read.
@param aLinAddr The address to copy the pages to.
@param aRequest The request to use for the read.
@param aPhysAddrs An array of the physical addresses for each page to read in.
*/
TInt DSwapManager::ReadSwapPages(DMemoryObject* aMemory, TUint aIndex, TUint aCount, TLinAddr aLinAddr, DPageReadRequest* aRequest, TPhysAddr* aPhysAddrs)
{
TInt r = KErrNone;
const TUint readUnitShift = iDevice->iReadUnitShift;
TUint readSize = KPageSize >> readUnitShift;
TThreadMessage* msg = const_cast<TThreadMessage*>(&aRequest->iMessage);
// Determine the wipe byte values for uninitialised pages.
TUint allocFlags = aMemory->RamAllocFlags();
TBool wipePages = !(allocFlags & Mmu::EAllocNoWipe);
TUint8 wipeByte = (allocFlags & Mmu::EAllocUseCustomWipeByte) ? (allocFlags >> Mmu::EAllocWipeByteShift) & 0xff : 0x03;
const TUint indexEnd = aIndex + aCount;
for (TUint index = aIndex; index < indexEnd; index++, aLinAddr += KPageSize, aPhysAddrs++)
{
START_PAGING_BENCHMARK;
MmuLock::Lock(); // MmuLock required for atomic access to manager data.
TUint swapData = aMemory->PagingManagerData(index);
if (!(swapData & EAllocated))
{// This page is not committed to the memory object
MmuLock::Unlock();
return KErrNotFound;
}
if (swapData & EUninitialised)
{// This page has not been written to yet so don't read from swap
// just wipe it if required.
MmuLock::Unlock();
if (wipePages)
{
memset((TAny*)aLinAddr, wipeByte, KPageSize);
}
}
else
{
__NK_ASSERT_DEBUG(swapData & ESaved);
TUint swapIndex = swapData >> ESwapIndexShift;
// OK to release as if the object's data is decommitted the pager
// will check that data is still valid before mapping it.
MmuLock::Unlock();
TUint readStart = (swapIndex << KPageShift) >> readUnitShift;
START_PAGING_BENCHMARK;
r = iDevice->Read(msg, aLinAddr, readStart, readSize, DPagingDevice::EDriveDataPaging);
if (r != KErrNone)
__KTRACE_OPT(KPANIC, Kern::Printf("DSwapManager::ReadSwapPages: error reading media at %08x + %x: %d", readStart << readUnitShift, readSize << readUnitShift, r));
__NK_ASSERT_DEBUG(r!=KErrNoMemory); // not allowed to allocate memory, therefore can't fail with KErrNoMemory
END_PAGING_BENCHMARK(EPagingBmReadDataMedia);
// TODO: Work out what to do if page in fails, unmap all pages????
__NK_ASSERT_ALWAYS(r == KErrNone);
}
END_PAGING_BENCHMARK(EPagingBmReadDataPage);
}
return r;
}
/**
Write the specified memory object's pages from the RAM into the swap.
@param aMemory The memory object who owns the pages.
@param aIndex The index within the memory object.
@param aCount The number of pages to write out.
@param aLinAddr The location of the pages to write out.
@param aRequest The demand paging request to use.
*/
TInt DSwapManager::WriteSwapPages(DMemoryObject* aMemory, TUint aIndex, TUint aCount, TLinAddr aLinAddr, DPageWriteRequest* aRequest)
{// The RamAllocLock prevents the object's swap pages being reassigned.
__NK_ASSERT_DEBUG(RamAllocLock::IsHeld());
// Write the page out to the swap.
TInt r = KErrNone;
const TUint readUnitShift = iDevice->iReadUnitShift;
TUint writeSize = KPageSize >> readUnitShift;
TThreadMessage* msg = const_cast<TThreadMessage*>(&aRequest->iMessage);
const TUint indexEnd = aIndex + aCount;
for (TUint index = aIndex; index < indexEnd; index++)
{
START_PAGING_BENCHMARK;
MmuLock::Lock();
TUint swapData = aMemory->PagingManagerData(index);
// OK to release as ram alloc lock prevents manager data being updated.
MmuLock::Unlock();
if (!(swapData & EAllocated))
{// This page is being decommited from aMemory so it is clean/unrequired.
continue;
}
TInt swapIndex = swapData >> ESwapIndexShift;
if (swapData & ESaved)
{// An old version of this page has been saved to swap so free it now
// as it will be out of date.
iBitMap->Free(swapIndex);
DoDeleteNotify(swapIndex);
}
// Get a new swap location for this page.
swapIndex = iBitMap->AllocFrom(iAllocOffset);
__NK_ASSERT_DEBUG(swapIndex != -1 && swapIndex < iBitMap->iSize);
iAllocOffset = swapIndex + 1;
if (iAllocOffset == (TUint)iBitMap->iSize)
iAllocOffset = 0;
TUint writeOffset = (swapIndex << KPageShift) >> readUnitShift;
{
START_PAGING_BENCHMARK;
r = iDevice->Write(msg, aLinAddr, writeOffset, writeSize, EFalse);
if (r != KErrNone)
__KTRACE_OPT(KPANIC, Kern::Printf("DSwapManager::WriteSwapPages: error writing media at %08x + %x: %d", writeOffset << readUnitShift, writeSize << readUnitShift, r));
__NK_ASSERT_DEBUG(r!=KErrNoMemory); // not allowed to allocate memory, therefore can't fail with KErrNoMemory
END_PAGING_BENCHMARK(EPagingBmWriteDataMedia);
}
// TODO: Work out what to do if page out fails.
__NK_ASSERT_ALWAYS(r == KErrNone);
MmuLock::Lock();
// The swap data should not have been modified.
__NK_ASSERT_DEBUG(swapData == aMemory->PagingManagerData(index));
// Store the new swap location and mark the page as saved.
swapData &= ~(EUninitialised | ESwapIndexMask);
swapData |= (swapIndex << ESwapIndexShift) | ESaved;
aMemory->SetPagingManagerData(index, swapData);
MmuLock::Unlock();
END_PAGING_BENCHMARK(EPagingBmWriteDataPage);
}
return r;
}
/**
Notify the media driver that the page written to swap is no longer required.
*/
void DSwapManager::DoDeleteNotify(TUint aSwapIndex)
{
// Ram Alloc lock prevents the swap location being assigned to another page.
__NK_ASSERT_DEBUG(RamAllocLock::IsHeld());
#ifdef __PAGING_DELETE_NOTIFY_ENABLED
const TUint readUnitShift = iDevice->iReadUnitShift;
const TUint size = KPageSize >> readUnitShift;
TUint offset = (aSwapIndex << KPageShift) >> readUnitShift;
START_PAGING_BENCHMARK;
// Ignore the return value as this is just an optimisation that is not supported on all media.
(void)iDevice->DeleteNotify(&iDelNotifyMsg, offset, size);
END_PAGING_BENCHMARK(EPagingBmDeleteNotifyDataPage);
#endif
}
// Check swap thresholds and notify (see K::CheckFreeMemoryLevel)
void DSwapManager::CheckSwapThresholds(TUint aInitial, TUint aFinal)
{
TUint changes = 0;
if (aFinal < iSwapThesholdLow && aInitial >= iSwapThesholdLow)
changes |= (EChangesFreeMemory | EChangesLowMemory);
if (aFinal >= iSwapThesholdGood && aInitial < iSwapThesholdGood)
changes |= EChangesFreeMemory;
if (changes)
Kern::AsyncNotifyChanges(changes);
}
void DSwapManager::GetSwapInfo(SVMSwapInfo& aInfoOut)
{
__NK_ASSERT_DEBUG(RamAllocLock::IsHeld());
aInfoOut.iSwapSize = iBitMap->iSize << KPageShift;
aInfoOut.iSwapFree = iBitMapFree << KPageShift;
}
TInt DSwapManager::SetSwapThresholds(const SVMSwapThresholds& aThresholds)
{
__NK_ASSERT_DEBUG(RamAllocLock::IsHeld());
if (aThresholds.iLowThreshold > aThresholds.iGoodThreshold)
return KErrArgument;
TInt low = (aThresholds.iLowThreshold + KPageSize - 1) >> KPageShift;
TInt good = (aThresholds.iGoodThreshold + KPageSize - 1) >> KPageShift;
if (good > iBitMap->iSize)
return KErrArgument;
iSwapThesholdLow = low;
iSwapThesholdGood = good;
return KErrNone;
}
TInt DDataPagedMemoryManager::InstallPagingDevice(DPagingDevice* aDevice)
{
TRACEB(("DDataPagedMemoryManager::InstallPagingDevice(0x%08x)",aDevice));
TUint dataPolicy = TheSuperPage().KernelConfigFlags() & EKernelConfigDataPagingPolicyMask;
TRACEB(("Data Paging Policy = %d", dataPolicy >> EKernelConfigDataPagingPolicyShift));
if (dataPolicy == EKernelConfigDataPagingPolicyNoPaging)
{// No paging allowed so don't register the device.
return KErrNone;
}
// Store the device, blocking any other devices from installing.
if (!NKern::CompareAndSwap((TAny*&)iDevice, (TAny*)NULL, (TAny*)aDevice))
{// Data paging device already installed.
__KTRACE_OPT2(KPAGING,KBOOT,Kern::Printf("**** Attempt to install more than one data paging device !!!!!!!! ****"));
return KErrAlreadyExists;
}
// Now we can determine the size of the swap, create the swap manager.
iSwapManager = new DSwapManager;
__NK_ASSERT_ALWAYS(iSwapManager);
TInt r = iSwapManager->Create(iDevice);
if (r != KErrNone)
{// Couldn't create the swap manager.
delete iSwapManager;
iSwapManager = NULL;
NKern::SafeSwap(NULL, (TAny*&)iDevice);
return r;
}
NKern::LockedSetClear(K::MemModelAttributes, 0, EMemModelAttrDataPaging);
return r;
}
TInt DDataPagedMemoryManager::AcquirePageReadRequest(DPageReadRequest*& aRequest, DMemoryObject* aMemory, TUint aIndex, TUint aCount)
{
aRequest = iDevice->iRequestPool->AcquirePageReadRequest(aMemory,aIndex,aCount);
return KErrNone;
}
TInt DDataPagedMemoryManager::AcquirePageWriteRequest(DPageWriteRequest*& aRequest, DMemoryObject* aMemory, TUint aIndex, TUint aCount)
{
aRequest = iDevice->iRequestPool->AcquirePageWriteRequest(aMemory,aIndex,aCount);
return KErrNone;
}
void DDataPagedMemoryManager::Init3()
{
}
TInt DDataPagedMemoryManager::Alloc(DMemoryObject* aMemory, TUint aIndex, TUint aCount)
{
__NK_ASSERT_DEBUG(MemoryObjectLock::IsHeld(aMemory));
// re-initialise any decommitted pages which we may still own because they were pinned...
ReAllocDecommitted(aMemory,aIndex,aCount);
// Reserve the swap pages required.
RamAllocLock::Lock();
TInt r = iSwapManager->ReserveSwap(aMemory, aIndex, aCount);
RamAllocLock::Unlock();
return r;
}
void DDataPagedMemoryManager::Free(DMemoryObject* aMemory, TUint aIndex, TUint aCount)
{
TRACE2(("DDataPagedMemoryManager::Free(0x%08x,0x%x,0x%x)", aMemory, aIndex, aCount));
__NK_ASSERT_DEBUG(MemoryObjectLock::IsHeld(aMemory));
// Unreserve the swap pages associated with the memory object. Do this before
// removing the page array entries to prevent a page fault reallocating these pages.
RamAllocLock::Lock();
TInt freed = iSwapManager->UnreserveSwap(aMemory, aIndex, aCount);
(void)freed;
RamAllocLock::Unlock();
DoFree(aMemory,aIndex,aCount);
}
/**
@copydoc DMemoryManager::Wipe
@todo Not yet implemented.
Need to handle this smartly, e.g. throw RAM away and set to uninitialised
*/
TInt DDataPagedMemoryManager::Wipe(DMemoryObject* aMemory)
{
__NK_ASSERT_ALWAYS(0); // not implemented yet
return KErrNotSupported;
}
TInt DDataPagedMemoryManager::ReadPages(DMemoryObject* aMemory, TUint aIndex, TUint aCount, TPhysAddr* aPages, DPageReadRequest* aRequest)
{
__NK_ASSERT_DEBUG(aRequest->CheckUse(aMemory,aIndex,aCount));
// Map pages temporarily so that we can copy into them.
const TLinAddr linAddr = aRequest->MapPages(aIndex, aCount, aPages);
TInt r = iSwapManager->ReadSwapPages(aMemory, aIndex, aCount, linAddr, aRequest, aPages);
// The memory object allows executable mappings then need IMB.
aRequest->UnmapPages(aMemory->IsExecutable());
return r;
}
TInt DDataPagedMemoryManager::WritePages(DMemoryObject* aMemory, TUint aIndex, TUint aCount, TPhysAddr* aPages, DPageWriteRequest* aRequest)
{
__NK_ASSERT_DEBUG(aRequest->CheckUse(aMemory,aIndex,aCount));
// Map pages temporarily so that we can copy into them.
const TLinAddr linAddr = aRequest->MapPages(aIndex, aCount, aPages);
TInt r = iSwapManager->WriteSwapPages(aMemory, aIndex, aCount, linAddr, aRequest);
// The memory object allows executable mappings then need IMB.
aRequest->UnmapPages(aMemory->IsExecutable());
return r;
}
TInt DDataPagedMemoryManager::CleanPage(DMemoryObject* aMemory, SPageInfo* aPageInfo, TPhysAddr*& aPageArrayEntry)
{
if(aPageInfo->IsDirty()==false)
return KErrNone;
// shouldn't be asked to clean a page which is writable...
__NK_ASSERT_DEBUG(aPageInfo->IsWritable()==false);
// mark page as being modified by us...
TUint modifierInstance; // dummy variable used only for it's storage address on the stack
aPageInfo->SetModifier(&modifierInstance);
// get info about page...
TUint index = aPageInfo->Index();
TPhysAddr physAddr = aPageInfo->PhysAddr();
// Release the mmu lock while we write out the page. This is safe as the
// RamAllocLock stops the physical address being freed from this object.
MmuLock::Unlock();
// get paging request object...
DPageWriteRequest* req;
TInt r = AcquirePageWriteRequest(req, aMemory, index, 1);
__NK_ASSERT_DEBUG(r==KErrNone); // we should always get a write request because the previous function blocks until it gets one
__NK_ASSERT_DEBUG(req); // we should always get a write request because the previous function blocks until it gets one
r = WritePages(aMemory, index, 1, &physAddr, req);
req->Release();
MmuLock::Lock();
if(r!=KErrNone)
return r;
// check if page is clean...
if(aPageInfo->CheckModified(&modifierInstance) || aPageInfo->IsWritable())
{
// someone else modified the page, or it became writable, so fail...
r = KErrInUse;
}
else
{
// page is now clean!
ThePager.SetClean(*aPageInfo);
}
return r;
}
TBool DDataPagedMemoryManager::IsAllocated(DMemoryObject* aMemory, TUint aIndex, TUint aCount)
{// MmuLock required to protect manager data.
// DPagedMemoryManager::DoPageInDone() won't allow MmuLock to be released
// so can only cope with a maximum of KMaxPagesInOneGo.
__NK_ASSERT_DEBUG(MmuLock::IsHeld());
__NK_ASSERT_DEBUG(aCount <= KMaxPagesInOneGo);
return iSwapManager->IsReserved(aMemory, aIndex, aCount);
}
void DDataPagedMemoryManager::GetSwapInfo(SVMSwapInfo& aInfoOut)
{
NKern::ThreadEnterCS();
RamAllocLock::Lock();
iSwapManager->GetSwapInfo(aInfoOut);
RamAllocLock::Unlock();
NKern::ThreadLeaveCS();
}
TInt DDataPagedMemoryManager::SetSwapThresholds(const SVMSwapThresholds& aThresholds)
{
NKern::ThreadEnterCS();
RamAllocLock::Lock();
TInt r = iSwapManager->SetSwapThresholds(aThresholds);
RamAllocLock::Unlock();
NKern::ThreadLeaveCS();
return r;
}
void GetSwapInfo(SVMSwapInfo& aInfoOut)
{
((DDataPagedMemoryManager*)TheDataPagedMemoryManager)->GetSwapInfo(aInfoOut);
}
TInt SetSwapThresholds(const SVMSwapThresholds& aThresholds)
{
return ((DDataPagedMemoryManager*)TheDataPagedMemoryManager)->SetSwapThresholds(aThresholds);
}