kernel/eka/memmodel/epoc/flexible/mmu/mptalloc.h
changeset 44 36bfc973b146
parent 43 96e5fb8b040d
child 117 5b5d147c7838
--- a/kernel/eka/memmodel/epoc/flexible/mmu/mptalloc.h	Thu Dec 17 09:24:54 2009 +0200
+++ b/kernel/eka/memmodel/epoc/flexible/mmu/mptalloc.h	Thu Jan 07 13:38:45 2010 +0200
@@ -44,6 +44,12 @@
 */
 const TUint KNumPagesToPinOnePageTable = 2; // 1 page table page + 1 page table info page
 
+/**
+The minimum number of unpinned paged page table pages required so a page fault 
+can't fail to allocate a page table.
+*/
+const TUint KMinUnpinnedPagedPtPages = KMaxCpus;
+
 
 /**
 Class for allocating MMU page tables.
@@ -159,7 +165,7 @@
 						at least #KNumPagesToPinOnePageTable replacement
 						pages available.
 	*/
-	static void PinPageTable(TPte* aPageTable, TPinArgs& aPinArgs);
+	TInt PinPageTable(TPte* aPageTable, TPinArgs& aPinArgs);
 
 	/**
 	Unpin the RAM page containing a page table, as well as the RAM page
@@ -172,7 +178,7 @@
 						completely unpinned, e.g. those which can be reused
 						as new replacement pages or freed.
 	*/
-	static void UnpinPageTable(TPte* aPageTable, TPinArgs& aPinArgs);
+	void UnpinPageTable(TPte* aPageTable, TPinArgs& aPinArgs);
 
 private:
 	/**
@@ -358,17 +364,97 @@
 		void Init2(TUint aNumInitPages);
 		TInt Alloc(TBool aDemandPaged);
 		void Free(TUint aPageIndex, TBool aDemandPaged);
-		TBool IsDemandPaged(SPageInfo* aPageInfo)
-			{// Is the highest page table index this page table info page can reference 
+		
+		/**
+		Determine if the page table info page is paged.
+		
+		@param aPageInfo Pointer to the SPageInfo of the page table info page.
+		@return ETrue if the page table info page is paged, EFalse otherwise.
+		@pre MmuLock is held.
+		*/
+		inline TBool IsDemandPagedPtInfo(SPageInfo* aPageInfo)
+			{
+			// Is the highest page table index this page table info page can reference 
 			// allocated within the demand paged region of the page table address space.
 			TUint groupIndex = aPageInfo->Index();
 			return ((groupIndex+1) * KPageTableGroupSize)-1 >= iUpperWaterMark;
 			}
+
+		/**
+		Determine if the page table page is paged.
+		
+		@param aPageInfo Pointer to the SPageInfo of the page table info page.
+		@return ETrue if the page table page is paged, EFalse otherwise.
+		@pre MmuLock is held.	
+		*/
+		inline TBool IsDemandPagedPt(SPageInfo* aPageInfo)
+			{
+			return aPageInfo->Index() >= iUpperWaterMark;
+			}
+
+		/**
+		Get a random paged page table page.
+		
+		@return The index of a paged page table page.
+		@pre All paged page table pages are allocated.
+		@pre Page tables lock is held.
+		*/
+		TUint RandomPagedPtPage();
+
+		/**
+		Increase the count of pinned paged page table pages.
+		
+		@return KErrNone on success, KErrNoMemory if too many pages are already pinned.
+		@pre MmuLock is held
+		*/
+		inline TInt PtPagePinCountInc()
+			{
+			if (AtPinnedPagedPtsLimit(iUpperWaterMark, iLowerWaterMark, iPinnedPageTablePages + 1))
+				{
+				return KErrNoMemory;
+				}
+			iPinnedPageTablePages++;
+			return KErrNone;
+			}
+
+		/**
+		Decrease the count of pinned paged page table pages.
+		
+		@pre MmuLock is held
+		*/
+		inline void PtPagePinCountDec()
+			{
+			__NK_ASSERT_DEBUG(iPinnedPageTablePages);	// Can't be zero.
+			iPinnedPageTablePages--;
+			}
+
+	private:
+		/**
+		Check whether it is safe to pin a paged page table or reduce the amount of 
+		virtual address space available to paged page tables.  By checking that we 
+		either have spare virtual address space to increase the	amount of paged page 
+		tables or that there are already enough unpinned paged page tables.
+		
+		@return ETrue if there isn't or EFalse if it is ok to pin more paged page
+				tables or increase the number of unpaged page tables.
+		*/
+		TBool AtPinnedPagedPtsLimit(TUint aUpperWaterMark, TUint aLowerWaterMark, TUint aPinnedPtPages)
+			{
+			TUint adjustedUpperWaterMark = aUpperWaterMark & ~(KPageTableGroupSize - 1);
+			TUint availPagedPtPages = KMaxPageTablePages - adjustedUpperWaterMark;
+			TUint availUnpinnedPagedPtPages = availPagedPtPages - aPinnedPtPages;
+			// This check is sufficient as we only increase the pinned paged page table 
+			// pages or unpaged page table pages one at a time.
+			return (aLowerWaterMark + 1 == adjustedUpperWaterMark && 
+					availUnpinnedPagedPtPages < KMinUnpinnedPagedPtPages);
+			}
+
 	private:
 		TBitMapAllocator* iLowerAllocator; ///< Allocator for unpaged page tables
 		TUint iLowerWaterMark; ///< Highest page index allocated by iLowerAllocator
 		TBitMapAllocator* iUpperAllocator; ///< Allocator for demand paged page tables
 		TUint iUpperWaterMark; ///< Lowest page index allocated by iUpperAllocator
+		TUint iPinnedPageTablePages; ///< The number of pinned paged page table pages.
 		};
 
 	/**