os/kernelhwsrv/kerneltest/e32test/emul/t_emul.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     1 // Copyright (c) 2002-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 the License "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 // e32test\emul\t_emul.cpp
    15 // Overview:
    16 // Test the mechanism to escape threads from the emulator in order
    17 // to block on Windows objects
    18 // Test launching processes doesn't leak windows TLS indices
    19 // API Information:
    20 // Emulator
    21 // Details:
    22 // - Test the mechanism to escape threads from the emulator in order
    23 // to block on Windows objects:
    24 // - test escape and re-enter mechanism.
    25 // - block on Windows in EPOC thread and escaped EPOC thread.
    26 // Platforms/Drives/Compatibility:
    27 // All.
    28 // Assumptions/Requirement/Pre-requisites:
    29 // Failures and causes:
    30 // Base Port information:
    31 // 
    32 //
    33 
    34 #define __E32TEST_EXTENSION__
    35 #include <f32file.h>
    36 #include <e32atomics.h>
    37 #include <e32std.h>
    38 #include <e32std_private.h>
    39 #include <e32ldr.h>
    40 #include <e32ldr_private.h>
    41 #include "e32test.h"
    42 #include "emulator.h"
    43 #include "t_emul.h"
    44 
    45 #define WIN32_LEAN_AND_MEAN
    46 #pragma warning( disable : 4201 ) // nonstandard extension used : nameless struct/union
    47 #include <windows.h>
    48 #pragma warning( default : 4201 ) // nonstandard extension used : nameless struct/union
    49 
    50 LOCAL_D RTest test(_L("t_emul"));
    51 
    52 static TInt ELock;
    53 static HANDLE ESemaphore;
    54 static TInt EResult;
    55 
    56 TInt EscapeTimeoutThread(TAny*)
    57 	{
    58 	User::After(1000000);
    59 	if (__e32_atomic_add_ord32(&ELock, 1) == 0)
    60 		{
    61 		EResult=KErrTimedOut;
    62 		ReleaseSemaphore(ESemaphore,1,NULL);
    63 		}
    64 	return KErrNone;
    65 	}
    66 
    67 TInt EscapeSignalThread(TAny*)
    68 	{
    69 	if (__e32_atomic_add_ord32(&ELock, 1) == 0)
    70 		{
    71 		EResult=KErrNone;
    72 		ReleaseSemaphore(ESemaphore,1,NULL);
    73 		}
    74 	return KErrNone;
    75 	}
    76 
    77 TInt DoTestEscape(TBool aDoEscape)
    78 //
    79 // Test the mechanism to escape threads from the emulator in order to block on Windows objects
    80 //
    81 	{
    82 	ELock = 0;
    83 	EResult = KRequestPending;
    84 	ESemaphore = CreateSemaphoreA(NULL,0,1,NULL);
    85 	test (ESemaphore != NULL);
    86 	RThread t1,t2;
    87 	TRequestStatus s1,s2;
    88 	TInt r = t1.Create(KNullDesC,&EscapeSignalThread,0x1000,NULL,NULL);
    89 	test (r == KErrNone);
    90 	t1.SetPriority(EPriorityLess);
    91 	t1.Logon(s1);
    92 	t1.Resume();
    93 	r = t2.Create(KNullDesC,&EscapeTimeoutThread,0x1000,NULL,NULL);
    94 	test (r == KErrNone);
    95 	t2.SetPriority(EPriorityMore);
    96 	t2.Logon(s2);
    97 	t2.Resume();
    98 //
    99 	if (aDoEscape)
   100 		Emulator::Escape();
   101 	r = WaitForSingleObject(ESemaphore,INFINITE);
   102 	if (aDoEscape)
   103 		Emulator::Reenter();
   104 	test (r==WAIT_OBJECT_0);
   105 //
   106 	r = EResult;
   107 	t1.Kill(0);
   108 	t2.Kill(0);
   109 	t1.Close();
   110 	t2.Close();
   111 	User::WaitForRequest(s1);
   112 	User::WaitForRequest(s2);
   113 //
   114 	CloseHandle(ESemaphore);
   115 	return r;
   116 	}
   117 
   118 void TestEscape()
   119 //
   120 // Test the mechanism to escape threads from the emulator in order to block on Windows objects
   121 //
   122 	{
   123 	test.Start(_L("Test escape and reenter mechanism"));
   124 	for (TInt i = 0;i<10000;++i)
   125 		{
   126 		Emulator::Escape();
   127 		if (i%100 == 0)
   128 			Sleep(10);
   129 		Emulator::Reenter();
   130 		}
   131 	test.Next(_L("Block on Windows in EPOC thread"));
   132 	TInt r = DoTestEscape(EFalse);
   133 	test (r == KErrTimedOut);
   134 	test.Next(_L("Block on Windows in escaped EPOC thread"));
   135 	r = DoTestEscape(ETrue);
   136 	test (r == KErrNone);
   137 	test.End();
   138 	}
   139 
   140 TInt CountRemainingTlsIndicies()
   141 	{
   142 	const TInt KMax = 2000;
   143 	
   144 	TBool allocated[KMax];
   145 	memclr(allocated, sizeof(TBool) * KMax);
   146 	TInt i;
   147 	for (i = 0 ; i < KMax ; ++i)
   148 		{
   149 		TInt index = TlsAlloc();
   150 		if (index == TLS_OUT_OF_INDEXES)
   151 			break;
   152 		test(index >= 0 && index < KMax);
   153 		allocated[index] = ETrue;
   154 		}
   155 	for (TInt j = 0 ; j < KMax ; ++j)
   156 		{
   157 		if (allocated[j])
   158 			test(TlsFree(j));
   159 		}
   160 	return i;
   161 	}
   162 	   
   163 void RunSlave(TSlaveAction aAction)
   164 	{
   165 	RProcess p;
   166 	TBuf<8> arg;
   167 	arg.Format(_L("%d"), aAction);
   168 	test_KErrNone(p.Create(KTEmulSlaveName, arg));
   169 	p.Resume();
   170 	TRequestStatus status;
   171 	p.Logon(status);
   172 	User::WaitForRequest(status);
   173 	test_KErrNone(status.Int());
   174 	test_Equal(EExitKill, p.ExitType());
   175 	p.Close();
   176 	}
   177 
   178 void TestRuntimeCleanup()
   179 	{
   180 	test.Start(_L("Test Codewarrior runtime library is correctly cleaned up"));
   181 	TInt initIndicies = CountRemainingTlsIndicies();
   182 	
   183 	test.Next(_L("Test creating a process doesn't leak windows TLS indicies"));
   184 	RunSlave(ESlaveDoNothing);
   185 	test_Equal(initIndicies, CountRemainingTlsIndicies());
   186 
   187 	test.Next(_L("Test leaving in an exe doesn't leak windows TLS indicies"));
   188 	RunSlave(ESlaveTrapExceptionInExe);
   189 	test_Equal(initIndicies, CountRemainingTlsIndicies());
   190 	
   191 	test.Next(_L("Test leaving in a linked DLL doesn't leak windows TLS indicies"));
   192 	RunSlave(ESlaveTrapExceptionInLinkedDll);
   193 	test_Equal(initIndicies, CountRemainingTlsIndicies());
   194 	
   195 	test.Next(_L("Test leaving in a loaded DLL doesn't leak windows TLS indicies"));
   196 	RunSlave(ESlaveTrapExceptionInLoadedDll);
   197 	test_Equal(initIndicies, CountRemainingTlsIndicies());
   198 
   199 	test.Next(_L("Test cleanup doesn't happen while DLL still loaded"));
   200 	RLibrary l;
   201 	test_KErrNone(l.Load(KTEmulDll2Name));
   202 	RunSlave(ESlaveTrapExceptionInLoadedDll);
   203 	TInt midCount = CountRemainingTlsIndicies();
   204 	test(initIndicies > midCount);
   205 
   206 	test.Next(_L("Test previous detach doesn't cause runtime to be re-initalised"));
   207 	TTrapExceptionInDllFunc func =
   208 		(TTrapExceptionInDllFunc)l.Lookup(KTrapExceptionInDllOrdinal);
   209 	test_NotNull(func);
   210 	func();
   211 	test_Equal(midCount, CountRemainingTlsIndicies());	
   212 	l.Close();
   213 	test_Equal(initIndicies, CountRemainingTlsIndicies());
   214 	
   215 	test.End();
   216 	}
   217 
   218 
   219 void DoSomething2L()
   220 	{
   221 	test.Printf(_L("@\n"));
   222 	}
   223 
   224 
   225 void DoSomething1L()
   226 	{
   227 	TInt i = -1, j = 1;
   228 	for ( ; ; )
   229 		{
   230 		i++;
   231 		//DoSomething2L() must only be called once , else we know that trap mechanism didn't work 
   232 		test( i<2);
   233 		if (i == j)  
   234 			{
   235 			User::Leave(KErrNotFound);
   236 			}
   237 
   238 		TRAP_IGNORE(DoSomething2L());
   239 		TRAPD(errr, DoSomething2L());
   240 		TInt r;
   241 		TRAP(r, DoSomething2L());
   242 
   243 		}
   244 	}
   245 
   246 
   247 void LeaveIfArgIsTwo(TInt aCall);
   248 
   249 class CFred : public CBase
   250 {
   251 	public:
   252 static CFred* NewLC();
   253 	CFred();
   254 	~CFred();
   255 };
   256 
   257 void DoSomething3L()
   258 	{
   259 	// Push something on the cleanup stack so we can see whyen it gets cleaned up.
   260 	CFred *fred = CFred::NewLC();
   261 		
   262 	TInt beforeFunc=0;
   263 	TInt betweenFuncAndTRAPD=0;
   264 	TInt afterTRAPD=0;
   265 	for(TInt loop=1; loop<=2; ++loop)
   266 		{
   267 		++beforeFunc;
   268 		test.Printf(_L("Before LeaveIfArgIsTwo()\n"));
   269 
   270 		// The first time around the loop, this function call works.
   271 		// The second time, it leaves KErrGeneral
   272 		// Then when TRAP mechanism isn't working properly the emulator (correctly) 
   273 		// would delete fred, and (incorrectly) jump to the line
   274 		// just after the TRAPD call a few lines further down the file!
   275 		LeaveIfArgIsTwo(loop);
   276 
   277 		++betweenFuncAndTRAPD;
   278 		test.Printf(_L("Between LeaveIfArgIsTwo() and TRAPD\n"));
   279 
   280 		TRAPD(err, test.Printf(_L("Inside TRAPD\n") ) );
   281 
   282 
   283 		// It should only be possible to reach this section of code by executing all the lines
   284 		// between LeaveIfArgIsTwo and here.
   285 		++afterTRAPD;
   286 		
   287 		}
   288 
   289 	// Should NEVER get here because LeaveIfArgIsTwo did a leave the second time around the loop
   290 	test.Printf(_L("After loop (should NEVER get here) -\n\
   291 					beforeFunc %d\n\
   292 					betweenFuncAndTRAPD %d\n\
   293 					afterTRAPD %d\n"),
   294 					beforeFunc, betweenFuncAndTRAPD, afterTRAPD);
   295 	
   296 	test.Printf(_L("It should be impossible for afterTRAPD to be larger than betweenFuncAndTRAPD\n"));
   297 	test(afterTRAPD <= betweenFuncAndTRAPD);
   298 
   299 	// Cleanup our cleanup stack. 
   300 	CleanupStack::PopAndDestroy(&fred);
   301 	}
   302 
   303 void LeaveIfArgIsTwo(TInt aCall)
   304 	{
   305 	
   306 	test.Printf(_L("aCall    %d\n"), aCall);
   307 	if(aCall == 2)
   308 		{
   309 		User::Leave(KErrGeneral);
   310 		}
   311 	}
   312 
   313 CFred *CFred::NewLC()
   314 	{
   315 	CFred *self = new(ELeave) CFred;
   316 	CleanupStack::PushL(self);
   317 	return self;
   318 	}
   319 
   320 CFred::CFred()
   321 	{
   322 	test.Printf(_L("CFred %x\n"), this);
   323 	}
   324 
   325 CFred::~CFred()
   326 	{
   327 	test.Printf(_L("~CFred %x\n"), this);
   328 	}
   329 
   330 
   331 
   332 GLDEF_C TInt E32Main()
   333 //
   334 //
   335 //
   336 	{
   337 	test.Title();
   338 	test.Start(_L("Starting tests ..."));
   339 
   340 	// Turn off evil lazy dll unloading
   341 	RLoader l;
   342 	test(l.Connect()==KErrNone);
   343 	test(l.CancelLazyDllUnload()==KErrNone);
   344 	l.Close();
   345 	
   346 	TestEscape();
   347 #ifdef __CW32__
   348 	TestRuntimeCleanup();
   349 #endif
   350 
   351 	// The following tests were added to test that the TRAP mechanism works correctly in case of
   352 	// nested TRAP's. A compiler bug (winscw) caused the following tests to fail, since the wrong 
   353 	// trap handler would be invoked, when User::Leave() was called.
   354 	
   355 	test.Next(_L("Check User::Leave is handled by the correct TRAP handler when nested TRAPs are present - Simple scenario\n")); 
   356 		
   357  	TRAPD(err, DoSomething1L());
   358 	test(err == KErrNotFound);
   359 	
   360 	test.Next(_L("Check User::Leave is handled by the correct TRAP handler when nested TRAPs are present - Cleanup stack scenario\n")); 		
   361 	__UHEAP_MARK;
   362 	CTrapCleanup* tc = CTrapCleanup::New();
   363 	if (tc == 0) return KErrNoMemory;
   364 	
   365 	TRAPD(err2, DoSomething3L());
   366 	test(err2==KErrGeneral);	
   367 
   368 	delete tc;
   369 	__UHEAP_MARKEND;
   370 	
   371 	
   372 	test.End();
   373 	test.Close();
   374 	return KErrNone;
   375 	}
   376