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