--- a/kernel/eka/memmodel/epoc/flexible/mmu/mpager.cpp Tue May 25 14:09:55 2010 +0300
+++ b/kernel/eka/memmodel/epoc/flexible/mmu/mpager.cpp Wed Jun 09 11:10:19 2010 +0300
@@ -498,56 +498,86 @@
}
-TInt DPager::TryStealOldestPage(SPageInfo*& aPageInfoOut)
+SPageInfo* DPager::StealOrAllocPage(TBool aAllowAlloc, Mmu::TRamAllocFlags aAllocFlags)
{
__NK_ASSERT_DEBUG(RamAllocLock::IsHeld());
__NK_ASSERT_DEBUG(MmuLock::IsHeld());
-
- // The PageCleaningLock may or may not be held. This method will release the RamAllocLock if it
- // has to wait for the PageCleaningLock
+
+ // The PageCleaningLock may or may not be held to start with
TBool pageCleaningLockAcquired = EFalse;
- // find oldest page in list...
SDblQueLink* link;
+ SPageInfo* pageInfo ;
+
+restart:
+
+ // if there is a free page in the live list then use that (it will be at the end)...
+ if (iOldestCleanCount)
+ {
+ __NK_ASSERT_DEBUG(!iOldestCleanList.IsEmpty());
+ link = iOldestCleanList.Last();
+ pageInfo = SPageInfo::FromLink(link);
+ if(pageInfo->Type()==SPageInfo::EUnused)
+ goto try_steal_from_page_info;
+ }
+
+ // maybe try getting a free page from the system pool...
+ if (aAllowAlloc && !HaveMaximumPages())
+ {
+ MmuLock::Unlock();
+ pageInfo = GetPageFromSystem(aAllocFlags);
+ MmuLock::Lock();
+ if (pageInfo)
+ goto exit;
+ }
+
+ // try stealing the oldest clean page on the live list if there is one...
if (iOldestCleanCount)
{
__NK_ASSERT_DEBUG(!iOldestCleanList.IsEmpty());
link = iOldestCleanList.Last();
+ goto try_steal_from_link;
}
- else if (iOldestDirtyCount)
+
+ // no clean oldest pages, see if we can clean multiple dirty pages in one go...
+ if (iOldestDirtyCount > 1 && iPagesToClean > 1)
{
__NK_ASSERT_DEBUG(!iOldestDirtyList.IsEmpty());
- // see if we can clean multiple dirty pages in one go...
- if (iPagesToClean > 1 && iOldestDirtyCount > 1)
+ // check if we hold page cleaning lock
+ TBool needPageCleaningLock = !PageCleaningLock::IsHeld();
+ if (needPageCleaningLock)
{
- if (!PageCleaningLock::IsHeld())
- {
- // temporarily release ram alloc mutex and acquire page cleaning mutex
- MmuLock::Unlock();
- RamAllocLock::Unlock();
- PageCleaningLock::Lock();
- MmuLock::Lock();
- pageCleaningLockAcquired = ETrue;
- }
-
- // there may be clean pages now if we've waited on the page cleaning mutex, if so don't
- // bother cleaning but just restart
- if (iOldestCleanCount == 0 && iOldestDirtyCount >= 1)
- CleanSomePages(EFalse);
-
- if (pageCleaningLockAcquired)
- {
- // release page cleaning mutex and re-aquire ram alloc mutex
- MmuLock::Unlock();
- PageCleaningLock::Unlock();
- RamAllocLock::Lock();
- MmuLock::Lock();
- }
-
- return 1; // tell caller to restart their operation
+ // temporarily release ram alloc mutex and acquire page cleaning mutex
+ MmuLock::Unlock();
+ RamAllocLock::Unlock();
+ PageCleaningLock::Lock();
+ MmuLock::Lock();
}
-
+
+ // there may be clean pages now if we've waited on the page cleaning mutex, if so don't
+ // bother cleaning but just restart
+ if (iOldestCleanCount == 0 && iOldestDirtyCount >= 1)
+ CleanSomePages(EFalse);
+
+ if (needPageCleaningLock)
+ {
+ // release page cleaning mutex and re-aquire ram alloc mutex
+ MmuLock::Unlock();
+ PageCleaningLock::Unlock();
+ RamAllocLock::Lock();
+ MmuLock::Lock();
+ }
+
+ // if there are now some clean pages we restart so as to take one of them
+ if (iOldestCleanCount > 0)
+ goto restart;
+ }
+
+ // otherwise just try to steal the oldest page...
+ if (iOldestDirtyCount)
+ {
+ __NK_ASSERT_DEBUG(!iOldestDirtyList.IsEmpty());
link = iOldestDirtyList.Last();
}
else if (iOldCount)
@@ -561,32 +591,44 @@
__NK_ASSERT_ALWAYS(!iYoungList.IsEmpty());
link = iYoungList.Last();
}
- SPageInfo* pageInfo = SPageInfo::FromLink(link);
-
- if (pageInfo->IsDirty())
+
+try_steal_from_link:
+
+ // lookup page info
+ __NK_ASSERT_DEBUG(link);
+ pageInfo = SPageInfo::FromLink(link);
+
+try_steal_from_page_info:
+
+ // if the page is dirty and we don't hold the page cleaning mutex then we have to wait on it,
+ // and restart - we clean with the ram alloc mutex held in this case
+ if (pageInfo->IsDirty() && !PageCleaningLock::IsHeld())
{
MmuLock::Unlock();
PageCleaningLock::Lock();
MmuLock::Lock();
pageCleaningLockAcquired = ETrue;
+ goto restart;
}
// try to steal it from owning object...
- TInt r = StealPage(pageInfo);
- if (r == KErrNone)
- {
- BalanceAges();
- aPageInfoOut = pageInfo;
- }
-
+ if (StealPage(pageInfo) != KErrNone)
+ goto restart;
+
+ BalanceAges();
+
+exit:
if (pageCleaningLockAcquired)
{
MmuLock::Unlock();
PageCleaningLock::Unlock();
MmuLock::Lock();
}
+
+ __NK_ASSERT_DEBUG(RamAllocLock::IsHeld());
+ __NK_ASSERT_DEBUG(MmuLock::IsHeld());
- return r;
+ return pageInfo;
}
@@ -1050,20 +1092,20 @@
__NK_ASSERT_DEBUG(MmuLock::IsHeld());
__NK_ASSERT_DEBUG(iNumberOfFreePages>0);
- SPageInfo* pageInfo = NULL;
- if (TryStealOldestPage(pageInfo) == KErrNone)
+ SPageInfo* pageInfo = StealOrAllocPage(EFalse, (Mmu::TRamAllocFlags)0);
+
+ // StealOrAllocPage may have released the MmuLock, so check there are still enough pages
+ // to remove one from the live list
+ if (iNumberOfFreePages>0)
{
- // TryStealOldestPage may have released the MmuLock, so check there are still enough pages
- // to remove one from the live list
- if (iNumberOfFreePages>0)
- {
- ReturnPageToSystem(*pageInfo);
- return ETrue;
- }
- else
- AddAsFreePage(pageInfo);
+ ReturnPageToSystem(*pageInfo);
+ return ETrue;
}
- return EFalse;
+ else
+ {
+ AddAsFreePage(pageInfo);
+ return EFalse;
+ }
}
@@ -1092,51 +1134,23 @@
SPageInfo* DPager::PageInAllocPage(Mmu::TRamAllocFlags aAllocFlags)
{
- SPageInfo* pageInfo;
- TPhysAddr pagePhys;
- TInt r = KErrGeneral;
+ // ram alloc mutex may or may not be held
+ __NK_ASSERT_DEBUG(!MmuLock::IsHeld());
RamAllocLock::Lock();
- MmuLock::Lock();
-
-find_a_page:
- // try getting a free page from our live list...
- if (iOldestCleanCount)
+
+ MmuLock::Lock();
+ SPageInfo* pageInfo = StealOrAllocPage(ETrue, aAllocFlags);
+ TBool wasAllocated = pageInfo->Type() == SPageInfo::EUnknown;
+ MmuLock::Unlock();
+
+ if (!wasAllocated)
{
- pageInfo = SPageInfo::FromLink(iOldestCleanList.Last());
- if(pageInfo->Type()==SPageInfo::EUnused)
- goto try_steal_oldest_page;
- }
-
- // try getting a free page from the system pool...
- if(!HaveMaximumPages())
- {
- MmuLock::Unlock();
- pageInfo = GetPageFromSystem(aAllocFlags);
- if(pageInfo)
- goto done;
- MmuLock::Lock();
+ // make page state same as a freshly allocated page...
+ TPhysAddr pagePhys = pageInfo->PhysAddr();
+ TheMmu.PagesAllocated(&pagePhys,1,aAllocFlags);
}
- // otherwise steal a page from the live list...
-try_steal_oldest_page:
- __NK_ASSERT_ALWAYS(iOldestCleanCount|iOldestDirtyCount|iOldCount|iYoungCount);
- r = TryStealOldestPage(pageInfo);
-
- // if this fails we restart whole process.
- // failure can be either KErrInUse if the page was used while we were stealing, or 1 to indicate
- // that some pages were cleaned and the operation should be restarted
- if (r != KErrNone)
- goto find_a_page;
-
- // otherwise we're done!
- MmuLock::Unlock();
-
- // make page state same as a freshly allocated page...
- pagePhys = pageInfo->PhysAddr();
- TheMmu.PagesAllocated(&pagePhys,1,aAllocFlags);
-
-done:
RamAllocLock::Unlock();
return pageInfo;
@@ -2046,9 +2060,9 @@
NKern::ThreadEnterCS();
RamAllocLock::Lock();
- // We must hold this otherwise TryStealOldestPage will release the RamAllocLock while waiting
- // for it. Note this method is not used in producton, so it's ok to hold both locks for longer
- // than would otherwise happen.
+ // We must hold this otherwise StealOrAllocPage will release the RamAllocLock while waiting for
+ // it. Note this method is not used in producton, so it's ok to hold both locks for longer than
+ // would otherwise happen.
PageCleaningLock::Lock();
MmuLock::Lock();