kerneltest/e32test/mmu/t_cachechunk.cpp
branchRCL_3
changeset 39 2bb754abd467
parent 24 41f0cfe18c80
--- a/kerneltest/e32test/mmu/t_cachechunk.cpp	Wed Jun 09 11:10:19 2010 +0300
+++ b/kerneltest/e32test/mmu/t_cachechunk.cpp	Mon Jun 21 17:12:14 2010 +0300
@@ -87,8 +87,9 @@
 #include "d_gobble.h"
 #include <dptest.h>
 #include "freeram.h"
+#include "..\demandpaging\t_dpcmn.h"
 
-LOCAL_D RTest test(_L("T_CACHECHUNK"));
+RTest test(_L("T_CACHECHUNK"));
 
 RMemoryTestLdd MemoryTest;
 
@@ -504,6 +505,175 @@
 	}
 
 
+TBool StopCacheThreads;
+
+TInt CacheThreadFunc(TAny* aMax)
+	{
+	RThread::Rendezvous(KErrNone);
+	while (!StopCacheThreads)
+		{
+		TInt maxSize = (TInt)aMax;
+		TInt minSize;
+		TInt r = KErrNone;
+		for (minSize = PageSize << 4; r == KErrNone && !StopCacheThreads; minSize += PageSize)
+			{
+			r = UserSvr::HalFunction(EHalGroupVM,EVMHalSetCacheSize,(TAny*)minSize,(TAny*)maxSize);
+			User::After(minSize/PageSize);
+			}
+		for (minSize -= PageSize; 
+			minSize > PageSize << 4 && r == KErrNone  && !StopCacheThreads;
+			minSize -= PageSize)
+			{
+			r = UserSvr::HalFunction(EHalGroupVM,EVMHalSetCacheSize,(TAny*)minSize,(TAny*)maxSize);
+			User::After(minSize/PageSize);
+			}
+		}
+	return KErrNone;
+	}
+
+
+TInt DonateThreadFunc(TAny*)
+	{
+	TChunkCreateInfo createInfo;
+	createInfo.SetCache(100 * PageSize);
+	RChunk chunk;
+	TInt r = chunk.Create(createInfo);
+	if (r != KErrNone)
+		{
+		RDebug::Printf("DonateThreadFunc: Failed to create cache chunk %d", r);
+		return r;
+		}
+	TUint chunkEnd = 0;
+	while (chunk.Commit(chunkEnd, PageSize) == KErrNone)
+		chunkEnd += PageSize;
+
+	RThread::Rendezvous(KErrNone);
+	while (!StopCacheThreads)
+		{
+		for (TUint i = PageSize; i <= chunkEnd && !StopCacheThreads; i += PageSize)
+			{
+			chunk.Unlock(0, i);
+			if (chunk.Lock(0, i) != KErrNone)
+				{// Recommit as many pages as possible.
+				while (chunk.Commit(0, chunkEnd) != KErrNone && !StopCacheThreads)
+					chunkEnd -= PageSize;
+				i = 0;
+				}
+			User::After(i/PageSize);
+			}
+		}
+	CLOSE_AND_WAIT(chunk);
+	return KErrNone;
+	}
+
+
+TInt DirtyThreadFunc(TAny*)
+	{
+	RThread::Rendezvous(KErrNone);
+
+	RChunk chunk;
+	TChunkCreateInfo createInfo;
+	createInfo.SetNormal(PageSize * 100, PageSize *100);
+	createInfo.SetPaging(TChunkCreateInfo::EPaged);
+	TInt r = chunk.Create(createInfo);
+	if (r != KErrNone)
+		{
+		RDebug::Printf("Failed to create a cache chunk %d", r);
+		return r;
+		}
+	TUint8* base = chunk.Base();
+	// Dirty each page in the chunk so that there are dirty pages in the live 
+	// list while it is being resized and pages are being unlocked.
+	while (!StopCacheThreads)
+		{
+		TUint8* p = base;
+		TUint8* pEnd = base + chunk.Size();
+		for (; p < pEnd && !StopCacheThreads; p += PageSize)
+			{
+			*p = (TUint8)(pEnd - p);
+			User::After((TUint8)(pEnd - p));
+			}
+		}
+	CLOSE_AND_WAIT(chunk);
+	return KErrNone;
+	}
+
+
+void TestResizeExcess()
+	{
+	test.Printf(_L("Commit all of memory again leaving 100 free pages\n"));
+	CommitEnd = 0;
+	TInt r;
+	while(KErrNone==(r=TestChunk.Commit(CommitEnd,PageSize)))
+		{
+		CommitEnd += PageSize;
+		}
+	test(r==KErrNoMemory);
+	test_KErrNone(TestChunk.Unlock(0, 100 * PageSize));
+
+	SVMCacheInfo info;
+	test_KErrNone(UserSvr::HalFunction(EHalGroupVM, EVMHalGetCacheSize, &info, 0));
+
+	StopCacheThreads = EFalse;
+	RThread cacheThread;
+	r = cacheThread.Create(	KNullDesC, CacheThreadFunc, KDefaultStackSize, PageSize,
+							PageSize, (TAny*)info.iMaxSize);
+	test_KErrNone(r);
+	TRequestStatus threadStarted;
+	cacheThread.Rendezvous(threadStarted);
+	TRequestStatus cacheStatus;
+	cacheThread.Logon(cacheStatus);
+	cacheThread.Resume();
+	User::WaitForRequest(threadStarted);
+	test_KErrNone(threadStarted.Int());
+
+	// Create the dirty thread before the donate thread as the donate thread may
+	// consume all the free ram periodically.
+	RThread dirtyThread;
+	r = dirtyThread.Create(KNullDesC, DirtyThreadFunc, KDefaultStackSize, PageSize, PageSize, NULL);
+	test_KErrNone(r);
+	dirtyThread.Rendezvous(threadStarted);
+	TRequestStatus dirtyStatus;
+	dirtyThread.Logon(dirtyStatus);
+	dirtyThread.Resume();
+	User::WaitForRequest(threadStarted);
+	test_KErrNone(threadStarted.Int());
+
+	RThread donateThread;
+	r = donateThread.Create(KNullDesC, DonateThreadFunc, KDefaultStackSize, PageSize, PageSize, NULL);
+	test_KErrNone(r);
+	donateThread.Rendezvous(threadStarted);
+	TRequestStatus donateStatus;
+	donateThread.Logon(donateStatus);
+	donateThread.Resume();
+	User::WaitForRequest(threadStarted);
+	test_KErrNone(threadStarted.Int());
+
+	// Run test for 10 secs.
+	User::After(10000000);
+
+	// End the test.
+	StopCacheThreads = ETrue;
+	User::WaitForRequest(donateStatus);
+	test_Equal(EExitKill, donateThread.ExitType());
+	test_KErrNone(donateThread.ExitReason());
+	User::WaitForRequest(dirtyStatus);
+	test_Equal(EExitKill, dirtyThread.ExitType());
+	test_KErrNone(dirtyThread.ExitReason());
+	User::WaitForRequest(cacheStatus);
+	test_Equal(EExitKill, cacheThread.ExitType());
+	test_KErrNone(cacheThread.ExitReason());
+
+	CLOSE_AND_WAIT(donateThread);
+	CLOSE_AND_WAIT(cacheThread);
+	CLOSE_AND_WAIT(dirtyThread);
+
+	test_KErrNone(UserSvr::HalFunction(	EHalGroupVM,
+										EVMHalSetCacheSize,
+										(TAny*)info.iMinSize,
+										(TAny*)info.iMaxSize));
+	}
+
 
 TInt E32Main()
 	{
@@ -636,6 +806,16 @@
 	if (resizeCache)
 		test_KErrNone(DPTest::SetCacheSize(originalMin, originalMax));
 
+	test_KErrNone(GetGlobalPolicies());
+	if (gDataPagingSupported)
+		{
+		test.Next(_L("Test interactions of chunk unlocking and page cache resizing"));
+		// Do this after the live list limit is restored.
+		test_KErrNone(TestChunk.Create(createInfo));
+		TestResizeExcess();
+		TestChunk.Close();
+		}
+
 	// end...
 	test.End();
 	MemoryTest.Close();