diff -r 000000000000 -r 094583676ce7 PECengine/CoreUtilsLib2/SrvSrc/PEngServerStarter.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/PECengine/CoreUtilsLib2/SrvSrc/PEngServerStarter.cpp Thu Dec 17 08:41:52 2009 +0200 @@ -0,0 +1,412 @@ +/* +* Copyright (c) 2005 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: Generic thread safe server starter. +* +*/ + + +// INCLUDE FILES +#include "PEngServerStarter.h" +#include "PEngServerStarterDefs.h" +#include "TPEngServerParams.h" +#include "PresenceDebugPrint.h" + +#include +#include +#include + + +_LIT( KPEngPathDelimiter, "\\" ); + + +/** + * RSessionBase accessor to give to the PEngServerStarter + * access to RSessionBase::CreateSession(). + * + * @since 2.6 + */ +class RPEngSessionBaseAccessor : public RSessionBase + { + public: // Constructor + + /** + * C++ constructor. + * + * @since 2.6 + */ + inline RPEngSessionBaseAccessor() + { + } + + public: // New functions + + + /** + * Calls the RSessionBase::CreateSession(). + * + * @since 2.6 + * @param aServer See RSessionBase::CreateSession(). + * @param aVersion See RSessionBase::CreateSession(). + * @param aAsyncMessageSlots See RSessionBase::CreateSession(). + * @return See RSessionBase::CreateSession(). + */ + inline TInt CreateSession( const TDesC& aServer, + const TVersion& aVersion, + TInt aAsyncMessageSlots ) + { + return RSessionBase::CreateSession( aServer, + aVersion, + aAsyncMessageSlots ); + } + }; + + + + + +// ============================= LOCAL FUNCTIONS =============================== + + + +// ----------------------------------------------------------------------------- +// GenerateFullServerExe() +// Local helper. +// Generates full server executable name and path. +// +// +// +// Param: aServerName - A plain server name for which to generate the fullname. +// Param: aFullServerPath - On the function return contains full +// server path and name. +// ----------------------------------------------------------------------------- +// +void GenerateFullServerExe( const TDesC& aServerName, TFileName& aFullServerPath ) + { + { + //Get drive (C:) + TFileName dllPath; + Dll::FileName( dllPath ); + aFullServerPath.Copy( TParsePtrC( dllPath ).Drive() ); + } + + + //Get path (\Xxxx\Xxxx) + aFullServerPath.Append( KDC_PROGRAMS_DIR ); + + //Fix the path delimeter if missing from path + TPtrC pathDelim = aFullServerPath.Right( KPEngPathDelimiter().Length() ); + if ( pathDelim != KPEngPathDelimiter ) + { + aFullServerPath.Append( KPEngPathDelimiter ); + } + + + //Server name + extension (aServer.EXT) + aFullServerPath.Append( aServerName ); + aFullServerPath.Append( KExtDelimiter ); + + aFullServerPath.Append( KServerNameExtExe ); + + PENG_DP( D_PENG_LIT( "GenerateFullServerExe() [%S]" ), &aFullServerPath ); + } + + + + +// ----------------------------------------------------------------------------- +// ProcessRunning() +// Local helper. +// Checks is there server process started from the given +// exe file (exe or dll). +// +// +// Param: aFullServerExe - Server exe which running status to check. +// NOTE!! In THUMB the process name is the name portion of the +// filename from which the executable is loaded. In WINS the +// thread name is similarly the name portion of the dll filename +// (See CreateWinsThread() below) ==> thus here must be used +// also the exe/dll as parameter. +// +// Return: KErrNotFound - no matching running process found. +// KErrNone - one matching running process found. +// KErrGeneral - more than one running process found. +// ----------------------------------------------------------------------------- +// +TInt ProcessRunning( const TDesC& aFullServerExe ) + { + TFindProcess find; + RProcess process; + + + //Initialize the find + TFullName name( TParsePtrC( aFullServerExe ).Name() ); + name.Append( KMatchAny ); + find.Find( name ); + + + PENG_DP( D_PENG_LIT( "ProcessRunning() [%S]" ), &name ); + + //loop through all of matching processes + TInt runningCount = 0; + while ( find.Next( name ) == KErrNone ) + { + TInt error = process.Open( find ); + if ( error != KErrNone ) + { + //if can't open, the process is .. not .. valid + PENG_DP( D_PENG_LIT( "ProcessRunning() - Couldn't open process [%S], error[%d]" ), &name, error ); + continue; + } + + TExitType exitType = process.ExitType(); + process.Close(); + + PENG_DP( D_PENG_LIT( "ProcessRunning() - Server process %d found [%S], ExitType[%d] ==> Running[%d]" ), + runningCount, &name, exitType, ( exitType == EExitPending ) ); + + //check if the processes is running + if ( exitType == EExitPending ) + { + runningCount++; + } + } + + + PENG_DP( D_PENG_LIT( "ProcessRunning() [%d] matches found" ), runningCount ); + switch ( runningCount ) + { + case 0: //No server running + { + return KErrNotFound; + } + + case 1: //One server running + { + return KErrNone; + } + + default: + { + //More than one server instance running + return KErrGeneral; + } + } + } + + +// ----------------------------------------------------------------------------- +// DoLaunchServer() +// Local helper. +// Launches the server process and waits it startup. +// +// Param: aFullServerExe - The dll / exe from which to launch the server process. +// aServerName - The server name to identify the server +// aParam1 & 2 - Client given parameters to give to created process. +// +// Return: System standard error code. +// +// ----------------------------------------------------------------------------- +// +TInt DoLaunchServer( const TDesC& aFullServerExe, + const TDesC& aServerName, + TInt aParam1, + TInt aParam2 ) + { + PENG_DP( D_PENG_LIT( "DoLaunchServer() [%S] as [%S]" ), &aFullServerExe, &aServerName ); + + TInt error( KErrNone ); + TPEngServerParams startParams( aServerName, aParam1, aParam2 ); + + + //Create thread / process according the platform + RProcess process; + error = process.Create( aFullServerExe, startParams.AsCommandLine() ); + + + if ( error != KErrNone ) + { + return error; + } + + + //and execute the process and wait it's startup + TRequestStatus rendezvousStatus; + process.Rendezvous( rendezvousStatus ); + + PENG_DP( D_PENG_LIT( "DoLaunchServer() - Waiting for startup or die..." ) ); + process.Resume(); + User::WaitForRequest( rendezvousStatus ); // CSI: 94 # + error = rendezvousStatus.Int(); + + if ( ( error == KErrNone ) && + ( process.ExitType() == EExitPending ) ) + { + //Startup signalled from process ==> server successfully started + PENG_DP( D_PENG_LIT( "DoLaunchServer() - Server started" ) ); + } + + else + { + //Something failed in server startup + TExitCategoryName exitCategory = KNullDesC(); + exitCategory = process.ExitCategory(); + PENG_DP( D_PENG_LIT( "DoLaunchServer() - Startup failed: ExitReason[%S, %d], Error[%d]" ), + &exitCategory, process.ExitReason(), error ); + + if ( error == KErrNone ) + { + error = KErrServerTerminated; + } + } + + process.Close(); + + return error; + } + + + + +// ============================ MEMBER FUNCTIONS =============================== + +// ----------------------------------------------------------------------------- +// PEngServerStarter::LaunchServer() +// Public member function for clients to launch the server process. +// ----------------------------------------------------------------------------- +// +EXPORT_C TInt PEngServerStarter::LaunchServer( const TDesC& aServerExeBaseName, + const TDesC& aServerName, + TInt aParam1, + TInt aParam2 ) + { + PENG_DP( D_PENG_LIT( "PEngServerStarter::LaunchServer() [%S]" ), &aServerExeBaseName ); + + RMutex launchMutex; + + { + // Dynamic mutex name used to allow code share. + TName launchMutexName( TParsePtrC( aServerExeBaseName ).Name() ); + launchMutexName.Append( KPEngLaunchMutexNameExtension ); + + // Open or Create mutex to serialize to access to server startup code. + // Way below is race condition safe. + TInt error( KErrNotFound ); + while ( error == KErrNotFound ) + { + error = launchMutex.CreateGlobal( launchMutexName ); + if ( error != KErrAlreadyExists ) + { + break; + } + error = launchMutex.OpenGlobal( launchMutexName ); + } + + if ( error != KErrNone ) + { + return error; + } + } + + + //Determine the drive for executable + TFileName fullServerExe; + GenerateFullServerExe( aServerExeBaseName, fullServerExe ); + + TInt error; + launchMutex.Wait(); + { + //Serialized section + error = ProcessRunning( fullServerExe ); + if ( error == KErrNotFound ) + { + //server not running + error = DoLaunchServer( fullServerExe, + aServerName, + aParam1, + aParam2 ); + } + } + + launchMutex.Signal(); + launchMutex.Close(); + + PENG_DP( D_PENG_LIT( "PEngServerStarter::LaunchServer() done[%d]" ), error ); + return error; + } + + + +// ----------------------------------------------------------------------------- +// PEngServerStarter::ConnectServer() +// Public member function for clients to connect to server. +// ----------------------------------------------------------------------------- +// +EXPORT_C TInt PEngServerStarter::ConnectServer( RSessionBase& aSession, + const TDesC& aServerName, + const TVersion& aVersion, + TInt aAsyncMessageSlots, + const TDesC& aServerExeBaseName, + TInt aParam1, + TInt aParam2 ) + { + if ( aSession.Handle() != KNullHandle ) + { + return KErrInUse; + } + + TInt err = KErrGeneral; + TInt wait = KPEngSrvConnRetryWait; + for ( TInt tries = 0 ; tries < KPEngSrvConnTries ; tries++ ) + { + RPEngSessionBaseAccessor acc; + err = acc.CreateSession( aServerName, aVersion, aAsyncMessageSlots ); + aSession = acc; //session ownership is now on client + + if ( err == KErrNone || + ( err != KErrNotFound && err != KErrServerTerminated ) ) + { + break; // connected ok or something else than missing server + } + + // if server not found, try to connect more times + if ( ( err == KErrNotFound ) && ( tries < 4 ) ) + { + continue; + } + + err = LaunchServer( aServerExeBaseName, aServerName, aParam1, aParam2 ); + if ( err != KErrNone ) + { + break; //launch failed + } + + + if ( tries > 0 ) + { + //2nd or subsequent try - qive some time for server to startup + PENG_DP( D_PENG_LIT( "PEngServerStarter::ConnectServer() - giving time for startup [%d]" ), wait ); + User::After( wait ); // CSI: 92 # + wait = wait + wait; //On next round wait longer + } + } + + + PENG_DP( D_PENG_LIT( "PEngServerStarter::ConnectServer( %d )" ), err ); + return err; + } + + + +// End of file +