kerneltest/e32test/thread/t_threadedserver.cpp
author Tom Cosgrove <tom.cosgrove@nokia.com>
Fri, 28 May 2010 16:29:07 +0100
changeset 30 8aab599e3476
parent 0 a41df078684a
permissions -rw-r--r--
Fix for bug 2283 (RVCT 4.0 support is missing from PDK 3.0.h) Have multiple extension sections in the bld.inf, one for each version of the compiler. The RVCT version building the tools will build the runtime libraries for its version, but make sure we extract all the other versions from zip archives. Also add the archive for RVCT4.

// 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);
	}