|
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 } |