496 break; |
496 break; |
497 } |
497 } |
498 } |
498 } |
499 |
499 |
500 |
500 |
501 TInt DPager::TryStealOldestPage(SPageInfo*& aPageInfoOut) |
501 SPageInfo* DPager::StealOrAllocPage(TBool aAllowAlloc, Mmu::TRamAllocFlags aAllocFlags) |
502 { |
502 { |
503 __NK_ASSERT_DEBUG(RamAllocLock::IsHeld()); |
503 __NK_ASSERT_DEBUG(RamAllocLock::IsHeld()); |
504 __NK_ASSERT_DEBUG(MmuLock::IsHeld()); |
504 __NK_ASSERT_DEBUG(MmuLock::IsHeld()); |
|
505 |
|
506 // The PageCleaningLock may or may not be held to start with |
|
507 TBool pageCleaningLockAcquired = EFalse; |
|
508 |
|
509 SDblQueLink* link; |
|
510 SPageInfo* pageInfo ; |
505 |
511 |
506 // The PageCleaningLock may or may not be held. This method will release the RamAllocLock if it |
512 restart: |
507 // has to wait for the PageCleaningLock |
513 |
508 TBool pageCleaningLockAcquired = EFalse; |
514 // if there is a free page in the live list then use that (it will be at the end)... |
509 |
|
510 // find oldest page in list... |
|
511 SDblQueLink* link; |
|
512 if (iOldestCleanCount) |
515 if (iOldestCleanCount) |
513 { |
516 { |
514 __NK_ASSERT_DEBUG(!iOldestCleanList.IsEmpty()); |
517 __NK_ASSERT_DEBUG(!iOldestCleanList.IsEmpty()); |
515 link = iOldestCleanList.Last(); |
518 link = iOldestCleanList.Last(); |
516 } |
519 pageInfo = SPageInfo::FromLink(link); |
517 else if (iOldestDirtyCount) |
520 if(pageInfo->Type()==SPageInfo::EUnused) |
|
521 goto try_steal_from_page_info; |
|
522 } |
|
523 |
|
524 // maybe try getting a free page from the system pool... |
|
525 if (aAllowAlloc && !HaveMaximumPages()) |
|
526 { |
|
527 MmuLock::Unlock(); |
|
528 pageInfo = GetPageFromSystem(aAllocFlags); |
|
529 MmuLock::Lock(); |
|
530 if (pageInfo) |
|
531 goto exit; |
|
532 } |
|
533 |
|
534 // try stealing the oldest clean page on the live list if there is one... |
|
535 if (iOldestCleanCount) |
|
536 { |
|
537 __NK_ASSERT_DEBUG(!iOldestCleanList.IsEmpty()); |
|
538 link = iOldestCleanList.Last(); |
|
539 goto try_steal_from_link; |
|
540 } |
|
541 |
|
542 // no clean oldest pages, see if we can clean multiple dirty pages in one go... |
|
543 if (iOldestDirtyCount > 1 && iPagesToClean > 1) |
518 { |
544 { |
519 __NK_ASSERT_DEBUG(!iOldestDirtyList.IsEmpty()); |
545 __NK_ASSERT_DEBUG(!iOldestDirtyList.IsEmpty()); |
520 |
546 |
521 // see if we can clean multiple dirty pages in one go... |
547 // check if we hold page cleaning lock |
522 if (iPagesToClean > 1 && iOldestDirtyCount > 1) |
548 TBool needPageCleaningLock = !PageCleaningLock::IsHeld(); |
|
549 if (needPageCleaningLock) |
523 { |
550 { |
524 if (!PageCleaningLock::IsHeld()) |
551 // temporarily release ram alloc mutex and acquire page cleaning mutex |
525 { |
552 MmuLock::Unlock(); |
526 // temporarily release ram alloc mutex and acquire page cleaning mutex |
553 RamAllocLock::Unlock(); |
527 MmuLock::Unlock(); |
554 PageCleaningLock::Lock(); |
528 RamAllocLock::Unlock(); |
555 MmuLock::Lock(); |
529 PageCleaningLock::Lock(); |
556 } |
530 MmuLock::Lock(); |
557 |
531 pageCleaningLockAcquired = ETrue; |
558 // there may be clean pages now if we've waited on the page cleaning mutex, if so don't |
532 } |
559 // bother cleaning but just restart |
533 |
560 if (iOldestCleanCount == 0 && iOldestDirtyCount >= 1) |
534 // there may be clean pages now if we've waited on the page cleaning mutex, if so don't |
561 CleanSomePages(EFalse); |
535 // bother cleaning but just restart |
562 |
536 if (iOldestCleanCount == 0 && iOldestDirtyCount >= 1) |
563 if (needPageCleaningLock) |
537 CleanSomePages(EFalse); |
564 { |
538 |
565 // release page cleaning mutex and re-aquire ram alloc mutex |
539 if (pageCleaningLockAcquired) |
566 MmuLock::Unlock(); |
540 { |
567 PageCleaningLock::Unlock(); |
541 // release page cleaning mutex and re-aquire ram alloc mutex |
568 RamAllocLock::Lock(); |
542 MmuLock::Unlock(); |
569 MmuLock::Lock(); |
543 PageCleaningLock::Unlock(); |
570 } |
544 RamAllocLock::Lock(); |
571 |
545 MmuLock::Lock(); |
572 // if there are now some clean pages we restart so as to take one of them |
546 } |
573 if (iOldestCleanCount > 0) |
547 |
574 goto restart; |
548 return 1; // tell caller to restart their operation |
575 } |
549 } |
576 |
550 |
577 // otherwise just try to steal the oldest page... |
|
578 if (iOldestDirtyCount) |
|
579 { |
|
580 __NK_ASSERT_DEBUG(!iOldestDirtyList.IsEmpty()); |
551 link = iOldestDirtyList.Last(); |
581 link = iOldestDirtyList.Last(); |
552 } |
582 } |
553 else if (iOldCount) |
583 else if (iOldCount) |
554 { |
584 { |
555 __NK_ASSERT_DEBUG(!iOldList.IsEmpty()); |
585 __NK_ASSERT_DEBUG(!iOldList.IsEmpty()); |
559 { |
589 { |
560 __NK_ASSERT_DEBUG(iYoungCount); |
590 __NK_ASSERT_DEBUG(iYoungCount); |
561 __NK_ASSERT_ALWAYS(!iYoungList.IsEmpty()); |
591 __NK_ASSERT_ALWAYS(!iYoungList.IsEmpty()); |
562 link = iYoungList.Last(); |
592 link = iYoungList.Last(); |
563 } |
593 } |
564 SPageInfo* pageInfo = SPageInfo::FromLink(link); |
594 |
565 |
595 try_steal_from_link: |
566 if (pageInfo->IsDirty()) |
596 |
|
597 // lookup page info |
|
598 __NK_ASSERT_DEBUG(link); |
|
599 pageInfo = SPageInfo::FromLink(link); |
|
600 |
|
601 try_steal_from_page_info: |
|
602 |
|
603 // if the page is dirty and we don't hold the page cleaning mutex then we have to wait on it, |
|
604 // and restart - we clean with the ram alloc mutex held in this case |
|
605 if (pageInfo->IsDirty() && !PageCleaningLock::IsHeld()) |
567 { |
606 { |
568 MmuLock::Unlock(); |
607 MmuLock::Unlock(); |
569 PageCleaningLock::Lock(); |
608 PageCleaningLock::Lock(); |
570 MmuLock::Lock(); |
609 MmuLock::Lock(); |
571 pageCleaningLockAcquired = ETrue; |
610 pageCleaningLockAcquired = ETrue; |
|
611 goto restart; |
572 } |
612 } |
573 |
613 |
574 // try to steal it from owning object... |
614 // try to steal it from owning object... |
575 TInt r = StealPage(pageInfo); |
615 if (StealPage(pageInfo) != KErrNone) |
576 if (r == KErrNone) |
616 goto restart; |
577 { |
617 |
578 BalanceAges(); |
618 BalanceAges(); |
579 aPageInfoOut = pageInfo; |
619 |
580 } |
620 exit: |
581 |
|
582 if (pageCleaningLockAcquired) |
621 if (pageCleaningLockAcquired) |
583 { |
622 { |
584 MmuLock::Unlock(); |
623 MmuLock::Unlock(); |
585 PageCleaningLock::Unlock(); |
624 PageCleaningLock::Unlock(); |
586 MmuLock::Lock(); |
625 MmuLock::Lock(); |
587 } |
626 } |
|
627 |
|
628 __NK_ASSERT_DEBUG(RamAllocLock::IsHeld()); |
|
629 __NK_ASSERT_DEBUG(MmuLock::IsHeld()); |
588 |
630 |
589 return r; |
631 return pageInfo; |
590 } |
632 } |
591 |
633 |
592 |
634 |
593 template <class T, TUint maxObjects> class TSequentialColourSelector |
635 template <class T, TUint maxObjects> class TSequentialColourSelector |
594 { |
636 { |
1048 { |
1090 { |
1049 __NK_ASSERT_DEBUG(RamAllocLock::IsHeld()); |
1091 __NK_ASSERT_DEBUG(RamAllocLock::IsHeld()); |
1050 __NK_ASSERT_DEBUG(MmuLock::IsHeld()); |
1092 __NK_ASSERT_DEBUG(MmuLock::IsHeld()); |
1051 __NK_ASSERT_DEBUG(iNumberOfFreePages>0); |
1093 __NK_ASSERT_DEBUG(iNumberOfFreePages>0); |
1052 |
1094 |
1053 SPageInfo* pageInfo = NULL; |
1095 SPageInfo* pageInfo = StealOrAllocPage(EFalse, (Mmu::TRamAllocFlags)0); |
1054 if (TryStealOldestPage(pageInfo) == KErrNone) |
1096 |
1055 { |
1097 // StealOrAllocPage may have released the MmuLock, so check there are still enough pages |
1056 // TryStealOldestPage may have released the MmuLock, so check there are still enough pages |
1098 // to remove one from the live list |
1057 // to remove one from the live list |
1099 if (iNumberOfFreePages>0) |
1058 if (iNumberOfFreePages>0) |
1100 { |
1059 { |
1101 ReturnPageToSystem(*pageInfo); |
1060 ReturnPageToSystem(*pageInfo); |
1102 return ETrue; |
1061 return ETrue; |
1103 } |
1062 } |
1104 else |
1063 else |
1105 { |
1064 AddAsFreePage(pageInfo); |
1106 AddAsFreePage(pageInfo); |
1065 } |
1107 return EFalse; |
1066 return EFalse; |
1108 } |
1067 } |
1109 } |
1068 |
1110 |
1069 |
1111 |
1070 void DPager::ReturnPageToSystem(SPageInfo& aPageInfo) |
1112 void DPager::ReturnPageToSystem(SPageInfo& aPageInfo) |
1071 { |
1113 { |
1090 } |
1132 } |
1091 |
1133 |
1092 |
1134 |
1093 SPageInfo* DPager::PageInAllocPage(Mmu::TRamAllocFlags aAllocFlags) |
1135 SPageInfo* DPager::PageInAllocPage(Mmu::TRamAllocFlags aAllocFlags) |
1094 { |
1136 { |
1095 SPageInfo* pageInfo; |
1137 // ram alloc mutex may or may not be held |
1096 TPhysAddr pagePhys; |
1138 __NK_ASSERT_DEBUG(!MmuLock::IsHeld()); |
1097 TInt r = KErrGeneral; |
|
1098 |
1139 |
1099 RamAllocLock::Lock(); |
1140 RamAllocLock::Lock(); |
1100 MmuLock::Lock(); |
|
1101 |
|
1102 find_a_page: |
|
1103 // try getting a free page from our live list... |
|
1104 if (iOldestCleanCount) |
|
1105 { |
|
1106 pageInfo = SPageInfo::FromLink(iOldestCleanList.Last()); |
|
1107 if(pageInfo->Type()==SPageInfo::EUnused) |
|
1108 goto try_steal_oldest_page; |
|
1109 } |
|
1110 |
|
1111 // try getting a free page from the system pool... |
|
1112 if(!HaveMaximumPages()) |
|
1113 { |
|
1114 MmuLock::Unlock(); |
|
1115 pageInfo = GetPageFromSystem(aAllocFlags); |
|
1116 if(pageInfo) |
|
1117 goto done; |
|
1118 MmuLock::Lock(); |
|
1119 } |
|
1120 |
|
1121 // otherwise steal a page from the live list... |
|
1122 try_steal_oldest_page: |
|
1123 __NK_ASSERT_ALWAYS(iOldestCleanCount|iOldestDirtyCount|iOldCount|iYoungCount); |
|
1124 r = TryStealOldestPage(pageInfo); |
|
1125 |
1141 |
1126 // if this fails we restart whole process. |
1142 MmuLock::Lock(); |
1127 // failure can be either KErrInUse if the page was used while we were stealing, or 1 to indicate |
1143 SPageInfo* pageInfo = StealOrAllocPage(ETrue, aAllocFlags); |
1128 // that some pages were cleaned and the operation should be restarted |
1144 TBool wasAllocated = pageInfo->Type() == SPageInfo::EUnknown; |
1129 if (r != KErrNone) |
|
1130 goto find_a_page; |
|
1131 |
|
1132 // otherwise we're done! |
|
1133 MmuLock::Unlock(); |
1145 MmuLock::Unlock(); |
1134 |
1146 |
1135 // make page state same as a freshly allocated page... |
1147 if (!wasAllocated) |
1136 pagePhys = pageInfo->PhysAddr(); |
1148 { |
1137 TheMmu.PagesAllocated(&pagePhys,1,aAllocFlags); |
1149 // make page state same as a freshly allocated page... |
1138 |
1150 TPhysAddr pagePhys = pageInfo->PhysAddr(); |
1139 done: |
1151 TheMmu.PagesAllocated(&pagePhys,1,aAllocFlags); |
|
1152 } |
|
1153 |
1140 RamAllocLock::Unlock(); |
1154 RamAllocLock::Unlock(); |
1141 |
1155 |
1142 return pageInfo; |
1156 return pageInfo; |
1143 } |
1157 } |
1144 |
1158 |
2044 return KErrArgument; |
2058 return KErrArgument; |
2045 |
2059 |
2046 NKern::ThreadEnterCS(); |
2060 NKern::ThreadEnterCS(); |
2047 RamAllocLock::Lock(); |
2061 RamAllocLock::Lock(); |
2048 |
2062 |
2049 // We must hold this otherwise TryStealOldestPage will release the RamAllocLock while waiting |
2063 // We must hold this otherwise StealOrAllocPage will release the RamAllocLock while waiting for |
2050 // for it. Note this method is not used in producton, so it's ok to hold both locks for longer |
2064 // it. Note this method is not used in producton, so it's ok to hold both locks for longer than |
2051 // than would otherwise happen. |
2065 // would otherwise happen. |
2052 PageCleaningLock::Lock(); |
2066 PageCleaningLock::Lock(); |
2053 |
2067 |
2054 MmuLock::Lock(); |
2068 MmuLock::Lock(); |
2055 |
2069 |
2056 __NK_ASSERT_ALWAYS(iYoungOldRatio); |
2070 __NK_ASSERT_ALWAYS(iYoungOldRatio); |