--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/stif/TestServer/src/TestServer.cpp Tue Feb 02 01:57:15 2010 +0200
@@ -0,0 +1,977 @@
+/*
+* 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 "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: This module contains implementation of CTestServer
+* class member functions.
+*
+*/
+
+// INCLUDE FILES
+#include <e32std.h>
+#include <e32svr.h>
+#include "TestEngineClient.h"
+#include <StifTestModule.h>
+#include <stifinternal/TestServerClient.h>
+#include "TestServer.h"
+#include "TestServerCommon.h"
+#include <stifinternal/TestThreadContainerRunnerFactory.h>
+
+// EXTERNAL DATA STRUCTURES
+
+// EXTERNAL FUNCTION PROTOTYPES
+
+// CONSTANTS
+
+// MACROS
+
+// LOCAL CONSTANTS AND MACROS
+
+// MODULE DATA STRUCTURES
+
+// Struct to pass parameters to server thread
+struct TThreadStartTestServer
+ {
+ TFileName iName; // Server name
+ RThread iServerThread; // The server thread
+ RSemaphore iStarted; // Startup syncronisation semaphore
+ TBool iInNewThread; // Is thread running in new process?
+ TInt iStartupResult;// Start-up result
+ TBool iUiTesting; // Is it testserver for UI testing
+ CTestThreadContainerRunnerFactory* iTestThreadContainerRunnerFactory; // Pointer to CTestThreadContainerRunner. Defined when
+ // iUiTesting is true
+ };
+
+// LOCAL FUNCTION PROTOTYPES
+
+// FORWARD DECLARATIONS
+
+// ==================== LOCAL FUNCTIONS =======================================
+
+// None
+
+// ================= MEMBER FUNCTIONS =========================================
+
+/*
+-------------------------------------------------------------------------------
+
+ Class: CTestServer
+
+ Method: PanicServer
+
+ Description: Panics the server.
+
+ Parameters: const TTestServerPanic aPanic: in: Panic code
+
+ Return Values: None
+
+ Errors/Exceptions: None
+
+ Status: Approved
+
+-------------------------------------------------------------------------------
+*/
+void CTestServer::PanicServer( const TTestServerPanic aPanic )
+ {
+
+#ifdef USE_LOGGER
+ // Check if logger is available, if so, use it.
+ CStifLogger* log = (CStifLogger*) Dll::Tls();
+ if ( log )
+ {
+ log->Log( CStifLogger::ERed, _L("TestServer.DLL Panic %d"), aPanic);
+ }
+#endif
+
+ RDebug::Print( _L( "CTestServer::PanicServer" ) );
+ _LIT( KTxtTestServer,"CTestServer" );
+ User::Panic( KTxtTestServer,aPanic );
+
+ }
+
+/*
+-------------------------------------------------------------------------------
+
+ Class: CTestServer
+
+ Method: NewL
+
+ Description: Returns new CTestServer object
+
+ Parameters: const TFileName& aName: in: Server name
+
+ Return Values: None
+
+ Errors/Exceptions: Leaves if memory allocation, ConstructL or StartL leaves.
+
+ Status: Approved
+
+-------------------------------------------------------------------------------
+*/
+CTestServer* CTestServer::NewL( const TFileName& aName )
+ {
+
+ CTestServer* self = new( ELeave ) CTestServer();
+ CleanupStack::PushL( self );
+
+ // Construct the server
+ self->ConstructL( aName );
+
+ // Start the server
+ self->StartL( aName );
+
+ CleanupStack::Pop( self );
+
+ return self;
+
+ }
+
+/*
+-------------------------------------------------------------------------------
+
+ Class: CTestServer
+
+ Method: ConstructL
+
+ Description: Second level constructor. Obtains pointer to library
+ entrypoint.
+
+ Parameters: const TFileName& aName: in: Server name
+
+ Return Values: None
+
+ Errors/Exceptions: Leaves if entrypoint can't be obtained.
+
+ Status: Approved
+
+-------------------------------------------------------------------------------
+*/
+void CTestServer::ConstructL( const TFileName& aName )
+ {
+ // Construct heap buffer for configuration file
+ iModuleNameBuffer = HBufC::NewL( aName.Length() );
+ iModuleName.Set ( iModuleNameBuffer->Des() );
+ iModuleName.Copy ( aName );
+
+ iContainerIndex = CObjectConIx::NewL();
+
+ }
+
+/*
+-------------------------------------------------------------------------------
+
+ Class: CTestServer
+
+ Method: CTestServer
+
+ Description: Constructor.
+
+ Initialises non-zero member variables and base class with correct
+ priority.
+
+ Parameters: None
+
+ Return Values: None
+
+ Errors/Exceptions: None
+
+ Status: Approved
+
+-------------------------------------------------------------------------------
+*/
+CTestServer::CTestServer() : CServer2( CTestServer::ETestServerPriority ),
+ iModuleName(0, 0),
+ iSessionCount( 0 )
+ {
+ iFirstTime = ETrue;
+
+ }
+
+/*
+-------------------------------------------------------------------------------
+
+ Class: CTestServer
+
+ Method: ~CTestServer
+
+ Description: Destructor
+ Frees memory.
+
+ Parameters: None
+
+ Return Values: None
+
+ Errors/Exceptions: None
+
+ Status: Approved
+
+-------------------------------------------------------------------------------
+*/
+CTestServer::~CTestServer()
+ {
+
+ delete iModuleNameBuffer;
+ iModuleNameBuffer = NULL;
+
+ delete iContainerIndex;
+ iContainerIndex = NULL;
+
+ }
+
+/*
+-------------------------------------------------------------------------------
+
+ Class: CTestServer
+
+ Method: NewContainerL
+
+ Description: Returns new container. Used to store subsessions
+
+ Parameters: None
+
+ Return Values: CObjectCon* New object container
+
+ Errors/Exceptions: None
+
+ Status: Approved
+
+-------------------------------------------------------------------------------
+*/
+CObjectCon* CTestServer::NewContainerL()
+ {
+
+ CObjectCon* container = iContainerIndex->CreateL();
+
+ iSessionCount++;
+
+ return container;
+
+ }
+
+/*
+-------------------------------------------------------------------------------
+
+ Class: CTestServer
+
+ Method: DeleteContainer
+
+ Description: Deletes a container.
+
+ Parameters: CObjectCon* aContainer: in: Container to be removed
+
+ Return Values: None
+
+ Errors/Exceptions: None
+
+ Status: Approved
+
+-------------------------------------------------------------------------------
+*/
+void CTestServer::DeleteContainer( CObjectCon* aContainer )
+ {
+ iContainerIndex->Remove( aContainer );
+
+ }
+
+/*
+-------------------------------------------------------------------------------
+
+ Class: CTestServer
+
+ Method: SessionClosed
+
+ Description: Inform Server that session is closed.
+
+ Parameters: None
+
+ Return Values: None
+
+ Errors/Exceptions: None
+
+ Status: Approved
+
+-------------------------------------------------------------------------------
+*/
+void CTestServer::SessionClosed()
+ {
+ // Decrease session count
+ iSessionCount--;
+
+ // Check if last session is closed
+ if ( iSessionCount <= 0 )
+ {
+ // Stop the active scheduler
+ // Execution will continue in ThreadFunction()
+ CActiveScheduler::Stop();
+ }
+
+ }
+/*
+-------------------------------------------------------------------------------
+
+ Class: CTestServer
+
+ Method: NewSessionL
+
+ Description: Returns new session.
+
+ Parameters: const TVersion &aVersion: in: Version required
+
+ Return Values: CSharableSession* New session
+
+ Errors/Exceptions: Leaves if invalid version or CTestModule construction
+ leaves
+
+ Status: Approved
+
+-------------------------------------------------------------------------------
+*/
+CSession2* CTestServer::NewSessionL( const TVersion& aVersion,
+ const RMessage2& /*aMessage*/ ) const
+ {
+ // check version is ok
+ TVersion v( KTestServerMajorVersionNumber,
+ KTestServerMinorVersionNumber,
+ KTestServerBuildVersionNumber
+ );
+ if( !User::QueryVersionSupported( v,aVersion ) )
+ {
+ User::Leave( KErrNotSupported );
+ }
+
+ return CTestModule::NewL( ( CTestServer* ) this );
+ }
+
+/*
+-------------------------------------------------------------------------------
+
+ Class: CTestServer
+
+ Method: ModuleName
+
+ Description: Returns module name
+
+ Parameters: None
+
+ Return Values: const TDesC&* Module name
+
+ Errors/Exceptions: None
+
+ Status: Approved
+
+-------------------------------------------------------------------------------
+*/
+const TDesC& CTestServer::ModuleName() const
+ {
+ return iModuleName;
+
+ }
+
+/*
+-------------------------------------------------------------------------------
+
+ Class: CTestServer
+
+ Method: FirstTime
+
+ Description: Is module already once initialised.
+
+ Parameters: None
+
+ Return Values: TBool Has module initialized?
+
+ Errors/Exceptions: None
+
+ Status: Approved
+
+-------------------------------------------------------------------------------
+*/
+//@spe const TBool CTestServer::FirstTime() const
+TBool CTestServer::FirstTime() const
+ {
+ return iFirstTime;
+
+ }
+
+/*
+-------------------------------------------------------------------------------
+
+ Class: CTestServer
+
+ Method: ClearFirstTime
+
+ Description: Clear module first time flag.
+
+ Parameters: None
+
+ Return Values: None
+
+ Errors/Exceptions: None
+
+ Status: Approved
+
+-------------------------------------------------------------------------------
+*/
+void CTestServer::ClearFirstTime()
+ {
+ iFirstTime = EFalse;
+
+ }
+
+/*
+-------------------------------------------------------------------------------
+
+ Class: CTestServer
+
+ Method: ThreadFunction
+
+ Description: The thread function, where Test Server lives in
+
+ Parameters: TAny* aStarted: in: Start-up information
+
+ Return Values: TInt Result from test module
+
+ Errors/Exceptions: Clean-up stack can't be created because cannot
+ leave, error checks are done locally.
+ Panics if:
+ invalid start-up information
+ Test Server can't be started
+
+ Status: Approved
+
+-------------------------------------------------------------------------------
+*/
+TInt CTestServer::ThreadFunction( TAny* aStarted )
+ {
+
+ __UHEAP_MARK;
+
+ TInt error( KErrNone );
+
+ // Get start-up information
+ TThreadStartTestServer* startInfo = ( TThreadStartTestServer* ) aStarted;
+ __ASSERT_ALWAYS( startInfo,PanicServer( ENoStartupInformation ) );
+
+ // Create clean-up stack
+ CTrapCleanup* tc = CTrapCleanup::New();
+ __ASSERT_ALWAYS( tc, PanicServer(ECreateTrapCleanup));
+
+ // Construct the logger
+ TName path = _L("C:\\logs\\testframework\\testserver\\");
+ TFileName name = _L("testserver_");
+ name.Append ( startInfo->iName );
+
+ // Create logger, in Wins use HTML in HW default logger
+ TLoggerSettings loggerSettings;
+
+ // Directory must create by hand if test server log wanted
+ loggerSettings.iCreateLogDirectories = EFalse;
+
+ loggerSettings.iOverwrite = ETrue;
+ loggerSettings.iTimeStamp = ETrue;
+ loggerSettings.iLineBreak = ETrue;
+ loggerSettings.iEventRanking = EFalse;
+ loggerSettings.iThreadId = EFalse;
+ loggerSettings.iHardwareFormat = CStifLogger::ETxt;
+#ifndef FORCE_STIF_INTERNAL_LOGGING_TO_RDEBUG
+ loggerSettings.iEmulatorFormat = CStifLogger::EHtml;
+ loggerSettings.iHardwareOutput = CStifLogger::EFile;
+ loggerSettings.iEmulatorOutput = CStifLogger::EFile;
+#else
+ RDebug::Print( _L( "STIF Test Server logging forced to RDebug" ) );
+ loggerSettings.iEmulatorFormat = CStifLogger::ETxt;
+ loggerSettings.iHardwareOutput = CStifLogger::ERDebug;
+ loggerSettings.iEmulatorOutput = CStifLogger::ERDebug;
+#endif
+ loggerSettings.iUnicode = EFalse;
+ loggerSettings.iAddTestCaseTitle = EFalse;
+
+ CStifLogger* logger = NULL;
+ TRAP ( error, logger = CStifLogger::NewL( path, name, loggerSettings ) );
+
+ // Thread Local Storage is used for get pointer to logger.
+ Dll::SetTls ( logger );
+
+ __TRACE( KInit,( _L( "TestServer.DLL server starting" ) ) );
+ __TRACE( KInit,( CStifLogger::EBold, _L( "Loading module: %S"), &startInfo->iName ) );
+
+ RLibrary module;
+ TInt ret = KErrNone;
+
+ TFileName newNameBuffer;
+ TInt check = CheckModuleName( startInfo->iName, newNameBuffer );
+ if( check == KErrNone )
+ {
+ // Load the module(TestScripter)
+ ret = module.Load( newNameBuffer );
+ }
+ else
+ {
+ RemoveOptionalIndex(startInfo->iName, newNameBuffer);
+ __TRACE(KInit, (CStifLogger::EBold, _L( "Valid module name is [%S] (extracted from [%S])"), &newNameBuffer, &startInfo->iName));
+ // Load the module(Others)
+ ret = module.Load(newNameBuffer);
+ }
+
+ // If test module loading fails, do not start server
+ if( ret != KErrNone )
+ {
+ __TRACE( KError,( CStifLogger::ERed, _L( "Test module loading failed, code = %d" ), ret ) );
+ __TRACE( KError,( _L( "Check that module is compiled properly and stored to correct directory and all DLLs that it requires are available" ) ) );
+
+ // Error will be handled in StartNewServer
+ startInfo->iStartupResult = ret;
+ startInfo->iStarted.Signal();
+ if ( !startInfo->iInNewThread )
+ {
+ startInfo->iStarted.Close();
+ }
+ module.Close();
+ Dll::FreeTls();
+ // Delete logger
+ delete logger;
+ logger = NULL;
+ // Delete clean-up stack
+ delete tc;
+ tc = NULL;
+ __UHEAP_MARKEND;
+ return ret;
+ }
+ else
+ {
+ __TRACE( KInit,( _L( "Test module loaded correctly" ) ) );
+ }
+
+ // Verify that there is function
+ CTestInterfaceFactory libEntry = ( CTestInterfaceFactory ) module.Lookup( 1 );
+ if( libEntry == NULL )
+ {
+ // Error will be handled in StartNewServer
+ __TRACE( KError,( CStifLogger::ERed, _L( "Can't find entrypoint from test module" ) ) );
+
+ startInfo->iStartupResult = KErrNotFound;
+ startInfo->iStarted.Signal();
+ if ( !startInfo->iInNewThread )
+ {
+ startInfo->iStarted.Close();
+ }
+ module.Close();
+ Dll::FreeTls();
+ // Delete logger
+ delete logger;
+ logger = NULL;
+ // Delete clean-up stack
+ delete tc;
+ tc = NULL;
+ __UHEAP_MARKEND;
+ return KErrNotFound;
+ }
+
+ module.Close();
+
+ // Construct and install active scheduler
+ CActiveScheduler* scheduler = new CActiveScheduler;
+ __ASSERT_ALWAYS( scheduler, PanicServer( EMainSchedulerError ) );
+ CActiveScheduler::Install( scheduler );
+
+ // Construct server
+ CTestServer* server = NULL;
+ TRAPD( err, server = CTestServer::NewL( startInfo->iName ) );
+ __ASSERT_ALWAYS( !err, PanicServer( ESvrCreateServer ) );
+
+ server->iUiTesting = startInfo->iUiTesting;
+ server->iTestThreadContainerRunnerFactory = startInfo->iTestThreadContainerRunnerFactory;
+
+ // Inform that we are up and running
+ startInfo->iStartupResult = KErrNone;
+ startInfo->iStarted.Signal();
+ if ( !startInfo->iInNewThread )
+ {
+ startInfo->iStarted.Close();
+ }
+
+ // Start handling requests
+ CActiveScheduler::Start();
+
+ // Execution continues from here after CActiveScheduler::Stop
+
+ __TRACE( KVerbose,( _L( "TestServer.DLL active scheduler stopped" ) ) );
+
+ // Delete the server
+ delete server;
+ server = NULL;
+ __TRACE( KVerbose,( _L( "TestServer.DLL server object deleted" ) ) );
+
+ delete scheduler;
+ scheduler = NULL;
+ __TRACE( KVerbose,( _L( "Active scheduler deleted" ) ) );
+
+ __TRACE ( KInit, (_L("TestServer.DLL ThreadFunction exiting, server closing")) );
+
+ Dll::FreeTls();
+ // Delete logger
+ delete logger;
+ logger = NULL;
+ // Delete clean-up stack
+ delete tc;
+ tc = NULL;
+
+ __UHEAP_MARKEND;
+
+ return KErrNone;
+
+ }
+
+/*
+-------------------------------------------------------------------------------
+
+ Class: CTestServer
+
+ Method: GetServerThreadId
+
+ Description: Returns server thread id
+
+ Parameters: None
+
+ Return Values: TInt : thread id
+
+ Errors/Exceptions: None
+
+ Status: Approved
+
+-------------------------------------------------------------------------------
+*/
+TInt CTestServer::GetServerThreadId()
+ {
+ RThread thread;
+ return thread.Id();
+
+ }
+
+/*
+-------------------------------------------------------------------------------
+
+ Class: CTestServer
+
+ Method: GetTestThreadContainerRunnerFactory
+
+ Description: Returns server thread id
+
+ Parameters: None
+
+ Return Values: TInt : thread id
+
+ Errors/Exceptions: None
+
+ Status: Approved
+
+-------------------------------------------------------------------------------
+*/
+CTestThreadContainerRunnerFactory* CTestServer::GetTestThreadContainerRunnerFactory()
+ {
+
+ return iTestThreadContainerRunnerFactory;
+ }
+
+/*
+-------------------------------------------------------------------------------
+
+ Class: CTestServer
+
+ Method: UiTesting
+
+ Description: Gets information if testserver supports UI testing
+
+ Parameters: None
+
+ Return Values: True if testserver supports UI testing, False if not.
+
+ Errors/Exceptions: None
+
+ Status: Approved
+
+-------------------------------------------------------------------------------
+*/
+TBool CTestServer::UiTesting()
+ {
+
+ return iUiTesting;
+ }
+
+/*
+-------------------------------------------------------------------------------
+
+ Class: CTestServer
+
+ Method: GetUiEnvProxy
+
+ Description: Gets UIEnvProxy
+
+ Parameters: None
+
+ Return Values: Pointer to UIEnvProxy.
+
+ Errors/Exceptions: None
+
+ Status: Approved
+
+-------------------------------------------------------------------------------
+*/
+CUiEnvProxy* CTestServer::GetUiEnvProxy()
+ {
+
+ return iTestThreadContainerRunnerFactory->GetUiEnvProxy();
+ }
+
+
+// ================= OTHER EXPORTED FUNCTIONS =================================
+
+/*
+-------------------------------------------------------------------------------
+
+ Class: -
+
+ Method: StartNewServer
+
+ Description: Starts a new server. Server will be running its own
+ thread and this functions returns when server is up and running or
+ server start-up fails.
+
+ Parameters: const TFileName& aModuleFileName: in: Module name
+ TFileName& aServerName: in: Server name
+ const TBool aInNewThread: in: Is new thread
+ RSemaphore aSynchronisation: in: For synchronisation
+ TBool aUiTestingServer: in: Indicates if testserver should support UI testing
+ CTestThreadContainerRunnerFactory* aTestThreadContainerRunnerFactory: in: Pointer to runner factory
+
+ Return Values: TInt: Symbian error code
+
+ Errors/Exceptions: None
+
+ Status: Approved
+
+-------------------------------------------------------------------------------
+*/
+EXPORT_C TInt StartNewServer( const TFileName& aModuleFileName,
+ TFileName& aServerName,
+ const TBool aInNewThread,
+ RSemaphore aSynchronisation,
+ TBool aUiTestingServer,
+ CTestThreadContainerRunnerFactory* aTestThreadContainerRunnerFactory
+ )
+ {
+
+ __UHEAP_MARK;
+
+ //Check server not already started
+ TFindServer findServer( aModuleFileName );
+ TFullName name;
+ if( findServer.Next( name ) == KErrNone )
+ {
+ // Server already started, nothing to do
+ aServerName = aModuleFileName;
+ __UHEAP_MARKEND;
+ return KErrAlreadyExists;
+ }
+
+ // Construct start-up information object
+ TThreadStartTestServer* startInfo = new TThreadStartTestServer();
+ if( startInfo == NULL )
+ {
+ __UHEAP_MARKEND;
+ return KErrNoMemory;
+ }
+
+ // Fill the start-up information
+ startInfo->iName = aModuleFileName;
+ startInfo->iStartupResult = KErrNone;
+ startInfo->iStarted = aSynchronisation;
+ startInfo->iInNewThread = aInNewThread;
+ startInfo->iUiTesting = aUiTestingServer;
+ startInfo->iTestThreadContainerRunnerFactory = aTestThreadContainerRunnerFactory;
+
+ // EKA1
+ if ( aInNewThread )
+ {
+ // Create thread
+ TInt res = startInfo->iServerThread.Create(
+ startInfo->iName , // Name of thread
+ CTestServer::ThreadFunction, // Thread function
+ KDefaultStackSize, // Stack size
+ KDefaultHeapSize, // Heap initial size
+ KMaxHeapSize, // Heap start max size
+ startInfo // Parameter to thread function
+ );
+
+ // If thread creation failed
+ if( res != KErrNone )
+ {
+ startInfo->iStarted.Close(); // Close semaphore
+ delete startInfo;
+ startInfo = NULL;
+ __UHEAP_MARKEND;
+ return res;
+ }
+
+ // Now start thread
+ startInfo->iServerThread.SetPriority( EPriorityMuchMore );
+ startInfo->iServerThread.Resume();
+
+ // Wait until the thread is started
+ startInfo->iStarted.Wait();
+
+ // Server is started( or it has returned error )
+
+
+ }
+
+ // EKA2 and EKA1's HW
+ else
+ {
+ // Call directly thread function, this starts server and
+ // blocks this thread.
+ // Priority is default, not known reason why should be greater
+ // than default priority (Work over a year).
+ CTestServer::ThreadFunction( startInfo );
+ }
+
+ // Set server name
+ aServerName = aModuleFileName;
+
+ // Free memory
+ TInt r = startInfo->iStartupResult;
+ startInfo->iServerThread.Close();
+ startInfo->iStarted.Close();
+ delete startInfo;
+ startInfo = NULL;
+
+ __UHEAP_MARKEND;
+
+ // Return start-up result.
+ return r;
+
+ }
+
+/*
+-------------------------------------------------------------------------------
+
+ Class: -
+
+ Method: StartNewServer
+
+ Description: Starts a new server. Server will be running its own
+ thread and this functions returns when server is up and running or
+ server start-up fails.
+
+ Parameters: const TFileName& aModuleFileName: in: Module name
+ TFileName& aServerName: in: Server name
+ const TBool aInNewThread: in: Is new thread
+ RSemaphore aSynchronisation: in: For synchronisation
+
+ Return Values: TInt: Symbian error code
+
+ Errors/Exceptions: None
+
+ Status: Approved
+
+-------------------------------------------------------------------------------
+*/
+EXPORT_C TInt StartNewServer( const TFileName& aModuleFileName,
+ TFileName& aServerName,
+ const TBool aInNewThread,
+ RSemaphore aSynchronisation
+ )
+ {
+
+ return StartNewServer( aModuleFileName, aServerName, aInNewThread, aSynchronisation, false, NULL );
+ }
+
+
+/*
+-------------------------------------------------------------------------------
+
+ Class: -
+
+ Method: StartNewServer
+
+ Description: Starts a new server. Server will be running its own
+ thread and this functions returns when server is up and running or
+ server start-up fails.
+
+ Parameters: const TFileName& aName: in: Module name to be used
+ TFileName& aServerName: out: The name of the server
+
+ Return Values: TInt Error code / KErrNone
+
+ Errors/Exceptions: None
+
+ Status: Proposal
+
+-------------------------------------------------------------------------------
+*/
+EXPORT_C TInt StartNewServer( const TFileName& aModuleFileName,
+ TFileName& aServerName
+ )
+ {
+
+ __UHEAP_MARK;
+
+ RMutex startupMutex;
+ TInt ret( KErrNone );
+ // Global mutex already created(see CTestEngineServer::ThreadFunction).
+ // Open global mutex.
+ ret = startupMutex.OpenGlobal( KStifTestServerStartupMutex );
+ if( ret != KErrNone )
+ {
+ // Not able to open mutex
+ return ret;
+ }
+
+ startupMutex.Wait();
+
+ //Check server not already started
+ TFindServer findServer( aModuleFileName );
+ TFullName name;
+ if( findServer.Next( name ) == KErrNone )
+ {
+ // Server already started, nothing to do
+ aServerName = aModuleFileName;
+
+ // release startupmutex
+ startupMutex.Signal();
+ startupMutex.Close();
+
+ __UHEAP_MARKEND;
+ return KErrAlreadyExists;
+ }
+
+ RSemaphore startupSemaphore;
+ startupSemaphore.CreateLocal( 0 );
+
+ // Start server in new thread
+ TInt r = StartNewServer ( aModuleFileName, aServerName, ETrue, startupSemaphore );
+
+ // startupSemaphore will be closed inside StartNewServer when start-up is done.
+
+ // release startupmutex
+ startupMutex.Signal();
+ startupMutex.Close();
+
+ __UHEAP_MARKEND;
+
+ // Return start-up result.
+ return r;
+
+ }
+
+
+// End of File