kernel/eka/memmodel/epoc/mmubase/defragbase.cpp
changeset 0 a41df078684a
child 22 2f92ad2dc5db
equal deleted inserted replaced
-1:000000000000 0:a41df078684a
       
     1 // Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of the License "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 // e32\memmodel\epoc\mmubase\defragbase.cpp
       
    15 // 
       
    16 //
       
    17 
       
    18 /**
       
    19  @file
       
    20  @internalComponent
       
    21 */
       
    22 #include <kernel/kern_priv.h>
       
    23 #include <defrag.h>
       
    24 #include <ramalloc.h>
       
    25 
       
    26 #ifndef __MEMMODEL_FLEXIBLE__
       
    27 #include <mmubase.inl>
       
    28 #else
       
    29 #include "mdefrag.inl"
       
    30 #endif //__MEMMODEL_FLEXIBLE__
       
    31 
       
    32 // Maximum number of times to attempt to defrag a particular zone.
       
    33 const TUint KDefragMaxRetries = 5;
       
    34 
       
    35 const TInt KDefragIdlingThreadPriority = 27;
       
    36 
       
    37 Defrag* Defrag::TheDefrag = NULL;
       
    38 
       
    39 _LIT(KDefragDfcThreadName, "DefragDFC");
       
    40 
       
    41 void Defrag::Panic(TPanic aPanic)
       
    42 	{
       
    43 	Kern::Fault("DEFRAG",aPanic);
       
    44 	}
       
    45 
       
    46 
       
    47 Defrag::Defrag()
       
    48 	{
       
    49 	}
       
    50 
       
    51 
       
    52 void Defrag::Init3(DRamAllocator* aRamAllocator)
       
    53 	{
       
    54 	TheDefrag = this;
       
    55 
       
    56 	TInt r = Kern::DfcQInit(&iTaskQ, KDefragIdlingThreadPriority, &KDefragDfcThreadName);
       
    57 	if (r!=KErrNone)
       
    58 		Panic(EDfcQInitFailed);
       
    59 
       
    60 	iRamAllocator = aRamAllocator;
       
    61 	}
       
    62 
       
    63 
       
    64 /**
       
    65 Move the movable pages in this zone into higher priority zones.
       
    66 
       
    67 @param aZone The zone to clear movable pages from
       
    68 @param aBestEffort Set to ETrue to always keep clearing pages even if all can't 
       
    69 be moved or other threads allocate into the zone.
       
    70 @param aRequest The request object containing the defrag parameters.
       
    71 @pre RamAlloc mutex held.
       
    72 @post RamAlloc mutex held.
       
    73 */
       
    74 TInt Defrag::ClearMovableFromZone(SZone& aZone, TBool aBestEffort, TRamDefragRequest* aRequest)
       
    75 	{
       
    76 	__KTRACE_OPT(KMMU, Kern::Printf("ClearMovableFromZone: ID %x ", aZone.iId));
       
    77 
       
    78 	TUint offset = 0;
       
    79 	TPhysAddr newAddr;
       
    80 	TBool zoneActive = EFalse;
       
    81 	TInt ret = iRamAllocator->NextAllocatedPage(&aZone, offset, EPageMovable);
       
    82 
       
    83 	// if not best effort mode keep moving pages unless someone allocates into 
       
    84 	// the zone or an unmovable page is hit.
       
    85 	// If in best effort mode then attempt to move all allocated pages in 
       
    86 	// the zone regardless.
       
    87 	while (	aZone.iAllocPages[EPageMovable] != 0 && ret == KErrNone) 
       
    88 		{
       
    89 		if (aRequest->PollForCancel())
       
    90 			{
       
    91 			__KTRACE_OPT(KMMU, Kern::Printf("ClearMovableFromZone: cancelled"));
       
    92 			return KErrCancel;
       
    93 			}
       
    94 		
       
    95 		TPhysAddr addr = (offset << M::PageShift()) + aZone.iPhysBase;
       
    96 
       
    97 		if (!aBestEffort && 
       
    98 			(aZone.iAllocPages[EPageMovable] > iRamAllocator->GenDefragFreePages(EPageMovable) ||
       
    99 			zoneActive))
       
   100 			{
       
   101 			__KTRACE_OPT(KMMU, Kern::Printf("ClearMovableFromZone: memory too low or zone active addr %x", addr));
       
   102 			return KErrNoMemory;
       
   103 			}
       
   104 		TInt moved = M::MovePage(addr, newAddr, aZone.iId, !aBestEffort);
       
   105 		if (moved != KErrNone)
       
   106 			{// Couldn't move the page so stop as we can't clear the zone
       
   107 			if (!aBestEffort)
       
   108 				{
       
   109 				__KTRACE_OPT(KMMU, Kern::Printf("ClearMovableFromZone exit: move fail zone %x addr %x", aZone.iId, addr));
       
   110 				return moved;
       
   111 				}
       
   112 			}
       
   113 		// Flash RAM alloc mutex to allow other allocations
       
   114 		iRamAllocator->ZoneMark(aZone);
       
   115 		M::RamAllocUnlock();
       
   116 		M::RamAllocLock();
       
   117 		zoneActive = !iRamAllocator->ZoneUnmark(aZone);
       
   118 		offset++;
       
   119 		ret = iRamAllocator->NextAllocatedPage(&aZone, offset, EPageMovable);
       
   120 		}
       
   121 	__KTRACE_OPT(KMMU, Kern::Printf("ClearMovableFromZone: ret %d off %x", ret, offset));
       
   122 	return KErrNone;
       
   123 	}
       
   124 
       
   125 
       
   126 /**
       
   127 Discard as many RAM cache pages from the specified zone as possible in one pass.
       
   128 The method will return when no more pages could be discarded.
       
   129 
       
   130 @param aZone 		The zone to clear of cache pages.
       
   131 @param aBestEffort 	Set to ETrue continue clearing the zone even if more allocations
       
   132 					are made into the zone or if it isn't possible to clear all the 
       
   133 					cache pages from the zone.  Otherwise set to EFalse.
       
   134 @param aRequest 	The request object containing the defrag parameters.
       
   135 @param aMaxDiscard	A pointer to the maximum number of discardable pages to discard.
       
   136 					Set to NULL if there is no maximum.
       
   137 @pre RamAlloc mutex held.
       
   138 @post RamAlloc mutex held.
       
   139 */
       
   140 TInt Defrag::ClearDiscardableFromZone(SZone& aZone, TBool aBestEffort, TRamDefragRequest* aRequest, TUint* aMaxDiscard)
       
   141 	{
       
   142 	__KTRACE_OPT(KMMU, Kern::Printf("ClearDiscardableFromZone: ID %x ", aZone.iId));
       
   143 
       
   144 	TUint offset = 0;
       
   145 	TBool zoneActive = EFalse;
       
   146 	TInt ret = iRamAllocator->NextAllocatedPage(&aZone, offset, EPageDiscard);
       
   147 
       
   148 
       
   149 	while (	aZone.iAllocPages[EPageDiscard] != 0 && ret == KErrNone && 
       
   150 			(!aMaxDiscard || *aMaxDiscard))
       
   151 		{
       
   152 		if (aRequest->PollForCancel())
       
   153 			{
       
   154 			__KTRACE_OPT(KMMU, Kern::Printf("ClearDiscardableFromZone: cancelled"));
       
   155 			return KErrCancel;
       
   156 			}
       
   157 
       
   158 		TPhysAddr addr = aZone.iPhysBase + (offset << M::PageShift());
       
   159 
       
   160 		// When running is best effort mode keep clearing pages whatever.  If not in 
       
   161 		// best effort stop the defrag if can't remove all the discardable pages 
       
   162 		// without reducing the cache beyond its minimum size or someone is 
       
   163 		// allocating into this zone or if it is active.
       
   164 		if (!aBestEffort && 
       
   165 			(iRamAllocator->GenDefragFreePages(EPageDiscard) + M::NumberOfFreeDpPages() < aZone.iAllocPages[EPageDiscard] ||
       
   166 			zoneActive))
       
   167 			{
       
   168 			__KTRACE_OPT(KMMU, Kern::Printf("ClearDiscardableFromZone: memory too low or zone active addr %x", addr));
       
   169 			return KErrNoMemory;
       
   170 			}
       
   171 
       
   172 		TInt discardRet = M::DiscardPage(addr, aZone.iId, !aBestEffort);
       
   173 		if (discardRet == KErrNone)
       
   174 			{// Page was discarded successfully.
       
   175 			if (aMaxDiscard)
       
   176 				(*aMaxDiscard)--;
       
   177 			}
       
   178 		else
       
   179 			{
       
   180 			if (!aBestEffort)
       
   181 				{// Page couldn't be discarded and this is a general defrag so stop.
       
   182 				__KTRACE_OPT(KMMU, Kern::Printf("ClearDiscardableFromZone: page discard fail addr %x r %d", addr, discardRet));
       
   183 				return discardRet;
       
   184 				}
       
   185 			}
       
   186 
       
   187 		// Give someone else ago on the RAM alloc mutex.
       
   188 		iRamAllocator->ZoneMark(aZone);
       
   189 		M::RamAllocUnlock();
       
   190 		M::RamAllocLock();
       
   191 		zoneActive = !iRamAllocator->ZoneUnmark(aZone);
       
   192 		offset++;
       
   193 		ret = iRamAllocator->NextAllocatedPage(&aZone, offset, EPageDiscard);
       
   194 		}
       
   195 	__KTRACE_OPT(KMMU, Kern::Printf("ClearDiscardableFromZone: ret %d off %x", ret, offset));
       
   196 	return KErrNone;
       
   197 	}
       
   198 
       
   199 
       
   200 /**
       
   201 Attempt to remove as many pages as possible from the zone.
       
   202 
       
   203 If there are not enough free zones to move pages to or there are fixed pages in the zone it 
       
   204 will not be possible to completely clear the zone, in this case this method will return 
       
   205 KErrNoMemory.
       
   206 
       
   207 @param aZone		The zone to be cleared
       
   208 @param aMaxRetries	The maximum number of passes to run through the zone
       
   209 @param aRequest		The request object containing the defrag parameters.
       
   210 @return KErrNone if zone cleared, KErrNoMemory if some pages still allocated in 
       
   211 the zone (see above), KErrCancel if the defrag operation was cancelled.
       
   212 
       
   213 @pre RamAlloc mutex held.
       
   214 @post RamAlloc mutex held.
       
   215 */
       
   216 TInt Defrag::ClearZone(SZone& aZone, TUint aMaxRetries, TRamDefragRequest* aRequest)
       
   217 	{
       
   218 	__KTRACE_OPT(KMMU, Kern::Printf("ClearZone ID%x retry %d", aZone.iId, aMaxRetries));
       
   219 
       
   220 	// Attempt to clear all pages from the zone.
       
   221 	// Keep retrying until no more progress is being made or the retry limit 
       
   222 	// has been reached
       
   223 	TUint retryCount = 0;
       
   224 	for (; 	aZone.iPhysPages != aZone.iFreePages && 
       
   225 			retryCount < aMaxRetries; 
       
   226 			retryCount++)
       
   227 		{
       
   228 		TUint prevFreePages = aZone.iFreePages;
       
   229 
       
   230 		// Discard all discardable pages in the zone
       
   231 		if (ClearDiscardableFromZone(aZone, ETrue, aRequest) == KErrCancel)
       
   232 			{// Defrag has been cancelled
       
   233 			return KErrCancel;
       
   234 			}
       
   235 
       
   236 		// Remove all the movable pages in the zone
       
   237 		if (ClearMovableFromZone(aZone, ETrue, aRequest) == KErrCancel)
       
   238 			{// Defrag has been cancelled
       
   239 			return KErrCancel;
       
   240 			}
       
   241 
       
   242 		if (prevFreePages >= aZone.iFreePages)
       
   243 			{// i.e. the number of free pages didn't increase so give up
       
   244 			break;
       
   245 			}
       
   246 		}
       
   247 	if (aZone.iPhysPages != aZone.iFreePages)
       
   248 		{// Zone couldn't be completely cleared
       
   249 		return KErrNoMemory;
       
   250 		}
       
   251 	return KErrNone;
       
   252 	}
       
   253 
       
   254 
       
   255 /**
       
   256 Perform a general defragmentation of the RAM zones.  Attempt to clear as many
       
   257 of the lowest preference zones of allocated pages as possible while still respecting
       
   258 the thresholds and still allowing other allocations to occur.
       
   259 
       
   260 @param aRequest A TRamDefragRequest object with the iMaxPages member set to 
       
   261 the maximum number of pages to clear during the defrag operation.
       
   262 
       
   263 @return KErrNone when done, KErrCancel when the defrag was cancelled.
       
   264 */
       
   265 TInt Defrag::GeneralDefrag(TRamDefragRequest* aRequest)
       
   266 	{
       
   267 	TInt ret = KErrNone;
       
   268 	TUint defragCount = 0;
       
   269 	TUint stage = EGenDefragStage1;
       
   270 
       
   271 	// Acquire RAM alloc mutex
       
   272 	M::RamAllocLock();
       
   273 
       
   274 	// Determine which stage the general defrag should begin at.
       
   275 	TUint requiredToDiscard = 0;
       
   276 	SZone* zone = iRamAllocator->GeneralDefragStart0((TGenDefragStage&)stage, requiredToDiscard);
       
   277 
       
   278 	// First stage is to clear any discardable pages that are required for
       
   279 	// movable pages to be allocated into.
       
   280 	if (aRequest->iMaxPages && aRequest->iMaxPages < requiredToDiscard)
       
   281 		{// Can't discard the required amount of pages without hitting the 
       
   282 		// max pages limit so no point continuing.
       
   283 		__KTRACE_OPT(KMMU, Kern::Printf("GeneralDefrag exit - zone %x max %x requiredToDiscard %x", 
       
   284 						zone->iId, aRequest->iMaxPages,	requiredToDiscard));
       
   285 		goto exit;
       
   286 		}
       
   287 	while (zone != NULL && requiredToDiscard)
       
   288 		{		
       
   289 		TUint prevRequired = requiredToDiscard;
       
   290 		if (ClearDiscardableFromZone(*zone, EFalse, aRequest, &requiredToDiscard) == KErrCancel)
       
   291 			{// Defrag cancelled
       
   292 			ret = KErrCancel;
       
   293 			goto exit;
       
   294 			}
       
   295 		defragCount += prevRequired - requiredToDiscard;
       
   296 		zone = iRamAllocator->GeneralDefragNextZone0();
       
   297 		}
       
   298 	for (; stage < EGenDefragStageEnd; stage++)
       
   299 		{
       
   300 
       
   301 		SZone* zone = NULL;
       
   302 		// Initialise the allocator for the current general defrag stage.
       
   303 		if (stage == EGenDefragStage1)
       
   304 			zone = iRamAllocator->GeneralDefragStart1();
       
   305 		else
       
   306 			zone = iRamAllocator->GeneralDefragStart2();
       
   307 
       
   308 		while (zone != NULL)
       
   309 			{
       
   310 			if (zone->iAllocPages[EPageMovable] > iRamAllocator->GenDefragFreePages(EPageMovable) ||
       
   311 				(aRequest->iMaxPages && 
       
   312 				zone->iAllocPages[EPageMovable] + zone->iAllocPages[EPageDiscard] > aRequest->iMaxPages - defragCount))
       
   313 				{// Not enough free pages in the more preferable RAM zone(s) or would hit the iMaxPages limit.
       
   314 				__KTRACE_OPT(KMMU, Kern::Printf("GeneralDefrag exit - zone %x max %x defrag %x", 
       
   315 								zone->iId, aRequest->iMaxPages,
       
   316 								zone->iAllocPages[EPageMovable] + zone->iAllocPages[EPageDiscard] + defragCount));
       
   317 				break;
       
   318 				}
       
   319 
       
   320 			// Discard all discardable pages in the zone.
       
   321 			defragCount += zone->iAllocPages[EPageDiscard];
       
   322 			if (ClearDiscardableFromZone(*zone, EFalse, aRequest) == KErrCancel)
       
   323 				{// Defrag cancelled
       
   324 				ret = KErrCancel;
       
   325 				goto exit;
       
   326 				}
       
   327 			if (zone->iAllocPages[EPageDiscard])
       
   328 				{// Couldn't discard all the discardable pages so no point continuing.
       
   329 				__KTRACE_OPT(KMMU, Kern::Printf("GeneralDefrag exit - zone%x Discardable %x", zone->iId, zone->iAllocPages[EPageDiscard]));
       
   330 				break;
       
   331 				}
       
   332 
       
   333 			// Should only have movable pages left in the zone now so shift them 
       
   334 			// to the higher preference zones.
       
   335 			defragCount += zone->iAllocPages[EPageMovable];
       
   336 			if (ClearMovableFromZone(*zone, EFalse, aRequest) == KErrCancel)
       
   337 				{// Defrag cancelled
       
   338 				ret = KErrCancel;
       
   339 				goto exit;
       
   340 				}
       
   341 			if (zone->iAllocPages[EPageMovable])
       
   342 				{// Couldn't move all the movable pages so no point continuing.
       
   343 				__KTRACE_OPT(KMMU, Kern::Printf("GeneralDefrag exit - zone%x Movable %x", zone->iId, zone->iAllocPages[EPageMovable]));
       
   344 				break;
       
   345 				}
       
   346 			// Get the next RAM zone to be defraged.
       
   347 			if (stage == EGenDefragStage1)
       
   348 				zone = iRamAllocator->GeneralDefragNextZone1();
       
   349 			else
       
   350 				zone = iRamAllocator->GeneralDefragNextZone2();
       
   351 			}
       
   352 		}
       
   353 exit:
       
   354 	iRamAllocator->GeneralDefragEnd();
       
   355 	M::RamAllocUnlock();
       
   356 	return ret;
       
   357 	}
       
   358 
       
   359 
       
   360 /**
       
   361 Claim a RAM zone by removing all the pages from it and then allocating it as fixed. 
       
   362 
       
   363 This method may return the following error codes:
       
   364 - KErrCancel: The call was cancelled, 
       
   365 - KErrArgument: The specified zone could not be found,
       
   366 - 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.
       
   367 
       
   368 @param aRequest A TRamDefragRequest object with the iId member set to the ID of 
       
   369 the zone to empty. On success the iPhysAddr member will contain the physical 
       
   370 base address of the zone that has been claimed.
       
   371 
       
   372 @return  KErrNone if successful or one of the errors described above.
       
   373 */
       
   374 TInt Defrag::ClaimRamZone(TRamDefragRequest* aRequest)
       
   375 	{
       
   376 	TInt ret = KErrNoMemory;
       
   377 
       
   378 	// Acquire RAM alloc mutex
       
   379 	M::RamAllocLock();
       
   380 
       
   381 	SZone* zone = iRamAllocator->ZoneFromId(aRequest->iId);
       
   382 	if (zone == NULL)
       
   383 		{// can't find zone
       
   384 		M::RamAllocUnlock();
       
   385 		__KTRACE_OPT(KMMU, Kern::Printf("ClaimZone exit - no zone %x", aRequest->iId));
       
   386 		return KErrArgument;
       
   387 		}
       
   388 	
       
   389 	// Mark the zone as restricted for future allocations
       
   390 	iRamAllocator->ZoneClaimStart(*zone);
       
   391 
       
   392 	if (zone->iAllocPages[EPageUnknown] != 0)
       
   393 		{// Can't ever empty this zone so stop
       
   394 		__KTRACE_OPT(KMMU, Kern::Printf("ClaimZone exit - zone%x unk%x", zone->iId, zone->iAllocPages[EPageUnknown]));
       
   395 		goto exit;
       
   396 		}
       
   397 
       
   398 	// Attempt to clear all pages from the zone.
       
   399 	ret = ClearZone(*zone, KDefragMaxRetries, aRequest);
       
   400 
       
   401 	if (ret == KErrNone)
       
   402 		{// The zone is empty so claim it
       
   403 		__KTRACE_OPT(KMMU, Kern::Printf("ClaimZone success - zone%x", zone->iId));
       
   404 #ifdef BTRACE_RAM_ALLOCATOR
       
   405 		BTrace4(BTrace::ERamAllocator, BTrace::ERamAllocClaimZone, zone->iId);
       
   406 #endif
       
   407 
       
   408 #ifdef BTRACE_KERNEL_MEMORY
       
   409 		TUint size = zone->iPhysPages << M::PageShift();
       
   410 		BTrace8(BTrace::EKernelMemory, BTrace::EKernelMemoryDrvPhysAlloc, size, zone->iPhysBase);
       
   411 		Epoc::DriverAllocdPhysRam += size;
       
   412 #endif
       
   413 
       
   414 		iRamAllocator->MarkPagesAllocated(zone->iPhysBase, zone->iPhysPages, EPageFixed);
       
   415 		*(aRequest->iPhysAddr) = zone->iPhysBase;
       
   416 		ret = KErrNone;
       
   417 		M::RamZoneClaimed(zone);
       
   418 		}
       
   419 exit:
       
   420 	// Release RAM alloc mutex and allow the zone to be allocated into
       
   421 	iRamAllocator->ZoneClaimEnd(*zone);
       
   422 	M::RamAllocUnlock();
       
   423 	return ret;
       
   424 	}
       
   425 
       
   426 
       
   427 /**
       
   428 Empty a RAM zone by removing as many pages as possible from it.
       
   429 
       
   430 This method may return the following errors:
       
   431 - KErrCancel: The defrag was cancelled, 
       
   432 - KErrArgument: The specified zone couldn't be found,
       
   433 - 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.
       
   434 
       
   435 @param aRequest A TRamDefragRequest object with the iId member set to the ID 
       
   436 of the zone to empty.
       
   437 
       
   438 @return KErrNone: Zone emptied or one of the above error codes.
       
   439 */
       
   440 TInt Defrag::EmptyRamZone(TRamDefragRequest* aRequest)
       
   441 	{
       
   442 	TInt ret = KErrNone;
       
   443 
       
   444 	// Acquire RAM alloc mutex
       
   445 	M::RamAllocLock();
       
   446 
       
   447 	SZone* zone = iRamAllocator->ZoneFromId(aRequest->iId);
       
   448 	if (zone == NULL)
       
   449 		{// can't find zone
       
   450 		ret = KErrArgument;
       
   451 		goto exit;
       
   452 		}
       
   453 
       
   454 	// Attempt to clear all the pages from the zone
       
   455 	ret = ClearZone(*zone, KDefragMaxRetries, aRequest);
       
   456 
       
   457 exit:
       
   458 	// Release RAM alloc mutex
       
   459 	M::RamAllocUnlock();
       
   460 	return ret;
       
   461 	}
       
   462 
       
   463 
       
   464 void Defrag::DefragTask(TAny* aArg)
       
   465 	{
       
   466 	Defrag& d = *Defrag::TheDefrag;
       
   467 	TRamDefragRequest* task = (TRamDefragRequest*)aArg;
       
   468 
       
   469 	TInt r = Kern::SetThreadPriority(task->iThreadPriority, NULL);
       
   470 	if (r!=KErrNone)
       
   471 		{
       
   472 		task->Complete(r);
       
   473 		return;
       
   474 		}
       
   475 	
       
   476 	d.iDefragPriority = task->iThreadPriority;
       
   477 
       
   478 
       
   479 	if (task->PollForCancel())
       
   480 		{
       
   481 		__KTRACE_OPT(KMMU, Kern::Printf("DefragTask: cancelled"));
       
   482 		r = KErrCancel;
       
   483 		goto exit;
       
   484 		}
       
   485 
       
   486 	switch (task->iOp)
       
   487 		{
       
   488 	case Epoc::ERamDefrag_DefragRam:
       
   489 		r = d.GeneralDefrag(task);
       
   490 		break;
       
   491 	case Epoc::ERamDefrag_EmptyRamZone:
       
   492 		r = d.EmptyRamZone(task);
       
   493 		break;
       
   494 	case Epoc::ERamDefrag_ClaimRamZone:
       
   495 		r = d.ClaimRamZone(task);
       
   496 		break;
       
   497 	default:
       
   498 		r = KErrNotSupported;
       
   499 		break;
       
   500 		}
       
   501 
       
   502 exit:
       
   503 	task->Complete(r);
       
   504 	Kern::SetThreadPriority(KDefragIdlingThreadPriority, NULL);
       
   505 	}
       
   506 
       
   507 /**
       
   508 Constructor for TRamDefragRequest.
       
   509 
       
   510 @publishedPartner
       
   511 @released
       
   512 */
       
   513 EXPORT_C TRamDefragRequest::TRamDefragRequest()
       
   514 	: TAsyncRequest(Defrag::DefragTask, &Defrag::TheDefrag->iTaskQ, 0)
       
   515 	{
       
   516 	}
       
   517 
       
   518 
       
   519 /**
       
   520 Performs a general defragmentation of RAM. Attempts to free/move as many
       
   521 pages from the lowest preference RAM zones as possible.
       
   522 
       
   523 @param aPriority	The thread priority for the defragmentation.
       
   524 					TRamDefragRequest::KInheritPriority to use the priority of the caller.
       
   525 @param aMaxPages 	The maximum number of pages to move or discard during defragmentation. 
       
   526 					Zero implies no limit.
       
   527 
       
   528 @return KErrNone if successful, or KErrArgument if the parameters given are invalid.
       
   529 
       
   530 @publishedPartner
       
   531 @released
       
   532 */
       
   533 EXPORT_C TInt TRamDefragRequest::DefragRam(TInt aPriority, TInt aMaxPages)
       
   534 	{
       
   535 	if (aMaxPages < 0 || aPriority < -1 || aPriority >= KNumPriorities)
       
   536 		return KErrArgument;
       
   537 	
       
   538 	iOp = Epoc::ERamDefrag_DefragRam;
       
   539 	iMaxPages = aMaxPages;
       
   540 	SetupPriority(aPriority);
       
   541 	return SendReceive();
       
   542 	}
       
   543 
       
   544 
       
   545 /**
       
   546 Performs a general defragmentation of RAM. Attempts to free/move as many
       
   547 pages from the lowest preference RAM zones as possible. 
       
   548 The function returns immediately.
       
   549 When the operation is complete (or cancelled), aSem is signalled.
       
   550 
       
   551 @param aSem			The fast semaphore to signal on completion of the operation.
       
   552 @param aPriority	The thread priority for the defragmentation.
       
   553 					TRamDefragRequest::KInheritPriority to use the priority of the caller.
       
   554 @param aMaxPages 	The maximum number of pages to move or discard during defragmentation. 
       
   555 					Zero implies no limit.
       
   556 
       
   557 @return KErrNone if successful, or a system-wide error code.
       
   558 
       
   559 @publishedPartner
       
   560 @released
       
   561 */
       
   562 EXPORT_C TInt TRamDefragRequest::DefragRam(NFastSemaphore* aSem, TInt aPriority, TInt aMaxPages)
       
   563 	{
       
   564 	if (aMaxPages < 0 || !aSem || aPriority < -1 || aPriority >= KNumPriorities)
       
   565 		return KErrArgument;
       
   566 	
       
   567 	iOp = Epoc::ERamDefrag_DefragRam;
       
   568 	iMaxPages = aMaxPages;
       
   569 	SetupPriority(aPriority);
       
   570 	Send(aSem);
       
   571 	return KErrNone;
       
   572 	}
       
   573 
       
   574 
       
   575 /**
       
   576 Performs a general defragmentation of RAM. Attempts to free or move as many
       
   577 pages from the lowest preference RAM zones as possible. 
       
   578 The function returns immediately.
       
   579 When the operation is complete (or cancelled), aDfc is enqueued.
       
   580 
       
   581 @param aDfc			The DFC to enqueue on completion of the operation.
       
   582 @param aPriority	The thread priority for the defragmentation.
       
   583 					TRamDefragRequest::KInheritPriority to use the priority of the caller.
       
   584 @param aMaxPages 	The maximum number of pages to move or discard during defragmentation. 
       
   585 					Zero implies no limit.
       
   586 
       
   587 @return KErrNone if successful, or a system-wide error code.
       
   588 
       
   589 @see TDfc
       
   590 
       
   591 @publishedPartner
       
   592 @released
       
   593 */
       
   594 EXPORT_C TInt TRamDefragRequest::DefragRam(TDfc* aDfc, TInt aPriority, TInt aMaxPages)
       
   595 	{
       
   596 	if (aMaxPages < 0 || !aDfc || aPriority < -1 || aPriority >= KNumPriorities)
       
   597 		return KErrArgument;
       
   598 	
       
   599 	iOp = Epoc::ERamDefrag_DefragRam;
       
   600 	iMaxPages = aMaxPages;
       
   601 	SetupPriority(aPriority);
       
   602 	Send(aDfc);
       
   603 	return KErrNone;
       
   604 	}
       
   605 
       
   606 
       
   607 /**
       
   608 Removes as many pages from the specified RAM zone as possible.
       
   609 
       
   610 This method may return the following errors:
       
   611 - KErrCancel: The defrag was cancelled, 
       
   612 - KErrArgument: The specified zone couldn't be found, or the parameters are invalid,
       
   613 - 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.
       
   614 
       
   615 @param aId			The ID of the RAM zone to empty.
       
   616 @param aPriority	The thread priority for the defragmentation.
       
   617 					TRamDefragRequest::KInheritPriority to use the priority of the caller.
       
   618 
       
   619 @return KErrNone if successful, see above for errors returned by this method.
       
   620 
       
   621 @publishedPartner
       
   622 @released
       
   623 */
       
   624 EXPORT_C TInt TRamDefragRequest::EmptyRamZone(TUint aId, TInt aPriority)
       
   625 	{
       
   626 	if (aPriority < -1 || aPriority >= KNumPriorities)
       
   627 		return KErrArgument;
       
   628 	
       
   629 	iOp = Epoc::ERamDefrag_EmptyRamZone;
       
   630 	iId = aId;
       
   631 	SetupPriority(aPriority);
       
   632 	return SendReceive();
       
   633 	}
       
   634 
       
   635 
       
   636 /**
       
   637 Removes as many pages from the specified RAM zone as possible. The function returns immediately. 
       
   638 When the operation is complete (or cancelled) aSem is signalled. The result of the request can 
       
   639 be found by calling TRamDefragRequest::Result(); the following may be returned:
       
   640 - KErrCancel: The defrag was cancelled, 
       
   641 - KErrArgument: The specified zone couldn't be found,
       
   642 - 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.
       
   643 
       
   644 @param aId			The ID of the RAM zone to empty.
       
   645 @param aSem			The fast semaphore to signal on completion of the operation.
       
   646 @param aPriority	The thread priority for the defragmentation.
       
   647 					TRamDefragRequest::KInheritPriority to use the priority of the caller.
       
   648 
       
   649 @return KErrNone if request sent or KErrArgument on invalid parameters
       
   650 
       
   651 @see NFastSemaphore
       
   652 
       
   653 @publishedPartner
       
   654 @released
       
   655 */
       
   656 EXPORT_C TInt TRamDefragRequest::EmptyRamZone(TUint aId, NFastSemaphore* aSem, TInt aPriority)
       
   657 	{
       
   658 	if (!aSem || aPriority < -1 || aPriority >= KNumPriorities)
       
   659 		return KErrArgument;
       
   660 	
       
   661 	iOp = Epoc::ERamDefrag_EmptyRamZone;
       
   662 	iId = aId;
       
   663 	SetupPriority(aPriority);
       
   664 	Send(aSem);
       
   665 	return KErrNone;
       
   666 	}
       
   667 
       
   668 
       
   669 /**
       
   670 Removes as many pages from the specified RAM zone as possible. The function returns immediately.
       
   671 When the operation is complete (or cancelled) aDfc is enqueued. The result of the request can be 
       
   672 found by calling TRamDefragRequest::Result(); the following may be returned:
       
   673 - KErrCancel: The defrag was cancelled, 
       
   674 - KErrArgument: The specified zone couldn't be found,
       
   675 - 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.
       
   676 
       
   677 @param aId			The ID of the RAM zone to empty.
       
   678 @param aDfc			The DFC to enqueue on completion of the operation.
       
   679 @param aPriority	The thread priority for the defragmentation.
       
   680 					TRamDefragRequest::KInheritPriority to use the priority of the caller.
       
   681 
       
   682 @return KErrNone if request sent or KErrArgument on invalid parameters
       
   683 
       
   684 @see TDfc
       
   685 
       
   686 @publishedPartner
       
   687 @released
       
   688 */
       
   689 EXPORT_C TInt TRamDefragRequest::EmptyRamZone(TUint aId, TDfc* aDfc, TInt aPriority)
       
   690 	{
       
   691 	if (!aDfc || aPriority < -1 || aPriority >= KNumPriorities)
       
   692 		return KErrArgument;
       
   693 	
       
   694 	iOp = Epoc::ERamDefrag_EmptyRamZone;
       
   695 	iId = aId;
       
   696 	SetupPriority(aPriority);
       
   697 	Send(aDfc);
       
   698 	return KErrNone;
       
   699 	}
       
   700 
       
   701 
       
   702 /**
       
   703 Attempts to claim the whole of the specified RAM zone.
       
   704 
       
   705 This method may return the following error codes:
       
   706 - KErrCancel: The call was cancelled, 
       
   707 - KErrArgument: aPriority was out of scope or the specified zone could not be found,
       
   708 - 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.
       
   709 
       
   710 @param aId			The ID of the RAM zone to claim.
       
   711 @param aPhysAddr	On success, this holds the base address of the claimed RAM zone
       
   712 @param aPriority	The thread priority for the defragmentation.
       
   713 					TRamDefragRequest::KInheritPriority to use the priority of the caller.
       
   714 
       
   715 @return KErrNone if successful, or a system-wide error code, see above.
       
   716 
       
   717 @see TPhysAddr
       
   718 
       
   719 @publishedPartner
       
   720 @released
       
   721 */
       
   722 EXPORT_C TInt TRamDefragRequest::ClaimRamZone(TUint aId, TPhysAddr& aPhysAddr, TInt aPriority)
       
   723 	{
       
   724 	if (aPriority < -1 || aPriority >= KNumPriorities)
       
   725 		return KErrArgument;
       
   726 	
       
   727 	iOp = Epoc::ERamDefrag_ClaimRamZone;
       
   728 	iId = aId;
       
   729 	iPhysAddr = &aPhysAddr;
       
   730 	SetupPriority(aPriority);
       
   731 	return SendReceive();
       
   732 	}
       
   733 
       
   734 
       
   735 /**
       
   736 Attempts to claim the whole of the specified RAM zone. 
       
   737 The function returns immediately. When the operation is complete (or cancelled) 
       
   738 aSem is signalled. The result of the request can be found by calling 
       
   739 TRamDefragRequest::Result(); the following may be returned:
       
   740 - KErrNone: The zone was claimed,
       
   741 - KErrCancel: The call was cancelled, 
       
   742 - KErrArgument: The specified zone could not be found,
       
   743 - 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.
       
   744 
       
   745 @param aId			The ID of the RAM zone to claim.
       
   746 @param aPhysAddr	On success, this holds the base address of the claimed RAM zone
       
   747 @param aSem			The fast semaphore to signal on completion of the operation.
       
   748 @param aPriority	The thread priority for the defragmentation.
       
   749 					TRamDefragRequest::KInheritPriority to use the priority of the caller.
       
   750 
       
   751 @return KErrNone if the request was sent or KErrArgument if parameters were invalid.
       
   752 
       
   753 @see TPhysAddr
       
   754 @see NFastSemaphore
       
   755 
       
   756 @publishedPartner
       
   757 @released
       
   758 */
       
   759 EXPORT_C TInt TRamDefragRequest::ClaimRamZone(TUint aId, TPhysAddr& aPhysAddr, NFastSemaphore* aSem, TInt aPriority)
       
   760 	{
       
   761 	if (!aSem || aPriority < -1 || aPriority >= KNumPriorities)
       
   762 		return KErrArgument;
       
   763 	
       
   764 	iOp = Epoc::ERamDefrag_ClaimRamZone;
       
   765 	iId = aId;
       
   766 	iPhysAddr = &aPhysAddr;
       
   767 	SetupPriority(aPriority);
       
   768 	Send(aSem);
       
   769 	return KErrNone;
       
   770 	}
       
   771 
       
   772 
       
   773 /**
       
   774 Attempts to claim the whole of the specified RAM zone. The function returns immediately.
       
   775 When the operation is complete (or cancelled) aDfc is enqueued. The result of the request 
       
   776 can be found by calling TRamDefragRequest::Result(); the following may be returned:
       
   777 - KErrNone: The zone was claimed,
       
   778 - KErrCancel: The call was cancelled, 
       
   779 - KErrArgument: The specified zone could not be found,
       
   780 - 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.
       
   781 
       
   782 @param aId			The ID of the RAM zone to claim.
       
   783 @param aPhysAddr	On success, this holds the base address of the claimed RAM zone
       
   784 @param aDfc			The DFC to enqueue on completion of the operation.
       
   785 @param aPriority	The thread priority for the defragmentation.
       
   786 					TRamDefragRequest::KInheritPriority to use the priority of the caller.
       
   787 
       
   788 @return KErrNone if the request was sent or KErrArgument if parameters were invalid.
       
   789 
       
   790 @see TPhysAddr
       
   791 @see TDfc
       
   792 
       
   793 @publishedPartner
       
   794 @released
       
   795 */
       
   796 EXPORT_C TInt TRamDefragRequest::ClaimRamZone(TUint aId, TPhysAddr& aPhysAddr, TDfc* aDfc, TInt aPriority)
       
   797 	{
       
   798 	if (!aDfc || aPriority < -1 || aPriority >= KNumPriorities)
       
   799 		return KErrArgument;
       
   800 	
       
   801 	iOp = Epoc::ERamDefrag_ClaimRamZone;
       
   802 	iId = aId;
       
   803 	iPhysAddr = &aPhysAddr;
       
   804 	SetupPriority(aPriority);
       
   805 	Send(aDfc);
       
   806 	return KErrNone;
       
   807 	}
       
   808 
       
   809 
       
   810 /**
       
   811 Retrieves the result of the last request. This value is only valid if notification of
       
   812 completion has been received (via DFC callback or by waiting on the semaphore).
       
   813 
       
   814 @return KErrNone if the last request was successful, or a system-wide error code.
       
   815 
       
   816 @publishedPartner
       
   817 @released
       
   818 */
       
   819 EXPORT_C TInt TRamDefragRequest::Result()
       
   820 	{
       
   821 	return iResult;
       
   822 	}
       
   823 
       
   824 
       
   825 /**
       
   826 Cancel the request. If the operation has already started, it terminates at the
       
   827 next opportunity. This function has no effect if no request has been made or if 
       
   828 the request has already finished.
       
   829 
       
   830 @publishedPartner
       
   831 @released
       
   832 */
       
   833 EXPORT_C void TRamDefragRequest::Cancel()
       
   834 	{
       
   835 	TAsyncRequest::Cancel();
       
   836 	}
       
   837 
       
   838 void TRamDefragRequest::SetupPriority(TInt aPriority)
       
   839 	{
       
   840 	if (aPriority == KInheritPriority)
       
   841 		iThreadPriority = NCurrentThread()->iPriority;
       
   842 	else
       
   843 		iThreadPriority = aPriority;
       
   844 
       
   845 	const TUint KPriorityDivisor = (TUint) ((KNumPriorities + KNumDfcPriorities - 1) / KNumDfcPriorities);
       
   846 	SetPriority(iThreadPriority / KPriorityDivisor);
       
   847 	}