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