egl/egltest/src/egltestcommonstep.cpp
changeset 0 5d03bc08d59c
child 26 15986eb6c500
equal deleted inserted replaced
-1:000000000000 0:5d03bc08d59c
       
     1 // Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 //
       
    15 
       
    16 /**
       
    17  @file
       
    18  @test
       
    19 */
       
    20 
       
    21 #include <test/tefunit.h> // for ASSERT macros
       
    22 #ifndef __INIPARSER_H__
       
    23 #include <cinidata.h>
       
    24 #endif // __INIPARSER_H__
       
    25 #include <apgtask.h>
       
    26 #include <e32math.h>
       
    27 #include <e32msgqueue.h> 
       
    28 
       
    29 #include "egltestcommonstep.h"
       
    30 #include "egltestcommonsession.h"
       
    31 #include "egltestcommonutils.h"
       
    32 #include "egltestcommonprocess.h"
       
    33 
       
    34 static const TUint KDefaultHeapSize = 0x100000;
       
    35 CEglTestStep::TThreadStatus::TThreadStatus()
       
    36     {
       
    37     for(TInt i=0; i<ESize; i++)
       
    38         {
       
    39         iStatus[i] = 0;
       
    40         }
       
    41     }
       
    42 
       
    43 EXPORT_C CEglTestStep::CEglTestStep() : 
       
    44     iWaitForCompletionOnPostamble(EFalse),
       
    45 	iSourceFormat(KDefaultSourceFormat),
       
    46 	iSurfaceFormat(KDefaultSurfaceFormat)
       
    47 	{
       
    48 	}
       
    49 
       
    50 EXPORT_C CEglTestStep::~CEglTestStep()
       
    51 	{
       
    52 	for (TInt i=0; i<KMaxProcessNumber; i++)
       
    53 		{
       
    54 		iProcessStatus[i].iProcess.Close();
       
    55 		}
       
    56 	TInt countThread = iThreadStatus.Count();
       
    57 	for (TInt i=0; i<countThread; i++)
       
    58 		{
       
    59 		iThreadStatus[i].iThread.Close();
       
    60 		}
       
    61 	iThreadStatus.Close();
       
    62 
       
    63     iSemaphore[0].Close();
       
    64     iSemaphore[1].Close();
       
    65   
       
    66     CleanAll();
       
    67     CloseWsSession();
       
    68 	}
       
    69 
       
    70 EXPORT_C TVerdict CEglTestStep::doTestStepPreambleL()
       
    71 	{
       
    72 	User::LeaveIfError(Logger().ShareAuto());
       
    73 	//When EGL Logging is enabled this causes a file server session to be allocated
       
    74 	//Which needs to be done before any handle checks otherwise the test will fail
       
    75 	ASSERT_EGL_TRUE(eglReleaseThread());	
       
    76 	__UHEAP_MARK;
       
    77 	HandleMark();
       
    78 	return TestStepResult();
       
    79 	}
       
    80 
       
    81 EXPORT_C TVerdict CEglTestStep::doTestStepPostambleL()
       
    82 	{
       
    83 	if(iWaitForCompletionOnPostamble && (iThreadStatus.Count() > 0))
       
    84         {
       
    85         INFO_PRINTF1(_L("Main thread waits for other threads to be terminated!!"));
       
    86         Test_MultiThread_WaitL(ETrue, TThreadStatus::ELogin);
       
    87         }	
       
    88 	
       
    89 	if (iDisplay != EGL_NO_DISPLAY)
       
    90 		{
       
    91 		// Output a warning because this should be done by the test
       
    92 		WARN_PRINTF1(_L("Terminating Display during doTestStepPostambleL"));
       
    93 		ASSERT_EGL_TRUE(eglTerminate(iDisplay));
       
    94 		iDisplay = EGL_NO_DISPLAY;
       
    95 		}
       
    96 
       
    97 	ASSERT_EGL_TRUE(eglReleaseThread());
       
    98 
       
    99 	HandleMarkEnd();
       
   100  	__UHEAP_MARKEND;
       
   101 	return TestStepResult();
       
   102 	}
       
   103 
       
   104 EXPORT_C void CEglTestStep::CleanAll()
       
   105 	{
       
   106 	delete iEglSess;
       
   107 	iEglSess = NULL;
       
   108 	
       
   109 	if (iDisplay != EGL_NO_DISPLAY)
       
   110 		{
       
   111 		ASSERT_EGL_TRUE(eglTerminate(iDisplay));
       
   112 		iDisplay = EGL_NO_DISPLAY;
       
   113 		}
       
   114 	ASSERT_EGL_TRUE(eglReleaseThread());
       
   115 	}
       
   116 
       
   117 /*****************************************************************************
       
   118  ** Utility methods
       
   119  *****************************************************************************/
       
   120 
       
   121 void CEglTestStep::HandleMark()
       
   122 	{
       
   123 	RThread().HandleCount(iProcHandleMark, iThreadHandleMark);
       
   124 	INFO_PRINTF3(_L("MARK: (%d) process-owned handle(s) / (%d) thread-owned handle(s)"), iProcHandleMark, iThreadHandleMark);
       
   125 	}
       
   126 
       
   127 void CEglTestStep::HandleMarkEnd()
       
   128 	{
       
   129 	RThread().HandleCount(iProcHandleMarkEnd, iThreadHandleMarkEnd);
       
   130 	INFO_PRINTF3(_L("MARK-END: (%d) process-owned handle(s) / (%d) thread-owned handle(s)"), iProcHandleMarkEnd, iThreadHandleMarkEnd);
       
   131 #ifdef __WINS__
       
   132 	WARN_PRINTF1(_L("Process-owned handle test is ignored on WINS build due to Pls() behaviour."));
       
   133 #endif
       
   134 	// When using Pls() on WINS build, it inteferes with handle count assert here due to Pls() behaviour which initialises PLS object
       
   135 	// on first call of Pls() rather than during DLL loading, which cause extra count into iProcHandleMark.
       
   136 	// ARMV5 build does not suffer this problem as proper WSD support is used.
       
   137 #ifndef __WINS__
       
   138 	ASSERT_EQUALS(iProcHandleMarkEnd, iProcHandleMark);
       
   139 #endif
       
   140 	ASSERT_EQUALS(iThreadHandleMarkEnd, iThreadHandleMark);
       
   141 	}
       
   142 
       
   143 /** Initialises the window server session and window group objects. */
       
   144 EXPORT_C void CEglTestStep::OpenWsSessionL(TInt aGroupId)
       
   145 	{
       
   146 	User::LeaveIfError(iWsSession.Connect());
       
   147 	iWindowGroup = RWindowGroup(iWsSession);
       
   148 	User::LeaveIfError(iWindowGroup.Construct(aGroupId));
       
   149 	}
       
   150 
       
   151 /** Uninitialises the window group object and the window server session. */
       
   152 EXPORT_C void CEglTestStep::CloseWsSession()
       
   153 	{
       
   154 	iWindowGroup.Close();
       
   155 	iWsSession.Close();
       
   156 	}
       
   157 
       
   158 /**
       
   159 Uses the Eikon Environment to construct a window and put it on top.
       
   160 @param aWindow A non-constructed window object
       
   161 @param aRect The intial position and size of the window
       
   162 @leave Standard system errors
       
   163 */
       
   164 EXPORT_C void CEglTestStep::ConstructWindowL(RWindow& aWindow, const TRect& aRect)
       
   165 	{
       
   166 	INFO_PRINTF1(_L("CEglTestStep::CreateWindowL()"));
       
   167 
       
   168 	const TUint32 ENullWsHandle = 0xFFFFFFFF;	// Events delivered to this handle are thrown away
       
   169 	aWindow = RWindow(iWsSession);
       
   170 	CleanupClosePushL(aWindow);
       
   171 	User::LeaveIfError(aWindow.Construct(iWindowGroup, ENullWsHandle));
       
   172 	aWindow.SetExtent(aRect.iTl, aRect.Size());
       
   173 	aWindow.Activate();
       
   174 	CleanupStack::Pop(&aWindow);
       
   175 	}
       
   176 
       
   177 /**
       
   178 Prints both the Source pixel format and the target pixel format
       
   179 */
       
   180 EXPORT_C void CEglTestStep::PrintUsedPixelConfiguration()
       
   181 	{
       
   182 	INFO_PRINTF1(_L("******UsedPixelConfiguration******"));
       
   183 	INFO_PRINTF1(_L("Source Pixel Format"));
       
   184 	PrintPixelFormat(iSourceFormat);	
       
   185 	
       
   186 	INFO_PRINTF1(_L("Target Format"));
       
   187 	PrintVGImageFormat(iSurfaceFormat);
       
   188 	INFO_PRINTF1(_L("**********************************"));
       
   189 	}
       
   190 
       
   191 EXPORT_C void CEglTestStep::PrintPixelFormat(TUidPixelFormat aFormat)
       
   192 	{
       
   193 	switch(aFormat)
       
   194 		{
       
   195         case EUidPixelFormatA_8:
       
   196             INFO_PRINTF1(_L("EUidPixelFormatA_8"));
       
   197             break;
       
   198 		case EUidPixelFormatRGB_565:
       
   199 			INFO_PRINTF1(_L("EUidPixelFormatRGB_565"));
       
   200 			break;
       
   201 		case EUidPixelFormatXRGB_8888:
       
   202 			INFO_PRINTF1(_L("EUidPixelFormatXRGB_8888"));
       
   203 			break;
       
   204 		case EUidPixelFormatARGB_8888:
       
   205 			INFO_PRINTF1(_L("EUidPixelFormatARGB_8888"));
       
   206 			break;
       
   207 		case EUidPixelFormatARGB_8888_PRE:
       
   208 			INFO_PRINTF1(_L("EUidPixelFormatARGB_8888_PRE"));
       
   209 			break;
       
   210 		default:
       
   211 			ERR_PRINTF2(_L("Unsupported pixel format (%d)"), aFormat);
       
   212 			ASSERT_TRUE(EFalse);
       
   213 		}
       
   214 	}
       
   215 
       
   216 EXPORT_C void CEglTestStep::PrintVGImageFormat(VGImageFormat aAttr)
       
   217 	{
       
   218 	switch(aAttr)
       
   219 		{
       
   220 		case VG_sRGB_565:
       
   221 			INFO_PRINTF1(_L("VG_sRGB_565"));
       
   222 			break;
       
   223 		case VG_sXRGB_8888:
       
   224 			INFO_PRINTF1(_L("VG_sXRGB_8888"));
       
   225 			break;
       
   226 		case VG_sARGB_8888:
       
   227 			INFO_PRINTF1(_L("VG_sARGB_8888"));
       
   228 			break;
       
   229 		case VG_sARGB_8888_PRE:
       
   230 			INFO_PRINTF1(_L("VG_sARGB_8888_PRE"));
       
   231 			break;
       
   232 		default:
       
   233 			ERR_PRINTF2(_L("Unsupported VGImage format (%d)"), aAttr);
       
   234 			ASSERT_TRUE(EFalse);
       
   235 		}
       
   236 	}
       
   237 
       
   238 
       
   239 /*****************************************************************************
       
   240  ** Multiprocess test utils
       
   241  *****************************************************************************/
       
   242 
       
   243 /**
       
   244 Launches the specified number of processes, where each process will perform the actions specified in 
       
   245 the doProcessFunctionL of the calling test. As no images TSgDrawableId has been passed, an 
       
   246 an array of one (NULL) TSgDrawableId will be created.
       
   247 @param aProcessCount Number of processes
       
   248 @param aTestName Name of the calling test case (so that it can call it's doProcessFunctionL method 
       
   249 @leave Standard system errors
       
   250 */  
       
   251 EXPORT_C void CEglTestStep::Test_MultiProcessL(const TDesC& aTestDllName, TInt aProcessCount, const TDesC& aTestStepName)
       
   252 	{
       
   253 	TSgDrawableId sgId;
       
   254 	Mem::FillZ(&sgId, sizeof(TSgDrawableId));
       
   255 	Test_MultiProcessL(aTestDllName, aProcessCount, aTestStepName, sgId);
       
   256 	}
       
   257 
       
   258 /**
       
   259 Launches the specified number of processes, where each process will perform the actions specified in 
       
   260 the doProcessFunctionL of the calling test.
       
   261 @param aProcessCount Number of processes
       
   262 @param aTestName Name of the calling test case (so that it can call it's doProcessFunctionL method 
       
   263 @param aSgId Images TSgDrawableId which will be used to create an array of one TSgDrawableId
       
   264 @leave Standard system errors
       
   265 */  
       
   266 EXPORT_C void CEglTestStep::Test_MultiProcessL(const TDesC& aTestDllName, TInt aProcessCount, const TDesC& aTestStepName, const TSgDrawableId& aSgId)
       
   267 	{
       
   268 	// we assume we pass the same Id to all the processes (array of one)
       
   269 	RArray<TSgDrawableId> sgIdList;
       
   270 	ASSERT_EQUALS(sgIdList.Insert(aSgId,0), KErrNone);
       
   271 	Test_MultiProcessL(aTestDllName, aProcessCount, aTestStepName, sgIdList);
       
   272 	sgIdList.Close();
       
   273 	}
       
   274 
       
   275 /**
       
   276 Launches the specified number of processes, where each process will perform the actions specified in 
       
   277 the doProcessFunctionL of the calling test. The association of images and processes is done via the
       
   278 predefined ImageIndexFromProcessId() method.
       
   279 @param aProcessCount Number of processes
       
   280 @param aTestName Name of the calling test case (so that it can call it's doProcessFunctionL method 
       
   281 @param aSgIdList Array containing the list of images' TSgDrawableId 
       
   282 @leave Standard system errors
       
   283 */  
       
   284 EXPORT_C void CEglTestStep::Test_MultiProcessL(const TDesC& aTestDllName, TInt aProcessCount, const TDesC& aTestStepName, const RArray<TSgDrawableId>& aSgIdList)
       
   285 	{
       
   286 	TInt imageCount = aSgIdList.Count();
       
   287 	if(aProcessCount <= 0 || imageCount <=0 || aProcessCount > KMaxProcessNumber || imageCount > aProcessCount)
       
   288 		{
       
   289 		ERR_PRINTF1(_L("Invalid process request!"));
       
   290 		User::Leave(KErrArgument);
       
   291 		}
       
   292 
       
   293     // create MsgQueue (only used in some test to pass data between 2 processes)
       
   294 	RMsgQueue<TSgDrawableId> messageQueueSgId;
       
   295 	TInt ret = messageQueueSgId.CreateGlobal(KNullDesC, 1, EOwnerProcess);
       
   296 	ASSERT_EQUALS(ret, KErrNone);
       
   297 
       
   298 	RMsgQueue<TProcessId> messageQueueProcId;
       
   299 	ret = messageQueueProcId.CreateGlobal(KNullDesC, 1, EOwnerProcess);
       
   300 	ASSERT_EQUALS(ret, KErrNone);
       
   301 
       
   302     // Create semphores that can be shared (only used in some test to synch between 2 process)
       
   303     ret = iSemaphore[0].CreateGlobal(KNullDesC(), 0, EOwnerProcess);
       
   304     ASSERT_EQUALS(ret, KErrNone);
       
   305     ret = iSemaphore[1].CreateGlobal(KNullDesC(), 0, EOwnerProcess);
       
   306     ASSERT_EQUALS(ret, KErrNone);
       
   307 
       
   308 	for (TInt i=0; i<aProcessCount; i++)
       
   309 		{
       
   310 		TProcessInfo info;
       
   311 		info.iIdx=i;
       
   312 		info.iSgId=	aSgIdList[ImageIndexFromProcessId(i, imageCount)];
       
   313 
       
   314 		ret = iProcessStatus[i].iProcess.Create(KEglTestServerWrapperProcess, KNullDesC);
       
   315 		User::LeaveIfError(ret);
       
   316       
       
   317 		// Specify the test for the process
       
   318 		ret = iProcessStatus[i].iProcess.SetParameter(EProcSlotTestDllName, aTestDllName);
       
   319 		User::LeaveIfError(ret);
       
   320 		ret = iProcessStatus[i].iProcess.SetParameter(EProcSlotTestStepName, aTestStepName);
       
   321 		User::LeaveIfError(ret);	
       
   322         
       
   323 		// Specify the non-handle params passed to the process
       
   324 		TPckg<TProcessInfo> pckgInfo(info);
       
   325 		ret = iProcessStatus[i].iProcess.SetParameter(EProcSlotParams, pckgInfo);
       
   326 		User::LeaveIfError(ret);
       
   327 
       
   328 		// Pass in the semaphores
       
   329 		ret = iProcessStatus[i].iProcess.SetParameter(EProcSlotSemaphore0, iSemaphore[0]);
       
   330 		User::LeaveIfError(ret);
       
   331 		ret = iProcessStatus[i].iProcess.SetParameter(EProcSlotSemaphore1, iSemaphore[1]);
       
   332 		User::LeaveIfError(ret);
       
   333 		ret = iProcessStatus[i].iProcess.SetParameter(EProcSlotMsgQueueSgId, messageQueueSgId);
       
   334 		User::LeaveIfError(ret);
       
   335 		ret = iProcessStatus[i].iProcess.SetParameter(EProcSlotMsgQueueProcId, messageQueueProcId);
       
   336 		User::LeaveIfError(ret);
       
   337 		ret = iProcessStatus[i].iProcess.SetParameter(EProcSlotSourceFormat, static_cast<TInt>(iSourceFormat));
       
   338 		User::LeaveIfError(ret);
       
   339 		ret = iProcessStatus[i].iProcess.SetParameter(EProcSlotSurfaceFormat, static_cast<TInt>(iSurfaceFormat));
       
   340 		User::LeaveIfError(ret);
       
   341 		               
       
   342 		iProcessStatus[i].iProcess.Logon(iProcessStatus[i].iStatus); 
       
   343 		iProcessStatus[i].iProcess.Resume();
       
   344 		}
       
   345 
       
   346 	// wait for all processes to complete (not worried about the order)
       
   347 	// This is needed, as the only way to determine whether the process step has failed is to check
       
   348 	//   the return value (using TEST(EFalse) has no effect on the spawned process)
       
   349 	for (TInt i=0; i<aProcessCount; i++)
       
   350 		{
       
   351 		User::WaitForRequest(iProcessStatus[i].iStatus);
       
   352 		CheckProcessStatusL(i, iProcessStatus[i].iStatus, iProcessStatus[i].iProcess);
       
   353 		RDebug::Print(_L(">>>>>(%d)>> status :%d"), i, iProcessStatus[i].iStatus.Int());
       
   354 		iProcessStatus[i].iProcess.Close();
       
   355 		}
       
   356 
       
   357 	// close MsgQueue and semaphores (as used in some test with 2 spawned processes)
       
   358 	messageQueueSgId.Close();
       
   359 	messageQueueProcId.Close();
       
   360 	iSemaphore[1].Close();
       
   361 	iSemaphore[0].Close();
       
   362 	}
       
   363 
       
   364 /**
       
   365 Check the status of a process running as part of the current teststep. 
       
   366 @param aIndex Index of the process
       
   367 @param aStatus The request status of the process in question. 
       
   368 @param aProcess The process object itself.  
       
   369 @leave Standard system errors
       
   370 */  
       
   371 void CEglTestStep::CheckProcessStatusL(TInt aIndex, const TRequestStatus& aStatus, const RProcess& aProcess)
       
   372 	{
       
   373 	TInt status = aStatus.Int();
       
   374 	if (status == KErrNone)
       
   375 		{
       
   376 		return;
       
   377 		}
       
   378 	if (status == KRequestPending)
       
   379 		{
       
   380 		// If the process is still running, that's an error, as we waited for the status  
       
   381 		ERR_PRINTF2(_L("Error in process %d - status should not be KRequestPending"), aIndex);
       
   382 		User::Leave(KErrTEFUnitFail);
       
   383 		}
       
   384 	// Something went wrong
       
   385 	switch (aProcess.ExitType())
       
   386 		{
       
   387 		case EExitPanic:		// The thread or process has been panicked.
       
   388 			{
       
   389 			TPtrC ptrExitCategory = aProcess.ExitCategory();
       
   390 			ERR_PRINTF4(_L("Panic in process %d - category:[%S] reason: %d"), aIndex, &ptrExitCategory, aProcess.ExitReason());
       
   391 			// Propagate the panic
       
   392 			User::Panic(aProcess.ExitCategory(), aProcess.ExitReason());
       
   393 			}
       
   394 			// follow through
       
   395 		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(). 
       
   396 		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. 
       
   397 		case EExitPending:		// The thread or process is alive. 
       
   398 		default:
       
   399 			// Propagate the error
       
   400 			ERR_PRINTF3(_L("Error in process %d - code %d"), aIndex, aStatus.Int());
       
   401 			User::Leave(aStatus.Int());
       
   402 		}
       
   403 	ASSERT(0);
       
   404 	}
       
   405 
       
   406 
       
   407 /*****************************************************************************
       
   408  ** Multithread test utils
       
   409  *****************************************************************************/
       
   410 
       
   411 /**
       
   412 Launches the specified number of threads, where each thread will perform the actions specified in 
       
   413 the doThreadFunctionL of the calling test. 
       
   414 @param aThreadCount Number of threads
       
   415 @param aWaitForCompletion To wait until the launched thread has completed 
       
   416 @leave Standard system errors
       
   417 */  
       
   418 EXPORT_C void CEglTestStep::Test_MultiThreadL(TInt aThreadCount, TBool aWaitForCompletion)
       
   419 	{
       
   420 	if(aThreadCount <= 0 || aThreadCount > KMaxThreadNumber)
       
   421 		{
       
   422 		ERR_PRINTF1(_L("Invalid thread request!"));
       
   423 		User::Leave(KErrArgument);
       
   424 		}
       
   425 
       
   426 	iWaitForCompletionOnPostamble = !aWaitForCompletion;
       
   427 	
       
   428 	//we just care for these 2 semaphores
       
   429 	ASSERT_EQUALS(iSemaphore[0].CreateLocal(0, EOwnerProcess), KErrNone);
       
   430 	ASSERT_EQUALS(iSemaphore[1].CreateLocal(0, EOwnerProcess), KErrNone);
       
   431 	
       
   432 	_LIT(KThread, "CEglTestStep_Thread");
       
   433 	_LIT(KUnderScore, "_");
       
   434  	
       
   435 	TInt ret = KErrNone;
       
   436 	ASSERT_EQUALS(iThreadStatus.Count(),0);
       
   437 	// Reserve space to avoid reallocation of iThreadStatus.iStatus
       
   438 	iThreadStatus.ReserveL(aThreadCount);
       
   439 	for (TInt i=0; i<aThreadCount; i++)	
       
   440 		{
       
   441 		iThreadInfos[i].iSelf=this;
       
   442 		iThreadInfos[i].iIdx=i;
       
   443  
       
   444 		TTime tm;
       
   445 		TBuf<32> bufTime;
       
   446 		tm.UniversalTime();
       
   447 	    tm.FormatL(bufTime, _L("_%H%T%S%C_"));
       
   448 
       
   449 		// guaranteed unique thread name (useful if several threads are created with aWaitForCompletion = false)
       
   450 		TName threadName(KThread);
       
   451 		threadName.Append(KUnderScore);
       
   452 		threadName.AppendNum(i, EDecimal);
       
   453 		threadName.Append(KUnderScore);
       
   454 		threadName.Append(bufTime); 
       
   455 	    threadName.AppendNum(Math::Random(), EHex);
       
   456 
       
   457 	    iThreadStatus.AppendL(TThreadStatus());
       
   458 		ret = iThreadStatus[i].iThread.Create(threadName, ThreadFunction, KDefaultStackSize, KMinHeapSize, KDefaultHeapSize, &iThreadInfos[i], EOwnerProcess);
       
   459 		User::LeaveIfError(ret);
       
   460 
       
   461 		if(!aWaitForCompletion)
       
   462 			{
       
   463 			// We want to wait for the notification that the extra thread is about to be launched
       
   464 			// Improves timing issues within a hardware WDP environment
       
   465 			iThreadStatus[i].iThread.Rendezvous(iThreadStatus[i].iStatus[TThreadStatus::ERendezvous]);
       
   466 			}
       
   467 		iThreadStatus[i].iThread.Logon(iThreadStatus[i].iStatus[TThreadStatus::ELogin]);
       
   468 		iThreadStatus[i].iThread.Resume();
       
   469 		}
       
   470     Test_MultiThread_WaitL(aWaitForCompletion, aWaitForCompletion ? TThreadStatus::ELogin : TThreadStatus::ERendezvous);
       
   471    	}
       
   472 
       
   473 EXPORT_C void CEglTestStep::Test_MultiThread_WaitL(TBool aCloseThreads, TThreadStatus::TStatusId aStatusId)
       
   474     {
       
   475     // Close handles and wait for all threads to complete (not worried about the order). Note that some 
       
   476     //   tests do not require to wait for completion. Nevertheless, care should be taken to ensure that the 
       
   477     //   spawned thread is capable of modifying the main TEF process TestStepResult.
       
   478        
       
   479     TInt countThread = iThreadStatus.Count();
       
   480     for (TInt i=0; i<countThread; i++)
       
   481         {
       
   482         User::WaitForRequest(iThreadStatus[i].iStatus[aStatusId]);
       
   483         CheckThreadStatusL(i, iThreadStatus[i].iStatus[aStatusId], iThreadStatus[i].iThread);
       
   484         INFO_PRINTF3(_L(">>>>>(%d)>> status :%d"), i, iThreadStatus[i].iStatus[aStatusId].Int());
       
   485 
       
   486         if(aCloseThreads)
       
   487             {
       
   488             iThreadStatus[i].iThread.Close();
       
   489             }
       
   490         }
       
   491     if(aCloseThreads)
       
   492         {
       
   493         iThreadStatus.Reset();
       
   494 
       
   495         iSemaphore[0].Close();
       
   496         iSemaphore[1].Close();
       
   497         }
       
   498     }
       
   499 
       
   500 /**
       
   501 Check the status of a thread running as part of the current teststep. 
       
   502 @param aIndex Index of the thread
       
   503 @param aStatus The request status of the thread in question. 
       
   504 @param aThread The thread object itself.  
       
   505 @leave Standard system errors
       
   506 */ 
       
   507 void CEglTestStep::CheckThreadStatusL(TInt aIndex, const TRequestStatus& aStatus, const RThread& aThread)
       
   508 	{
       
   509 	TInt status = aStatus.Int();
       
   510 	if (status == KErrNone)
       
   511 		{
       
   512 		// All went well
       
   513 		return;
       
   514 		}
       
   515 	if (status == KRequestPending)
       
   516 		{
       
   517 		// If the thread is still running, that's an error, as we waited for the status  
       
   518 		ERR_PRINTF2(_L("Error in thread %d - status should not be KRequestPending"), aIndex);
       
   519 		User::Leave(KErrTEFUnitFail);
       
   520 		}
       
   521 	// Something went wrong
       
   522 	switch (aThread.ExitType())
       
   523 		{
       
   524 		case EExitPanic:		// The thread or process has been panicked.
       
   525 			{
       
   526 			TPtrC ptrExitCategory = aThread.ExitCategory();
       
   527 			ERR_PRINTF4(_L("Panic in thread %d - category:[%S] reason: %d"), aIndex, &ptrExitCategory, aThread.ExitReason());
       
   528 			User::Panic(aThread.ExitCategory(), aThread.ExitReason());
       
   529 			}
       
   530 			// follow through
       
   531 		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(). 
       
   532 		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. 
       
   533 		case EExitPending:		// The thread or process is alive. 
       
   534 		default:
       
   535 			// Propagate the error
       
   536 			ERR_PRINTF3(_L("Error in thread %d - code %d"), aIndex, status);
       
   537 			User::Leave(aStatus.Int());
       
   538 		}
       
   539 	// We should not get here!
       
   540 	ASSERT(0);
       
   541 	}
       
   542 
       
   543 TInt CEglTestStep::ThreadFunction(TAny* aInfo)
       
   544 // static
       
   545 	{
       
   546 	__UHEAP_MARK;
       
   547 	CTrapCleanup* cleanup = CTrapCleanup::New();
       
   548 	if(cleanup == NULL)
       
   549 		{
       
   550 		return KErrNoMemory;
       
   551 		}
       
   552 
       
   553 	CEglTestStep::TThreadInfo* info = reinterpret_cast<CEglTestStep::TThreadInfo*>(aInfo);
       
   554 	TRAPD(err, info->iSelf->ThreadFunctionL(*info));
       
   555 
       
   556 	delete cleanup;
       
   557 	__UHEAP_MARKEND;
       
   558 	return err;
       
   559 	}
       
   560 
       
   561 void CEglTestStep::ThreadFunctionL(TThreadInfo& aInfo)
       
   562 	{
       
   563 	// Mark the handle count for this thread
       
   564 	TInt processHandleMark=0;
       
   565 	TInt threadHandleMark=0;
       
   566 	RThread().HandleCount(processHandleMark, threadHandleMark);
       
   567 	INFO_PRINTF4(_L("MARK: THREAD %d: (%d) process-owned handle(s) / (%d) thread-owned handle(s)"), aInfo.iIdx, processHandleMark, threadHandleMark);	
       
   568 	
       
   569 	// Notify the main thread that we are about to launch the extra thread
       
   570 	RThread::Rendezvous(KErrNone);
       
   571 	
       
   572 	// Run the real thread funciton
       
   573 	aInfo.iSelf->doThreadFunctionL(aInfo.iIdx);
       
   574 
       
   575 	// Release EGL thread state
       
   576 	INFO_PRINTF2(_L("thread %d: Calling eglReleaseThread()"), aInfo.iIdx);
       
   577 	ASSERT_EGL_TRUE(eglReleaseThread());
       
   578 	
       
   579 	// Check the handle count for this thread has not changed
       
   580 	TInt processHandleMarkEnd=0;
       
   581 	TInt threadHandleMarkEnd=0;
       
   582 	RThread().HandleCount(processHandleMarkEnd, threadHandleMarkEnd);
       
   583 	INFO_PRINTF4(_L("MARK-END: THREAD %d: (%d) process-owned handle(s) / (%d) thread-owned handle(s)"), aInfo.iIdx, processHandleMarkEnd, threadHandleMarkEnd);
       
   584 	
       
   585 	//Not testing equality of process-owned handles as these should only be tested from the main thread.
       
   586 	//Process handlecount is dependent on all threads, therefore process handle imbalances could be the responsibility of other threads.
       
   587 	ASSERT_EQUALS(threadHandleMark, threadHandleMarkEnd);
       
   588 	}
       
   589 
       
   590 /**
       
   591 Tests should override this method for multithreaded testing
       
   592 */
       
   593 EXPORT_C void CEglTestStep::doThreadFunctionL(TInt aIdx)
       
   594 	{
       
   595 	// Not supported for this test step
       
   596 	ERR_PRINTF2(_L("thread %d: Calling CEglTestStep::doThreadFunctionL() - should be overriden"), aIdx);
       
   597 	User::Leave(KErrNotSupported);
       
   598 	}
       
   599 
       
   600 EXPORT_C void CEglTestStep::doThreadFunctionL(TInt aIdx,const TSgDrawableId& aSgId)
       
   601 	{
       
   602 	// Not supported for this test step
       
   603 	ERR_PRINTF3(_L("thread %d: Calling CEglTestStep::doThreadFunctionL() - should be overriden, TSgDrawableId %lu."), aIdx, aSgId.iId);
       
   604 	User::Leave(KErrNotSupported);
       
   605 	}
       
   606 
       
   607 /**
       
   608 Tests should override this method for multiprocess testing
       
   609 */
       
   610 EXPORT_C void CEglTestStep::doProcessFunctionL(TInt aIdx)
       
   611 	{
       
   612 	// Not supported for this test step
       
   613 	ERR_PRINTF2(_L("Process %d: Calling CEglTestStep::doProcessFunctionL() - should be overriden"), aIdx);
       
   614 	User::Leave(KErrNotSupported);
       
   615 	}
       
   616 
       
   617 EXPORT_C void CEglTestStep::doProcessFunctionL(TInt aIdx,const TSgDrawableId& aSgId)
       
   618 	{
       
   619 	// Not supported for this test step
       
   620 	ERR_PRINTF3(_L("Process %d: Calling CEglTestStep::doProcessFunctionL() - should be overriden, TSgDrawableId %lu."), aIdx, aSgId.iId);
       
   621 	User::Leave(KErrNotSupported);
       
   622 	}
       
   623 
       
   624 
       
   625 /**
       
   626 Rendezvous: Ensures that both threads get to this point before continuing
       
   627 @param aIdx The thread index value that was passed into
       
   628 			the override of CEglTestStep::doThreadFunctionL()
       
   629 */
       
   630 EXPORT_C void CEglTestStep::Rendezvous(TInt aIdx)
       
   631 	{
       
   632 	if(aIdx >= 2)
       
   633 	    {
       
   634 	    // Currently Rendezvous is only supported between threads with index 0 and index 1
       
   635 	    INFO_PRINTF2(_L("CEglTestStep::Rendezvous() - aIdx (%d) is too big!!"), aIdx);
       
   636 	    ASSERT(0);
       
   637 	    }
       
   638 	INFO_PRINTF2(_L("thread %d: ...At Rendezvous..."), aIdx);
       
   639 	iSemaphore[aIdx].Signal();
       
   640 	iSemaphore[1-aIdx].Wait();
       
   641 	}
       
   642 
       
   643 
       
   644 /*****************************************************************************
       
   645  ** Egl Helpers
       
   646  *****************************************************************************/
       
   647  
       
   648 /**
       
   649 Temporarily initializes the EGL thread and display in order to check for the 
       
   650 supplied extension string.
       
   651 The display is then released and terminated.
       
   652 Use this method to pre-check for the existence of an extension string prior 
       
   653 to starting a test.
       
   654 There are 2 ways to ask for an extension, via the ID (the default way to do it) 
       
   655 or passing a string containing the full name of the extension (used in some tests only)
       
   656 @param aExtensions The extension ID to look for
       
   657 @param aExtensionName The extension name to look for
       
   658 @return Whether the extension string can be found
       
   659 */
       
   660 EXPORT_C TBool CEglTestStep::CheckForExtensionL(TInt aExtensions, const TDesC& aExtensionName)
       
   661 	{
       
   662 	ASSERT_TRUE(iDisplay == EGL_NO_DISPLAY);
       
   663 	GetDisplayL();
       
   664 	CTestEglSession* eglSess = CTestEglSession::NewLC(Logger(), iDisplay, -1);
       
   665 	eglSess->InitializeL();
       
   666 	
       
   667 	TBool bFoundExtensions = eglSess->CheckNeededExtensionL(aExtensions, aExtensionName);
       
   668 	
       
   669 	// Cleanup EGL Completely
       
   670 	CleanupStack::PopAndDestroy(eglSess);
       
   671 	eglSess = NULL;
       
   672 	TerminateDisplayL();
       
   673 	ASSERT_EGL_TRUE(eglReleaseThread());
       
   674 
       
   675 	// return whether the extension string was found
       
   676 	return bFoundExtensions;
       
   677 	}
       
   678 
       
   679 /**
       
   680 Uses eglGetDisplay() to initialise iDisplay, and to check the result of the call
       
   681 */
       
   682 EXPORT_C void CEglTestStep::GetDisplayL()
       
   683 	{
       
   684 	INFO_PRINTF1(_L("Calling eglGetDisplay..."));
       
   685 	
       
   686 	iDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
       
   687 	ASSERT_EGL_TRUE(iDisplay != EGL_NO_DISPLAY);
       
   688 	}
       
   689 
       
   690 /**
       
   691 If the iDisplay has been initialised then this method uses eglTerminate() 
       
   692 to terminate iDisplay, and to check the result of the call.
       
   693 This method also resets the value of iDisplay to EGL_NO_DISPLAY to indicate
       
   694 that the display is no longer initialised.
       
   695 */
       
   696 EXPORT_C void CEglTestStep::TerminateDisplayL()
       
   697 	{
       
   698 	if (iDisplay != EGL_NO_DISPLAY)
       
   699 		{
       
   700 		INFO_PRINTF1(_L("Calling eglTerminate..."));
       
   701 		ASSERT_EGL_TRUE(eglTerminate(iDisplay));
       
   702 		iDisplay = EGL_NO_DISPLAY;
       
   703 		}
       
   704 	}
       
   705 
       
   706 /**
       
   707 Cut and paste from CTestStep::SetLogger() - which is not exported
       
   708 As the name suggests, this is for use by the egl test process wrapper
       
   709 */
       
   710 void CEglTestStep::SetLoggerForProcessWrapperL()
       
   711 	{
       
   712 	// Create a cinidata object for parsing the testexecute.ini
       
   713 	CTestExecuteIniData* parseTestExecuteIni = NULL;
       
   714 	TBuf<KMaxTestExecuteNameLength> resultFilePath;
       
   715 	TBuf<KMaxTestExecuteNameLength> xmlFilePath;
       
   716 	TInt logMode;
       
   717 	TInt logLevel;
       
   718 	
       
   719 	TRAPD(err,parseTestExecuteIni = CTestExecuteIniData::NewL());
       
   720 	if (err == KErrNone)
       
   721 		{
       
   722 		CleanupStack::PushL(parseTestExecuteIni);
       
   723 		parseTestExecuteIni->ExtractValuesFromIni();
       
   724 		parseTestExecuteIni->GetKeyValueFromIni(KTEFHtmlKey, resultFilePath);
       
   725 		parseTestExecuteIni->GetKeyValueFromIni(KTEFXmlKey, xmlFilePath);
       
   726 		parseTestExecuteIni->GetKeyValueFromIni(KTEFLogMode, logMode);
       
   727 		parseTestExecuteIni->GetKeyValueFromIni(KTEFLogSeverityKey, logLevel);
       
   728 		parseTestExecuteIni->GetKeyValueFromIni(KTEFEnableIniAccessLog, IniAccessLog());
       
   729 		}
       
   730 	else
       
   731 		{
       
   732 		resultFilePath.Copy(KTestExecuteLogPath);
       
   733 		xmlFilePath.Copy(KTestExecuteLogPath);
       
   734 		logMode = TLoggerOptions(ELogHTMLOnly);
       
   735 		logLevel = RFileFlogger::TLogSeverity(ESevrAll);
       
   736 		IniAccessLog() = ETrue;
       
   737 		}
       
   738 	Logger().SetLoggerOptions(logMode);
       
   739 		
       
   740 	// Initialise a handle to the file logger
       
   741 	User::LeaveIfError(Logger().Connect());
       
   742 	RFs fS;
       
   743 	User::LeaveIfError(fS.Connect());
       
   744 	CleanupClosePushL(fS);
       
   745 	RFile file;
       
   746 	TBuf<KMaxTestExecuteNameLength> xmlLogFile(xmlFilePath);
       
   747 	TBuf<KMaxTestExecuteNameLength> logFile;
       
   748 	TBuf<KMaxTestExecuteNameLength> logFileNameFile(resultFilePath);
       
   749 	logFileNameFile.Append(KTestExecuteScheduleTestLogCompatibilityNameFile);
       
   750 	if(file.Open(fS,logFileNameFile,EFileRead | EFileShareAny) != KErrNone)
       
   751 		{
       
   752 		// For the old flogger we have to create an individual file
       
   753 		logFile.Copy(TestStepName());
       
   754 		_LIT(KTxtExtension,".txt");
       
   755 		logFile.Append(KTxtExtension);
       
   756 		logMode = TLoggerOptions(0);
       
   757 		Logger().SetLoggerOptions(logMode);
       
   758 		}
       
   759 	else
       
   760 		{
       
   761 		CleanupClosePushL(file);
       
   762 		TBuf8<KMaxTestExecuteNameLength> logFile8;
       
   763 		TInt fileSize;
       
   764 		User::LeaveIfError(file.Size(fileSize));
       
   765 		User::LeaveIfError(file.Read(logFile8,fileSize));
       
   766 		logFile.Copy(logFile8);
       
   767 		xmlLogFile.Append(logFile);
       
   768 		_LIT(KXmlExtension,".xml");
       
   769 		xmlLogFile.Append(KXmlExtension);
       
   770 		_LIT(KHtmExtension,".htm");
       
   771 		logFile.Append(KHtmExtension);
       
   772 		CleanupStack::Pop(&file);
       
   773 		file.Close();
       
   774 		}
       
   775 	TBuf<KMaxTestExecuteLogFilePath> logFilePath(resultFilePath);
       
   776 	logFilePath.Append(logFile);
       
   777 	CleanupStack::Pop(&fS);
       
   778 	fS.Close();
       
   779 	
       
   780 	if (logMode == 0 || logMode == 2)
       
   781 		{
       
   782 		User::LeaveIfError(Logger().HtmlLogger().CreateLog(logFilePath,RTestExecuteLogServ::ELogModeAppend));
       
   783 		Logger().HtmlLogger().SetLogLevel(TLogSeverity(logLevel));
       
   784 		}
       
   785 	if (logMode == 1 || logMode == 2)
       
   786 		{
       
   787 		User::LeaveIfError(Logger().XmlLogger().CreateLog(xmlLogFile,RFileFlogger::ELogModeAppend));
       
   788 		Logger().XmlLogger().SetLogLevel(RFileFlogger::TLogSeverity(logLevel));
       
   789 		}
       
   790 	if (parseTestExecuteIni != NULL)
       
   791 		{
       
   792 		CleanupStack::PopAndDestroy(parseTestExecuteIni);
       
   793 		}
       
   794 	}
       
   795 
       
   796 EXPORT_C void CEglTestStep::PartialInitialiseL(const TDesC& aStepName)
       
   797 	{
       
   798 	SetTestStepName(aStepName);	
       
   799 	SetLoggerForProcessWrapperL();
       
   800 	// Assume pass
       
   801 	SetTestStepResult(EPass);
       
   802 	}
       
   803 
       
   804 EXPORT_C void CEglTestStep::CreateEglSessionL(TInt aIdx)
       
   805 	{
       
   806 	delete iEglSess; //just in case it was called twice
       
   807 	iEglSess = CTestEglSession::NewL(Logger(), iDisplay, aIdx);
       
   808 	}
       
   809