65 /// Note that this does not always correspond to the state of the page in RAM - for example a |
65 /// Note that this does not always correspond to the state of the page in RAM - for example a |
66 /// page can be dirty in RAM but blank in swap if it has never been written out. |
66 /// page can be dirty in RAM but blank in swap if it has never been written out. |
67 enum TSwapState |
67 enum TSwapState |
68 { |
68 { |
69 EStateUnreserved = 0, ///< swap space not yet reserved, or page is being decommitted |
69 EStateUnreserved = 0, ///< swap space not yet reserved, or page is being decommitted |
70 EStateBlank = 1, ///< swap page has never been written or the last write failed |
70 EStateBlank = 1, ///< swap page has never been written |
71 EStateWritten = 2, ///< swap page has been written out at least once |
71 EStateWritten = 2, ///< swap page has been written out at least once |
72 EStateWriting = 3 ///< swap page is in the process of being written out |
72 EStateWriting = 3 ///< swap page is in the process of being written out |
73 }; |
73 }; |
74 |
74 |
75 enum |
75 enum |
155 private: |
155 private: |
156 TInt WritePages(DMemoryObject** aMemory, TUint* aIndex, TPhysAddr* aPages, TUint aCount, DPageWriteRequest *aRequest, TBool aAnyExecutable, TBool aBackground); |
156 TInt WritePages(DMemoryObject** aMemory, TUint* aIndex, TPhysAddr* aPages, TUint aCount, DPageWriteRequest *aRequest, TBool aAnyExecutable, TBool aBackground); |
157 |
157 |
158 private: |
158 private: |
159 /** |
159 /** |
160 The paging device used for accessing the backing store. |
160 The paging device used for accessing the backing store. |
161 This is set by #InstallPagingDevice. |
161 This is set by #InstallPagingDevice. |
162 */ |
162 */ |
163 DPagingDevice* iDevice; |
163 DPagingDevice* iDevice; |
164 |
164 |
165 /** |
165 /** |
166 The instance of #DSwapManager being used by this manager. |
166 The instance of #DSwapManager being used by this manager. |
167 */ |
167 */ |
168 DSwapManager* iSwapManager; |
168 DSwapManager* iSwapManager; |
169 |
169 |
170 /** |
170 /** |
171 Whether to read and write pages by physical address without mapping them first. |
171 Whether to read and write pages by physical address without mapping them first. |
172 |
172 |
173 Set if the paging media driver supports it. |
173 Set if the paging media driver supports it. |
174 */ |
174 */ |
175 TBool iUsePhysicalAccess; |
175 TBool iUsePhysicalAccess; |
176 |
176 |
177 public: |
177 public: |
178 /** |
178 /** |
179 The single instance of this manager class. |
179 The single instance of this manager class. |
180 */ |
180 */ |
181 static DDataPagedMemoryManager TheManager; |
181 static DDataPagedMemoryManager TheManager; |
182 }; |
182 }; |
183 |
183 |
184 |
184 |
185 DDataPagedMemoryManager DDataPagedMemoryManager::TheManager; |
185 DDataPagedMemoryManager DDataPagedMemoryManager::TheManager; |
186 DPagedMemoryManager* TheDataPagedMemoryManager = &DDataPagedMemoryManager::TheManager; |
186 DPagedMemoryManager* TheDataPagedMemoryManager = &DDataPagedMemoryManager::TheManager; |
187 |
187 |
188 |
188 |
189 /** |
189 /** |
190 Create a swap manager. |
190 Create a swap manager. |
191 |
191 |
192 @param aDevice The demand paging device for access to the swap. |
192 @param aDevice The demand paging device for access to the swap. |
193 */ |
193 */ |
194 TInt DSwapManager::Create(DPagingDevice* aDevice) |
194 TInt DSwapManager::Create(DPagingDevice* aDevice) |
195 { |
195 { |
196 __ASSERT_COMPILE(!(ESwapIndexMask & ESwapStateMask)); |
196 __ASSERT_COMPILE(!(ESwapIndexMask & ESwapStateMask)); |
197 __NK_ASSERT_DEBUG(iDevice == NULL); |
197 __NK_ASSERT_DEBUG(iDevice == NULL); |
242 } |
242 } |
243 |
243 |
244 |
244 |
245 inline TUint DSwapManager::SwapData(TSwapState aSwapState, TInt aSwapIndex) |
245 inline TUint DSwapManager::SwapData(TSwapState aSwapState, TInt aSwapIndex) |
246 { |
246 { |
247 __NK_ASSERT_DEBUG(aSwapIndex < (1 << (32 - ESwapIndexShift))); |
|
248 return (aSwapIndex << ESwapIndexShift) | aSwapState; |
247 return (aSwapIndex << ESwapIndexShift) | aSwapState; |
249 } |
248 } |
250 |
249 |
251 |
250 |
252 /** |
251 /** |
253 Allocate one or more page's worth of space within the swap area. |
252 Allocate one or more page's worth of space within the swap area. |
254 |
253 |
255 The location is represented by a page-based index into the swap area. |
254 The location is represented by a page-based index into the swap area. |
256 |
255 |
257 @param aCount The number of page's worth of space to allocate. |
256 @param aCount The number of page's worth of space to allocate. |
258 |
257 |
259 @return The swap index of the first location allocated. |
258 @return The swap index of the first location allocated. |
260 */ |
259 */ |
261 TInt DSwapManager::AllocSwapIndex(TUint aCount) |
260 TInt DSwapManager::AllocSwapIndex(TUint aCount) |
262 { |
261 { |
263 TRACE2(("DSwapManager::AllocSwapIndex %d", aCount)); |
262 TRACE2(("DSwapManager::AllocSwapIndex %d", aCount)); |
264 |
263 |
327 NKern::FMSignal(&iSwapLock); |
326 NKern::FMSignal(&iSwapLock); |
328 } |
327 } |
329 |
328 |
330 |
329 |
331 /** |
330 /** |
332 Reserve some swap pages for the requested region of the memory object |
331 Reserve some swap pages for the requested region of the memory object |
333 |
332 |
334 @param aMemory The memory object to reserve pages for. |
333 @param aMemory The memory object to reserve pages for. |
335 @param aStartIndex The page index in the memory object of the start of the region. |
334 @param aStartIndex The page index in the memory object of the start of the region. |
336 @param aPageCount The number of pages to reserve. |
335 @param aPageCount The number of pages to reserve. |
337 |
336 |
338 @return KErrNone on success, KErrNoMemory if not enough swap space available. |
337 @return KErrNone on success, KErrNoMemory if not enough swap space available. |
339 @pre aMemory's lock is held. |
338 @pre aMemory's lock is held. |
340 @post aMemory's lock is held. |
339 @post aMemory's lock is held. |
341 */ |
340 */ |
342 TInt DSwapManager::ReserveSwap(DMemoryObject* aMemory, TUint aStartIndex, TUint aPageCount) |
341 TInt DSwapManager::ReserveSwap(DMemoryObject* aMemory, TUint aStartIndex, TUint aPageCount) |
343 { |
342 { |
344 __NK_ASSERT_DEBUG(MemoryObjectLock::IsHeld(aMemory)); |
343 __NK_ASSERT_DEBUG(MemoryObjectLock::IsHeld(aMemory)); |
345 |
344 |
368 return KErrNone; |
367 return KErrNone; |
369 } |
368 } |
370 |
369 |
371 |
370 |
372 /** |
371 /** |
373 Unreserve swap pages for the requested region of the memory object. |
372 Unreserve swap pages for the requested region of the memory object. |
374 |
373 |
375 @param aMemory The memory object to unreserve pages for. |
374 @param aMemory The memory object to unreserve pages for. |
376 @param aStartIndex The page index in the memory object of the start of the region. |
375 @param aStartIndex The page index in the memory object of the start of the region. |
377 @param aPageCount The number of pages to unreserve. |
376 @param aPageCount The number of pages to unreserve. |
378 |
377 |
379 @return The number of pages freed. |
378 @return The number of pages freed. |
380 @pre aMemory's lock is held. |
379 @pre aMemory's lock is held. |
381 @post aMemory's lock is held. |
380 @post aMemory's lock is held. |
382 */ |
381 */ |
383 TInt DSwapManager::UnreserveSwap(DMemoryObject* aMemory, TUint aStartIndex, TUint aPageCount) |
382 TInt DSwapManager::UnreserveSwap(DMemoryObject* aMemory, TUint aStartIndex, TUint aPageCount) |
384 { |
383 { |
385 __NK_ASSERT_DEBUG(MemoryObjectLock::IsHeld(aMemory)); |
384 __NK_ASSERT_DEBUG(MemoryObjectLock::IsHeld(aMemory)); |
386 |
385 |
423 return freedPages; |
422 return freedPages; |
424 } |
423 } |
425 |
424 |
426 |
425 |
427 /** |
426 /** |
428 Determine whether the specified pages in the memory object have swap reserved for them. |
427 Determine whether the specified pages in the memory object have swap reserved for them. |
429 |
428 |
430 @param aMemory The memory object that owns the pages. |
429 @param aMemory The memory object that owns the pages. |
431 @param aStartIndex The first index of the pages to check. |
430 @param aStartIndex The first index of the pages to check. |
432 @param aPageCount The number of pages to check. |
431 @param aPageCount The number of pages to check. |
433 |
432 |
434 @return ETrue if swap is reserved for all the pages, EFalse otherwise. |
433 @return ETrue if swap is reserved for all the pages, EFalse otherwise. |
435 */ |
434 */ |
436 TBool DSwapManager::IsReserved(DMemoryObject* aMemory, TUint aStartIndex, TUint aPageCount) |
435 TBool DSwapManager::IsReserved(DMemoryObject* aMemory, TUint aStartIndex, TUint aPageCount) |
437 {// MmuLock required to protect manager data. |
436 {// MmuLock required to protect manager data. |
438 __NK_ASSERT_DEBUG(MmuLock::IsHeld()); |
437 __NK_ASSERT_DEBUG(MmuLock::IsHeld()); |
439 __NK_ASSERT_DEBUG(aStartIndex < aMemory->iSizeInPages); |
438 __NK_ASSERT_DEBUG(aStartIndex < aMemory->iSizeInPages); |
450 return ETrue; |
449 return ETrue; |
451 } |
450 } |
452 |
451 |
453 |
452 |
454 /** |
453 /** |
455 Read from the swap the specified pages associated with the memory object. |
454 Read from the swap the specified pages associated with the memory object. |
456 |
455 |
457 @param aMemory The memory object to read the pages for |
456 @param aMemory The memory object to read the pages for |
458 @param aIndex The index of the first page within the memory object. |
457 @param aIndex The index of the first page within the memory object. |
459 @param aCount The number of pages to read. |
458 @param aCount The number of pages to read. |
460 @param aLinAddr The address to copy the pages to. |
459 @param aLinAddr The address to copy the pages to. |
461 @param aRequest The request to use for the read. |
460 @param aRequest The request to use for the read. |
462 @param aPhysAddrs An array of the physical addresses for each page to read in. |
461 @param aPhysAddrs An array of the physical addresses for each page to read in. |
463 */ |
462 */ |
464 TInt DSwapManager::ReadSwapPages(DMemoryObject* aMemory, TUint aIndex, TUint aCount, TLinAddr aLinAddr, TPhysAddr* aPhysAddrs) |
463 TInt DSwapManager::ReadSwapPages(DMemoryObject* aMemory, TUint aIndex, TUint aCount, TLinAddr aLinAddr, TPhysAddr* aPhysAddrs) |
465 { |
464 { |
466 __ASSERT_CRITICAL; |
465 __ASSERT_CRITICAL; |
467 |
466 |
|
467 TInt r = KErrNone; |
468 const TUint readUnitShift = iDevice->iReadUnitShift; |
468 const TUint readUnitShift = iDevice->iReadUnitShift; |
469 TUint readSize = KPageSize >> readUnitShift; |
469 TUint readSize = KPageSize >> readUnitShift; |
470 TThreadMessage message; |
470 TThreadMessage message; |
471 |
471 |
472 const TUint indexEnd = aIndex + aCount; |
472 const TUint indexEnd = aIndex + aCount; |
475 START_PAGING_BENCHMARK; |
475 START_PAGING_BENCHMARK; |
476 |
476 |
477 MmuLock::Lock(); // MmuLock required for atomic access to manager data. |
477 MmuLock::Lock(); // MmuLock required for atomic access to manager data. |
478 TUint swapData = aMemory->PagingManagerData(index); |
478 TUint swapData = aMemory->PagingManagerData(index); |
479 TSwapState state = SwapState(swapData); |
479 TSwapState state = SwapState(swapData); |
480 TUint swapPage = SwapIndex(swapData); |
|
481 |
480 |
482 if (state == EStateUnreserved) |
481 if (state == EStateUnreserved) |
483 { |
482 {// This page is not committed to the memory object |
484 // This page is not committed to the memory object |
|
485 MmuLock::Unlock(); |
483 MmuLock::Unlock(); |
486 return KErrNotFound; |
484 return KErrNotFound; |
487 } |
485 } |
488 else if (state == EStateBlank) |
486 else if (state == EStateBlank) |
489 { |
487 {// This page has not been written to yet so don't read from swap |
490 if (swapPage != 0) |
488 // just wipe it if required. |
|
489 TUint allocFlags = aMemory->RamAllocFlags(); |
|
490 MmuLock::Unlock(); |
|
491 TBool wipePages = !(allocFlags & Mmu::EAllocNoWipe); |
|
492 if (wipePages) |
491 { |
493 { |
492 // An error occured while writing the page out, so report it now |
494 TUint8 wipeByte = (allocFlags & Mmu::EAllocUseCustomWipeByte) ? |
493 MmuLock::Unlock(); |
495 (allocFlags >> Mmu::EAllocWipeByteShift) & 0xff : |
494 return -swapPage; |
496 0x03; |
495 } |
497 memset((TAny*)aLinAddr, wipeByte, KPageSize); |
496 else |
|
497 { |
|
498 // This page has not been written to yet so don't read from swap |
|
499 // just wipe it if required. |
|
500 TUint allocFlags = aMemory->RamAllocFlags(); |
|
501 MmuLock::Unlock(); |
|
502 TBool wipePages = !(allocFlags & Mmu::EAllocNoWipe); |
|
503 if (wipePages) |
|
504 { |
|
505 TUint8 wipeByte = (allocFlags & Mmu::EAllocUseCustomWipeByte) ? |
|
506 (allocFlags >> Mmu::EAllocWipeByteShift) & 0xff : |
|
507 0x03; |
|
508 memset((TAny*)aLinAddr, wipeByte, KPageSize); |
|
509 } |
|
510 } |
498 } |
511 } |
499 } |
512 else |
500 else |
513 { |
501 { |
514 // It is not possible to get here if the page is in state EStateWriting as if so it must |
502 // It is not possible to get here if the page is in state EStateWriting as if so it must |
516 __NK_ASSERT_DEBUG(state == EStateWritten); |
504 __NK_ASSERT_DEBUG(state == EStateWritten); |
517 |
505 |
518 // OK to release as if the object's data is decommitted the pager |
506 // OK to release as if the object's data is decommitted the pager |
519 // will check that data is still valid before mapping it. |
507 // will check that data is still valid before mapping it. |
520 MmuLock::Unlock(); |
508 MmuLock::Unlock(); |
521 TUint readStart = (swapPage << KPageShift) >> readUnitShift; |
509 TUint readStart = (SwapIndex(swapData) << KPageShift) >> readUnitShift; |
522 START_PAGING_BENCHMARK; |
510 START_PAGING_BENCHMARK; |
523 TInt r = iDevice->Read(&message, aLinAddr, readStart, readSize, DPagingDevice::EDriveDataPaging); |
511 r = iDevice->Read(&message, aLinAddr, readStart, readSize, DPagingDevice::EDriveDataPaging); |
|
512 if (r != KErrNone) |
|
513 __KTRACE_OPT(KPANIC, Kern::Printf("DSwapManager::ReadSwapPages: error reading media at %08x + %x: %d", readStart << readUnitShift, readSize << readUnitShift, r)); |
|
514 __NK_ASSERT_DEBUG(r!=KErrNoMemory); // not allowed to allocate memory, therefore can't fail with KErrNoMemory |
524 END_PAGING_BENCHMARK(EPagingBmReadDataMedia); |
515 END_PAGING_BENCHMARK(EPagingBmReadDataMedia); |
525 __NK_ASSERT_DEBUG(r!=KErrNoMemory); // not allowed to allocate memory, therefore shouldn't fail with KErrNoMemory |
516 __NK_ASSERT_ALWAYS(r == KErrNone); |
526 if (r != KErrNone) |
|
527 __KTRACE_OPT(KPANIC, Kern::Printf("DSwapManager::ReadSwapPages: error reading media at %08x + %x: %d", readStart << readUnitShift, readSize << readUnitShift, r)); |
|
528 r = ThePager.EmbedErrorContext(EPagingErrorContextDataRead, r); |
|
529 if (r != KErrNone) |
|
530 return r; |
|
531 } |
517 } |
532 END_PAGING_BENCHMARK(EPagingBmReadDataPage); |
518 END_PAGING_BENCHMARK(EPagingBmReadDataPage); |
533 } |
519 } |
534 |
520 |
535 return KErrNone; |
521 return r; |
536 } |
522 } |
537 |
523 |
538 |
524 |
539 /** |
525 /** |
540 Write the specified memory object's pages from the RAM into the swap. |
526 Write the specified memory object's pages from the RAM into the swap. |
541 |
527 |
542 @param aMemory The memory object who owns the pages. |
528 @param aMemory The memory object who owns the pages. |
543 @param aIndex The index within the memory object. |
529 @param aIndex The index within the memory object. |
544 @param aCount The number of pages to write out. |
530 @param aCount The number of pages to write out. |
545 @param aLinAddr The location of the pages to write out. |
531 @param aLinAddr The location of the pages to write out. |
546 @param aBackground Whether this is being called in the background by the page cleaning thread |
532 @param aBackground Whether this is being called in the background by the page cleaning thread |
547 as opposed to on demand when a free page is required. |
533 as opposed to on demand when a free page is required. |
548 |
534 |
549 @pre Called with page cleaning lock held |
535 @pre Called with page cleaning lock held |
550 */ |
536 */ |
551 TInt DSwapManager::WriteSwapPages(DMemoryObject** aMemory, TUint* aIndex, TUint aCount, TLinAddr aLinAddr, TPhysAddr* aPhysAddrs, TBool aBackground) |
537 TInt DSwapManager::WriteSwapPages(DMemoryObject** aMemory, TUint* aIndex, TUint aCount, TLinAddr aLinAddr, TPhysAddr* aPhysAddrs, TBool aBackground) |
552 { |
538 { |
553 TRACE(("DSwapManager::WriteSwapPages %d pages", aCount)); |
539 TRACE(("DSwapManager::WriteSwapPages %d pages", aCount)); |
554 |
540 |
638 TInt r; |
624 TInt r; |
639 if (aLinAddr == 0) |
625 if (aLinAddr == 0) |
640 r = iDevice->WritePhysical(&msg, aPhysAddrs, aCount, writeOffset, aBackground); |
626 r = iDevice->WritePhysical(&msg, aPhysAddrs, aCount, writeOffset, aBackground); |
641 else |
627 else |
642 r = iDevice->Write(&msg, aLinAddr + (aPageIndex << KPageShift), writeOffset, writeSize, aBackground); |
628 r = iDevice->Write(&msg, aLinAddr + (aPageIndex << KPageShift), writeOffset, writeSize, aBackground); |
643 END_PAGING_BENCHMARK(EPagingBmWriteDataMedia); |
|
644 |
629 |
645 if (r != KErrNone) |
630 if (r != KErrNone) |
646 { |
631 { |
647 __KTRACE_OPT(KPANIC, Kern::Printf("DSwapManager::WriteSwapPages: error writing media from %08x to %08x + %x: %d", aLinAddr, writeOffset << readUnitShift, writeSize << readUnitShift, r)); |
632 __KTRACE_OPT(KPANIC, Kern::Printf("DSwapManager::WriteSwapPages: error writing media from %08x to %08x + %x: %d", aLinAddr, writeOffset << readUnitShift, writeSize << readUnitShift, r)); |
648 if (r > 0) |
|
649 r = KErrGeneral; |
|
650 } |
633 } |
651 __NK_ASSERT_DEBUG(r!=KErrNoMemory); // not allowed to allocate memory, therefore can't fail with KErrNoMemory |
634 __NK_ASSERT_DEBUG(r!=KErrNoMemory); // not allowed to allocate memory, therefore can't fail with KErrNoMemory |
652 r = ThePager.EmbedErrorContext(EPagingErrorContextDataWrite, r); |
635 __NK_ASSERT_ALWAYS(r == KErrNone); |
|
636 END_PAGING_BENCHMARK(EPagingBmWriteDataMedia); |
653 |
637 |
654 TUint i; |
638 TUint i; |
655 TUint swapData[KMaxPagesToClean]; |
639 TUint swapData[KMaxPagesToClean]; |
656 |
640 |
657 MmuLock::Lock(); |
641 MmuLock::Lock(); |
661 swapData[i] = aMemory[i]->PagingManagerData(aIndex[i]); |
645 swapData[i] = aMemory[i]->PagingManagerData(aIndex[i]); |
662 TSwapState s = SwapState(swapData[i]); |
646 TSwapState s = SwapState(swapData[i]); |
663 __NK_ASSERT_DEBUG(s == EStateUnreserved || s == EStateWriting); |
647 __NK_ASSERT_DEBUG(s == EStateUnreserved || s == EStateWriting); |
664 if (s == EStateWriting) |
648 if (s == EStateWriting) |
665 { |
649 { |
666 // Store the new swap location and mark the page as saved, or if an error occured then |
650 // Store the new swap location and mark the page as saved. |
667 // record the error code instead |
651 aMemory[i]->SetPagingManagerData(aIndex[i], SwapData(EStateWritten, aSwapIndex + i)); |
668 TUint swapData = (r == KErrNone) |
|
669 ? SwapData(EStateWritten, aSwapIndex + i) |
|
670 : SwapData(EStateBlank, -r); |
|
671 aMemory[i]->SetPagingManagerData(aIndex[i], swapData); |
|
672 } |
652 } |
673 } |
653 } |
674 MmuLock::Unlock(); |
654 MmuLock::Unlock(); |
675 |
655 |
676 for (i = 0 ; i < aCount ; ++i) |
656 for (i = 0 ; i < aCount ; ++i) |
677 { |
657 { |
678 TSwapState s = SwapState(swapData[i]); |
658 TSwapState s = SwapState(swapData[i]); |
679 if (s == EStateUnreserved || s == EStateBlank) |
659 if (s == EStateUnreserved) |
680 { |
660 { |
681 // The page was either decommitted while we were cleaning it, or an error occured while |
661 // The page was decommitted while we were cleaning it, so free the swap page we |
682 // writing. Free the swap page and don't modify the state. |
662 // allocated and continue, leaving this page in the unreserved state. |
683 FreeSwapIndex(aSwapIndex + i); |
663 FreeSwapIndex(aSwapIndex + i); |
684 } |
664 } |
685 } |
665 } |
686 |
666 |
687 // write errors are not reported at this point as this will just kill a thread unrelated to the |
667 return KErrNone; |
688 // one whose data has been lost |
|
689 return KErrNone; |
|
690 } |
668 } |
691 |
669 |
692 |
670 |
693 /** |
671 /** |
694 Notify the media driver that the page written to swap is no longer required. |
672 Notify the media driver that the page written to swap is no longer required. |