kernel/eka/memmodel/epoc/flexible/mmu/mpager.cpp
branchRCL_3
changeset 36 bbf8bed59bcb
parent 28 5b5d147c7838
child 39 2bb754abd467
equal deleted inserted replaced
28:5b5d147c7838 36:bbf8bed59bcb
   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);