kernel/eka/memmodel/epoc/flexible/mmu/mpager.h
branchRCL_3
changeset 110 c734af59ce98
parent 87 2f92ad2dc5db
child 117 5b5d147c7838
equal deleted inserted replaced
97:41f0cfe18c80 110:c734af59ce98
    19 */
    19 */
    20 
    20 
    21 #ifndef MPAGER_H
    21 #ifndef MPAGER_H
    22 #define MPAGER_H
    22 #define MPAGER_H
    23 
    23 
       
    24 #include "mmu.h"
       
    25 #include <kern_priv.h>
       
    26 
       
    27 /**
       
    28 Maximum number of pages to attempt to clean in one go.
       
    29 */
       
    30 const TInt KMaxPagesToClean = 4;
       
    31 
    24 struct SVMCacheInfo;
    32 struct SVMCacheInfo;
    25 class DMemModelThread;
    33 class DMemModelThread;
    26 class DMemoryMappingBase;
    34 class DMemoryMappingBase;
    27 
    35 
    28 class DPager
    36 class DPager
    59 	FORCE_INLINE void SetWritable(SPageInfo& aPageInfo)
    67 	FORCE_INLINE void SetWritable(SPageInfo& aPageInfo)
    60 		{
    68 		{
    61 		if (!aPageInfo.IsDirty())
    69 		if (!aPageInfo.IsDirty())
    62 			{// This is the first mapping to write to the page so increase the 
    70 			{// This is the first mapping to write to the page so increase the 
    63 			// dirty page count.
    71 			// dirty page count.
    64 			aPageInfo.SetWritable();
       
    65 			iNumberOfDirtyPages++;
    72 			iNumberOfDirtyPages++;
    66 			}
    73 			}
       
    74 		aPageInfo.SetWritable();
    67 		}
    75 		}
    68 	
    76 	
    69 	FORCE_INLINE void SetClean(SPageInfo& aPageInfo)
    77 	FORCE_INLINE void SetClean(SPageInfo& aPageInfo)
    70 		{
    78 		{
    71 		__NK_ASSERT_DEBUG(iNumberOfDirtyPages);
    79 		__NK_ASSERT_DEBUG(iNumberOfDirtyPages);
   242 	TBool ReservePages(TUint aRequiredCount, TUint& aCount);
   250 	TBool ReservePages(TUint aRequiredCount, TUint& aCount);
   243 
   251 
   244 	/**
   252 	/**
   245 	*/
   253 	*/
   246 	void UnreservePages(TUint& aCount);
   254 	void UnreservePages(TUint& aCount);
       
   255 
       
   256 	/**
       
   257 	Indicates whether there are any dirty pages available to be cleaned by #CleanSomePages.
       
   258 
       
   259 	This is called by the page cleaner to work out whether it has any work to do.
       
   260 
       
   261 	@return Whether there are any dirty pages in the oldest section of the live list.
       
   262 	*/
       
   263 	TBool HasPagesToClean();
       
   264 
       
   265 	/**
       
   266 	Attempt to clean one or more dirty pages in one go.
       
   267 
       
   268 	Called by the page cleaner to clean pages and by PageInAllocPage when needs to steal a page from
       
   269 	the live list, but the oldest clean list is empty.
       
   270 
       
   271 	May or may not succeed in acually cleaning any pages.
       
   272 
       
   273 	@param aBackground Whether the activity should be ignored when determining whether the paging
       
   274 	                   device is busy.  This is used by the page cleaner.
       
   275 
       
   276 	@return The number of pages this method attempted to clean.  If it returns zero, there were no
       
   277 	        pages eligible to be cleaned.
       
   278 	*/
       
   279 	TInt CleanSomePages(TBool aBackground);
   247 
   280 
   248 	/**
   281 	/**
   249 	Enumeration of instrumented paging events which only require the
   282 	Enumeration of instrumented paging events which only require the
   250 	SPageInfo object as an argument. 
   283 	SPageInfo object as an argument. 
   251 	*/
   284 	*/
   304 	@param aBlockRest	Set to ETrue when we don't want the allocator to search for new pages if the RAM 
   337 	@param aBlockRest	Set to ETrue when we don't want the allocator to search for new pages if the RAM 
   305 						zone with ID==aBlockZoneId is encountered, i.e. a general RAM defrag operation.
   338 						zone with ID==aBlockZoneId is encountered, i.e. a general RAM defrag operation.
   306 	*/
   339 	*/
   307 	TInt DiscardPage(SPageInfo* aOldPageInfo, TUint aBlockZoneId, TBool aBlockRest);
   340 	TInt DiscardPage(SPageInfo* aOldPageInfo, TUint aBlockZoneId, TBool aBlockRest);
   308 
   341 
       
   342 	/**
       
   343 	Attempt to discard the specified page and then allocate a page of type aPageType
       
   344 	in its place.
       
   345 	
       
   346 	@param aPageInfo	The page info of the page to discard.
       
   347 	@param aPageType 	The new page type to allocate into aPageInfo's physical address.
       
   348 	*/
       
   349 	TInt DiscardAndAllocPage(SPageInfo* aPageInfo, TZonePageType aPageType);
       
   350 
   309 
   351 
   310 	/**
   352 	/**
   311 	Update any live list links to replace the old page with the new page.
   353 	Update any live list links to replace the old page with the new page.
   312 	This is to be used when a page has been moved.
   354 	This is to be used when a page has been moved.
   313 
   355 
   355 	@post MmuLock left unchanged.
   397 	@post MmuLock left unchanged.
   356 	*/
   398 	*/
   357 	void RemovePage(SPageInfo* aPageInfo);
   399 	void RemovePage(SPageInfo* aPageInfo);
   358 
   400 
   359 	/**
   401 	/**
       
   402 	Try to remove the oldest page from the live page list and perform #StealPage.
       
   403 
       
   404 	@param aPageInfoOut Set to the SPageInfo pointer for the stolen page if any.
       
   405 	
       
   406 	@return KErrNone on success, KErrInUse if stealing failed or 1 to indicate the the oldest page
       
   407 	was dirty and the PageCleaning mutex was not held.
       
   408 	
       
   409 	@pre MmuLock held
       
   410 	@post MmuLock left unchanged.
       
   411 	*/
       
   412 	TInt TryStealOldestPage(SPageInfo*& aPageInfoOut);
       
   413 
       
   414 	/**
   360 	Remove the oldest page from the live page list and perform #StealPage.
   415 	Remove the oldest page from the live page list and perform #StealPage.
   361 
   416 
   362 	@pre MmuLock held
   417 	@pre MmuLock held
   363 	@post MmuLock left unchanged.
   418 	@post MmuLock held (but may have been released by this function)
   364 	*/
   419 	*/
   365 	SPageInfo* StealOldestPage();
   420 	SPageInfo* StealOldestPage();
   366 
   421 
   367 	/**
   422 	/**
   368 	Steal a page from the memory object (if any) which is using the page.
   423 	Steal a page from the memory object (if any) which is using the page.
   369 	If successful the returned page will be in the EUnknown state and the
   424 	If successful the returned page will be in the EUnknown state and the
   370 	cache state for the page is indeterminate. This is the same state as
   425 	cache state for the page is indeterminate. This is the same state as
   371 	if the page had been allocated by Mmu::AllocRam.
   426 	if the page had been allocated by Mmu::AllocRam.
   372 
   427 
   373 	@pre RamAlloc mutex held
   428 	@pre RamAlloc mutex held
       
   429 	@pre If the page is dirty the PageCleaning lock must be held.
   374 	@pre MmuLock held
   430 	@pre MmuLock held
   375 	@post MmuLock held (but may have been released by this function)
   431 	@post MmuLock held (but may have been released by this function)
   376 	*/
   432 	*/
   377 	TInt StealPage(SPageInfo* aPageInfo);
   433 	TInt StealPage(SPageInfo* aPageInfo);
   378 
   434 
   424 	1. An unused page in the live page list.
   480 	1. An unused page in the live page list.
   425 	2. The systems free pool.
   481 	2. The systems free pool.
   426 	3. The oldest page from the live page list.
   482 	3. The oldest page from the live page list.
   427 	*/
   483 	*/
   428 	SPageInfo* PageInAllocPage(Mmu::TRamAllocFlags aAllocFlags);
   484 	SPageInfo* PageInAllocPage(Mmu::TRamAllocFlags aAllocFlags);
       
   485 
       
   486 	/**
       
   487 	Called by CleanSomePages() to determine which pages should be cleaned.
       
   488 
       
   489 	This deals with the complexity of page colouring, which means that pages can only be mapped at
       
   490 	certain locations.  When cleaning multiple pages at once we need to find a set of pages that we
       
   491 	can map in memory sequentially.
       
   492 
       
   493 	@pre MmuLock held
       
   494 	
       
   495 	@param aPageInfosOut Pointer to an array of SPageInfo pointers, which must be at least
       
   496 	KMaxPagesToClean long.  This will be filled in to indicate the pages to clean.
       
   497 	
       
   498 	@return The numnber of pages to clean.
       
   499 	*/
       
   500 	TInt SelectPagesToClean(SPageInfo** aPageInfosOut);
   429 
   501 
   430 	/**
   502 	/**
   431 	If the number of young pages exceeds that specified by iYoungOldRatio then a
   503 	If the number of young pages exceeds that specified by iYoungOldRatio then a
   432 	single page is made 'old'. Call this after adding a new 'young' page.
   504 	single page is made 'old'. Call this after adding a new 'young' page.
   433 
   505 
   519 	TUint16 iYoungOldRatio;		/**< Ratio of young to old pages in the live page list */
   591 	TUint16 iYoungOldRatio;		/**< Ratio of young to old pages in the live page list */
   520 	SDblQue iYoungList;			/**< Head of 'young' page list. */
   592 	SDblQue iYoungList;			/**< Head of 'young' page list. */
   521 	TUint iYoungCount;			/**< Number of young pages */
   593 	TUint iYoungCount;			/**< Number of young pages */
   522 	SDblQue iOldList;			/**< Head of 'old' page list. */
   594 	SDblQue iOldList;			/**< Head of 'old' page list. */
   523 	TUint iOldCount;			/**< Number of old pages */
   595 	TUint iOldCount;			/**< Number of old pages */
   524 #ifdef _USE_OLDEST_LISTS
       
   525 	SDblQue iOldestCleanList;	/**< Head of 'oldestClean' page list. */
   596 	SDblQue iOldestCleanList;	/**< Head of 'oldestClean' page list. */
   526 	TUint iOldestCleanCount;	/**< Number of 'oldestClean' pages */
   597 	TUint iOldestCleanCount;	/**< Number of 'oldestClean' pages */
   527 	SDblQue iOldestDirtyList;	/**< Head of 'oldestDirty' page list. */
   598 	SDblQue iOldestDirtyList;	/**< Head of 'oldestDirty' page list. */
   528 	TUint iOldestDirtyCount;	/**< Number of 'oldestDirty' pages */
   599 	TUint iOldestDirtyCount;	/**< Number of 'oldestDirty' pages */
   529 	TUint16 iOldOldestRatio;	/**< Ratio of old pages to oldest to clean and dirty in the live page list*/
   600 	TUint16 iOldOldestRatio;	/**< Ratio of old pages to oldest to clean and dirty in the live page list*/
   530 #endif
       
   531 	TUint iNumberOfFreePages;
   601 	TUint iNumberOfFreePages;
   532 	TUint iNumberOfDirtyPages;	/**< The total number of dirty pages in the paging cache. Protected by MmuLock */
   602 	TUint iNumberOfDirtyPages;	/**< The total number of dirty pages in the paging cache. Protected by MmuLock */
   533 	TUint iInitMinimumPageCount;/**< Initial value for iMinimumPageCount */
   603 	TUint iInitMinimumPageCount;/**< Initial value for iMinimumPageCount */
   534 	TUint iInitMaximumPageCount;/**< Initial value for iMaximumPageCount  */
   604 	TUint iInitMaximumPageCount;/**< Initial value for iMaximumPageCount  */
   535 	TUint iReservePageCount;	/**< Number of pages reserved for locking */
   605 	TUint iReservePageCount;	/**< Number of pages reserved for locking */
   537 								     iMinimumPageCount >= iMinimumPageLimit + iReservePageCount */
   607 								     iMinimumPageCount >= iMinimumPageLimit + iReservePageCount */
   538 	SVMEventInfo iEventInfo;
   608 	SVMEventInfo iEventInfo;
   539 
   609 
   540 #ifdef __DEMAND_PAGING_BENCHMARKS__
   610 #ifdef __DEMAND_PAGING_BENCHMARKS__
   541 public:
   611 public:
   542 	void RecordBenchmarkData(TPagingBenchmark aBm, TUint32 aStartTime, TUint32 aEndTime);
   612 	void RecordBenchmarkData(TPagingBenchmark aBm, TUint32 aStartTime, TUint32 aEndTime, TUint aCount);
   543 	void ResetBenchmarkData(TPagingBenchmark aBm);
   613 	void ResetBenchmarkData(TPagingBenchmark aBm);
       
   614 	void ReadBenchmarkData(TPagingBenchmark aBm, SPagingBenchmarkInfo& aDataOut);
       
   615 	TSpinLock iBenchmarkLock;
   544 	SPagingBenchmarkInfo iBenchmarkInfo[EMaxPagingBm];
   616 	SPagingBenchmarkInfo iBenchmarkInfo[EMaxPagingBm];
   545 #endif //__DEMAND_PAGING_BENCHMARKS__
   617 #endif //__DEMAND_PAGING_BENCHMARKS__
   546 	};
   618 	};
   547 
   619 
   548 extern DPager ThePager;
   620 extern DPager ThePager;
   549 
   621 
   550 
   622 
   551 #ifdef __DEMAND_PAGING_BENCHMARKS__
   623 #ifdef __DEMAND_PAGING_BENCHMARKS__
   552 
   624 
   553 #define START_PAGING_BENCHMARK TUint32 _bmStart = NKern::FastCounter()
   625 #define START_PAGING_BENCHMARK TUint32 _bmStart = NKern::FastCounter()
   554 #define END_PAGING_BENCHMARK(bm) ThePager.RecordBenchmarkData(bm, _bmStart, NKern::FastCounter())
   626 #define END_PAGING_BENCHMARK(bm) ThePager.RecordBenchmarkData(bm, _bmStart, NKern::FastCounter(), 1)
       
   627 #define END_PAGING_BENCHMARK_N(bm, n) ThePager.RecordBenchmarkData(bm, _bmStart, NKern::FastCounter(), (n))
   555 
   628 
   556 #else
   629 #else
   557 
   630 
   558 #define START_PAGING_BENCHMARK
   631 #define START_PAGING_BENCHMARK
   559 #define END_PAGING_BENCHMARK(bm)
   632 #define END_PAGING_BENCHMARK(bm)
       
   633 #define END_PAGING_BENCHMARK_N(bm, n)
   560 #endif // __DEMAND_PAGING_BENCHMARKS__
   634 #endif // __DEMAND_PAGING_BENCHMARKS__
   561 
   635 
   562 
   636 
   563 FORCE_INLINE void DPager::Event(TEventSimple aEvent, SPageInfo* aPageInfo)
   637 FORCE_INLINE void DPager::Event(TEventSimple aEvent, SPageInfo* aPageInfo)
   564 	{
   638 	{
   696 Multiplier for number of request objects in pool per drive that supports paging.
   770 Multiplier for number of request objects in pool per drive that supports paging.
   697 */
   771 */
   698 const TInt KPagingRequestsPerDevice = 2;
   772 const TInt KPagingRequestsPerDevice = 2;
   699 
   773 
   700 
   774 
   701 class DPagingRequest;
   775 class DPoolPagingRequest;
   702 class DPageReadRequest;
   776 class DPageReadRequest;
   703 class DPageWriteRequest;
   777 class DPageWriteRequest;
   704 
   778 
   705 /**
   779 /**
   706 A pool of paging requests for use by a single paging device.
   780 A pool of paging requests for use by a single paging device.
   707 */
   781 */
   708 class DPagingRequestPool : public DBase
   782 class DPagingRequestPool : public DBase
   709 	{
   783 	{
   710 public:
   784 public:
   711 	DPagingRequestPool(TUint aNumPageReadRequest,TUint aNumPageWriteRequest);
   785 	DPagingRequestPool(TUint aNumPageReadRequest, TBool aWriteRequest);
   712 	DPageReadRequest* AcquirePageReadRequest(DMemoryObject* aMemory, TUint aIndex, TUint aCount);
   786 	DPageReadRequest* AcquirePageReadRequest(DMemoryObject* aMemory, TUint aIndex, TUint aCount);
   713 	DPageWriteRequest* AcquirePageWriteRequest(DMemoryObject* aMemory, TUint aIndex, TUint aCount);
   787 	DPageWriteRequest* AcquirePageWriteRequest(DMemoryObject** aMemory, TUint* aIndex, TUint aCount);
   714 private:
   788 private:
   715 	~DPagingRequestPool();
   789 	~DPagingRequestPool();
   716 private:
   790 private:
   717 	class TGroup
   791 	class TGroup
   718 		{
   792 		{
   719 	public:
   793 	public:
   720 		TGroup(TUint aNumRequests);
   794 		TGroup(TUint aNumRequests);
   721 		DPagingRequest* FindCollision(DMemoryObject* aMemory, TUint aIndex, TUint aCount);
   795 		DPoolPagingRequest* FindCollisionContiguous(DMemoryObject* aMemory, TUint aIndex, TUint aCount);
   722 		DPagingRequest* GetRequest(DMemoryObject* aMemory, TUint aIndex, TUint aCount);
   796 		DPoolPagingRequest* GetRequest(DMemoryObject* aMemory, TUint aIndex, TUint aCount);
   723 		void Signal(DPagingRequest* aRequest);
   797 		void Signal(DPoolPagingRequest* aRequest);
   724 	public:
   798 	public:
   725 		TUint iNumRequests;
   799 		TUint iNumRequests;
   726 		DPagingRequest** iRequests;
   800 		DPoolPagingRequest** iRequests;
   727 		SDblQue iFreeList;
   801 		SDblQue iFreeList;
   728 		};
   802 		};
   729 	TGroup iPageReadRequests;
   803 	TGroup iPageReadRequests;
   730 	TGroup iPageWriteRequests;
   804 	DPageWriteRequest* iPageWriteRequest;
   731 
   805 
   732 	friend class DPagingRequest;
   806 	friend class DPoolPagingRequest;
   733 	friend class DPageReadRequest;
   807 	friend class DPageReadRequest;
   734 	friend class DPageWriteRequest;
   808 	friend class DPageWriteRequest;
   735 	};
   809 	};
   736 
   810 
   737 
   811 
   739 Resources needed to service a paging request.
   813 Resources needed to service a paging request.
   740 */
   814 */
   741 class DPagingRequest : public SDblQueLink
   815 class DPagingRequest : public SDblQueLink
   742 	{
   816 	{
   743 public:
   817 public:
   744 	DPagingRequest(DPagingRequestPool::TGroup& aPoolGroup);
   818 	enum
   745 	void Release();
   819 		{
       
   820 		EMaxPages = 4
       
   821 		};
       
   822 	DPagingRequest();
       
   823 	TLinAddr MapPages(TUint aColour, TUint aCount, TPhysAddr* aPages);
       
   824 	void UnmapPages(TBool aIMBRequired);
       
   825 	void SetUseContiguous(DMemoryObject* aMemory, TUint aIndex, TUint aCount);
       
   826 	void SetUseDiscontiguous(DMemoryObject** aMemory, TUint* aIndex, TUint aCount);
       
   827 	void ResetUse();
       
   828 	TBool CheckUseContiguous(DMemoryObject* aMemory, TUint aIndex, TUint aCount);
       
   829 	TBool CheckUseDiscontiguous(DMemoryObject** aMemory, TUint* aIndex, TUint aCount);
       
   830 	TBool IsCollisionContiguous(DMemoryObject* aMemory, TUint aIndex, TUint aCount);
       
   831 public:
       
   832 	DMutex*			iMutex;		/**< A mutex for synchronisation and priority inheritance. */
       
   833 protected:
       
   834 	Mmu::TTempMapping	iTempMapping;
       
   835 private:
       
   836 	// used to identify memory request is used for...
       
   837 	TUint			iUseRegionCount;
       
   838 	DMemoryObject*	iUseRegionMemory[EMaxPages];
       
   839 	TUint			iUseRegionIndex[EMaxPages];
       
   840 	};
       
   841 
       
   842 
       
   843 __ASSERT_COMPILE(DPagingRequest::EMaxPages >= KMaxPagesToClean);
       
   844 
       
   845 
       
   846 /**
       
   847 A paging request that is part of a pool of similar request objects.
       
   848 */
       
   849 class DPoolPagingRequest : public DPagingRequest
       
   850 	{
       
   851 public:
       
   852 	DPoolPagingRequest(DPagingRequestPool::TGroup& aPoolGroup);
       
   853  	void Release();
   746 	void Wait();
   854 	void Wait();
   747 	void Signal();
   855 	void Signal();
   748 	void SetUse(DMemoryObject* aMemory, TUint aIndex, TUint aCount);
   856 public:
   749 	TBool CheckUse(DMemoryObject* aMemory, TUint aIndex, TUint aCount);
   857 	TInt			iUsageCount;	/**< How many threads are using or waiting for this object. */	
   750 	TBool IsCollision(DMemoryObject* aMemory, TUint aIndex, TUint aCount);
       
   751 	TLinAddr MapPages(TUint aColour, TUint aCount, TPhysAddr* aPages);
       
   752 	void UnmapPages(TBool aIMBRequired);
       
   753 public:
       
   754 	TThreadMessage	iMessage;	/**< Used by the media driver to queue requests */
       
   755 	DMutex*			iMutex;		/**< A mutex for synchronisation and priority inheritance. */
       
   756 	TInt			iUsageCount;/**< How many threads are using or waiting for this object. */
       
   757 	TLinAddr		iBuffer;	/**< A buffer to read compressed data into. Size is EMaxPages+1 pages.*/
       
   758 protected:
       
   759 	Mmu::TTempMapping	iTempMapping;
       
   760 private:
   858 private:
   761 	DPagingRequestPool::TGroup& iPoolGroup;
   859 	DPagingRequestPool::TGroup& iPoolGroup;
   762 	// used to identify memory request is used for...
       
   763 	DMemoryObject*	iUseRegionMemory;
       
   764 	TUint			iUseRegionIndex;
       
   765 	TUint			iUseRegionCount;
       
   766 	};
   860 	};
   767 
   861 
   768 
   862 	
   769 /**
   863 /**
   770 Resources needed to service a page in request.
   864 Resources needed to service a page in request.
   771 */
   865 */
   772 class DPageReadRequest : public DPagingRequest
   866 class DPageReadRequest : public DPoolPagingRequest
   773 	{
   867 	{
   774 public:
   868 public:
   775 	inline DPageReadRequest(DPagingRequestPool::TGroup& aPoolGroup)
   869 	DPageReadRequest(DPagingRequestPool::TGroup& aPoolGroup);
   776 		: DPagingRequest(aPoolGroup)
       
   777 		{}
       
   778 	TInt Construct();
   870 	TInt Construct();
   779 	enum
       
   780 		{
       
   781 		EMaxPages = 4
       
   782 		};
       
   783 	static TUint ReservedPagesRequired();
   871 	static TUint ReservedPagesRequired();
   784 private:
   872 private:
   785 	~DPageReadRequest(); // can't delete
   873 	~DPageReadRequest(); // can't delete
   786 public:
   874 public:
   787 	TLinAddr		iBuffer;	/**< A buffer to read compressed data into. Size is EMaxPages+1 pages.*/
   875 	TLinAddr		iBuffer;	/**< A buffer to read compressed data into. Size is EMaxPages+1 pages.*/
   802 Resources needed to service a page out request.
   890 Resources needed to service a page out request.
   803 */
   891 */
   804 class DPageWriteRequest : public DPagingRequest
   892 class DPageWriteRequest : public DPagingRequest
   805 	{
   893 	{
   806 public:
   894 public:
   807 	inline DPageWriteRequest(DPagingRequestPool::TGroup& aPoolGroup)
   895 	DPageWriteRequest();
   808 		: DPagingRequest(aPoolGroup)
   896  	void Release();
   809 		{}
       
   810 	TInt Construct();
       
   811 	enum
       
   812 		{
       
   813 		EMaxPages = 1
       
   814 		};
       
   815 private:
   897 private:
   816 	~DPageWriteRequest(); // can't delete
   898 	~DPageWriteRequest(); // can't delete
   817 private:
       
   818 	static TInt iAllocNext;
       
   819 	};
   899 	};
   820 
   900 
   821 
   901 
       
   902 /**
       
   903 Class providing access to the mutex used to protect page cleaning operations;
       
   904 this is the mutex DPager::iPageCleaningLock.
       
   905 */
       
   906 class PageCleaningLock
       
   907 	{
       
   908 public:
       
   909 	/**
       
   910 	Acquire the lock.
       
   911 	The lock may be acquired multiple times by a thread, and will remain locked
       
   912 	until #Unlock has been used enough times to balance this.
       
   913 	*/
       
   914 	static void Lock();
       
   915 
       
   916 	/**
       
   917 	Release the lock.
       
   918 
       
   919 	@pre The current thread has previously acquired the lock.
       
   920 	*/
       
   921 	static void Unlock();
       
   922 
       
   923 	/**
       
   924 	Return true if the current thread holds the lock.
       
   925 	This is used for debug checks.
       
   926 	*/
       
   927 	static TBool IsHeld();
       
   928 
       
   929 	/**
       
   930 	Create the lock.
       
   931 	Called by DPager::Init3().
       
   932 	*/
       
   933 	static void Init();	
       
   934 	};
       
   935 
       
   936 
   822 #endif
   937 #endif