os/graphics/egl/egltest/src/egltestcommonstep.cpp
changeset 0 bde4ae8d615e
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/os/graphics/egl/egltest/src/egltestcommonstep.cpp	Fri Jun 15 03:10:57 2012 +0200
     1.3 @@ -0,0 +1,819 @@
     1.4 +// Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).
     1.5 +// All rights reserved.
     1.6 +// This component and the accompanying materials are made available
     1.7 +// under the terms of "Eclipse Public License v1.0"
     1.8 +// which accompanies this distribution, and is available
     1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
    1.10 +//
    1.11 +// Initial Contributors:
    1.12 +// Nokia Corporation - initial contribution.
    1.13 +//
    1.14 +// Contributors:
    1.15 +//
    1.16 +// Description:
    1.17 +//
    1.18 +
    1.19 +/**
    1.20 + @file
    1.21 + @test
    1.22 +*/
    1.23 +
    1.24 +#include <test/tefunit.h> // for ASSERT macros
    1.25 +#include <iniparser.h>
    1.26 +#include <apgtask.h>
    1.27 +#include <e32math.h>
    1.28 +#include <e32msgqueue.h> 
    1.29 +
    1.30 +#include "egltestcommonstep.h"
    1.31 +#include "egltestcommonsession.h"
    1.32 +#include "egltestcommonutils.h"
    1.33 +#include "egltestcommonprocess.h"
    1.34 +
    1.35 +static const TUint KDefaultHeapSize = 0x100000;
    1.36 +CEglTestStep::TThreadStatus::TThreadStatus()
    1.37 +    {
    1.38 +    for(TInt i=0; i<ESize; i++)
    1.39 +        {
    1.40 +        iStatus[i] = 0;
    1.41 +        }
    1.42 +    }
    1.43 +
    1.44 +EXPORT_C CEglTestStep::CEglTestStep() : 
    1.45 +    iWaitForCompletionOnPostamble(EFalse),
    1.46 +	iSourceFormat(KDefaultSourceFormat),
    1.47 +	iSurfaceFormat(KDefaultSurfaceFormat)
    1.48 +	{
    1.49 +	}
    1.50 +
    1.51 +EXPORT_C CEglTestStep::~CEglTestStep()
    1.52 +	{
    1.53 +	for (TInt i=0; i<KMaxProcessNumber; i++)
    1.54 +		{
    1.55 +		iProcessStatus[i].iProcess.Close();
    1.56 +		}
    1.57 +	TInt countThread = iThreadStatus.Count();
    1.58 +	for (TInt i=0; i<countThread; i++)
    1.59 +		{
    1.60 +		iThreadStatus[i].iThread.Close();
    1.61 +		}
    1.62 +	iThreadStatus.Close();
    1.63 +
    1.64 +    iSemaphore[0].Close();
    1.65 +    iSemaphore[1].Close();
    1.66 +  
    1.67 +    CleanAll();
    1.68 +    CloseWsSession();
    1.69 +	}
    1.70 +
    1.71 +EXPORT_C TVerdict CEglTestStep::doTestStepPreambleL()
    1.72 +	{
    1.73 +	User::LeaveIfError(Logger().ShareAuto());
    1.74 +	//When EGL Logging is enabled this causes a file server session to be allocated
    1.75 +	//Which needs to be done before any handle checks otherwise the test will fail
    1.76 +	ASSERT_EGL_TRUE(eglReleaseThread());	
    1.77 +	__UHEAP_MARK;
    1.78 +	HandleMark();
    1.79 +	return TestStepResult();
    1.80 +	}
    1.81 +
    1.82 +EXPORT_C TVerdict CEglTestStep::doTestStepPostambleL()
    1.83 +	{
    1.84 +	if(iWaitForCompletionOnPostamble && (iThreadStatus.Count() > 0))
    1.85 +        {
    1.86 +        INFO_PRINTF1(_L("Main thread waits for other threads to be terminated!!"));
    1.87 +        Test_MultiThread_WaitL(ETrue, TThreadStatus::ELogin);
    1.88 +        }	
    1.89 +	
    1.90 +	if (iDisplay != EGL_NO_DISPLAY)
    1.91 +		{
    1.92 +		// Output a warning because this should be done by the test
    1.93 +		WARN_PRINTF1(_L("Terminating Display during doTestStepPostambleL"));
    1.94 +		ASSERT_EGL_TRUE(eglTerminate(iDisplay));
    1.95 +		iDisplay = EGL_NO_DISPLAY;
    1.96 +		}
    1.97 +
    1.98 +	ASSERT_EGL_TRUE(eglReleaseThread());
    1.99 +
   1.100 +	HandleMarkEnd();
   1.101 + 	__UHEAP_MARKEND;
   1.102 +	return TestStepResult();
   1.103 +	}
   1.104 +
   1.105 +EXPORT_C void CEglTestStep::CleanAll()
   1.106 +	{
   1.107 +	delete iEglSess;
   1.108 +	iEglSess = NULL;
   1.109 +	
   1.110 +	if (iDisplay != EGL_NO_DISPLAY)
   1.111 +		{
   1.112 +		ASSERT_EGL_TRUE(eglTerminate(iDisplay));
   1.113 +		iDisplay = EGL_NO_DISPLAY;
   1.114 +		}
   1.115 +	ASSERT_EGL_TRUE(eglReleaseThread());
   1.116 +	}
   1.117 +
   1.118 +/*****************************************************************************
   1.119 + ** Utility methods
   1.120 + *****************************************************************************/
   1.121 +
   1.122 +void CEglTestStep::HandleMark()
   1.123 +	{
   1.124 +	RThread().HandleCount(iProcHandleMark, iThreadHandleMark);
   1.125 +	INFO_PRINTF3(_L("MARK: (%d) process-owned handle(s) / (%d) thread-owned handle(s)"), iProcHandleMark, iThreadHandleMark);
   1.126 +	}
   1.127 +
   1.128 +void CEglTestStep::HandleMarkEnd()
   1.129 +	{
   1.130 +	RThread().HandleCount(iProcHandleMarkEnd, iThreadHandleMarkEnd);
   1.131 +	INFO_PRINTF3(_L("MARK-END: (%d) process-owned handle(s) / (%d) thread-owned handle(s)"), iProcHandleMarkEnd, iThreadHandleMarkEnd);
   1.132 +#ifdef __WINS__
   1.133 +	WARN_PRINTF1(_L("Process-owned handle test is ignored on WINS build due to Pls() behaviour."));
   1.134 +#endif
   1.135 +	// When using Pls() on WINS build, it inteferes with handle count assert here due to Pls() behaviour which initialises PLS object
   1.136 +	// on first call of Pls() rather than during DLL loading, which cause extra count into iProcHandleMark.
   1.137 +	// ARMV5 build does not suffer this problem as proper WSD support is used.
   1.138 +#ifndef __WINS__
   1.139 +	ASSERT_EQUALS(iProcHandleMarkEnd, iProcHandleMark);
   1.140 +#endif
   1.141 +	ASSERT_EQUALS(iThreadHandleMarkEnd, iThreadHandleMark);
   1.142 +	}
   1.143 +
   1.144 +/** Initialises the window server session and window group objects. */
   1.145 +EXPORT_C void CEglTestStep::OpenWsSessionL(TInt aGroupId)
   1.146 +	{
   1.147 +	User::LeaveIfError(iWsSession.Connect());
   1.148 +	iWindowGroup = RWindowGroup(iWsSession);
   1.149 +	User::LeaveIfError(iWindowGroup.Construct(aGroupId));
   1.150 +	}
   1.151 +
   1.152 +/** Uninitialises the window group object and the window server session. */
   1.153 +EXPORT_C void CEglTestStep::CloseWsSession()
   1.154 +	{
   1.155 +	iWindowGroup.Close();
   1.156 +	iWsSession.Close();
   1.157 +	}
   1.158 +
   1.159 +/**
   1.160 +Uses the Eikon Environment to construct a window and put it on top.
   1.161 +@param aWindow A non-constructed window object
   1.162 +@param aRect The intial position and size of the window
   1.163 +@leave Standard system errors
   1.164 +*/
   1.165 +EXPORT_C void CEglTestStep::ConstructWindowL(RWindow& aWindow, const TRect& aRect)
   1.166 +	{
   1.167 +	INFO_PRINTF1(_L("CEglTestStep::CreateWindowL()"));
   1.168 +
   1.169 +	const TUint32 ENullWsHandle = 0xFFFFFFFF;	// Events delivered to this handle are thrown away
   1.170 +	aWindow = RWindow(iWsSession);
   1.171 +	CleanupClosePushL(aWindow);
   1.172 +	User::LeaveIfError(aWindow.Construct(iWindowGroup, ENullWsHandle));
   1.173 +	aWindow.SetExtent(aRect.iTl, aRect.Size());
   1.174 +	aWindow.Activate();
   1.175 +	CleanupStack::Pop(&aWindow);
   1.176 +	}
   1.177 +
   1.178 +/**
   1.179 +Prints both the Source pixel format and the target pixel format
   1.180 +*/
   1.181 +EXPORT_C void CEglTestStep::PrintUsedPixelConfiguration()
   1.182 +	{
   1.183 +	INFO_PRINTF1(_L("******UsedPixelConfiguration******"));
   1.184 +	INFO_PRINTF1(_L("Source Pixel Format"));
   1.185 +	PrintPixelFormat(iSourceFormat);	
   1.186 +	
   1.187 +	INFO_PRINTF1(_L("Target Format"));
   1.188 +	PrintVGImageFormat(iSurfaceFormat);
   1.189 +	INFO_PRINTF1(_L("**********************************"));
   1.190 +	}
   1.191 +
   1.192 +EXPORT_C void CEglTestStep::PrintPixelFormat(TUidPixelFormat aFormat)
   1.193 +	{
   1.194 +	switch(aFormat)
   1.195 +		{
   1.196 +        case EUidPixelFormatA_8:
   1.197 +            INFO_PRINTF1(_L("EUidPixelFormatA_8"));
   1.198 +            break;
   1.199 +		case EUidPixelFormatRGB_565:
   1.200 +			INFO_PRINTF1(_L("EUidPixelFormatRGB_565"));
   1.201 +			break;
   1.202 +		case EUidPixelFormatXRGB_8888:
   1.203 +			INFO_PRINTF1(_L("EUidPixelFormatXRGB_8888"));
   1.204 +			break;
   1.205 +		case EUidPixelFormatARGB_8888:
   1.206 +			INFO_PRINTF1(_L("EUidPixelFormatARGB_8888"));
   1.207 +			break;
   1.208 +		case EUidPixelFormatARGB_8888_PRE:
   1.209 +			INFO_PRINTF1(_L("EUidPixelFormatARGB_8888_PRE"));
   1.210 +			break;
   1.211 +		default:
   1.212 +			ERR_PRINTF2(_L("Unsupported pixel format (%d)"), aFormat);
   1.213 +			ASSERT_TRUE(EFalse);
   1.214 +		}
   1.215 +	}
   1.216 +
   1.217 +EXPORT_C void CEglTestStep::PrintVGImageFormat(VGImageFormat aAttr)
   1.218 +	{
   1.219 +	switch(aAttr)
   1.220 +		{
   1.221 +		case VG_sRGB_565:
   1.222 +			INFO_PRINTF1(_L("VG_sRGB_565"));
   1.223 +			break;
   1.224 +		case VG_sXRGB_8888:
   1.225 +			INFO_PRINTF1(_L("VG_sXRGB_8888"));
   1.226 +			break;
   1.227 +		case VG_sARGB_8888:
   1.228 +			INFO_PRINTF1(_L("VG_sARGB_8888"));
   1.229 +			break;
   1.230 +		case VG_sARGB_8888_PRE:
   1.231 +			INFO_PRINTF1(_L("VG_sARGB_8888_PRE"));
   1.232 +			break;
   1.233 +		default:
   1.234 +			ERR_PRINTF2(_L("Unsupported VGImage format (%d)"), aAttr);
   1.235 +			ASSERT_TRUE(EFalse);
   1.236 +		}
   1.237 +	}
   1.238 +
   1.239 +
   1.240 +/*****************************************************************************
   1.241 + ** Multiprocess test utils
   1.242 + *****************************************************************************/
   1.243 +
   1.244 +/**
   1.245 +Launches the specified number of processes, where each process will perform the actions specified in 
   1.246 +the doProcessFunctionL of the calling test. As no images TSgDrawableId has been passed, an 
   1.247 +an array of one (NULL) TSgDrawableId will be created.
   1.248 +@param aProcessCount Number of processes
   1.249 +@param aTestName Name of the calling test case (so that it can call it's doProcessFunctionL method 
   1.250 +@leave Standard system errors
   1.251 +*/  
   1.252 +EXPORT_C void CEglTestStep::Test_MultiProcessL(const TDesC& aTestDllName, TInt aProcessCount, const TDesC& aTestStepName)
   1.253 +	{
   1.254 +	TSgDrawableId sgId;
   1.255 +	Mem::FillZ(&sgId, sizeof(TSgDrawableId));
   1.256 +	Test_MultiProcessL(aTestDllName, aProcessCount, aTestStepName, sgId);
   1.257 +	}
   1.258 +
   1.259 +/**
   1.260 +Launches the specified number of processes, where each process will perform the actions specified in 
   1.261 +the doProcessFunctionL of the calling test.
   1.262 +@param aProcessCount Number of processes
   1.263 +@param aTestName Name of the calling test case (so that it can call it's doProcessFunctionL method 
   1.264 +@param aSgId Images TSgDrawableId which will be used to create an array of one TSgDrawableId
   1.265 +@leave Standard system errors
   1.266 +*/  
   1.267 +EXPORT_C void CEglTestStep::Test_MultiProcessL(const TDesC& aTestDllName, TInt aProcessCount, const TDesC& aTestStepName, const TSgDrawableId& aSgId)
   1.268 +	{
   1.269 +	// we assume we pass the same Id to all the processes (array of one)
   1.270 +	RArray<TSgDrawableId> sgIdList;
   1.271 +	ASSERT_EQUALS(sgIdList.Insert(aSgId,0), KErrNone);
   1.272 +	Test_MultiProcessL(aTestDllName, aProcessCount, aTestStepName, sgIdList);
   1.273 +	sgIdList.Close();
   1.274 +	}
   1.275 +
   1.276 +/**
   1.277 +Launches the specified number of processes, where each process will perform the actions specified in 
   1.278 +the doProcessFunctionL of the calling test. The association of images and processes is done via the
   1.279 +predefined ImageIndexFromProcessId() method.
   1.280 +@param aProcessCount Number of processes
   1.281 +@param aTestName Name of the calling test case (so that it can call it's doProcessFunctionL method 
   1.282 +@param aSgIdList Array containing the list of images' TSgDrawableId 
   1.283 +@leave Standard system errors
   1.284 +*/  
   1.285 +EXPORT_C void CEglTestStep::Test_MultiProcessL(const TDesC& aTestDllName, TInt aProcessCount, const TDesC& aTestStepName, const RArray<TSgDrawableId>& aSgIdList)
   1.286 +	{
   1.287 +	TInt imageCount = aSgIdList.Count();
   1.288 +	if(aProcessCount <= 0 || imageCount <=0 || aProcessCount > KMaxProcessNumber || imageCount > aProcessCount)
   1.289 +		{
   1.290 +		ERR_PRINTF1(_L("Invalid process request!"));
   1.291 +		User::Leave(KErrArgument);
   1.292 +		}
   1.293 +
   1.294 +    // create MsgQueue (only used in some test to pass data between 2 processes)
   1.295 +	RMsgQueue<TSgDrawableId> messageQueueSgId;
   1.296 +	TInt ret = messageQueueSgId.CreateGlobal(KNullDesC, 1, EOwnerProcess);
   1.297 +	ASSERT_EQUALS(ret, KErrNone);
   1.298 +	CleanupClosePushL(messageQueueSgId);
   1.299 +
   1.300 +	RMsgQueue<TProcessId> messageQueueProcId;
   1.301 +	ret = messageQueueProcId.CreateGlobal(KNullDesC, 1, EOwnerProcess);
   1.302 +	ASSERT_EQUALS(ret, KErrNone);
   1.303 +	CleanupClosePushL(messageQueueProcId);
   1.304 +
   1.305 +    // Create semphores that can be shared (only used in some test to synch between 2 process)
   1.306 +    ret = iSemaphore[0].CreateGlobal(KNullDesC(), 0, EOwnerProcess);
   1.307 +    ASSERT_EQUALS(ret, KErrNone);
   1.308 +    ret = iSemaphore[1].CreateGlobal(KNullDesC(), 0, EOwnerProcess);
   1.309 +    ASSERT_EQUALS(ret, KErrNone);
   1.310 +
   1.311 +    // create MsgQueue (only used in some tests to pass data from client processes to the main process)
   1.312 +    RMsgQueue<TEglStepMessageBuffer> messageQueueClientProcParam;
   1.313 +    ret = messageQueueClientProcParam.CreateGlobal(KNullDesC, 1, EOwnerProcess);
   1.314 +    ASSERT_EQUALS(ret, KErrNone);
   1.315 +    CleanupClosePushL(messageQueueClientProcParam);
   1.316 +    
   1.317 +	for (TInt i=0; i<aProcessCount; i++)
   1.318 +		{
   1.319 +		TProcessInfo info;
   1.320 +		info.iIdx=i;
   1.321 +		info.iSgId=	aSgIdList[ImageIndexFromProcessId(i, imageCount)];
   1.322 +
   1.323 +		ret = iProcessStatus[i].iProcess.Create(KEglTestServerWrapperProcess, KNullDesC);
   1.324 +		User::LeaveIfError(ret);
   1.325 +      
   1.326 +		// Specify the test for the process
   1.327 +		ret = iProcessStatus[i].iProcess.SetParameter(EProcSlotTestDllName, aTestDllName);
   1.328 +		User::LeaveIfError(ret);
   1.329 +		ret = iProcessStatus[i].iProcess.SetParameter(EProcSlotTestStepName, aTestStepName);
   1.330 +		User::LeaveIfError(ret);	
   1.331 +        
   1.332 +		// Specify the non-handle params passed to the process
   1.333 +		TPckg<TProcessInfo> pckgInfo(info);
   1.334 +		ret = iProcessStatus[i].iProcess.SetParameter(EProcSlotParams, pckgInfo);
   1.335 +		User::LeaveIfError(ret);
   1.336 +
   1.337 +		// Pass in the semaphores
   1.338 +		ret = iProcessStatus[i].iProcess.SetParameter(EProcSlotSemaphore0, iSemaphore[0]);
   1.339 +		User::LeaveIfError(ret);
   1.340 +		ret = iProcessStatus[i].iProcess.SetParameter(EProcSlotSemaphore1, iSemaphore[1]);
   1.341 +		User::LeaveIfError(ret);
   1.342 +		ret = iProcessStatus[i].iProcess.SetParameter(EProcSlotMsgQueueSgId, messageQueueSgId);
   1.343 +		User::LeaveIfError(ret);
   1.344 +		ret = iProcessStatus[i].iProcess.SetParameter(EProcSlotMsgQueueProcId, messageQueueProcId);
   1.345 +		User::LeaveIfError(ret);
   1.346 +		ret = iProcessStatus[i].iProcess.SetParameter(EProcSlotSourceFormat, static_cast<TInt>(iSourceFormat));
   1.347 +		User::LeaveIfError(ret);
   1.348 +		ret = iProcessStatus[i].iProcess.SetParameter(EProcSlotSurfaceFormat, static_cast<TInt>(iSurfaceFormat));
   1.349 +		User::LeaveIfError(ret);
   1.350 +        ret = iProcessStatus[i].iProcess.SetParameter(EProcSlotCustomClientParam, messageQueueClientProcParam);
   1.351 +        User::LeaveIfError(ret);
   1.352 +		
   1.353 +		iProcessStatus[i].iProcess.Logon(iProcessStatus[i].iStatus); 
   1.354 +		iProcessStatus[i].iProcess.Resume();
   1.355 +		}
   1.356 +    
   1.357 +	//by default an empty implementation
   1.358 +    ReceiveMessageFromClient(messageQueueClientProcParam);
   1.359 +
   1.360 +	// wait for all processes to complete (not worried about the order)
   1.361 +	// This is needed, as the only way to determine whether the process step has failed is to check
   1.362 +	//  the return value (using TEST(EFalse) has no effect on the spawned process)
   1.363 +	for (TInt i=0; i<aProcessCount; i++)
   1.364 +		{
   1.365 +		User::WaitForRequest(iProcessStatus[i].iStatus);
   1.366 +		CheckProcessStatusL(i, iProcessStatus[i].iStatus, iProcessStatus[i].iProcess);
   1.367 +		RDebug::Print(_L(">>>>>(%d)>> status :%d"), i, iProcessStatus[i].iStatus.Int());
   1.368 +		iProcessStatus[i].iProcess.Close();
   1.369 +		}
   1.370 +
   1.371 +	// close MsgQueue and semaphores (as used in some test with 2 spawned processes)
   1.372 +	CleanupStack::PopAndDestroy(3, &messageQueueSgId); //messageQueueClientProcParam, messageQueueProcId
   1.373 +	iSemaphore[1].Close();
   1.374 +	iSemaphore[0].Close();
   1.375 +	}
   1.376 +
   1.377 +/**
   1.378 +Check the status of a process running as part of the current teststep. 
   1.379 +@param aIndex Index of the process
   1.380 +@param aStatus The request status of the process in question. 
   1.381 +@param aProcess The process object itself.  
   1.382 +@leave Standard system errors
   1.383 +*/  
   1.384 +void CEglTestStep::CheckProcessStatusL(TInt aIndex, const TRequestStatus& aStatus, const RProcess& aProcess)
   1.385 +	{
   1.386 +	TInt status = aStatus.Int();
   1.387 +	if (status == KErrNone)
   1.388 +		{
   1.389 +		return;
   1.390 +		}
   1.391 +	if (status == KRequestPending)
   1.392 +		{
   1.393 +		// If the process is still running, that's an error, as we waited for the status  
   1.394 +		ERR_PRINTF2(_L("Error in process %d - status should not be KRequestPending"), aIndex);
   1.395 +		User::Leave(KErrTEFUnitFail);
   1.396 +		}
   1.397 +	// Something went wrong
   1.398 +	switch (aProcess.ExitType())
   1.399 +		{
   1.400 +		case EExitPanic:		// The thread or process has been panicked.
   1.401 +			{
   1.402 +			TPtrC ptrExitCategory = aProcess.ExitCategory();
   1.403 +			ERR_PRINTF4(_L("Panic in process %d - category:[%S] reason: %d"), aIndex, &ptrExitCategory, aProcess.ExitReason());
   1.404 +			// Propagate the panic
   1.405 +			User::Panic(aProcess.ExitCategory(), aProcess.ExitReason());
   1.406 +			}
   1.407 +			// follow through
   1.408 +		case EExitKill: 		// The thread or process has ended as a result of a kill, i.e. Kill() has been called on the RThread or RProcess handle. Or a thread was ended as a result of calling User::Exit(). 
   1.409 +		case EExitTerminate: 	// The thread or process has ended as a result of a terminate, i.e. Terminate() has been called on the RThread or RProcess handle. 
   1.410 +		case EExitPending:		// The thread or process is alive. 
   1.411 +		default:
   1.412 +			// Propagate the error
   1.413 +			ERR_PRINTF3(_L("Error in process %d - code %d"), aIndex, aStatus.Int());
   1.414 +			User::Leave(aStatus.Int());
   1.415 +		}
   1.416 +	ASSERT(0);
   1.417 +	}
   1.418 +
   1.419 +
   1.420 +/*****************************************************************************
   1.421 + ** Multithread test utils
   1.422 + *****************************************************************************/
   1.423 +
   1.424 +/**
   1.425 +Launches the specified number of threads, where each thread will perform the actions specified in 
   1.426 +the doThreadFunctionL of the calling test. 
   1.427 +@param aThreadCount Number of threads
   1.428 +@param aWaitForCompletion To wait until the launched thread has completed 
   1.429 +@leave Standard system errors
   1.430 +*/  
   1.431 +EXPORT_C void CEglTestStep::Test_MultiThreadL(TInt aThreadCount, TBool aWaitForCompletion)
   1.432 +	{
   1.433 +	if(aThreadCount <= 0 || aThreadCount > KMaxThreadNumber)
   1.434 +		{
   1.435 +		ERR_PRINTF1(_L("Invalid thread request!"));
   1.436 +		User::Leave(KErrArgument);
   1.437 +		}
   1.438 +
   1.439 +	iWaitForCompletionOnPostamble = !aWaitForCompletion;
   1.440 +	
   1.441 +	//we just care for these 2 semaphores
   1.442 +	ASSERT_EQUALS(iSemaphore[0].CreateLocal(0, EOwnerProcess), KErrNone);
   1.443 +	ASSERT_EQUALS(iSemaphore[1].CreateLocal(0, EOwnerProcess), KErrNone);
   1.444 +	
   1.445 +	_LIT(KThread, "CEglTestStep_Thread");
   1.446 +	_LIT(KUnderScore, "_");
   1.447 + 	
   1.448 +	TInt ret = KErrNone;
   1.449 +	ASSERT_EQUALS(iThreadStatus.Count(),0);
   1.450 +	// Reserve space to avoid reallocation of iThreadStatus.iStatus
   1.451 +	iThreadStatus.ReserveL(aThreadCount);
   1.452 +	for (TInt i=0; i<aThreadCount; i++)	
   1.453 +		{
   1.454 +		iThreadInfos[i].iSelf=this;
   1.455 +		iThreadInfos[i].iIdx=i;
   1.456 + 
   1.457 +		TTime tm;
   1.458 +		TBuf<32> bufTime;
   1.459 +		tm.UniversalTime();
   1.460 +	    tm.FormatL(bufTime, _L("_%H%T%S%C_"));
   1.461 +
   1.462 +		// guaranteed unique thread name (useful if several threads are created with aWaitForCompletion = false)
   1.463 +		TName threadName(KThread);
   1.464 +		threadName.Append(KUnderScore);
   1.465 +		threadName.AppendNum(i, EDecimal);
   1.466 +		threadName.Append(KUnderScore);
   1.467 +		threadName.Append(bufTime); 
   1.468 +	    threadName.AppendNum(Math::Random(), EHex);
   1.469 +
   1.470 +	    iThreadStatus.AppendL(TThreadStatus());
   1.471 +		ret = iThreadStatus[i].iThread.Create(threadName, ThreadFunction, KDefaultStackSize, KMinHeapSize, KDefaultHeapSize, &iThreadInfos[i], EOwnerProcess);
   1.472 +		User::LeaveIfError(ret);
   1.473 +
   1.474 +		if(!aWaitForCompletion)
   1.475 +			{
   1.476 +			// We want to wait for the notification that the extra thread is about to be launched
   1.477 +			// Improves timing issues within a hardware WDP environment
   1.478 +			iThreadStatus[i].iThread.Rendezvous(iThreadStatus[i].iStatus[TThreadStatus::ERendezvous]);
   1.479 +			}
   1.480 +		iThreadStatus[i].iThread.Logon(iThreadStatus[i].iStatus[TThreadStatus::ELogin]);
   1.481 +		iThreadStatus[i].iThread.Resume();
   1.482 +		}
   1.483 +    Test_MultiThread_WaitL(aWaitForCompletion, aWaitForCompletion ? TThreadStatus::ELogin : TThreadStatus::ERendezvous);
   1.484 +   	}
   1.485 +
   1.486 +EXPORT_C void CEglTestStep::Test_MultiThread_WaitL(TBool aCloseThreads, TThreadStatus::TStatusId aStatusId)
   1.487 +    {
   1.488 +    // Close handles and wait for all threads to complete (not worried about the order). Note that some 
   1.489 +    //   tests do not require to wait for completion. Nevertheless, care should be taken to ensure that the 
   1.490 +    //   spawned thread is capable of modifying the main TEF process TestStepResult.
   1.491 +       
   1.492 +    TInt countThread = iThreadStatus.Count();
   1.493 +    for (TInt i=0; i<countThread; i++)
   1.494 +        {
   1.495 +        User::WaitForRequest(iThreadStatus[i].iStatus[aStatusId]);
   1.496 +        CheckThreadStatusL(i, iThreadStatus[i].iStatus[aStatusId], iThreadStatus[i].iThread);
   1.497 +        INFO_PRINTF3(_L(">>>>>(%d)>> status :%d"), i, iThreadStatus[i].iStatus[aStatusId].Int());
   1.498 +
   1.499 +        if(aCloseThreads)
   1.500 +            {
   1.501 +            iThreadStatus[i].iThread.Close();
   1.502 +            }
   1.503 +        }
   1.504 +    if(aCloseThreads)
   1.505 +        {
   1.506 +        iThreadStatus.Reset();
   1.507 +
   1.508 +        iSemaphore[0].Close();
   1.509 +        iSemaphore[1].Close();
   1.510 +        }
   1.511 +    }
   1.512 +
   1.513 +/**
   1.514 +Check the status of a thread running as part of the current teststep. 
   1.515 +@param aIndex Index of the thread
   1.516 +@param aStatus The request status of the thread in question. 
   1.517 +@param aThread The thread object itself.  
   1.518 +@leave Standard system errors
   1.519 +*/ 
   1.520 +void CEglTestStep::CheckThreadStatusL(TInt aIndex, const TRequestStatus& aStatus, const RThread& aThread)
   1.521 +	{
   1.522 +	TInt status = aStatus.Int();
   1.523 +	if (status == KErrNone)
   1.524 +		{
   1.525 +		// All went well
   1.526 +		return;
   1.527 +		}
   1.528 +	if (status == KRequestPending)
   1.529 +		{
   1.530 +		// If the thread is still running, that's an error, as we waited for the status  
   1.531 +		ERR_PRINTF2(_L("Error in thread %d - status should not be KRequestPending"), aIndex);
   1.532 +		User::Leave(KErrTEFUnitFail);
   1.533 +		}
   1.534 +	// Something went wrong
   1.535 +	switch (aThread.ExitType())
   1.536 +		{
   1.537 +		case EExitPanic:		// The thread or process has been panicked.
   1.538 +			{
   1.539 +			TPtrC ptrExitCategory = aThread.ExitCategory();
   1.540 +			ERR_PRINTF4(_L("Panic in thread %d - category:[%S] reason: %d"), aIndex, &ptrExitCategory, aThread.ExitReason());
   1.541 +			User::Panic(aThread.ExitCategory(), aThread.ExitReason());
   1.542 +			}
   1.543 +			// follow through
   1.544 +		case EExitKill: 		// The thread or process has ended as a result of a kill, i.e. Kill() has been called on the RThread or RProcess handle. Or a thread was ended as a result of calling User::Exit(). 
   1.545 +		case EExitTerminate: 	// The thread or process has ended as a result of a terminate, i.e. Terminate() has been called on the RThread or RProcess handle. 
   1.546 +		case EExitPending:		// The thread or process is alive. 
   1.547 +		default:
   1.548 +			// Propagate the error
   1.549 +			ERR_PRINTF3(_L("Error in thread %d - code %d"), aIndex, status);
   1.550 +			User::Leave(aStatus.Int());
   1.551 +		}
   1.552 +	// We should not get here!
   1.553 +	ASSERT(0);
   1.554 +	}
   1.555 +
   1.556 +TInt CEglTestStep::ThreadFunction(TAny* aInfo)
   1.557 +// static
   1.558 +	{
   1.559 +	__UHEAP_MARK;
   1.560 +	CTrapCleanup* cleanup = CTrapCleanup::New();
   1.561 +	if(cleanup == NULL)
   1.562 +		{
   1.563 +		return KErrNoMemory;
   1.564 +		}
   1.565 +
   1.566 +	CEglTestStep::TThreadInfo* info = reinterpret_cast<CEglTestStep::TThreadInfo*>(aInfo);
   1.567 +	TRAPD(err, info->iSelf->ThreadFunctionL(*info));
   1.568 +
   1.569 +	delete cleanup;
   1.570 +	__UHEAP_MARKEND;
   1.571 +	return err;
   1.572 +	}
   1.573 +
   1.574 +void CEglTestStep::ThreadFunctionL(TThreadInfo& aInfo)
   1.575 +	{
   1.576 +	// Mark the handle count for this thread
   1.577 +	TInt processHandleMark=0;
   1.578 +	TInt threadHandleMark=0;
   1.579 +	RThread().HandleCount(processHandleMark, threadHandleMark);
   1.580 +	INFO_PRINTF4(_L("MARK: THREAD %d: (%d) process-owned handle(s) / (%d) thread-owned handle(s)"), aInfo.iIdx, processHandleMark, threadHandleMark);	
   1.581 +	
   1.582 +	// Notify the main thread that we are about to launch the extra thread
   1.583 +	RThread::Rendezvous(KErrNone);
   1.584 +	
   1.585 +	// Run the real thread funciton
   1.586 +	aInfo.iSelf->doThreadFunctionL(aInfo.iIdx);
   1.587 +
   1.588 +	// Release EGL thread state
   1.589 +	INFO_PRINTF2(_L("thread %d: Calling eglReleaseThread()"), aInfo.iIdx);
   1.590 +	ASSERT_EGL_TRUE(eglReleaseThread());
   1.591 +	
   1.592 +	// Check the handle count for this thread has not changed
   1.593 +	TInt processHandleMarkEnd=0;
   1.594 +	TInt threadHandleMarkEnd=0;
   1.595 +	RThread().HandleCount(processHandleMarkEnd, threadHandleMarkEnd);
   1.596 +	INFO_PRINTF4(_L("MARK-END: THREAD %d: (%d) process-owned handle(s) / (%d) thread-owned handle(s)"), aInfo.iIdx, processHandleMarkEnd, threadHandleMarkEnd);
   1.597 +	
   1.598 +	//Not testing equality of process-owned handles as these should only be tested from the main thread.
   1.599 +	//Process handlecount is dependent on all threads, therefore process handle imbalances could be the responsibility of other threads.
   1.600 +	ASSERT_EQUALS(threadHandleMark, threadHandleMarkEnd);
   1.601 +	}
   1.602 +
   1.603 +/**
   1.604 +Tests should override this method for multithreaded testing
   1.605 +*/
   1.606 +EXPORT_C void CEglTestStep::doThreadFunctionL(TInt aIdx)
   1.607 +	{
   1.608 +	// Not supported for this test step
   1.609 +	ERR_PRINTF2(_L("thread %d: Calling CEglTestStep::doThreadFunctionL() - should be overriden"), aIdx);
   1.610 +	User::Leave(KErrNotSupported);
   1.611 +	}
   1.612 +
   1.613 +EXPORT_C void CEglTestStep::doThreadFunctionL(TInt aIdx,const TSgDrawableId& aSgId)
   1.614 +	{
   1.615 +	// Not supported for this test step
   1.616 +	ERR_PRINTF3(_L("thread %d: Calling CEglTestStep::doThreadFunctionL() - should be overriden, TSgDrawableId %lu."), aIdx, aSgId.iId);
   1.617 +	User::Leave(KErrNotSupported);
   1.618 +	}
   1.619 +
   1.620 +/**
   1.621 +Tests should override this method for multiprocess testing
   1.622 +*/
   1.623 +EXPORT_C void CEglTestStep::doProcessFunctionL(TInt aIdx)
   1.624 +	{
   1.625 +	// Not supported for this test step
   1.626 +	ERR_PRINTF2(_L("Process %d: Calling CEglTestStep::doProcessFunctionL() - should be overriden"), aIdx);
   1.627 +	User::Leave(KErrNotSupported);
   1.628 +	}
   1.629 +
   1.630 +EXPORT_C void CEglTestStep::doProcessFunctionL(TInt aIdx,const TSgDrawableId& aSgId)
   1.631 +	{
   1.632 +	// Not supported for this test step
   1.633 +	ERR_PRINTF3(_L("Process %d: Calling CEglTestStep::doProcessFunctionL() - should be overriden, TSgDrawableId %lu."), aIdx, aSgId.iId);
   1.634 +	User::Leave(KErrNotSupported);
   1.635 +	}
   1.636 +
   1.637 +
   1.638 +/**
   1.639 +Rendezvous: Ensures that both threads get to this point before continuing
   1.640 +@param aIdx The thread index value that was passed into
   1.641 +			the override of CEglTestStep::doThreadFunctionL()
   1.642 +*/
   1.643 +EXPORT_C void CEglTestStep::Rendezvous(TInt aIdx)
   1.644 +	{
   1.645 +	if(aIdx >= 2)
   1.646 +	    {
   1.647 +	    // Currently Rendezvous is only supported between threads with index 0 and index 1
   1.648 +	    INFO_PRINTF2(_L("CEglTestStep::Rendezvous() - aIdx (%d) is too big!!"), aIdx);
   1.649 +	    ASSERT(0);
   1.650 +	    }
   1.651 +	INFO_PRINTF2(_L("thread %d: ...At Rendezvous..."), aIdx);
   1.652 +	iSemaphore[aIdx].Signal();
   1.653 +	iSemaphore[1-aIdx].Wait();
   1.654 +	}
   1.655 +
   1.656 +
   1.657 +/*****************************************************************************
   1.658 + ** Egl Helpers
   1.659 + *****************************************************************************/
   1.660 + 
   1.661 +/**
   1.662 +Temporarily initializes the EGL thread and display in order to check for the 
   1.663 +supplied extension string.
   1.664 +The display is then released and terminated.
   1.665 +Use this method to pre-check for the existence of an extension string prior 
   1.666 +to starting a test.
   1.667 +There are 2 ways to ask for an extension, via the ID (the default way to do it) 
   1.668 +or passing a string containing the full name of the extension (used in some tests only)
   1.669 +@param aExtensions The extension ID to look for
   1.670 +@param aExtensionName The extension name to look for
   1.671 +@return Whether the extension string can be found
   1.672 +*/
   1.673 +EXPORT_C TBool CEglTestStep::CheckForExtensionL(TInt aExtensions, const TDesC& aExtensionName)
   1.674 +	{
   1.675 +	ASSERT_TRUE(iDisplay == EGL_NO_DISPLAY);
   1.676 +	GetDisplayL();
   1.677 +	CTestEglSession* eglSess = CTestEglSession::NewLC(Logger(), iDisplay, -1);
   1.678 +	eglSess->InitializeL();
   1.679 +	
   1.680 +	TBool bFoundExtensions = eglSess->CheckNeededExtensionL(aExtensions, aExtensionName);
   1.681 +	
   1.682 +	// Cleanup EGL Completely
   1.683 +	CleanupStack::PopAndDestroy(eglSess);
   1.684 +	eglSess = NULL;
   1.685 +	TerminateDisplayL();
   1.686 +	ASSERT_EGL_TRUE(eglReleaseThread());
   1.687 +
   1.688 +	// return whether the extension string was found
   1.689 +	return bFoundExtensions;
   1.690 +	}
   1.691 +
   1.692 +/**
   1.693 +Uses eglGetDisplay() to initialise iDisplay, and to check the result of the call
   1.694 +*/
   1.695 +EXPORT_C void CEglTestStep::GetDisplayL()
   1.696 +	{
   1.697 +	INFO_PRINTF1(_L("Calling eglGetDisplay..."));
   1.698 +	
   1.699 +	iDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
   1.700 +	ASSERT_EGL_TRUE(iDisplay != EGL_NO_DISPLAY);
   1.701 +	}
   1.702 +
   1.703 +/**
   1.704 +If the iDisplay has been initialised then this method uses eglTerminate() 
   1.705 +to terminate iDisplay, and to check the result of the call.
   1.706 +This method also resets the value of iDisplay to EGL_NO_DISPLAY to indicate
   1.707 +that the display is no longer initialised.
   1.708 +*/
   1.709 +EXPORT_C void CEglTestStep::TerminateDisplayL()
   1.710 +	{
   1.711 +	if (iDisplay != EGL_NO_DISPLAY)
   1.712 +		{
   1.713 +		INFO_PRINTF1(_L("Calling eglTerminate..."));
   1.714 +		ASSERT_EGL_TRUE(eglTerminate(iDisplay));
   1.715 +		iDisplay = EGL_NO_DISPLAY;
   1.716 +		}
   1.717 +	}
   1.718 +
   1.719 +/**
   1.720 +Cut and paste from CTestStep::SetLogger() - which is not exported
   1.721 +As the name suggests, this is for use by the egl test process wrapper
   1.722 +*/
   1.723 +void CEglTestStep::SetLoggerForProcessWrapperL()
   1.724 +	{
   1.725 +	// Create a cinidata object for parsing the testexecute.ini
   1.726 +	CTestExecuteIniData* parseTestExecuteIni = NULL;
   1.727 +	TBuf<KMaxTestExecuteNameLength> resultFilePath;
   1.728 +	TBuf<KMaxTestExecuteNameLength> xmlFilePath;
   1.729 +	TInt logMode;
   1.730 +	TInt logLevel;
   1.731 +	
   1.732 +	TRAPD(err,parseTestExecuteIni = CTestExecuteIniData::NewL());
   1.733 +	if (err == KErrNone)
   1.734 +		{
   1.735 +		CleanupStack::PushL(parseTestExecuteIni);
   1.736 +		parseTestExecuteIni->ExtractValuesFromIni();
   1.737 +		parseTestExecuteIni->GetKeyValueFromIni(KTEFHtmlKey, resultFilePath);
   1.738 +		parseTestExecuteIni->GetKeyValueFromIni(KTEFXmlKey, xmlFilePath);
   1.739 +		parseTestExecuteIni->GetKeyValueFromIni(KTEFLogMode, logMode);
   1.740 +		parseTestExecuteIni->GetKeyValueFromIni(KTEFLogSeverityKey, logLevel);
   1.741 +		parseTestExecuteIni->GetKeyValueFromIni(KTEFEnableIniAccessLog, IniAccessLog());
   1.742 +		}
   1.743 +	else
   1.744 +		{
   1.745 +		resultFilePath.Copy(KTestExecuteLogPath);
   1.746 +		xmlFilePath.Copy(KTestExecuteLogPath);
   1.747 +		logMode = TLoggerOptions(ELogHTMLOnly);
   1.748 +		logLevel = RFileFlogger::TLogSeverity(ESevrAll);
   1.749 +		IniAccessLog() = ETrue;
   1.750 +		}
   1.751 +	Logger().SetLoggerOptions(logMode);
   1.752 +		
   1.753 +	// Initialise a handle to the file logger
   1.754 +	User::LeaveIfError(Logger().Connect());
   1.755 +	RFs fS;
   1.756 +	User::LeaveIfError(fS.Connect());
   1.757 +	CleanupClosePushL(fS);
   1.758 +	RFile file;
   1.759 +	TBuf<KMaxTestExecuteNameLength> xmlLogFile(xmlFilePath);
   1.760 +	TBuf<KMaxTestExecuteNameLength> logFile;
   1.761 +	TBuf<KMaxTestExecuteNameLength> logFileNameFile(resultFilePath);
   1.762 +	logFileNameFile.Append(KTestExecuteScheduleTestLogCompatibilityNameFile);
   1.763 +	if(file.Open(fS,logFileNameFile,EFileRead | EFileShareAny) != KErrNone)
   1.764 +		{
   1.765 +		// For the old flogger we have to create an individual file
   1.766 +		logFile.Copy(TestStepName());
   1.767 +		_LIT(KTxtExtension,".txt");
   1.768 +		logFile.Append(KTxtExtension);
   1.769 +		logMode = TLoggerOptions(0);
   1.770 +		Logger().SetLoggerOptions(logMode);
   1.771 +		}
   1.772 +	else
   1.773 +		{
   1.774 +		CleanupClosePushL(file);
   1.775 +		TBuf8<KMaxTestExecuteNameLength> logFile8;
   1.776 +		TInt fileSize;
   1.777 +		User::LeaveIfError(file.Size(fileSize));
   1.778 +		User::LeaveIfError(file.Read(logFile8,fileSize));
   1.779 +		logFile.Copy(logFile8);
   1.780 +		xmlLogFile.Append(logFile);
   1.781 +		_LIT(KXmlExtension,".xml");
   1.782 +		xmlLogFile.Append(KXmlExtension);
   1.783 +		_LIT(KHtmExtension,".htm");
   1.784 +		logFile.Append(KHtmExtension);
   1.785 +		CleanupStack::Pop(&file);
   1.786 +		file.Close();
   1.787 +		}
   1.788 +	TBuf<KMaxTestExecuteLogFilePath> logFilePath(resultFilePath);
   1.789 +	logFilePath.Append(logFile);
   1.790 +	CleanupStack::Pop(&fS);
   1.791 +	fS.Close();
   1.792 +	
   1.793 +	if (logMode == 0 || logMode == 2)
   1.794 +		{
   1.795 +		User::LeaveIfError(Logger().HtmlLogger().CreateLog(logFilePath,RTestExecuteLogServ::ELogModeAppend));
   1.796 +		Logger().HtmlLogger().SetLogLevel(TLogSeverity(logLevel));
   1.797 +		}
   1.798 +	if (logMode == 1 || logMode == 2)
   1.799 +		{
   1.800 +		User::LeaveIfError(Logger().XmlLogger().CreateLog(xmlLogFile,RFileFlogger::ELogModeAppend));
   1.801 +		Logger().XmlLogger().SetLogLevel(RFileFlogger::TLogSeverity(logLevel));
   1.802 +		}
   1.803 +	if (parseTestExecuteIni != NULL)
   1.804 +		{
   1.805 +		CleanupStack::PopAndDestroy(parseTestExecuteIni);
   1.806 +		}
   1.807 +	}
   1.808 +
   1.809 +EXPORT_C void CEglTestStep::PartialInitialiseL(const TDesC& aStepName)
   1.810 +	{
   1.811 +	SetTestStepName(aStepName);	
   1.812 +	SetLoggerForProcessWrapperL();
   1.813 +	// Assume pass
   1.814 +	SetTestStepResult(EPass);
   1.815 +	}
   1.816 +
   1.817 +EXPORT_C void CEglTestStep::CreateEglSessionL(TInt aIdx)
   1.818 +	{
   1.819 +	delete iEglSess; //just in case it was called twice
   1.820 +	iEglSess = CTestEglSession::NewL(Logger(), iDisplay, aIdx);
   1.821 +	}
   1.822 +