stif/TestServer/src/TestServer.cpp
branchRCL_3
changeset 59 8ad140f3dd41
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/stif/TestServer/src/TestServer.cpp	Wed Oct 13 16:17:58 2010 +0300
@@ -0,0 +1,976 @@
+/*
+* 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