diff -r 000000000000 -r 3da2a79470a7 testexecmgmt/ucc/Source/Uccs.v2/Core/UCCS_CBatchEngine.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/testexecmgmt/ucc/Source/Uccs.v2/Core/UCCS_CBatchEngine.cpp Mon Mar 08 15:04:18 2010 +0800 @@ -0,0 +1,428 @@ +/* +* Copyright (c) 2005-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: +* Filename: UCCS_CBatchEngine.cpp +* System Includes +* +*/ + + + +#include +#include +#include +#include + + +/*********************************************************************************** + * + * Local Includes + * + **********************************************************************************/ +#include "UCCS_CBatchEngine.h" +#include "UCCS_ErrorCodes.h" + + +/*********************************************************************************** + * + * Definitions + * + **********************************************************************************/ +#define IS_WHITESPACE(c) (((c) == '\t')||((c) == '\n')||((c) == ' ')) +#define MAXCOMMANDLENGTH 2048 + + +/*********************************************************************************** + * + * Definitions + * + **********************************************************************************/ +DWORD WINAPI ThreadProc(LPVOID lpParameter); + + +/*********************************************************************************** + * + * PUBLIC METHOD: Construction + * + **********************************************************************************/ +CBatchEngine::CBatchEngine( IRetrieveCommand *aRetrieveCommand, IOutput *aOutput ) +{ + // check parameters + assert( aRetrieveCommand != NULL ); + assert( aOutput != NULL ); + + // init the vars + iRetrieveCommand = aRetrieveCommand; + iOutput = aOutput; + + // set all other state + iExecutionThreadState = ETS_IDLE; + iControlThreadState = CTS_IDLE; + + // the rest are set according to the state -- for idle their value is irrelevant + // but I'd like to set them anyway for completeness + iLastError = 0; + iSync = NULL; + iUsecaseID = INVALID_USECASE_ID; + hThreadHandle = NULL; + iExecuteCommand = NULL; +} + + +/*********************************************************************************** + * + * PUBLIC METHOD: Destruction + * + **********************************************************************************/ +CBatchEngine::~CBatchEngine() +{ + // clean up any memory holding state variables + if( iExecuteCommand != NULL ) { + delete iExecuteCommand; + iExecuteCommand = NULL; + } + if( hThreadHandle != NULL ) { + CloseHandle(hThreadHandle); + hThreadHandle = NULL; + } + if( iSync != NULL ) { + delete iSync; + iSync = NULL; + } +} + + +/*********************************************************************************** + * + * PUBLIC METHOD: StartUseCase + * + **********************************************************************************/ +int CBatchEngine::StartUsecase( int aUsecaseID ) +{ + int err; + DWORD dwThreadID; + + // check that the control thread is currently in idle + if( iControlThreadState != CTS_IDLE ) { + return UCCS_ALREADYSTARTEDUSECASE; + } + assert( iExecutionThreadState == ETS_IDLE ); + + // ask the retriever to get the use-case description + err = iRetrieveCommand->StartUseCase( aUsecaseID ); + if( err != UCCS_OK ) { + return err; + } + + // set all the state appropriatley + assert( iSync == NULL ); + iSync = new CSynchronisation( iOutput ); + assert( iSync != NULL ); + assert( iExecuteCommand == NULL ); + iExecuteCommand = new CExecuteCommand( iSync, iOutput ); + assert( iExecuteCommand != NULL ); + iLastError = 0; + iUsecaseID = aUsecaseID; + + // set the state + iExecutionThreadState = ETS_EXECUTING_SCRIPT; + iControlThreadState = CTS_USECASE_STARTED; + + // output that we have started + iOutput->StartUsecase( aUsecaseID ); + + // start the thread that goes and executes the steps +#ifndef TESTCASEBATCH + hThreadHandle = CreateThread( NULL, 0, ThreadProc, this, 0, &dwThreadID ); +#else + hThreadHandle = 0; +#endif + if( hThreadHandle == 0 ) { + delete iSync; + iSync = NULL; + delete iExecuteCommand; + iExecuteCommand = NULL; + iUsecaseID = INVALID_USECASE_ID; + iExecutionThreadState = ETS_IDLE; + iControlThreadState = CTS_IDLE; + return UCCS_FAILEDTOCREATEEXECUTETHREAD; + } + + // done - return OK to the external controller + return UCCS_OK; +} + + +/*********************************************************************************** + * + * PUBLIC METHOD: EndUsecase + * + **********************************************************************************/ +int CBatchEngine::EndUsecase( int aUsecaseID, int aResult, int *aScriptResult ) +{ + int err; + + // check that the control thread is in the correct state + if( iControlThreadState != CTS_USECASE_STARTED ) { + *aScriptResult = UCCS_NOUSECASERUNNING; + return UCCS_NOUSECASERUNNING; + } + + // update the state of the control thread to ended -- this will cause the execution + // thread to exit on it's next iteration. + iControlThreadState = CTS_USECASE_ENDED; + + // We clear the synchronisation so that if the execution thread is (or is just about + // to) wait on a semaphore then it will not get stuck forever + iSync->ClearSynchronisation(); + + // Wait for the thread to really exit + err = WaitForSingleObject( hThreadHandle, INFINITE ); + if( err != WAIT_OBJECT_0 ) { + iOutput->Error( UCCS_SYSTEMERROR, "An error occured while waiting for the executing script thread to finish." ); + } + CloseHandle( hThreadHandle ); + hThreadHandle = NULL; + + // cleanup the rest of the state + assert( iExecutionThreadState == ETS_IDLE ); + iControlThreadState = CTS_IDLE; + delete iSync; + iSync = NULL; + delete iExecuteCommand; + iExecuteCommand = NULL; + iUsecaseID = INVALID_USECASE_ID; + + // output that endusecase has been called + iOutput->EndUsecase( aUsecaseID, aResult ); + + // done -- return the information + *aScriptResult = iLastError; + iLastError = 0; + return UCCS_OK; +} + +/*********************************************************************************** + * + * PUBLIC METHOD: GetVariableName + * + **********************************************************************************/ +int CBatchEngine::GetEnvVariable( char *aVariableName, char *aOutputBuffer, int aOutputBufferLen ) +{ + // check params + assert ( aVariableName != NULL ); + assert ( aOutputBuffer != NULL ); + assert ( aOutputBufferLen > 0 ); + + // check that there is an actual usecase running + if( iControlThreadState != CTS_USECASE_STARTED ) { + return UCCS_NOUSECASERUNNING; + } + + // check that there is actually a command around + if( iExecuteCommand == NULL ) { + return UCCS_COMMANDEXECUTIONNOTSTARTEDYET; + } + + // change aVariableName to uppercase -a s it is stored in the data record as uppercase. + _strupr( aVariableName ); + + // now go get the environment var + return iExecuteCommand->GetEnvironmentVariable( aVariableName, aOutputBuffer, aOutputBufferLen ); +} + +/*********************************************************************************** + * + * PUBLIC METHOD: RunCommand + * + **********************************************************************************/ +int CBatchEngine::RunCommand( char* aCommandLine ) +{ + // check params + assert ( aCommandLine != NULL ); + + // check that there is actually a command around + if( iSync == NULL ) { + iSync = new CSynchronisation( iOutput ); + } + if( iExecuteCommand == NULL ) { + iExecuteCommand = new CExecuteCommand( iSync, iOutput ); + } + + // now go get the environment var + return iExecuteCommand->ExecuteCommand( aCommandLine ); +} +/*********************************************************************************** + * + * PUBLIC METHOD: Signal + * + **********************************************************************************/ + +int CBatchEngine::Signal( int aUsecaseID ) +{ + // check that the state is valid + if( iControlThreadState != CTS_USECASE_STARTED ) { + return UCCS_NOUSECASERUNNING; + } + return iSync->SignalFromDevice(); +} + + +/*********************************************************************************** + * + * PUBLIC METHOD: Rendezvous + * + **********************************************************************************/ +int CBatchEngine::Rendezvous( int aUseCaseID ) +{ + // check that the control state is valid + if( iControlThreadState != CTS_USECASE_STARTED ) { + return UCCS_NOUSECASERUNNING; + } + + // check that the execution thread is still running + if( iExecutionThreadState != ETS_EXECUTING_SCRIPT ) { + return UCCS_SCRIPTFINISHED; + } + + // do the sync + return iSync->RendezvousFromDevice(); +} + + +/*********************************************************************************** + * + * PUBLIC METHOD: Wait + * + **********************************************************************************/ +int CBatchEngine::Wait( int aUseCaseID ) +{ + // check that the control state is valid + if( iControlThreadState != CTS_USECASE_STARTED ) { + return UCCS_NOUSECASERUNNING; + } + + // check that the execution thread is still running + if( iExecutionThreadState != ETS_EXECUTING_SCRIPT ) { + return UCCS_SCRIPTFINISHED; + } + + // do the sync + return iSync->WaitFromDevice(); +} + + +/*********************************************************************************** + * + * PUBLIC METHOD: ExecuteScript + * + **********************************************************************************/ +int CBatchEngine::ExecuteScript( void ) +{ + int err; + char *c; + char command_buffer[MAXCOMMANDLENGTH]; + int rv = 0; + + // execute all the commands + while( 1 ) { + + // if the controller has ended the usecase then we stop executing commands + if( iControlThreadState != CTS_USECASE_STARTED ) { + break; + } + + // get the next command to execute + err = iRetrieveCommand->GetNextCommand( command_buffer, MAXCOMMANDLENGTH ); + if( err == UCCS_NOMORECOMMANDS ) { + iOutput->CompletedScript(); + break; + } + assert( err == UCCS_OK ); + + // NOTE: the code below is the correct implementation of handling generic errors from the input + // module. It has been taken out because the input modules don't return anything except UCCS_NOMORECOMMANDS + // and UCCS_OK so there is no way to test the condition (and it messes up our coverage results!). But + // if new error codes are put in this implementation should be used. +// else if( err != UCCS_OK ) { +// iOutput->Error( err, "GetNextCommand returned error. Stopping script execution." ); +// rv = err; +// break; +// } + + // if the first not whitespace char is 0, or #, or // then return the comment + for( c = command_buffer; IS_WHITESPACE(*c); c++ ) + ; + if( (*c == 0) || (*c == '#') || ((c[0] == '/') && (c[1] == '/'))) { + continue; + } + + // now execute the command + iOutput->ExecuteString( c ); + err = iExecuteCommand->ExecuteCommand( c ); + iOutput->ExecuteStringResult( err ); + if( (err != UCCS_OK) && (err != UCCS_QUIT) ) { + iOutput->Error( err, NULL ); + } + + // if the return value from the command was quit (i.e. the script had a + // quit command) then we print the message and break from the loop. + if( err == UCCS_QUIT ) { + iOutput->CompletedScript(); + break; + } + + // save the last error -- this is so we can notify the device is an error occured + if( err != UCCS_OK ) { + iLastError = err; + } + + // if we do a require or requirenot that fails then make a point about it! + if( (err == UCCS_REQUIREDVALUEERROR) || (err == UCCS_REQUIREDVALUEINCORRECT) || (err == UCCS_REQUIREDNOTVALUEERROR) || (err == UCCS_REQUIREDNOTVALUEMATCH) ) { + // should break out here -- problem is that at the moment there are no reset calls so we can't recover!! + } + } + + // set the state of this thread to completed and clear the synchronisation state so that + // the control thread won't wait forever. The state of the execution thread should stop + // the control thread from being able to wait again + iExecutionThreadState = ETS_COMPLETED_SCRIPT; + iSync->ClearSynchronisation(); + + // tell the input module that we are done with it + err = iRetrieveCommand->EndUseCase(); + assert( err == UCCS_OK ); + + // set the state to idle + iExecutionThreadState = ETS_IDLE; + + // done + return rv; +} + + +/*********************************************************************************** + * + * FUNCTION: Entry point for second thread -- call executescript on the passed + * batch engine object. + * + **********************************************************************************/ +DWORD WINAPI ThreadProc(LPVOID lpParameter) +{ + CBatchEngine* aLocalBatchEngine; + aLocalBatchEngine = (CBatchEngine*)lpParameter; + return aLocalBatchEngine->ExecuteScript(); +} + +