kerneltest/e32test/misc/t_svr6.cpp
changeset 0 a41df078684a
child 109 b3a1d9898418
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kerneltest/e32test/misc/t_svr6.cpp	Mon Oct 19 15:55:17 2009 +0100
@@ -0,0 +1,727 @@
+// Copyright (c) 1995-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of the License "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+// e32test\misc\t_svr6.cpp
+// 
+//
+
+#define __E32TEST_EXTENSION__
+#include <e32base.h>
+#include <e32base_private.h>
+#include <e32test.h>
+#include <e32svr.h>
+#include "u32std.h"
+#include "../misc/prbs.h"
+#include "../mmu/freeram.h"
+
+const TInt KStackSize=0x1000;
+const TInt KHeapMaxSize=0x100000;
+const TInt KMajorVersionNumber=1;
+const TInt KMinorVersionNumber=0;
+const TInt KBuildVersionNumber=1;
+const TInt KNumMessageSlots=10;
+
+_LIT(KServerName,"StressSvr");
+
+LOCAL_D RTest test(_L("T_SVR6"));
+
+class CMySession : public CSession2
+	{
+public:
+	CMySession();
+	virtual void ServiceL(const RMessage2& aMessage);			 //pure virtual fns.
+	void Process(const RMessage2& aMessage);
+public:
+	TInt iOutstanding;
+	TUint iSeed[2];
+	};
+
+class CMyServer : public CServer2
+	{
+public:
+	enum {ETest};
+public:
+	CMyServer(TInt aPriority);
+	static CMyServer* New(TInt aPriority);
+	virtual CSession2* NewSessionL(const TVersion& aVersion, const RMessage2&) const;//Overloading
+	};
+
+class CMyActiveScheduler : public CActiveScheduler
+	{
+public:
+	virtual void Error(TInt anError) const;  //Overloading pure virtual function
+	};
+
+class RStressSvr : public RSessionBase
+	{
+public:
+	TInt Connect();
+	TInt Test();
+	void Test(TRequestStatus& aStatus);
+	TVersion Version();
+	};
+
+class CThread : public CActive
+	{
+public:
+	CThread(TInt aPriority);
+	~CThread();
+	virtual void RunL();
+	virtual void DoCancel();
+	virtual void DisplayStats()=0;
+	virtual TBool PanicBadHandleAllowed();
+	virtual void RegisterAllowedPanic();
+	virtual void Cleanup();
+	virtual TInt ProcessStartError(TInt anError);
+	TInt Start();
+public:
+	virtual TInt StartThread()=0;
+public:
+	RThread iThread;
+	TInt iExitCount;
+	TInt iServerTerminatedCount;
+	TInt iTerminateCount;
+	};
+
+class CServerThread : public CThread
+	{
+public:
+	static void NewL();
+	CServerThread();
+	virtual TInt StartThread();
+	virtual void DisplayStats();
+public:
+	TInt iMessagesReceived;
+	};
+
+class CClientThread : public CThread
+	{
+public:
+	static void NewL(TInt anId, TInt aPrimaryId);
+	CClientThread(TInt anId);
+	virtual TInt StartThread();
+	virtual void DisplayStats();
+	virtual TBool PanicBadHandleAllowed();
+	virtual void RegisterAllowedPanic();
+	virtual void Cleanup();
+	virtual TInt ProcessStartError(TInt anError);
+public:
+	TInt iId;
+	TInt iCloses;
+	CClientThread* iPrimary;
+	RStressSvr iSession;
+	TBool iConnected;
+	TBool iWaitingToRestart;
+	};
+
+class CRandomTimer : public CActive
+	{
+public:
+	static void NewL();
+	CRandomTimer(TInt aPriority);
+	~CRandomTimer();
+	virtual void RunL();
+	virtual void DoCancel();
+	void Start();
+public:
+	RTimer iTimer;
+	TUint iSeed[2];
+	TInt iCount;
+	};
+
+class CStatsTimer : public CActive
+	{
+public:
+	static void NewL();
+	CStatsTimer(TInt aPriority);
+	~CStatsTimer();
+	virtual void RunL();
+	virtual void DoCancel();
+	void Start();
+public:
+	RTimer iTimer;
+	TInt iInitFreeRam;
+	TInt iMaxDelta;
+	TInt iCount;
+	};
+
+const TInt KNumPrimaryClients=3;
+const TInt KNumSecondariesPerPrimary=3;
+const TInt KNumClients=KNumPrimaryClients*KNumSecondariesPerPrimary;
+LOCAL_D CServerThread* TheServer;
+LOCAL_D CClientThread* TheClients[KNumClients];
+LOCAL_D CRandomTimer* TheRandomTimer;
+
+CMySession::CMySession()
+//
+// Constructor
+//
+	{
+	iSeed[0]=User::TickCount();
+	}
+
+CMyServer* CMyServer::New(TInt aPriority)
+//
+// Create a new CMyServer.
+//
+	{
+
+	return new CMyServer(aPriority);
+	}
+
+CMyServer::CMyServer(TInt aPriority)
+//
+// Constructor.
+//
+	: CServer2(aPriority, ESharableSessions)
+	{}
+
+CSession2* CMyServer::NewSessionL(const TVersion& aVersion, const RMessage2&) const
+//
+// Create a new client for this server.
+//
+	{
+
+	TVersion v(KMajorVersionNumber,KMinorVersionNumber,KBuildVersionNumber);
+	if (!User::QueryVersionSupported(v,aVersion))
+		User::Leave(KErrNotSupported);
+	return new(ELeave) CMySession;
+	}
+
+void CMySession::ServiceL(const RMessage2& aMessage)
+//
+// Handle messages for this server.
+//
+	{
+
+	++TheServer->iMessagesReceived;
+	switch (aMessage.Function())
+		{
+		case CMyServer::ETest:
+			if (iOutstanding==KNumMessageSlots-1)
+				Process(aMessage);
+			else
+				++iOutstanding;
+			break;
+		default:
+			aMessage.Complete(KErrNotSupported);
+			break;
+		}
+	}
+
+void CMySession::Process(const RMessage2& aMessage)
+	{
+	TUint x=Random(iSeed)&16383;
+	if (x==0)
+		User::Exit(0);			// exit the server
+	else if (x<8)
+		aMessage.Terminate(0);	// terminate the client
+	else
+		aMessage.Complete(KErrNone);
+	}
+
+void CMyActiveScheduler::Error(TInt anError) const
+//
+// Called if any Run() method leaves.
+//
+	{
+
+	User::Panic(_L("Server Error"),anError);
+	}
+
+TInt RStressSvr::Connect()
+//
+// Connect to the server
+//
+	{
+
+	TInt r=CreateSession(KServerName,Version(),KNumMessageSlots);
+	if (r==KErrNone)
+		r=ShareAuto();
+	return r;
+	}
+
+TInt RStressSvr::Test()
+//
+// Send a message and wait for completion.
+//
+	{
+
+	return SendReceive(CMyServer::ETest);
+	}
+
+void RStressSvr::Test(TRequestStatus& aStatus)
+//
+// Send a message asynchronously
+//
+	{
+
+	SendReceive(CMyServer::ETest,aStatus);
+	}
+
+TVersion RStressSvr::Version()
+//
+// Return the current version.
+//
+	{
+
+	TVersion v(KMajorVersionNumber,KMinorVersionNumber,KBuildVersionNumber);
+	return(v);
+	}
+
+LOCAL_C TInt ServerThread(TAny*)
+	{
+
+	CMyActiveScheduler* pR=new CMyActiveScheduler;
+	if (!pR)
+		return KErrNoMemory;
+	CActiveScheduler::Install(pR);
+	CMyServer* pS=CMyServer::New(0);
+	if (!pS)
+		return KErrNoMemory;
+	TInt r=pS->Start(KServerName);
+	if (r!=KErrNone)
+		return r;
+
+	CActiveScheduler::Start();
+
+	delete pS;
+	delete pR;
+	return KErrNone;
+	}
+
+LOCAL_C TInt ClientThread(TAny* aPtr)
+	{
+	CClientThread* pT=(CClientThread*)aPtr;
+	CClientThread* pP=pT->iPrimary;
+	TBool primary=(pP==pT);
+	RStressSvr& d=pP->iSession;
+	TUint seed[2];
+	seed[0]=User::TickCount();
+	seed[1]=0;
+	TInt r=KErrNone;
+	TInt i;
+	if (primary)
+		{
+		FOREVER
+			{
+			FOREVER
+				{
+				r=d.Connect();
+				if (r!=KErrNotFound)
+					break;
+				User::After(50000);
+				}
+			if (r!=KErrNone)
+				return r;
+			pT->iConnected=ETrue;
+			TRequestStatus s[KNumMessageSlots];
+			for (i=0; i<KNumMessageSlots-1; i++)
+				d.Test(s[i]);
+			TInt n=Random(seed)&16383;
+			for (i=0; i<n && r==KErrNone; i++)
+				r=d.Test();
+			pT->iConnected=EFalse;
+			d.Close();
+			++pT->iCloses;
+			}
+		}
+	else
+		{
+		TRequestStatus s[KNumMessageSlots];
+		for (i=0; i<KNumMessageSlots-1; i++)
+			d.Test(s[i]);
+		FOREVER
+			{
+			if (pP->iConnected)
+				{
+				RStressSvr dd;
+				dd.SetHandle(pP->iSession.Handle());
+				TInt n=Random(seed)&16383;
+				for (i=0; i<n && r==KErrNone; i++)
+					r=dd.Test();
+				}
+			TInt ms=(Random(seed)&7)+1;
+			User::AfterHighRes(ms*1000);
+			}
+		}
+	}
+
+CThread::CThread(TInt aPriority)
+	: CActive(aPriority)
+	{
+	}
+
+CThread::~CThread()
+	{
+	Cancel();
+	iThread.Kill(0);
+	iThread.Close();
+	}
+
+_LIT(KLitKernExec,"KERN-EXEC");
+void CThread::RunL()
+	{
+	TExitType exitType=iThread.ExitType();
+	TInt exitReason=iThread.ExitReason();
+	TBuf<32> exitCat=iThread.ExitCategory();
+	TBool bad=EFalse;
+	if (exitType==EExitKill)
+		{
+		if (exitReason!=KErrNone && exitReason!=KErrServerTerminated)
+			bad=ETrue;
+		}
+	else if (exitType==EExitPanic)
+		{
+		if (!PanicBadHandleAllowed() || exitCat!=KLitKernExec || exitReason!=EBadHandle)
+			bad=ETrue;
+		else
+			RegisterAllowedPanic();
+		}
+	if (bad)
+		{
+		TFullName n(iThread.FullName());
+		test.Printf(_L("Thread %S exited %d,%d,%S\n"),&n,exitType,exitReason,&exitCat);
+		CActiveScheduler::Stop();
+		return;
+		}
+	Cleanup();
+	iThread.Close();
+	if (exitType==EExitTerminate)
+		++iTerminateCount;
+	else if (exitType==EExitKill && exitReason==KErrNone)
+		++iExitCount;
+	else if (exitReason==KErrServerTerminated)
+		++iServerTerminatedCount;
+	TInt r=Start();
+	if (r!=KErrNone)
+		{
+		test.Printf(_L("Start thread error %d\n"),r);
+		CActiveScheduler::Stop();
+		}
+	}
+
+void CThread::DoCancel()
+	{
+	iThread.LogonCancel(iStatus);
+	}
+
+const TInt KThreadStartAttempts=3;
+TInt CThread::Start()
+	{
+	TInt r=KErrNone;
+	TInt n=KThreadStartAttempts;
+	while(n--)
+		{
+		r=StartThread();
+		if (r==KErrNone)
+			break;
+		if (r!=KErrAlreadyExists)
+			break;
+		User::After(100000);
+		}
+	if (r==KErrNone)
+		{
+		iThread.Logon(iStatus);
+		SetActive();
+		}
+	return ProcessStartError(r);
+	}
+
+TBool CThread::PanicBadHandleAllowed()
+	{
+	return EFalse;
+	}
+
+void CThread::RegisterAllowedPanic()
+	{
+	}
+
+void CThread::Cleanup()
+	{
+	}
+
+TInt CThread::ProcessStartError(TInt anError)
+	{
+	return anError;
+	}
+
+CServerThread::CServerThread()
+	: CThread(0)
+	{
+	}
+
+TInt CServerThread::StartThread()
+	{
+	TUint seed[2];
+	seed[1]=0;
+	seed[0]=User::TickCount();
+	TInt heapMin=TInt(Random(seed)&0x0f)+1;
+	heapMin<<=12;
+	TInt r=iThread.Create(KNullDesC(),ServerThread,KStackSize,heapMin,KHeapMaxSize,this);	// use unnamed thread
+	if (r!=KErrNone)
+		return r;
+	iThread.Resume();
+	return KErrNone;
+	}
+
+void CServerThread::NewL()
+	{
+	CServerThread* pT=new (ELeave) CServerThread;
+	TheServer=pT;
+	CActiveScheduler::Add(pT);
+	User::LeaveIfError(pT->Start());
+	}
+
+void CServerThread::DisplayStats()
+	{
+	test.Printf(_L("Svr  : X:%9d ST:%9d T:%9d RX:%9d\n"),iExitCount,iServerTerminatedCount,iTerminateCount,iMessagesReceived);
+	}
+
+CClientThread::CClientThread(TInt anId)
+	: CThread(0), iId(anId)
+	{
+	}
+
+TInt CClientThread::StartThread()
+	{
+	TInt r=iThread.Create(KNullDesC(),ClientThread,KStackSize,NULL,this);	// use unnamed threads
+	if (r!=KErrNone)
+		return r;
+	iSession.SetHandle(0);
+	iThread.Resume();
+	return KErrNone;
+	}
+
+void CClientThread::NewL(TInt anId, TInt aPrimaryId)
+	{
+	CClientThread* pT=new (ELeave) CClientThread(anId);
+	TheClients[anId]=pT;
+	pT->iPrimary=TheClients[aPrimaryId];
+	CActiveScheduler::Add(pT);
+	User::LeaveIfError(pT->Start());
+	}
+
+void CClientThread::DisplayStats()
+	{
+	test.Printf(_L("Cli %1d: X:%9d ST:%9d T:%9d CL:%9d\n"),iId,iExitCount,iServerTerminatedCount,iTerminateCount,iCloses);
+	}
+
+TBool CClientThread::PanicBadHandleAllowed()
+	{
+	return (iPrimary!=this);
+	}
+
+void CClientThread::RegisterAllowedPanic()
+	{
+	++iCloses;
+	}
+
+void CClientThread::Cleanup()
+	{
+	TInt r=KErrNone;
+	if (iPrimary==this)
+		{
+		if (!IsLocalHandle(iSession.Handle()))	// don't close if not shared yet
+			iSession.Close();
+		CClientThread* pS1=TheClients[iId+1];
+		CClientThread* pS2=TheClients[iId+2];
+		if (pS1->iWaitingToRestart)
+			r=pS1->Start();
+		if (r==KErrNone && pS2->iWaitingToRestart)
+			r=pS2->Start();
+		if (r!=KErrNone)
+			{
+			test.Printf(_L("Start thread error %d\n"),r);
+			CActiveScheduler::Stop();
+			}
+		}
+	}
+
+TInt CClientThread::ProcessStartError(TInt anError)
+	{
+	if (anError==KErrAlreadyExists && iPrimary!=this && !iWaitingToRestart)
+		{
+		iWaitingToRestart=ETrue;
+		return KErrNone;
+		}
+	iWaitingToRestart=EFalse;
+	return anError;
+	}
+
+void CRandomTimer::NewL()
+	{
+	CRandomTimer* pR=new (ELeave) CRandomTimer(20);
+	User::LeaveIfError(pR->iTimer.CreateLocal());
+	CActiveScheduler::Add(pR);
+	TheRandomTimer=pR;
+	pR->Start();
+	}
+
+CRandomTimer::CRandomTimer(TInt aPriority)
+	: CActive(aPriority)
+	{
+	iSeed[0]=User::TickCount();
+	}
+
+CRandomTimer::~CRandomTimer()
+	{
+	Cancel();
+	iTimer.Close();
+	}
+
+void CRandomTimer::RunL()
+	{
+	++iCount;
+	TUint x=Random(iSeed)&15;
+	CThread* pT=NULL;
+	if (x==0)
+		pT=TheServer;
+	else if (x<10)
+		{
+		pT=TheClients[x-1];
+		if (((CClientThread*)pT)->iWaitingToRestart)
+			pT=NULL;
+		}
+	if (pT)
+		pT->iThread.Kill(0);
+	Start();
+	}
+
+void CRandomTimer::Start()
+	{
+	TUint x=Random(iSeed)&63;
+	x+=64;
+	iTimer.HighRes(iStatus, x*1000);
+	SetActive();
+	}
+
+void CRandomTimer::DoCancel()
+	{
+	iTimer.Cancel();
+	}
+
+void CStatsTimer::NewL()
+	{
+	CStatsTimer* pT=new (ELeave) CStatsTimer(-10);
+	User::LeaveIfError(pT->iTimer.CreateLocal());
+	CActiveScheduler::Add(pT);
+	pT->Start();
+	}
+
+CStatsTimer::CStatsTimer(TInt aPriority)
+	: CActive(aPriority)
+	{
+	iInitFreeRam = FreeRam();
+	}
+
+CStatsTimer::~CStatsTimer()
+	{
+	Cancel();
+	iTimer.Close();
+	}
+
+void CStatsTimer::RunL()
+	{
+	TheServer->DisplayStats();
+	TInt i;
+	for (i=0; i<KNumClients; i++)
+		TheClients[i]->DisplayStats();
+	test.Printf(_L("RndTm: %9d\n"),TheRandomTimer->iCount);
+	TInt free_ram = FreeRam();
+	TInt delta_ram = iInitFreeRam - free_ram;
+	if (delta_ram > iMaxDelta)
+		iMaxDelta = delta_ram;
+	if (++iCount==10)
+		{
+		test.Printf(_L("Max RAM delta %dK Free RAM %08x\n"), iMaxDelta/1024, free_ram);
+		iCount=0;
+		}
+	Start();
+	}
+
+void CStatsTimer::Start()
+	{
+	iTimer.After(iStatus, 1000000);
+	SetActive();
+	}
+
+void CStatsTimer::DoCancel()
+	{
+	iTimer.Cancel();
+	}
+
+void InitialiseL()
+	{
+	CActiveScheduler* pA=new (ELeave) CActiveScheduler;
+	CActiveScheduler::Install(pA);
+	CServerThread::NewL();
+	TInt p;
+	TInt s;
+	TInt id=0;
+	for (p=0; p<KNumClients; p+=KNumSecondariesPerPrimary)
+		{
+		for (s=0; s<KNumSecondariesPerPrimary; s++)
+			{
+			CClientThread::NewL(id,p);
+			id++;
+			}
+		}
+	CRandomTimer::NewL();
+	CStatsTimer::NewL();
+	}
+
+GLDEF_C TInt E32Main()
+//
+// Test timers.
+//
+	{
+
+	test.Title();
+
+	User::SetCritical(User::ESystemCritical);
+	RThread().SetPriority(EPriorityMore);
+	User::SetJustInTime(EFalse);	// prevent the debugger picking up expected thread panics.
+
+	TRAPD(r,InitialiseL());
+	test(r==KErrNone);
+
+	CActiveScheduler::Start();
+
+	test(0);
+
+	return(0);
+	}
+
+// Override heap creation for this process
+// This function runs at the beginning of every thread
+// Initial heap is shared but subsequent heaps are single threaded
+TInt UserHeap::SetupThreadHeap(TBool aNotFirst, SStdEpocThreadCreateInfo& aInfo)
+	{
+	TInt r = KErrNone;
+	if (!aInfo.iAllocator && aInfo.iHeapInitialSize>0)
+		{
+		// new heap required
+		RHeap* pH = NULL;
+		r = CreateThreadHeap(aInfo, pH, 0, aNotFirst);
+		}
+	else if (aInfo.iAllocator)
+		{
+		// sharing a heap
+		RAllocator* pA = aInfo.iAllocator;
+		pA->Open();
+		User::SwitchAllocator(pA);
+		}
+	return r;
+	}
+