diff -r b42b9ce90ea9 -r 661475905584 kernel/eka/memmodel/epoc/flexible/mmu/mpager.cpp --- a/kernel/eka/memmodel/epoc/flexible/mmu/mpager.cpp Fri Apr 23 22:02:01 2010 +0100 +++ b/kernel/eka/memmodel/epoc/flexible/mmu/mpager.cpp Fri Apr 23 22:08:41 2010 +0100 @@ -92,7 +92,7 @@ #elif defined(__CPU_X86) -/* Need at least 6 mapped pages to guarantee to be able to execute all ARM instructions, +/* Need at least 6 mapped pages to guarantee to be able to execute all X86 instructions, plus enough pages for 6 page tables to map those pages, plus enough pages for the page table info structures of those page tables. (Worst case is (?) a MOV [X],[Y] instruction with instruction, 'X' and 'Y' all @@ -200,8 +200,7 @@ TInt r = m.AllocRam(&pagePhys, 1, (Mmu::TRamAllocFlags)(EMemAttNormalCached|Mmu::EAllocNoWipe|Mmu::EAllocNoPagerReclaim), EPageDiscard); - if(r!=KErrNone) - __NK_ASSERT_ALWAYS(0); + __NK_ASSERT_ALWAYS(r == KErrNone); MmuLock::Lock(); AddAsFreePage(SPageInfo::FromPhysAddr(pagePhys)); MmuLock::Unlock(); @@ -214,50 +213,50 @@ #ifdef _DEBUG -TBool DPager::CheckLists() +#ifdef FMM_PAGER_CHECK_LISTS +TBool CheckList(SDblQueLink* aHead, TUint aCount) { -#if 0 - __NK_ASSERT_DEBUG(MmuLock::IsHeld()); - SDblQueLink* head = &iOldList.iA; - TInt n = iOldCount; - SDblQueLink* link = head; - while(n--) + SDblQueLink* link = aHead; + while(aCount--) { link = link->iNext; - if(link==head) - return false; + if(link == aHead) + return EFalse; } link = link->iNext; - if(link!=head) - return false; - - head = &iYoungList.iA; - n = iYoungCount; - link = head; - while(n--) - { - link = link->iNext; - if(link==head) - return false; - } - link = link->iNext; - if(link!=head) - return false; - -// TRACEP(("DP: y=%d o=%d f=%d",iYoungCount,iOldCount,iNumberOfFreePages)); -#endif -// TraceCounts(); + if(link != aHead) + return EFalse; + return ETrue; + } +#endif // #ifdef FMM_PAGER_CHECK_LISTS + +TBool DPager::CheckLists() + { +#ifdef FMM_PAGER_CHECK_LISTS + __NK_ASSERT_DEBUG(MmuLock::IsHeld()); + if (!CheckList(&iOldList.iA, iOldCount)) + return EFalse; + if (!CheckList(&iYoungList.iA, iYoungCount)) + return EFalse; + if (!CheckList(&iOldestCleanList.iA, iOldestCleanCount)) + return EFalse; + if (!CheckList(&iOldestDirtyList.iA, iOldestDirtyCount)) + return EFalse; + TRACEP(("DP: y=%d o=%d oc=%d od=%d f=%d", iYoungCount, iOldCount, + iOldestCleanCount, iOldestDirtyCount, iNumberOfFreePages)); + TraceCounts(); +#endif // #ifdef FMM_PAGER_CHECK_LISTS return true; } void DPager::TraceCounts() { - TRACEP(("DP: y=%d o=%d f=%d min=%d max=%d ml=%d res=%d", - iYoungCount,iOldCount,iNumberOfFreePages,iMinimumPageCount, - iMaximumPageCount,iMinimumPageLimit,iReservePageCount)); + TRACEP(("DP: y=%d o=%d oc=%d od=%d f=%d min=%d max=%d ml=%d res=%d", + iYoungCount, iOldCount, iOldestCleanCount, iOldestDirtyCount, + iNumberOfFreePages, iMinimumPageCount, iMaximumPageCount, + iMinimumPageLimit, iReservePageCount)); } - -#endif +#endif //#ifdef _DEBUG TBool DPager::HaveTooManyPages() @@ -1292,6 +1291,10 @@ TInt r = Kern::AddHalEntry(EHalGroupVM, VMHalFunction, 0); __NK_ASSERT_ALWAYS(r==KErrNone); PageCleaningLock::Init(); +#ifdef __DEMAND_PAGING_BENCHMARKS__ + for (TInt i = 0 ; i < EMaxPagingBm ; ++i) + ResetBenchmarkData((TPagingBenchmark)i); +#endif } @@ -1984,7 +1987,7 @@ MmuLock::Lock(); - __NK_ASSERT_ALWAYS(iYoungOldRatio!=0); + __NK_ASSERT_ALWAYS(iYoungOldRatio); // Make sure aMinimumPageCount is not less than absolute minimum we can cope with... iMinimumPageLimit = iMinYoungPages * (1 + iYoungOldRatio) / iYoungOldRatio @@ -1997,9 +2000,8 @@ aMaximumPageCount=aMinimumPageCount; // Increase iMaximumPageCount? - TInt extra = aMaximumPageCount-iMaximumPageCount; - if(extra>0) - iMaximumPageCount += extra; + if(aMaximumPageCount > iMaximumPageCount) + iMaximumPageCount = aMaximumPageCount; // Reduce iMinimumPageCount? TInt spare = iMinimumPageCount-aMinimumPageCount; @@ -2126,6 +2128,100 @@ } +TInt DPager::FlushRegion(DMemModelProcess* aProcess, TLinAddr aStartAddress, TUint aSize) + { + if (aSize == 0) + return KErrNone; + + // find mapping + NKern::ThreadEnterCS(); + TUint offsetInMapping; + TUint mapInstanceCount; + DMemoryMapping* mapping = MM::FindMappingInProcess(aProcess, aStartAddress, aSize, + offsetInMapping, mapInstanceCount); + if (!mapping) + { + NKern::ThreadLeaveCS(); + return KErrBadDescriptor; + } + + // check whether memory is demand paged + MmuLock::Lock(); + DMemoryObject* memory = mapping->Memory(); + if(mapInstanceCount != mapping->MapInstanceCount() || memory == NULL || !memory->IsDemandPaged()) + { + MmuLock::Unlock(); + mapping->Close(); + NKern::ThreadLeaveCS(); + return KErrNone; + } + + TRACE(("DPager::FlushRegion: %O %08x +%d", aProcess, aStartAddress, aSize)); + if (!K::Initialising) + TRACE2((" context %T %d", NCurrentThread(), NKern::CurrentContext())); + + // why did we not get assertion failures before I added this? + __NK_ASSERT_DEBUG(!Kern::CurrentThread().IsRealtime()); + + // acquire necessary locks + MmuLock::Unlock(); + RamAllocLock::Lock(); + PageCleaningLock::Lock(); + MmuLock::Lock(); + + // find region in memory object + TUint startPage = (offsetInMapping >> KPageShift) + mapping->iStartIndex; + TUint sizeInPages = ((aStartAddress & KPageMask) + aSize - 1) >> KPageShift; + TUint endPage = startPage + sizeInPages; + TRACE2(("DPager::FlushRegion: page range is %d to %d", startPage, endPage)); + + // attempt to flush each page + TUint index = startPage; + while (mapping->MapInstanceCount() == mapInstanceCount && + mapping->Memory() && index <= endPage) + { + TRACE2(("DPager::FlushRegion: flushing page %d", index)); + TPhysAddr physAddr = memory->iPages.PhysAddr(index); + + if (physAddr != KPhysAddrInvalid) + { + TRACE2(("DPager::FlushRegion: phys addr is %08x", physAddr)); + SPageInfo* pi = SPageInfo::SafeFromPhysAddr(physAddr); + if (pi) + { + __NK_ASSERT_DEBUG(pi->Type() == SPageInfo::EManaged); + SPageInfo::TPagedState state = pi->PagedState(); + if (state==SPageInfo::EPagedYoung || state==SPageInfo::EPagedOld || + state==SPageInfo::EPagedOldestClean || state==SPageInfo::EPagedOldestDirty) + { + TRACE2(("DPager::FlushRegion: attempt to steal page")); + TInt r = StealPage(pi); + if(r==KErrNone) + { + TRACE2(("DPager::FlushRegion: attempt to page out %08x", physAddr)); + AddAsFreePage(pi); + TRACE2(("DPager::FlushRegion: paged out %08x", physAddr)); + } + else + TRACE2(("DPager::FlushRegion: page out %08x failed with %d", physAddr, r)); + } + } + } + + MmuLock::Flash(); + ++index; + } + + MmuLock::Unlock(); + PageCleaningLock::Unlock(); + RamAllocLock::Unlock(); + mapping->Close(); + NKern::ThreadLeaveCS(); + TRACE2(("DPager::FlushRegion: done")); + return KErrNone; + } + + void DPager::GetLiveListInfo(SVMCacheInfo& aInfo) { MmuLock::Lock(); // ensure consistent set of values are read... @@ -2837,15 +2933,15 @@ EXPORT_C TInt DDemandPagingLock::Lock(DThread* aThread, TLinAddr aStart, TInt aSize) { // TRACEP(("DDemandPagingLock[0x%08x]::Lock(0x%08x,0x%08x,0x%08x)",this,aThread,aStart,aSize)); - if(iLockedPageCount) - __NK_ASSERT_ALWAYS(0); // lock already used + __NK_ASSERT_ALWAYS(!iLockedPageCount); // lock already used // calculate the number of pages that need to be locked... TUint mask=KPageMask; TUint offset=aStart&mask; TInt numPages = (aSize+offset+mask)>>KPageShift; - if(numPages>iMaxPageCount) - __NK_ASSERT_ALWAYS(0); + + // Should never be asked to lock more pages than are allocated to this object. + __NK_ASSERT_ALWAYS(numPages <= iMaxPageCount); NKern::ThreadEnterCS();