diff -r 000000000000 -r a41df078684a kernel/eka/memmodel/epoc/mmubase/defragbase.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kernel/eka/memmodel/epoc/mmubase/defragbase.cpp Mon Oct 19 15:55:17 2009 +0100 @@ -0,0 +1,847 @@ +// Copyright (c) 2006-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\mmubase\defragbase.cpp +// +// + +/** + @file + @internalComponent +*/ +#include +#include +#include + +#ifndef __MEMMODEL_FLEXIBLE__ +#include +#else +#include "mdefrag.inl" +#endif //__MEMMODEL_FLEXIBLE__ + +// Maximum number of times to attempt to defrag a particular zone. +const TUint KDefragMaxRetries = 5; + +const TInt KDefragIdlingThreadPriority = 27; + +Defrag* Defrag::TheDefrag = NULL; + +_LIT(KDefragDfcThreadName, "DefragDFC"); + +void Defrag::Panic(TPanic aPanic) + { + Kern::Fault("DEFRAG",aPanic); + } + + +Defrag::Defrag() + { + } + + +void Defrag::Init3(DRamAllocator* aRamAllocator) + { + TheDefrag = this; + + TInt r = Kern::DfcQInit(&iTaskQ, KDefragIdlingThreadPriority, &KDefragDfcThreadName); + if (r!=KErrNone) + Panic(EDfcQInitFailed); + + iRamAllocator = aRamAllocator; + } + + +/** +Move the movable pages in this zone into higher priority zones. + +@param aZone The zone to clear movable pages from +@param aBestEffort Set to ETrue to always keep clearing pages even if all can't +be moved or other threads allocate into the zone. +@param aRequest The request object containing the defrag parameters. +@pre RamAlloc mutex held. +@post RamAlloc mutex held. +*/ +TInt Defrag::ClearMovableFromZone(SZone& aZone, TBool aBestEffort, TRamDefragRequest* aRequest) + { + __KTRACE_OPT(KMMU, Kern::Printf("ClearMovableFromZone: ID %x ", aZone.iId)); + + TUint offset = 0; + TPhysAddr newAddr; + TBool zoneActive = EFalse; + TInt ret = iRamAllocator->NextAllocatedPage(&aZone, offset, EPageMovable); + + // if not best effort mode keep moving pages unless someone allocates into + // the zone or an unmovable page is hit. + // If in best effort mode then attempt to move all allocated pages in + // the zone regardless. + while ( aZone.iAllocPages[EPageMovable] != 0 && ret == KErrNone) + { + if (aRequest->PollForCancel()) + { + __KTRACE_OPT(KMMU, Kern::Printf("ClearMovableFromZone: cancelled")); + return KErrCancel; + } + + TPhysAddr addr = (offset << M::PageShift()) + aZone.iPhysBase; + + if (!aBestEffort && + (aZone.iAllocPages[EPageMovable] > iRamAllocator->GenDefragFreePages(EPageMovable) || + zoneActive)) + { + __KTRACE_OPT(KMMU, Kern::Printf("ClearMovableFromZone: memory too low or zone active addr %x", addr)); + return KErrNoMemory; + } + TInt moved = M::MovePage(addr, newAddr, aZone.iId, !aBestEffort); + if (moved != KErrNone) + {// Couldn't move the page so stop as we can't clear the zone + if (!aBestEffort) + { + __KTRACE_OPT(KMMU, Kern::Printf("ClearMovableFromZone exit: move fail zone %x addr %x", aZone.iId, addr)); + return moved; + } + } + // Flash RAM alloc mutex to allow other allocations + iRamAllocator->ZoneMark(aZone); + M::RamAllocUnlock(); + M::RamAllocLock(); + zoneActive = !iRamAllocator->ZoneUnmark(aZone); + offset++; + ret = iRamAllocator->NextAllocatedPage(&aZone, offset, EPageMovable); + } + __KTRACE_OPT(KMMU, Kern::Printf("ClearMovableFromZone: ret %d off %x", ret, offset)); + return KErrNone; + } + + +/** +Discard as many RAM cache pages from the specified zone as possible in one pass. +The method will return when no more pages could be discarded. + +@param aZone The zone to clear of cache pages. +@param aBestEffort Set to ETrue continue clearing the zone even if more allocations + are made into the zone or if it isn't possible to clear all the + cache pages from the zone. Otherwise set to EFalse. +@param aRequest The request object containing the defrag parameters. +@param aMaxDiscard A pointer to the maximum number of discardable pages to discard. + Set to NULL if there is no maximum. +@pre RamAlloc mutex held. +@post RamAlloc mutex held. +*/ +TInt Defrag::ClearDiscardableFromZone(SZone& aZone, TBool aBestEffort, TRamDefragRequest* aRequest, TUint* aMaxDiscard) + { + __KTRACE_OPT(KMMU, Kern::Printf("ClearDiscardableFromZone: ID %x ", aZone.iId)); + + TUint offset = 0; + TBool zoneActive = EFalse; + TInt ret = iRamAllocator->NextAllocatedPage(&aZone, offset, EPageDiscard); + + + while ( aZone.iAllocPages[EPageDiscard] != 0 && ret == KErrNone && + (!aMaxDiscard || *aMaxDiscard)) + { + if (aRequest->PollForCancel()) + { + __KTRACE_OPT(KMMU, Kern::Printf("ClearDiscardableFromZone: cancelled")); + return KErrCancel; + } + + TPhysAddr addr = aZone.iPhysBase + (offset << M::PageShift()); + + // When running is best effort mode keep clearing pages whatever. If not in + // best effort stop the defrag if can't remove all the discardable pages + // without reducing the cache beyond its minimum size or someone is + // allocating into this zone or if it is active. + if (!aBestEffort && + (iRamAllocator->GenDefragFreePages(EPageDiscard) + M::NumberOfFreeDpPages() < aZone.iAllocPages[EPageDiscard] || + zoneActive)) + { + __KTRACE_OPT(KMMU, Kern::Printf("ClearDiscardableFromZone: memory too low or zone active addr %x", addr)); + return KErrNoMemory; + } + + TInt discardRet = M::DiscardPage(addr, aZone.iId, !aBestEffort); + if (discardRet == KErrNone) + {// Page was discarded successfully. + if (aMaxDiscard) + (*aMaxDiscard)--; + } + else + { + if (!aBestEffort) + {// Page couldn't be discarded and this is a general defrag so stop. + __KTRACE_OPT(KMMU, Kern::Printf("ClearDiscardableFromZone: page discard fail addr %x r %d", addr, discardRet)); + return discardRet; + } + } + + // Give someone else ago on the RAM alloc mutex. + iRamAllocator->ZoneMark(aZone); + M::RamAllocUnlock(); + M::RamAllocLock(); + zoneActive = !iRamAllocator->ZoneUnmark(aZone); + offset++; + ret = iRamAllocator->NextAllocatedPage(&aZone, offset, EPageDiscard); + } + __KTRACE_OPT(KMMU, Kern::Printf("ClearDiscardableFromZone: ret %d off %x", ret, offset)); + return KErrNone; + } + + +/** +Attempt to remove as many pages as possible from the zone. + +If there are not enough free zones to move pages to or there are fixed pages in the zone it +will not be possible to completely clear the zone, in this case this method will return +KErrNoMemory. + +@param aZone The zone to be cleared +@param aMaxRetries The maximum number of passes to run through the zone +@param aRequest The request object containing the defrag parameters. +@return KErrNone if zone cleared, KErrNoMemory if some pages still allocated in +the zone (see above), KErrCancel if the defrag operation was cancelled. + +@pre RamAlloc mutex held. +@post RamAlloc mutex held. +*/ +TInt Defrag::ClearZone(SZone& aZone, TUint aMaxRetries, TRamDefragRequest* aRequest) + { + __KTRACE_OPT(KMMU, Kern::Printf("ClearZone ID%x retry %d", aZone.iId, aMaxRetries)); + + // Attempt to clear all pages from the zone. + // Keep retrying until no more progress is being made or the retry limit + // has been reached + TUint retryCount = 0; + for (; aZone.iPhysPages != aZone.iFreePages && + retryCount < aMaxRetries; + retryCount++) + { + TUint prevFreePages = aZone.iFreePages; + + // Discard all discardable pages in the zone + if (ClearDiscardableFromZone(aZone, ETrue, aRequest) == KErrCancel) + {// Defrag has been cancelled + return KErrCancel; + } + + // Remove all the movable pages in the zone + if (ClearMovableFromZone(aZone, ETrue, aRequest) == KErrCancel) + {// Defrag has been cancelled + return KErrCancel; + } + + if (prevFreePages >= aZone.iFreePages) + {// i.e. the number of free pages didn't increase so give up + break; + } + } + if (aZone.iPhysPages != aZone.iFreePages) + {// Zone couldn't be completely cleared + return KErrNoMemory; + } + return KErrNone; + } + + +/** +Perform a general defragmentation of the RAM zones. Attempt to clear as many +of the lowest preference zones of allocated pages as possible while still respecting +the thresholds and still allowing other allocations to occur. + +@param aRequest A TRamDefragRequest object with the iMaxPages member set to +the maximum number of pages to clear during the defrag operation. + +@return KErrNone when done, KErrCancel when the defrag was cancelled. +*/ +TInt Defrag::GeneralDefrag(TRamDefragRequest* aRequest) + { + TInt ret = KErrNone; + TUint defragCount = 0; + TUint stage = EGenDefragStage1; + + // Acquire RAM alloc mutex + M::RamAllocLock(); + + // Determine which stage the general defrag should begin at. + TUint requiredToDiscard = 0; + SZone* zone = iRamAllocator->GeneralDefragStart0((TGenDefragStage&)stage, requiredToDiscard); + + // First stage is to clear any discardable pages that are required for + // movable pages to be allocated into. + if (aRequest->iMaxPages && aRequest->iMaxPages < requiredToDiscard) + {// Can't discard the required amount of pages without hitting the + // max pages limit so no point continuing. + __KTRACE_OPT(KMMU, Kern::Printf("GeneralDefrag exit - zone %x max %x requiredToDiscard %x", + zone->iId, aRequest->iMaxPages, requiredToDiscard)); + goto exit; + } + while (zone != NULL && requiredToDiscard) + { + TUint prevRequired = requiredToDiscard; + if (ClearDiscardableFromZone(*zone, EFalse, aRequest, &requiredToDiscard) == KErrCancel) + {// Defrag cancelled + ret = KErrCancel; + goto exit; + } + defragCount += prevRequired - requiredToDiscard; + zone = iRamAllocator->GeneralDefragNextZone0(); + } + for (; stage < EGenDefragStageEnd; stage++) + { + + SZone* zone = NULL; + // Initialise the allocator for the current general defrag stage. + if (stage == EGenDefragStage1) + zone = iRamAllocator->GeneralDefragStart1(); + else + zone = iRamAllocator->GeneralDefragStart2(); + + while (zone != NULL) + { + if (zone->iAllocPages[EPageMovable] > iRamAllocator->GenDefragFreePages(EPageMovable) || + (aRequest->iMaxPages && + zone->iAllocPages[EPageMovable] + zone->iAllocPages[EPageDiscard] > aRequest->iMaxPages - defragCount)) + {// Not enough free pages in the more preferable RAM zone(s) or would hit the iMaxPages limit. + __KTRACE_OPT(KMMU, Kern::Printf("GeneralDefrag exit - zone %x max %x defrag %x", + zone->iId, aRequest->iMaxPages, + zone->iAllocPages[EPageMovable] + zone->iAllocPages[EPageDiscard] + defragCount)); + break; + } + + // Discard all discardable pages in the zone. + defragCount += zone->iAllocPages[EPageDiscard]; + if (ClearDiscardableFromZone(*zone, EFalse, aRequest) == KErrCancel) + {// Defrag cancelled + ret = KErrCancel; + goto exit; + } + if (zone->iAllocPages[EPageDiscard]) + {// Couldn't discard all the discardable pages so no point continuing. + __KTRACE_OPT(KMMU, Kern::Printf("GeneralDefrag exit - zone%x Discardable %x", zone->iId, zone->iAllocPages[EPageDiscard])); + break; + } + + // Should only have movable pages left in the zone now so shift them + // to the higher preference zones. + defragCount += zone->iAllocPages[EPageMovable]; + if (ClearMovableFromZone(*zone, EFalse, aRequest) == KErrCancel) + {// Defrag cancelled + ret = KErrCancel; + goto exit; + } + if (zone->iAllocPages[EPageMovable]) + {// Couldn't move all the movable pages so no point continuing. + __KTRACE_OPT(KMMU, Kern::Printf("GeneralDefrag exit - zone%x Movable %x", zone->iId, zone->iAllocPages[EPageMovable])); + break; + } + // Get the next RAM zone to be defraged. + if (stage == EGenDefragStage1) + zone = iRamAllocator->GeneralDefragNextZone1(); + else + zone = iRamAllocator->GeneralDefragNextZone2(); + } + } +exit: + iRamAllocator->GeneralDefragEnd(); + M::RamAllocUnlock(); + return ret; + } + + +/** +Claim a RAM zone by removing all the pages from it and then allocating it as fixed. + +This method may return the following error codes: +- KErrCancel: The call was cancelled, +- KErrArgument: The specified zone could not be found, +- KErrNoMemory: ClaimRamZone failed; there may be no free zones to move pages to, there may be fixed pages in the zone which can not be moved. + +@param aRequest A TRamDefragRequest object with the iId member set to the ID of +the zone to empty. On success the iPhysAddr member will contain the physical +base address of the zone that has been claimed. + +@return KErrNone if successful or one of the errors described above. +*/ +TInt Defrag::ClaimRamZone(TRamDefragRequest* aRequest) + { + TInt ret = KErrNoMemory; + + // Acquire RAM alloc mutex + M::RamAllocLock(); + + SZone* zone = iRamAllocator->ZoneFromId(aRequest->iId); + if (zone == NULL) + {// can't find zone + M::RamAllocUnlock(); + __KTRACE_OPT(KMMU, Kern::Printf("ClaimZone exit - no zone %x", aRequest->iId)); + return KErrArgument; + } + + // Mark the zone as restricted for future allocations + iRamAllocator->ZoneClaimStart(*zone); + + if (zone->iAllocPages[EPageUnknown] != 0) + {// Can't ever empty this zone so stop + __KTRACE_OPT(KMMU, Kern::Printf("ClaimZone exit - zone%x unk%x", zone->iId, zone->iAllocPages[EPageUnknown])); + goto exit; + } + + // Attempt to clear all pages from the zone. + ret = ClearZone(*zone, KDefragMaxRetries, aRequest); + + if (ret == KErrNone) + {// The zone is empty so claim it + __KTRACE_OPT(KMMU, Kern::Printf("ClaimZone success - zone%x", zone->iId)); +#ifdef BTRACE_RAM_ALLOCATOR + BTrace4(BTrace::ERamAllocator, BTrace::ERamAllocClaimZone, zone->iId); +#endif + +#ifdef BTRACE_KERNEL_MEMORY + TUint size = zone->iPhysPages << M::PageShift(); + BTrace8(BTrace::EKernelMemory, BTrace::EKernelMemoryDrvPhysAlloc, size, zone->iPhysBase); + Epoc::DriverAllocdPhysRam += size; +#endif + + iRamAllocator->MarkPagesAllocated(zone->iPhysBase, zone->iPhysPages, EPageFixed); + *(aRequest->iPhysAddr) = zone->iPhysBase; + ret = KErrNone; + M::RamZoneClaimed(zone); + } +exit: + // Release RAM alloc mutex and allow the zone to be allocated into + iRamAllocator->ZoneClaimEnd(*zone); + M::RamAllocUnlock(); + return ret; + } + + +/** +Empty a RAM zone by removing as many pages as possible from it. + +This method may return the following errors: +- KErrCancel: The defrag was cancelled, +- KErrArgument: The specified zone couldn't be found, +- KErrNoMemory: The zone could not be completely cleared, there may be not enough free zones to move pages to, there may be are fixed pages in the zone. + +@param aRequest A TRamDefragRequest object with the iId member set to the ID +of the zone to empty. + +@return KErrNone: Zone emptied or one of the above error codes. +*/ +TInt Defrag::EmptyRamZone(TRamDefragRequest* aRequest) + { + TInt ret = KErrNone; + + // Acquire RAM alloc mutex + M::RamAllocLock(); + + SZone* zone = iRamAllocator->ZoneFromId(aRequest->iId); + if (zone == NULL) + {// can't find zone + ret = KErrArgument; + goto exit; + } + + // Attempt to clear all the pages from the zone + ret = ClearZone(*zone, KDefragMaxRetries, aRequest); + +exit: + // Release RAM alloc mutex + M::RamAllocUnlock(); + return ret; + } + + +void Defrag::DefragTask(TAny* aArg) + { + Defrag& d = *Defrag::TheDefrag; + TRamDefragRequest* task = (TRamDefragRequest*)aArg; + + TInt r = Kern::SetThreadPriority(task->iThreadPriority, NULL); + if (r!=KErrNone) + { + task->Complete(r); + return; + } + + d.iDefragPriority = task->iThreadPriority; + + + if (task->PollForCancel()) + { + __KTRACE_OPT(KMMU, Kern::Printf("DefragTask: cancelled")); + r = KErrCancel; + goto exit; + } + + switch (task->iOp) + { + case Epoc::ERamDefrag_DefragRam: + r = d.GeneralDefrag(task); + break; + case Epoc::ERamDefrag_EmptyRamZone: + r = d.EmptyRamZone(task); + break; + case Epoc::ERamDefrag_ClaimRamZone: + r = d.ClaimRamZone(task); + break; + default: + r = KErrNotSupported; + break; + } + +exit: + task->Complete(r); + Kern::SetThreadPriority(KDefragIdlingThreadPriority, NULL); + } + +/** +Constructor for TRamDefragRequest. + +@publishedPartner +@released +*/ +EXPORT_C TRamDefragRequest::TRamDefragRequest() + : TAsyncRequest(Defrag::DefragTask, &Defrag::TheDefrag->iTaskQ, 0) + { + } + + +/** +Performs a general defragmentation of RAM. Attempts to free/move as many +pages from the lowest preference RAM zones as possible. + +@param aPriority The thread priority for the defragmentation. + TRamDefragRequest::KInheritPriority to use the priority of the caller. +@param aMaxPages The maximum number of pages to move or discard during defragmentation. + Zero implies no limit. + +@return KErrNone if successful, or KErrArgument if the parameters given are invalid. + +@publishedPartner +@released +*/ +EXPORT_C TInt TRamDefragRequest::DefragRam(TInt aPriority, TInt aMaxPages) + { + if (aMaxPages < 0 || aPriority < -1 || aPriority >= KNumPriorities) + return KErrArgument; + + iOp = Epoc::ERamDefrag_DefragRam; + iMaxPages = aMaxPages; + SetupPriority(aPriority); + return SendReceive(); + } + + +/** +Performs a general defragmentation of RAM. Attempts to free/move as many +pages from the lowest preference RAM zones as possible. +The function returns immediately. +When the operation is complete (or cancelled), aSem is signalled. + +@param aSem The fast semaphore to signal on completion of the operation. +@param aPriority The thread priority for the defragmentation. + TRamDefragRequest::KInheritPriority to use the priority of the caller. +@param aMaxPages The maximum number of pages to move or discard during defragmentation. + Zero implies no limit. + +@return KErrNone if successful, or a system-wide error code. + +@publishedPartner +@released +*/ +EXPORT_C TInt TRamDefragRequest::DefragRam(NFastSemaphore* aSem, TInt aPriority, TInt aMaxPages) + { + if (aMaxPages < 0 || !aSem || aPriority < -1 || aPriority >= KNumPriorities) + return KErrArgument; + + iOp = Epoc::ERamDefrag_DefragRam; + iMaxPages = aMaxPages; + SetupPriority(aPriority); + Send(aSem); + return KErrNone; + } + + +/** +Performs a general defragmentation of RAM. Attempts to free or move as many +pages from the lowest preference RAM zones as possible. +The function returns immediately. +When the operation is complete (or cancelled), aDfc is enqueued. + +@param aDfc The DFC to enqueue on completion of the operation. +@param aPriority The thread priority for the defragmentation. + TRamDefragRequest::KInheritPriority to use the priority of the caller. +@param aMaxPages The maximum number of pages to move or discard during defragmentation. + Zero implies no limit. + +@return KErrNone if successful, or a system-wide error code. + +@see TDfc + +@publishedPartner +@released +*/ +EXPORT_C TInt TRamDefragRequest::DefragRam(TDfc* aDfc, TInt aPriority, TInt aMaxPages) + { + if (aMaxPages < 0 || !aDfc || aPriority < -1 || aPriority >= KNumPriorities) + return KErrArgument; + + iOp = Epoc::ERamDefrag_DefragRam; + iMaxPages = aMaxPages; + SetupPriority(aPriority); + Send(aDfc); + return KErrNone; + } + + +/** +Removes as many pages from the specified RAM zone as possible. + +This method may return the following errors: +- KErrCancel: The defrag was cancelled, +- KErrArgument: The specified zone couldn't be found, or the parameters are invalid, +- KErrNoMemory: The zone could not be completely cleared, there may be not enough free zones to move pages to, there may be fixed pages in the zone. + +@param aId The ID of the RAM zone to empty. +@param aPriority The thread priority for the defragmentation. + TRamDefragRequest::KInheritPriority to use the priority of the caller. + +@return KErrNone if successful, see above for errors returned by this method. + +@publishedPartner +@released +*/ +EXPORT_C TInt TRamDefragRequest::EmptyRamZone(TUint aId, TInt aPriority) + { + if (aPriority < -1 || aPriority >= KNumPriorities) + return KErrArgument; + + iOp = Epoc::ERamDefrag_EmptyRamZone; + iId = aId; + SetupPriority(aPriority); + return SendReceive(); + } + + +/** +Removes as many pages from the specified RAM zone as possible. The function returns immediately. +When the operation is complete (or cancelled) aSem is signalled. The result of the request can +be found by calling TRamDefragRequest::Result(); the following may be returned: +- KErrCancel: The defrag was cancelled, +- KErrArgument: The specified zone couldn't be found, +- KErrNoMemory: The zone could not be completely cleared, there may be not enough free zones to move pages to, there may be fixed pages in the zone. + +@param aId The ID of the RAM zone to empty. +@param aSem The fast semaphore to signal on completion of the operation. +@param aPriority The thread priority for the defragmentation. + TRamDefragRequest::KInheritPriority to use the priority of the caller. + +@return KErrNone if request sent or KErrArgument on invalid parameters + +@see NFastSemaphore + +@publishedPartner +@released +*/ +EXPORT_C TInt TRamDefragRequest::EmptyRamZone(TUint aId, NFastSemaphore* aSem, TInt aPriority) + { + if (!aSem || aPriority < -1 || aPriority >= KNumPriorities) + return KErrArgument; + + iOp = Epoc::ERamDefrag_EmptyRamZone; + iId = aId; + SetupPriority(aPriority); + Send(aSem); + return KErrNone; + } + + +/** +Removes as many pages from the specified RAM zone as possible. The function returns immediately. +When the operation is complete (or cancelled) aDfc is enqueued. The result of the request can be +found by calling TRamDefragRequest::Result(); the following may be returned: +- KErrCancel: The defrag was cancelled, +- KErrArgument: The specified zone couldn't be found, +- KErrNoMemory: The zone could not be completely cleared, there may be not enough free zones to move pages to, there may be fixed pages in the zone. + +@param aId The ID of the RAM zone to empty. +@param aDfc The DFC to enqueue on completion of the operation. +@param aPriority The thread priority for the defragmentation. + TRamDefragRequest::KInheritPriority to use the priority of the caller. + +@return KErrNone if request sent or KErrArgument on invalid parameters + +@see TDfc + +@publishedPartner +@released +*/ +EXPORT_C TInt TRamDefragRequest::EmptyRamZone(TUint aId, TDfc* aDfc, TInt aPriority) + { + if (!aDfc || aPriority < -1 || aPriority >= KNumPriorities) + return KErrArgument; + + iOp = Epoc::ERamDefrag_EmptyRamZone; + iId = aId; + SetupPriority(aPriority); + Send(aDfc); + return KErrNone; + } + + +/** +Attempts to claim the whole of the specified RAM zone. + +This method may return the following error codes: +- KErrCancel: The call was cancelled, +- KErrArgument: aPriority was out of scope or the specified zone could not be found, +- KErrNoMemory: ClaimRamZone failed; may be no free zones to move pages to, there may be fixed pages in the zone which can not be moved. + +@param aId The ID of the RAM zone to claim. +@param aPhysAddr On success, this holds the base address of the claimed RAM zone +@param aPriority The thread priority for the defragmentation. + TRamDefragRequest::KInheritPriority to use the priority of the caller. + +@return KErrNone if successful, or a system-wide error code, see above. + +@see TPhysAddr + +@publishedPartner +@released +*/ +EXPORT_C TInt TRamDefragRequest::ClaimRamZone(TUint aId, TPhysAddr& aPhysAddr, TInt aPriority) + { + if (aPriority < -1 || aPriority >= KNumPriorities) + return KErrArgument; + + iOp = Epoc::ERamDefrag_ClaimRamZone; + iId = aId; + iPhysAddr = &aPhysAddr; + SetupPriority(aPriority); + return SendReceive(); + } + + +/** +Attempts to claim the whole of the specified RAM zone. +The function returns immediately. When the operation is complete (or cancelled) +aSem is signalled. The result of the request can be found by calling +TRamDefragRequest::Result(); the following may be returned: +- KErrNone: The zone was claimed, +- KErrCancel: The call was cancelled, +- KErrArgument: The specified zone could not be found, +- KErrNoMemory: ClaimRamZone failed; there may be no free zones to move pages to, there may be fixed pages in the zone which can not be moved. + +@param aId The ID of the RAM zone to claim. +@param aPhysAddr On success, this holds the base address of the claimed RAM zone +@param aSem The fast semaphore to signal on completion of the operation. +@param aPriority The thread priority for the defragmentation. + TRamDefragRequest::KInheritPriority to use the priority of the caller. + +@return KErrNone if the request was sent or KErrArgument if parameters were invalid. + +@see TPhysAddr +@see NFastSemaphore + +@publishedPartner +@released +*/ +EXPORT_C TInt TRamDefragRequest::ClaimRamZone(TUint aId, TPhysAddr& aPhysAddr, NFastSemaphore* aSem, TInt aPriority) + { + if (!aSem || aPriority < -1 || aPriority >= KNumPriorities) + return KErrArgument; + + iOp = Epoc::ERamDefrag_ClaimRamZone; + iId = aId; + iPhysAddr = &aPhysAddr; + SetupPriority(aPriority); + Send(aSem); + return KErrNone; + } + + +/** +Attempts to claim the whole of the specified RAM zone. The function returns immediately. +When the operation is complete (or cancelled) aDfc is enqueued. The result of the request +can be found by calling TRamDefragRequest::Result(); the following may be returned: +- KErrNone: The zone was claimed, +- KErrCancel: The call was cancelled, +- KErrArgument: The specified zone could not be found, +- KErrNoMemory: ClaimRamZone failed; there may be no free zones to move pages to, there may be fixed pages in the zone which can not be moved. + +@param aId The ID of the RAM zone to claim. +@param aPhysAddr On success, this holds the base address of the claimed RAM zone +@param aDfc The DFC to enqueue on completion of the operation. +@param aPriority The thread priority for the defragmentation. + TRamDefragRequest::KInheritPriority to use the priority of the caller. + +@return KErrNone if the request was sent or KErrArgument if parameters were invalid. + +@see TPhysAddr +@see TDfc + +@publishedPartner +@released +*/ +EXPORT_C TInt TRamDefragRequest::ClaimRamZone(TUint aId, TPhysAddr& aPhysAddr, TDfc* aDfc, TInt aPriority) + { + if (!aDfc || aPriority < -1 || aPriority >= KNumPriorities) + return KErrArgument; + + iOp = Epoc::ERamDefrag_ClaimRamZone; + iId = aId; + iPhysAddr = &aPhysAddr; + SetupPriority(aPriority); + Send(aDfc); + return KErrNone; + } + + +/** +Retrieves the result of the last request. This value is only valid if notification of +completion has been received (via DFC callback or by waiting on the semaphore). + +@return KErrNone if the last request was successful, or a system-wide error code. + +@publishedPartner +@released +*/ +EXPORT_C TInt TRamDefragRequest::Result() + { + return iResult; + } + + +/** +Cancel the request. If the operation has already started, it terminates at the +next opportunity. This function has no effect if no request has been made or if +the request has already finished. + +@publishedPartner +@released +*/ +EXPORT_C void TRamDefragRequest::Cancel() + { + TAsyncRequest::Cancel(); + } + +void TRamDefragRequest::SetupPriority(TInt aPriority) + { + if (aPriority == KInheritPriority) + iThreadPriority = NCurrentThread()->iPriority; + else + iThreadPriority = aPriority; + + const TUint KPriorityDivisor = (TUint) ((KNumPriorities + KNumDfcPriorities - 1) / KNumDfcPriorities); + SetPriority(iThreadPriority / KPriorityDivisor); + }