kerneltest/e32test/thread/t_threadedserver.cpp
changeset 0 a41df078684a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kerneltest/e32test/thread/t_threadedserver.cpp	Mon Oct 19 15:55:17 2009 +0100
@@ -0,0 +1,330 @@
+// Copyright (c) 1998-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\thread\t_threadedserver.cpp
+// Tests the multi-threaded server/session support in CServer2/CSession2
+// Overview:
+// Tests the CServer2::SetMaster and CSession2:SetServer functions
+// API Information:
+// CServer2, CSession2
+// Details:
+// - Test creating multiple sessions with a single-threaded server
+// - Test creating multiple sessions with a multi-threaded server
+// - Verify that requests to a multi-threaded server can run in parallel and complete out-of-order
+// Platforms/Drives/Compatibility:
+// All.
+// Assumptions/Requirement/Pre-requisites:
+// Failures and causes:
+// Base Port information:
+//
+
+
+
+#define __E32TEST_EXTENSION__
+#include <e32test.h>
+#include <e32panic.h>
+#include <e32debug.h>
+
+_LIT(KMyName, "T_THREADEDSERVER");
+_LIT(KServerName,"MyServer");
+const TInt KHeapSize = 4096;
+
+LOCAL_D RTest test(KMyName);
+
+class CMySession : public CSession2
+	{
+public:
+	enum TMyRequests { EFinish, EDelay5, EPing };
+	CMySession(TInt aId);
+	virtual void ServiceL(const RMessage2& aMessage);
+private:
+	const TInt iD;
+	};
+
+CMySession::CMySession(TInt aId) :
+	iD(aId)
+	{
+	}
+
+void CMySession::ServiceL(const RMessage2& aMessage)
+	{
+	TInt err = KErrNotSupported;
+
+	RDebug::Printf("Session %d: received message %d", iD, aMessage.Function());
+	switch (aMessage.Function())
+		{
+		case EFinish:
+			CActiveScheduler::Stop();
+			err = KErrNone;
+			break;
+
+		case EDelay5:
+			User::After(5000000);
+			err = KErrNone;
+			break;
+
+		case EPing:
+			User::After(1000000);
+			err = KErrNone;
+			break;
+
+		default:
+			break;
+		}
+
+	RDebug::Printf("Session %d: completing message %d, err %d", iD, aMessage.Function(), err);
+	if (err == KErrNone)
+		aMessage.Complete(err);
+	else
+		aMessage.Panic(KServerName, err);
+	}
+
+
+class CMyServer : public CServer2
+	{
+public:
+	CMyServer();
+	virtual CSession2* NewSessionL(const TVersion& aVersion, const RMessage2& aMessage) const;
+private:
+	mutable TInt iCount;
+	};
+
+static CMyServer* TheMaster = NULL;
+static CMyServer* TheSlave = NULL;
+
+CMyServer::CMyServer() :
+	CServer2(0),
+	iCount(0)
+	{
+	}
+
+CSession2* CMyServer::NewSessionL(const TVersion&, const RMessage2&) const
+	{
+	RDebug::Printf("Server: creating session, slave is $%x", TheSlave);
+	iCount += 1;
+	CSession2* mySession = new (ELeave) CMySession(iCount);
+	if (iCount > 1 && TheSlave != NULL)
+		mySession->SetServer(TheSlave);
+	RDebug::Printf("Server: created session %d", iCount);
+	return mySession;
+	}
+
+TInt RunServerCode(TAny* aFlag)
+	{
+	TInt mode = (TInt)aFlag;
+	TInt r = KErrNoMemory;
+	RDebug::Printf("Server: start, mode %d", mode);
+
+	CTrapCleanup* cleanup = CTrapCleanup::New();
+	if (cleanup == NULL)
+		return r;
+
+	CActiveScheduler* pR = new CActiveScheduler;
+	if (pR == NULL)
+		return r;
+
+	CActiveScheduler::Install(pR);
+	CMyServer* pS = new CMyServer();
+	if (pS == NULL)
+		return r;
+
+	switch (mode)
+		{
+		case 0:
+			r = pS->Start(KServerName);
+			break;
+		case 1:
+			TheMaster = pS;
+			pS->SetMaster(TheMaster);
+			r = pS->Start(KServerName);
+			break;
+		case 2:
+			TheSlave = pS;
+			pS->SetMaster(TheMaster);
+			r = pS->Start(KNullDesC);
+			break;
+		}
+	if (r != KErrNone)
+		return r;
+
+	RThread::Rendezvous(KErrNone);
+	TRAP(r, CActiveScheduler::Start());
+	if (r != KErrNone)
+		return r;
+
+	delete pS;
+	delete pR;
+	delete cleanup;
+
+	RDebug::Printf("Server: exit");
+	return KErrNone;
+	}
+
+
+class RSession : public RSessionBase
+	{
+public:
+	TInt Create();
+	void Request(TInt aRequest, TRequestStatus& aStatus);
+	void Request(TInt aRequest);
+	};
+
+TInt RSession::Create()
+	{
+	return CreateSession(KServerName, TVersion());
+	}
+
+void RSession::Request(TInt aRequest, TRequestStatus& aStatus)
+	{
+	SendReceive(aRequest, TIpcArgs(), aStatus);
+	}
+
+void RSession::Request(TInt aRequest)
+	{
+	SendReceive(aRequest, TIpcArgs());
+	}
+
+TInt RunClientCode(TAny* aFlag)
+	{
+	TInt mode = (TInt)aFlag;
+	RDebug::Printf("Client: open sessions");
+	RSession session1, session2;
+	session1.Create();
+	session2.Create();
+
+	TBool ooc = EFalse;
+	TRequestStatus status1 (KRequestPending), status2 (KRequestPending);
+	RDebug::Printf("Client: send request 1");
+	session1.Request(CMySession::EDelay5, status1);
+	User::After(1000000);
+	RDebug::Printf("Client: send request 2");
+	session2.Request(CMySession::EPing, status2);
+
+	User::WaitForRequest(status1, status2);
+	if (status1 == KRequestPending)
+		{
+		// request2 finished first ...
+		ooc = ETrue;
+		RDebug::Printf("Client: request 2 completed %d", status2.Int());
+		User::WaitForRequest(status1);
+		}
+	else
+		{
+		RDebug::Printf("Client: request 1 completed %d", status1.Int());
+		User::WaitForRequest(status2);
+		}
+	RDebug::Printf("Client: status1 %d status2 %d OOC %d", status1.Int(), status2.Int(), ooc);
+	test_KErrNone(status1.Int());
+	test_KErrNone(status2.Int());
+	test_Equal(ooc, mode > 0);
+
+	if (mode)
+		session2.Request(CMySession::EFinish);
+	session1.Request(CMySession::EFinish);
+	RDebug::Printf("Client: exit");
+	return KErrNone;
+	}
+
+
+void TestSequential()
+	{
+	TRequestStatus status;
+
+	RDebug::Printf("Main: start server");
+	RThread serverThread;
+	test_KErrNone(serverThread.Create(_L("server"), RunServerCode, KHeapSize, NULL, (TAny*)0));
+	serverThread.Rendezvous(status);
+	serverThread.Resume();
+	User::WaitForRequest(status);
+	test_KErrNone(status.Int());
+
+	RDebug::Printf("Main: start client");
+	RThread clientThread;
+	test_KErrNone(clientThread.Create(_L("client"), RunClientCode, KHeapSize, NULL, (TAny*)0));
+	clientThread.Logon(status);
+	clientThread.Resume();
+	User::WaitForRequest(status);
+	test_KErrNone(clientThread.ExitReason());
+	test_Equal(EExitKill, clientThread.ExitType());
+
+	serverThread.Logon(status);
+	User::WaitForRequest(status);
+	test_KErrNone(serverThread.ExitReason());
+	test_Equal(EExitKill, serverThread.ExitType());
+
+	User::After(1000);
+	RDebug::Printf("Main: exit");
+	}
+
+void TestParallel()
+	{
+	TRequestStatus status;
+
+	RDebug::Printf("Main: start master server");
+	RThread masterThread;
+	test_KErrNone(masterThread.Create(_L("master"), RunServerCode, KHeapSize, NULL, (TAny*)1));
+	masterThread.Rendezvous(status);
+	masterThread.Resume();
+	User::WaitForRequest(status);
+	test_KErrNone(status.Int());
+
+	RDebug::Printf("Main: start slave server");
+	RThread slaveThread;
+	test_KErrNone(slaveThread.Create(_L("slave"), RunServerCode, KHeapSize, NULL, (TAny*)2));
+	slaveThread.Rendezvous(status);
+	slaveThread.Resume();
+	User::WaitForRequest(status);
+	test_KErrNone(status.Int());
+
+	RDebug::Printf("Main: start client");
+	RThread clientThread;
+	test_KErrNone(clientThread.Create(_L("client2"), RunClientCode, KHeapSize, NULL, (TAny*)3));
+	clientThread.Logon(status);
+	clientThread.Resume();
+	User::WaitForRequest(status);
+	test_KErrNone(clientThread.ExitReason());
+	test_Equal(EExitKill, clientThread.ExitType());
+
+	slaveThread.Logon(status);
+	User::WaitForRequest(status);
+	test_KErrNone(slaveThread.ExitReason());
+	test_Equal(EExitKill, slaveThread.ExitType());
+
+	masterThread.Logon(status);
+	User::WaitForRequest(status);
+	test_KErrNone(masterThread.ExitReason());
+	test_Equal(EExitKill, masterThread.ExitType());
+
+	User::After(1000);
+	RDebug::Printf("Main: exit");
+	}
+
+
+GLDEF_C TInt E32Main()
+//
+// Main
+//
+	{	
+	test.Title();
+	__UHEAP_MARK;
+
+	test.Start(_L("Test threaded server support"));
+	test.Next(_L("Test two sessions to the same server (single-threaded)"));
+	TestSequential();
+	test.Next(_L("Test two sessions to the same server (multi-threaded)"));
+	TestParallel();
+	test.End();
+
+	__UHEAP_MARKEND;
+	return(KErrNone);
+	}