kerneltest/e32test/mmu/t_shbuf_perfserver.cpp
author Tom Cosgrove <tom.cosgrove@nokia.com>
Fri, 28 May 2010 16:26:05 +0100
branchRCL_3
changeset 29 743008598095
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) 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:
// t_shbuf_perfserver.cpp
//
//

/**
 *  @file
 * 
 *  Test server used for Performance Testing of shared buffers.
 */

#include <e32std.h>
#include <e32debug.h>
#include <e32msgqueue.h>
#include <e32shbuf.h>

#include "t_shbuf_perfserver.h"


/**
 *  Second phase constructor for sessions. Called by the CServer2 framework
 *  when a session is created (e.g. a connection is made to the server).
 */
void CShBufTestServerSession::CreateL()
	{
	Server().AddSessionL(this);
	} // CShBufTestServerSession::CreateL()


/**
 *  Destructor for session classes. When this is called it indicates that
 *  a session is closing its connection with the server.
 */
CShBufTestServerSession::~CShBufTestServerSession()
	{
	Server().DropSession(this);
	} // CShBufTestServerSession::~CShBufTestServerSession()


/**
 *  Handle message requests for this session. Leaving is handled by
 *  CShBufTestServer::RunError() which reports the error code to the client.
 *
 *  @param aMessage  RMessage2 reference which encapsulates a client request.
 */
void CShBufTestServerSession::ServiceL(const RMessage2& aMessage)

	{
	switch (aMessage.Function())
		{
		case EShBufServerShutdownServer:
			{
			ShutdownServerL(aMessage);
			}
			break;

		case EShBufServerFromTPtr8ProcessAndReturn:
			{
			FromTPtr8ProcessAndReturnL(aMessage);
			}
			break;

		case EShBufServerFromTPtr8ProcessAndRelease:
			{
			FromTPtr8ProcessAndReleaseL(aMessage);
			}
			break;

		case EShBufServerOpenRShBufPool:
			{
			OpenRShBufPoolL(aMessage);
			}
			break;

		case EShBufServerCloseRShBufPool:
			{
			CloseRShBufPoolL(aMessage);
			}
			break;

		case EShBufServerFromRShBufProcessAndReturn:
			{
			FromRShBufProcessAndReturnL(aMessage);
			}
			break;

		case EShBufServerFromRShBufProcessAndRelease:
			{
			FromRShBufProcessAndReleaseL(aMessage);
			}
			break;

		case EShBufServerDbgMarkHeap:
			{
			DbgMarkHeapL(aMessage);
			}
			break;

		case EShBufServerDbgCheckHeap:
			{
			DbgCheckHeapL(aMessage);
			}
			break;

		case EShBufServerDbgMarkEnd:
			{
			DbgMarkEndL(aMessage);
			}
			break;

		case EShBufServerDbgFailNext:
			{
			DbgFailNextL(aMessage);
			}
			break;

		default:
			{
			aMessage.Panic(KRShBufTestServerName, 999);
			}
			break;
		}
	} // CShBufTestServerSession::ServiceL()


/**
 *  Completes a client request. This function provides a single point of
 *  message completion which benefits debugging and maintenance.
 *
 *  @param aMessage  The RMessage2 client request.
 *  @param aResult   Result of the request.
 */
void CShBufTestServerSession::CompleteRequest(const RMessage2& aMessage,
										      TInt aResult) const
	{
	if (aMessage.IsNull() == EFalse)
		{
	    aMessage.Complete(aResult);
		}
    } // CShBufTestServerSession::CompleteRequest()


/**
 *  Takes a buffer from the client, sends to the driver and back to the client.
 *
 *  @param aMessage  RMessage2 client request.
 */
void CShBufTestServerSession::FromTPtr8ProcessAndReturnL(const RMessage2& aMessage)
	{
	//
	// Read the client buffer...
	//
	TPtr8  bufPtr(iSessionTempBuffer, sizeof(iSessionTempBuffer));
	
	aMessage.ReadL(0, bufPtr); 

	TUint bufSize;

	bufSize = aMessage.Int1();

	//
	// Pass to the server to pass to the driver and back...
	//
	TInt  result;
	
	result = Server().FromTPtr8ProcessAndReturn(bufPtr, bufSize);

	//
	// Write the client buffer back...
	//
	aMessage.WriteL(0, bufPtr); 

	//
	// Complete the request...
	//
	CompleteRequest(aMessage, result);
	} // CShBufTestServerSession::FromTPtr8ProcessAndReturnL


/**
 *  Takes a buffer from the client and sends to the driver.
 *
 *  @param aMessage  RMessage2 client request.
 */
void CShBufTestServerSession::FromTPtr8ProcessAndReleaseL(const RMessage2& aMessage)
	{
	//
	// Read the client buffer...
	//
	TPtr8  bufPtr(iSessionTempBuffer, sizeof(iSessionTempBuffer));
	
	aMessage.ReadL(0, bufPtr); 

	//
	// Pass to the server to pass to the driver and back...
	//
	TInt  result;
	
	result = Server().FromTPtr8ProcessAndRelease(bufPtr);

	//
	// Complete the request...
	//
	CompleteRequest(aMessage, result);
	} // CShBufTestServerSession::FromTPtr8ProcessAndReleaseL


/**
 *  Allows the client to ask the test server to open a buffer pool.
 *
 *  @param aMessage  RMessage2 client request.
 */
void CShBufTestServerSession::OpenRShBufPoolL(const RMessage2& aMessage)
	{
	//
	// Read the handle...
	//
	TInt  poolHandle = aMessage.Int0();
	
	//
	// Read the pool info...
	//
	TShPoolInfo  shPoolInfo;
	TPckg<TShPoolInfo>  shPoolInfoPckg(shPoolInfo);
	
	aMessage.ReadL(1, shPoolInfoPckg); 

	//
	// Pass to the server to open the pool...
	//
	TInt  result = Server().OpenRShBufPool(poolHandle, shPoolInfo);

	//
	// Complete the request...
	//
	CompleteRequest(aMessage, result);
	} // CShBufTestServerSession::OpenRShBufPoolL


/**
 *  Allows the client to ask the test server to close a buffer pool.
 *
 *  @param aMessage  RMessage2 client request.
 */
void CShBufTestServerSession::CloseRShBufPoolL(const RMessage2& aMessage)
	{
	//
	// Pass to the server to close the pool...
	//
	TInt  result = Server().CloseRShBufPool();

	//
	// Complete the request...
	//
	CompleteRequest(aMessage, result);
	} // CShBufTestServerSession::CloseRShBufPoolL


/**
 *  Takes a buffer from the client, sends to the driver and back to the client.
 *
 *  @param aMessage  RMessage2 client request.
 */
void CShBufTestServerSession::FromRShBufProcessAndReturnL(const RMessage2& aMessage)
	{
	//
	// Read the client handle buffer...
	//
	RShBuf shBuf;
	TUint bufSize;

	bufSize = aMessage.Int1();

	//
	// Pass to the server to pass to the driver and back...
	//
	TInt  result;

	result = Server().FromRShBufProcessAndReturn(shBuf, bufSize);

	//
	// Write the client buffer handle back...
	//
#ifdef CAN_TRANSFER_SHBUF_TO_ANOTHER_PROCESS
	// TDBD aMessage.Complete(shbuf->Handle());
#else
	TPckg<TInt> handlePckg(shBuf.Handle());
	aMessage.WriteL(0, handlePckg);
#endif

	//
	// Complete the request...
	//
	CompleteRequest(aMessage, result);
	} // CShBufTestServerSession::FromRShBufProcessAndReturnL


/**
 *  Takes a buffer from the client and sends to the driver.
 *
 *  @param aMessage  RMessage2 client request.
 */
void CShBufTestServerSession::FromRShBufProcessAndReleaseL(const RMessage2& aMessage)
	{
	//
	// Read the client buffer handle...
	//

	RShBuf  shBuf;

#ifdef CAN_TRANSFER_SHBUF_TO_ANOTHER_PROCESS
	// TBD RShBuf.Open(aMessage, 0);
#else
	shBuf.SetReturnedHandle(aMessage.Int0());
#endif

	//
	// Pass to the server to pass to the driver and back...
	//
	TInt  result;
	
	result = Server().FromRShBufProcessAndRelease(shBuf);

	//
	// Complete the request...
	//
	CompleteRequest(aMessage, result);
	} // CShBufTestServerSession::FromRShBufProcessAndReleaseL


/**
 *  Requests the server to mark the start of checking the server's heap.
 *  This function only works in debug releases and is a synchronous request
 *  which will be completed when the procedure returns.
 *
 *  @param aMessage  RMessage2 client request.
 */
void CShBufTestServerSession::DbgMarkHeapL(const RMessage2& aMessage)
	{
	TInt  result;
	
	result = Server().DbgMarkHeap();

	//
	// Complete the request...
	//
	CompleteRequest(aMessage, result);
	} // CShBufTestServerSession::DbgMarkHeapL()


/**
 *  Requests the server to check that the number of allocated cells at the
 *  current nested level on the server's heap is the same as the specified value.
 *  This function only works for debug builds and is a synchronous request
 *  which will be completed when the procedure returns.
 *
 *  @param aMessage  RMessage2 client request.
 */
void CShBufTestServerSession::DbgCheckHeapL(const RMessage2& aMessage)
	{
	TInt  count = aMessage.Int0();
	TInt  result;
	
	result = Server().DbgCheckHeap(count);

	//
	// Complete the request...
	//
	CompleteRequest(aMessage, result);
	} // CShBufTestServerSession::DbgCheckHeapL()


/**
 *  Requests the server to mark the end of checking the server's heap. This
 *  function must match an earlier call to DbgMarkHeap() and only functions
 *  on debug releases. This is a synchronous request which will be completed
 *  when the procedure returns.
 *
 *  @param aMessage  RMessage2 client request.
 */
void CShBufTestServerSession::DbgMarkEndL(const RMessage2& aMessage)
	{
	TInt  count = aMessage.Int0();
	TInt  result;
	
	result = Server().DbgMarkEnd(count);

	//
	// Complete the request...
	//
	CompleteRequest(aMessage, result);
	} // CShBufTestServerSession::DbgMarkEndL()


/**
 *  Simulates heap allocation failure for the sever. The failure occurs on
 *  the next call to new or any of the functions which allocate memory from
 *  the heap. This is defined only for debug builds and is a synchronous
 *  request which will be completed when the procedure returns.
 *
 *  @param aMessage  RMessage2 client request.
 */
void CShBufTestServerSession::DbgFailNextL(const RMessage2& aMessage)
	{
	TInt  count = aMessage.Int0();
	TInt  result;
	
	result = Server().DbgFailNext(count);

	//
	// Complete the request...
	//
	CompleteRequest(aMessage, result);
	} // CShBufTestServerSession::DbgFailNextL()


/**
 *  Requests the server to shut down when it no longer has any connected
 *  sessions. This procedure is only premitted in debug builds for security
 *  reasons (e.g. to prevent a denial of service attack) and is provided
 *  for testing purposes. This is a synchronous request which will be
 *  completed when the procedure returns. The server will shutdown when the
 *  last session disconnects.
 *
 *  @param aMessage  RMessage2 client request.
 */
void CShBufTestServerSession::ShutdownServerL(const RMessage2& aMessage)
	{
	TInt  result = Server().ShutdownServer();
	
	//
	// Complete the request...
	//
	CompleteRequest(aMessage, result);
	} // CShBufTestServerSession::ShutdownServerL()


/**
 *  Static factory method used to create a CShBufTestServer object.
 *
 *  @return  Pointer to the created CShBufTestServer object, or NULL.
 */
CShBufTestServer* CShBufTestServer::NewL()
	{
	CShBufTestServer* self = new (ELeave) CShBufTestServer();
	CleanupStack::PushL(self);
	self->ConstructL();
	CleanupStack::Pop(self);

	return self;
	} // CShBufTestServer::NewL


/**
 *  Standard constructor.
 */
CShBufTestServer::CShBufTestServer()
	: CServer2(EPriorityNormal),
	iShouldShutdownServer(EFalse)
	{
	__DECLARE_NAME(_L("CShBufTestServer"));
	} // CShBufTestServer::CShBufTestServer


/**
 *  Second phase constructor. Ensures the server is created and ready to run.
 */
void CShBufTestServer::ConstructL()
	{
	//
	// Open the driver...
	//
	TInt  ret;
	
	ret = User::LoadLogicalDevice(_L("D_SHBUF_CLIENT.LDD"));
	if (ret != KErrAlreadyExists)
		{
		User::LeaveIfError(ret);
		}
	
	ret = User::LoadLogicalDevice(_L("D_SHBUF_OWN.LDD"));
	if (ret != KErrAlreadyExists)
		{
		User::LeaveIfError(ret);
		}
	
	User::LeaveIfError(iShBufLdd.Open(RShBufTestChannel::EClientThread));
	
	StartL(KRShBufTestServerName);
	} // CShBufTestServer::ConstructL


/**
 *  Destructor.
 */
CShBufTestServer::~CShBufTestServer()
	{
	iSessionArray.Reset();
	iShBufLdd.Close();
	} // CShBufTestServer::~CShBufTestServer


/**
 *  Create a new client session.
 */
CSession2* CShBufTestServer::NewSessionL(const TVersion&, const RMessage2& /*aMessage*/) const
	{
	return new(ELeave) CShBufTestServerSession();
	} // CShBufTestServer::NewSessionL


/**
 *  Called by the session class when it is being created.
 *
 *  @param aSession  Server side session.
 */
void CShBufTestServer::AddSessionL(CShBufTestServerSession* aSession)
	{
	//
	// Store this session in the list of sessions...
	//
	iSessionArray.Append(aSession);
	} // CShBufTestServer::AddSessionL


/**
 *  Called by the session class when it is being destroyed.
 *
 *  @param aSession  Server side session.
 */
void CShBufTestServer::DropSession(CShBufTestServerSession* aSession)
	{
	//
	// Remove this session from the session array list...
	//
	TInt  position;
	
	position = iSessionArray.Find(aSession);
 	if (position != KErrNotFound) 
		{
 		iSessionArray.Remove(position);
		}

	//
	// If we are shuting down then unconfigure and stop...
	//
	if (iSessionArray.Count() == 0  &&  iShouldShutdownServer)
		{
		CActiveScheduler::Stop();
		}
	} // CShBufTestServer::DropSession


TInt CShBufTestServer::FromTPtr8ProcessAndReturn(TDes8& aBuf, TUint aBufSize)
	{
	// clear cache
	memset(iClearCache, 0xFF, sizeof(iClearCache));

	return iShBufLdd.FromTPtr8ProcessAndReturn(aBuf, aBufSize);
	} // CShBufTestServer::FromTPtr8ProcessAndReturn


TInt CShBufTestServer::FromTPtr8ProcessAndRelease(TDes8& aBuf)
	{
	return iShBufLdd.FromTPtr8ProcessAndRelease(aBuf);
	} // CShBufTestServer::FromTPtr8ProcessAndRelease


TInt CShBufTestServer::OpenRShBufPool(TInt aHandle, const TShPoolInfo& aPoolInfo)
	{
	return iShBufLdd.OpenUserPool(aHandle, aPoolInfo);
	} // CShBufTestServer::OpenRShBufPool

	
TInt CShBufTestServer::CloseRShBufPool()
	{
	return iShBufLdd.CloseUserPool();
	} // CShBufTestServer::CloseRShBufPool

	
TInt CShBufTestServer::FromRShBufProcessAndReturn(RShBuf& aShBuf, TUint aBufSize)
	{
	TInt ret;

	// clear cache
	memset(iClearCache, 0xFF, sizeof(iClearCache));

	ret = iShBufLdd.FromRShBufProcessAndReturn(aBufSize);

	if (ret > 0)
		{
		aShBuf.SetReturnedHandle(ret);
		return KErrNone;
		}

	return ret;
	} // CShBufTestServer::FromRShBufProcessAndReturn


TInt CShBufTestServer::FromRShBufProcessAndRelease(RShBuf& aShBuf)
	{
	return iShBufLdd.FromRShBufProcessAndRelease(aShBuf.Handle());
	} // CShBufTestServer::FromRShBufProcessAndRelease 


/**
 *  Marks the start of checking the server's heap. This function only works
 *  in debug releases.
 *
 *  Calls to this function can be nested but each call must be matched by
 *  corresponding DbgMarkEnd().
 *
 *  @return  KErrNone.
 */
TInt CShBufTestServer::DbgMarkHeap() const
	{
#ifdef _DEBUG
	__UHEAP_MARK;
#endif

	return(KErrNone);
	} // CShBufTestServer::DbgMarkHeap


/**
 *  Checks that the number of allocated cells at the current nested level on
 *  the server's heap is the same as the specified value. This function only
 *  works for debug builds.
 *
 *  @param aCount  The number of heap cells expected to be allocated at
 *                 the current nest level.
 *
 *  @return  KErrNone.
 */
TInt CShBufTestServer::DbgCheckHeap(TInt aCount) const
	{
#ifdef _DEBUG 
	__UHEAP_CHECK(aCount);
#else
	(void) aCount;
#endif

	return(KErrNone);
	} // CShBufTestServer::DbgCheckHeap


/**
 *  Marks the end of checking the current server's heap. 
 *
 *  The function expects aCount heap cells to remain allocated at the
 *  current nest level. This function must match an earlier call to
 *  DbgMarkHeap() and only functions on debug releases.
 *
 *  @param aCount  The number of heap cells expected to remain allocated
 *                 at the current nest level.
 *
 *  @return  KErrNone.
 */
TInt CShBufTestServer::DbgMarkEnd(TInt aCount) const
	{
#ifdef _DEBUG
	__UHEAP_MARKENDC(aCount);
#else
	(void) aCount;
#endif

	return(KErrNone);
	} // CShBufTestServer::DbgMarkEnd


/**
 *  Simulates heap allocation failure for the server.
 *
 *  The failure occurs on the next call to new or any of the functions which 
 *  allocate memory from the heap. This is defined only for debug builds.
 *
 *  @param aCount  Determines when the allocation will fail.
 *
 *  @return  KErrNone.
 */
TInt CShBufTestServer::DbgFailNext(TInt aCount) const
	{
#ifdef _DEBUG
	if (aCount == 0)
		{
		__UHEAP_RESET;
		}
	else
		{
		__UHEAP_FAILNEXT(aCount);
		}
#else
	(void) aCount;
#endif

	return(KErrNone);
	} // CShBufTestServer::DbgFailNext


/**
 *  Requests the server to shut down when it no longer has any connected
 *  sessions. This procedure is only premitted in debug builds and is provided
 *  for testing purposes.
 *
 *  The server will shutdown when the last session disconnects.
 *
 *  @return KErrNone if the shutdown request was accepted, otherwise returns
 *          an error.
 */
TInt CShBufTestServer::ShutdownServer()
	{
	iShouldShutdownServer = ETrue;

	return(KErrNone);
	} // CShBufTestServer::ShutdownServer



/**
 *  Standard Active Object RunError() method, called when the RunL() method
 *  leaves, which will be when the CShBufTestServerSession::ServiceL() leaves.
 *
 *  Find the current message and complete it before restarting the server.
 *
 *  @param aError  Leave code from CShBufTestServerSession::ServiceL().
 *
 *  @return KErrNone
 */
TInt CShBufTestServer::RunError(TInt aError)
	{
	//
	// Complete the request with the available error code.
	//
	if (Message().IsNull() == EFalse)
		{
		Message().Complete(aError);
		}

	//
	// The leave will result in an early return from CServer::RunL(), skipping
	// the call to request another message. So do that now in order to keep the
	// server running.
	//
	ReStart();

	return KErrNone;
	} // CShBufTestServer::RunError


/**
 *  Perform all server initialisation, in particular creation of the
 *  scheduler and server and then run the scheduler.
 */
static void RunServerL()
	{
	//
	// Naming the server thread after the server helps to debug panics.
	//
	User::LeaveIfError(User::RenameThread(KRShBufTestServerName));

	//
	// Increase priority so that requests are handled promptly...
	//
	RThread().SetPriority(EPriorityMuchMore);

	//	
	// Create a new Active Scheduler...
	//
	CActiveScheduler*  scheduler = new CActiveScheduler();
	CleanupStack::PushL(scheduler);	
	CActiveScheduler::Install(scheduler);
	
	//
	// Create a new PhoneBookServer...
	//
	CShBufTestServer*  server = CShBufTestServer::NewL();
	CleanupStack::PushL(server);
	
	//
	// Initialisation complete, now signal the client thread...
	//
#ifdef CAN_TRANSFER_SHBUF_TO_ANOTHER_PROCESS
	RProcess::Rendezvous(KErrNone);
#else
	RThread::Rendezvous(KErrNone);
#endif

	//
	// Run the server...
	//
	CActiveScheduler::Start();
	
	CleanupStack::PopAndDestroy(2, scheduler);
	} // RunServerL


/**
 *  Server process entry-point.
 *
 *  @return  KErrNone or a standard Symbian error code.
 */
#ifdef CAN_TRANSFER_SHBUF_TO_ANOTHER_PROCESS
TInt E32Main()
#else
TInt RShBufTestServerThread(TAny* /*aPtr*/)
#endif
	{
	__UHEAP_MARK;

	CTrapCleanup*  cleanup = CTrapCleanup::New();
	TInt  ret(KErrNoMemory);

	if (cleanup)
		{
		TRAP(ret, RunServerL());
		delete cleanup;
		}

	__UHEAP_MARKEND;

	return ret;
	} // E32Main