os/kernelhwsrv/kerneltest/e32test/dll/t_tls.cpp
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
     1 // Copyright (c) 1996-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\dll\t_tls.cpp
    15 // Overview:
    16 // Test and benchmark TLS (Thread Local Storage) functions
    17 // API Information:
    18 // UserSvr
    19 // Details:
    20 // - Use the UserSvr methods: DllTls, DllSetTls and DllFreeTls to test 
    21 // the thread local storage. Verify the expected results. Verify that 
    22 // the heap was not corrupted by any of the tests.
    23 // - In a separate thread, use the UserSvr methods: DllTls, DllSetTls and 
    24 // DllFreeTls to test the thread local storage. Verify the expected results.
    25 // - Test the TLS cleanup handlers and verify results are as expected. Verify 
    26 // that the heap was not corrupted by any of the tests.
    27 // - Benchmark how many DllSetTls, DllTls and DllFreeTls operations can be
    28 // performed in 1/2 second.
    29 // Platforms/Drives/Compatibility:
    30 // All.
    31 // Assumptions/Requirement/Pre-requisites:
    32 // Failures and causes:
    33 // Base Port information:
    34 // Tests and benchmarks Tls functions
    35 // 14/10/96 Modified scheme on Arm release
    36 // SetTls - 352	~1300
    37 // Tls - 3510 ~1600
    38 // 15/10/96 Array scheme on Arm release
    39 // Set Tls - ~1900
    40 // Tls - ~2550
    41 // 
    42 //
    43 
    44 #define __E32TEST_EXTENSION__
    45 
    46 #include <e32test.h>
    47 #include <e32svr.h>
    48 #include <f32dbg.h>
    49 #include <e32def.h>
    50 #include <e32def_private.h>
    51 #include "u32std.h"
    52 
    53 // Can't tell whether allocations will be on the kernel or user heap, so perform all heap check
    54 // operations on both
    55 #define HEAP_MARK			__UHEAP_MARK; __KHEAP_MARK
    56 #define HEAP_MARKEND		__UHEAP_MARKEND; __KHEAP_MARKEND
    57 #define HEAP_RESET			__UHEAP_RESET; __KHEAP_RESET
    58 #define HEAP_CHECK(x)		__UHEAP_CHECK(x); __KHEAP_CHECK(x)
    59 #define HEAP_FAILNEXT(x)	__UHEAP_FAILNEXT(x); __KHEAP_FAILNEXT(x)
    60 
    61 TInt const KCheckHandle=67338721;
    62 TUint8* const KCheckValue=(TUint8*)8525124;
    63 
    64 LOCAL_D RTest test(_L("T_TLS"));
    65 
    66 _LIT(KTestDllName, "t_tlsdll");
    67 const TInt KTestDllOrdSet	= 1;
    68 const TInt KTestDllOrdGet	= 2;
    69 const TInt KTestDllOrdFree	= 3;
    70 
    71 typedef TInt (*TTestDllSetFn)(TAny*);
    72 typedef TAny* (*TTestDllGetFn)();
    73 typedef void (*TTestDllFreeFn)();
    74 
    75 TInt TestDllSetTls(RLibrary aLib, TAny* aValue)
    76 	{
    77 	TTestDllSetFn f = (TTestDllSetFn)aLib.Lookup(KTestDllOrdSet);
    78 	return (*f)(aValue);
    79 	}
    80 
    81 TAny* TestDllGetTls(RLibrary aLib)
    82 	{
    83 	TTestDllGetFn f = (TTestDllGetFn)aLib.Lookup(KTestDllOrdGet);
    84 	return (*f)();
    85 	}
    86 
    87 void TestDllFreeTls(RLibrary aLib)
    88 	{
    89 	TTestDllFreeFn f = (TTestDllFreeFn)aLib.Lookup(KTestDllOrdFree);
    90 	(*f)();
    91 	}
    92 
    93 #define DISPLAY_PROGRESS	test.Printf(_L("Line %d\n"), __LINE__)
    94 
    95 void Test()
    96 	{
    97 	test.Start(_L("Stuff without Setting"));
    98 
    99 	HEAP_MARK;
   100 
   101 	test(UserSvr::DllTls(KCheckHandle)==NULL);
   102 	UserSvr::DllFreeTls(KCheckHandle);
   103 	test(UserSvr::DllTls(KCheckHandle)==NULL);
   104 	test(UserSvr::DllTls(0)==NULL);
   105 	UserSvr::DllFreeTls(0);
   106 	test(UserSvr::DllTls(0)==NULL);
   107 
   108 	HEAP_CHECK(0);
   109 
   110 	test.Next(_L("Set"));
   111 	test(UserSvr::DllSetTls(KCheckHandle,KCheckValue)==KErrNone);
   112 	test.Next(_L("Get"));
   113 	test(UserSvr::DllTls(KCheckHandle)==KCheckValue);
   114 	test.Next(_L("Free"));
   115 	UserSvr::DllFreeTls(KCheckHandle);
   116 	test(UserSvr::DllTls(KCheckHandle)==NULL);
   117 
   118 	HEAP_CHECK(0);
   119 
   120 	test.Next(_L("Set lots"));
   121 	TInt i=0;
   122 	for(;i<1000;i+=3)
   123 		{
   124 		test(UserSvr::DllSetTls(KCheckHandle+i,KCheckValue-i)==KErrNone);
   125 		test(UserSvr::DllTls(KCheckHandle+i)==KCheckValue-i);
   126 		}
   127 	for(i=999;i>0;i-=3)
   128 		{
   129 		test(UserSvr::DllTls(KCheckHandle+i)==KCheckValue-i);
   130 		UserSvr::DllFreeTls(KCheckHandle+i);
   131 		test(UserSvr::DllTls(KCheckHandle+i)==NULL);
   132 		}
   133 	test(UserSvr::DllTls(KCheckHandle+i)==KCheckValue-i);
   134 	UserSvr::DllFreeTls(KCheckHandle+i);
   135 	test(UserSvr::DllTls(KCheckHandle+i)==NULL);
   136 
   137 	HEAP_MARKEND;
   138 
   139 
   140 	test.Next(_L("Test with DLL ID"));
   141 
   142 	HEAP_MARK;
   143 
   144 	test(UserSvr::DllTls(KCheckHandle, 1)==0);
   145 	test(UserSvr::DllTls(KCheckHandle, 2)==0);
   146 	DISPLAY_PROGRESS;
   147 #ifdef _DEBUG
   148 	HEAP_FAILNEXT(1);
   149 	DISPLAY_PROGRESS;
   150 	test(UserSvr::DllSetTls(KCheckHandle, 1, KCheckValue)==KErrNoMemory);
   151 #endif
   152 	test(UserSvr::DllSetTls(KCheckHandle, 1, KCheckValue)==KErrNone);
   153 	test(UserSvr::DllTls(KCheckHandle, 1)==KCheckValue);
   154 	test(UserSvr::DllTls(KCheckHandle, 2)==0);
   155 	DISPLAY_PROGRESS;
   156 	HEAP_FAILNEXT(1);
   157 	DISPLAY_PROGRESS;
   158 	test(UserSvr::DllSetTls(KCheckHandle, 3, KCheckValue)==KErrNone);
   159 
   160 #ifdef _DEBUG
   161 	RSemaphore s;
   162 	test(s.CreateLocal(0)==KErrNoMemory);
   163 #endif
   164 
   165 	HEAP_RESET;
   166 
   167 	test(UserSvr::DllTls(KCheckHandle, 1)==0);
   168 	test(UserSvr::DllTls(KCheckHandle, 2)==0);
   169 	test(UserSvr::DllTls(KCheckHandle, 3)==KCheckValue);
   170 	UserSvr::DllFreeTls(KCheckHandle);
   171 
   172 	DISPLAY_PROGRESS;
   173 	HEAP_MARKEND;
   174 	DISPLAY_PROGRESS;
   175 
   176 	test.Next(_L("Test reloading DLL"));
   177 
   178 	RLibrary l;
   179 	TInt r = l.Load(KTestDllName);
   180 	test(r==KErrNone);
   181 	for (i=0; i<2; ++i)
   182 		{
   183 		test.Printf(_L("i=%d\n"),i);
   184 		test(TestDllGetTls(l)==0);
   185 		test(TestDllSetTls(l, KCheckValue)==KErrNone);
   186 		test(TestDllGetTls(l)==KCheckValue);
   187 		if (i==0)
   188 			{
   189 			TestDllFreeTls(l);
   190 			test(TestDllGetTls(l)==0);
   191 			}
   192 		l.Close();
   193 		r = l.Load(KTestDllName);
   194 		test(r==KErrNone);
   195 		test(TestDllGetTls(l)==0);
   196 		TestDllFreeTls(l);
   197 		}
   198 	l.Close();
   199 
   200 	test.End();
   201 	}
   202 
   203 TInt TestThread(TAny*)
   204 	{
   205 	RTest test(_L("T_TLS Thread"));
   206 	test.Start(_L("Stuff without Setting"));
   207 	test(UserSvr::DllTls(KCheckHandle)==NULL);
   208 	UserSvr::DllFreeTls(KCheckHandle);
   209 	test(UserSvr::DllTls(KCheckHandle)==NULL);
   210 	test(UserSvr::DllTls(0)==NULL);
   211 	UserSvr::DllFreeTls(0);
   212 	test(UserSvr::DllTls(0)==NULL);
   213 	test.Next(_L("Set"));
   214 	test(UserSvr::DllSetTls(KCheckHandle,KCheckValue)==KErrNone);
   215 	test.Next(_L("Get"));
   216 	test(UserSvr::DllTls(KCheckHandle)==KCheckValue);
   217 	test.Next(_L("Free"));
   218 	UserSvr::DllFreeTls(KCheckHandle);
   219 	test(UserSvr::DllTls(KCheckHandle)==NULL);
   220 	test.Next(_L("Set lots"));
   221 	TInt i=0;
   222 	for(;i<1000;i+=3)
   223 		{
   224 		test(UserSvr::DllSetTls(KCheckHandle+i,KCheckValue-i)==KErrNone);
   225 		test(UserSvr::DllTls(KCheckHandle+i)==KCheckValue-i);
   226 		}
   227 	for(i=999;i>=0;i-=3)
   228 		{
   229 		test(UserSvr::DllTls(KCheckHandle+i)==KCheckValue-i);
   230 		UserSvr::DllFreeTls(KCheckHandle+i);
   231 		test(UserSvr::DllTls(KCheckHandle+i)==NULL);
   232 		}
   233 
   234 	test.Close();
   235 	return KErrNone;
   236 	}
   237 
   238 TInt HeapSize(RHeap* aHeap = NULL)
   239 	{
   240 	if (!aHeap)
   241 		aHeap = &User::Heap();
   242 	TInt size;
   243 	aHeap->AllocSize(size);
   244 	return size;
   245 	}
   246 
   247 TBool TLSStoredOnUserHeap()
   248 	{
   249 	TInt initCount = HeapSize();
   250 	TInt i;
   251 	const TInt KMax = 2;
   252 	for(i = 0 ; i < KMax ; ++i)
   253 		test(UserSvr::DllSetTls(KCheckHandle+i,KCheckValue-i) == KErrNone);
   254 	TInt finalCount = HeapSize();
   255 	for(i = 0 ; i < KMax ; ++i)
   256 		UserSvr::DllFreeTls(KCheckHandle+i);
   257 	return initCount != finalCount;
   258 	}
   259 
   260 class RDummyAllocator : public RAllocator
   261 	{
   262 public:
   263 	TInt AccessCount() { return iAccessCount; }
   264 	};
   265 
   266 RHeap* MainHeap = NULL;
   267 
   268 TInt HeapAccessCount(TAny* aHeap)
   269 	{
   270 	RDummyAllocator* heap = (RDummyAllocator*)aHeap;
   271 	return heap->AccessCount();
   272 	}
   273 
   274 TBool HeapExists(RHeap* aHeap)
   275 	{
   276 	RThread thread;
   277 	test_KErrNone(thread.Create(_L("HeapExistsThread"), HeapAccessCount, 0x1000, MainHeap, (TAny*)aHeap));
   278 	TRequestStatus status;
   279 	thread.Logon(status);
   280 	thread.Resume();
   281 	User::WaitForRequest(status);
   282 
   283 	TInt r;
   284 	if (thread.ExitType() == EExitKill)
   285 		{
   286 		r = thread.ExitReason();
   287 		test_NotNegative(r);
   288 		}
   289 	else
   290 		{
   291 		test_Equal(EExitPanic, thread.ExitType());
   292 		test_Equal(3, thread.ExitReason());
   293 		r = 0;
   294 		}
   295 	thread.Close();
   296 	
   297 	return r != 0;
   298 	}
   299 
   300 TInt TestUserSideTls1Thread(TAny*)
   301 	{
   302 	// Ensure TLS uses initial heap
   303 	if (UserSvr::DllSetTls(KCheckHandle,KCheckValue) != KErrNone)
   304 		return __LINE__;
   305 	UserSvr::DllFreeTls(KCheckHandle);
   306 
   307 	RHeap* tlsHeap = &User::Heap();
   308 	TInt tlsInitSize = HeapSize(tlsHeap);
   309 
   310 	// Switch heap
   311 	RHeap* newHeap = User::ChunkHeap(NULL, 0x1000, 0x1000);
   312 	if (!newHeap)
   313 		return __LINE__;
   314 	TInt newInitSize = HeapSize(newHeap);
   315 	User::SwitchHeap(newHeap);
   316 	tlsHeap->Close();
   317 
   318 	// Allocate more TLS data
   319 	for(TInt i = 0 ; i < 100 ; ++i)
   320 		{
   321 		if (UserSvr::DllSetTls(KCheckHandle+i,KCheckValue-i) != KErrNone)
   322 			return __LINE__;
   323 		}
   324 
   325 	// Test TLS data was allocated on original heap
   326 	if (!(HeapSize(tlsHeap) > tlsInitSize))
   327 		return __LINE__;
   328 	if (HeapSize(newHeap) != newInitSize)
   329 		return __LINE__;
   330 	
   331 	return KErrNone;
   332 	}
   333 
   334 void TestUserSideTls1()
   335 	{
   336 	test.Next(_L("Test user-side TLS behaviour when switching heaps"));
   337 
   338 	RThread thread;
   339 	test_KErrNone(thread.Create(_L("TestUserSideTls1Thread"), TestUserSideTls1Thread, 0x1000, 0x1000, 0x1000, 0));
   340 	
   341 	TRequestStatus status;
   342 	thread.Logon(status);
   343 	thread.Resume();
   344 	User::WaitForRequest(status);
   345 	
   346 	test_Equal(EExitKill, thread.ExitType());
   347 	test_Equal(KErrNone, thread.ExitReason());
   348 	thread.Close();
   349 	}
   350 
   351 TInt TestUserSideTls2Thread(TAny*)
   352 	{
   353 	// Allocate some TLS data
   354 	for(TInt i = 0 ; i < 100 ; ++i)
   355 		{
   356 		if (UserSvr::DllSetTls(KCheckHandle+i,KCheckValue-i) != KErrNone)
   357 			return __LINE__;
   358 		}
   359 
   360 	// Exit normally
   361 	return KErrNone;
   362 	}
   363 
   364 void TestUserSideTls2()
   365 	{
   366 	test.Next(_L("Test user-side TLS data cleanup on thread exit"));
   367 
   368 	RHeap* tlsHeap = User::ChunkHeap(NULL, 0x1000, 0x1000);
   369 	test_NotNull(tlsHeap);
   370 	TInt initSize = HeapSize(tlsHeap);
   371 
   372 	RThread thread;
   373 	test_KErrNone(thread.Create(_L("TestUserSideTls2Thread"), TestUserSideTls2Thread, 0x1000, tlsHeap, 0));
   374 	TThreadId id = thread.Id();
   375 	
   376 	TRequestStatus status;
   377 	thread.Logon(status);
   378 	thread.Resume();
   379 	User::WaitForRequest(status);
   380 	
   381 	test_Equal(EExitKill, thread.ExitType());
   382 	test_Equal(KErrNone, thread.ExitReason());
   383 	thread.Close();
   384 
   385 	// Check TLS data freed
   386 	test_Equal(initSize, HeapSize(tlsHeap));	
   387 	tlsHeap->Close();
   388 
   389 	// Check heap no longer exists
   390 	test(!HeapExists(tlsHeap));
   391 
   392 	// Check thread no longer exists
   393 	RThread thread2;
   394 	test_Equal(KErrNotFound, thread2.Open(id));
   395 	}
   396 
   397 TInt TestUserSideTls3Thread(TAny*)
   398 	{
   399 	// Allocate some TLS data
   400 	for(TInt i = 0 ; i < 100 ; ++i)
   401 		{
   402 		if (UserSvr::DllSetTls(KCheckHandle+i,KCheckValue-i) != KErrNone)
   403 			return __LINE__;
   404 		}
   405 
   406 	// Panic
   407 	User::Panic(_L("Test"), 999);
   408 	return KErrNone;
   409 	}
   410 
   411 void TestUserSideTls3()
   412 	{
   413 	test.Next(_L("Test user-side TLS data cleanup on thread panic"));
   414 
   415 	RHeap* tlsHeap = User::ChunkHeap(NULL, 0x1000, 0x1000);
   416 	test_NotNull(tlsHeap);
   417 
   418 	RThread thread;
   419 	test_KErrNone(thread.Create(_L("TestUserSideTls3Thread"), TestUserSideTls3Thread, 0x1000, tlsHeap, 0));
   420 	TThreadId id = thread.Id();
   421 	
   422 	TRequestStatus status;
   423 	thread.Logon(status);
   424 	thread.Resume();
   425 	User::WaitForRequest(status);
   426 	
   427 	test_Equal(EExitPanic, thread.ExitType());
   428 	test_Equal(999, thread.ExitReason());
   429 	
   430 	thread.Close();
   431 	tlsHeap->Close();
   432 	
   433 	// Check heap no longer exists
   434 	test(!HeapExists(tlsHeap));
   435 
   436 	// Check thread no longer exists
   437 	RThread thread2;
   438 	test_Equal(KErrNotFound, thread2.Open(id));
   439 	}
   440 
   441 TInt TestUserSideTls4Thread(TAny*)
   442 	{
   443 	// Shouldn't ever run
   444 	return KErrGeneral;
   445 	}
   446 
   447 void TestUserSideTls4()
   448 	{
   449 	test.Next(_L("Test user-side TLS data cleanup on early thread kill"));
   450 	
   451 	RHeap* tlsHeap = User::ChunkHeap(NULL, 0x1000, 0x1000);
   452 	test_NotNull(tlsHeap);
   453 
   454 	RThread thread;
   455 	test_KErrNone(thread.Create(_L("TestUserSideTls4Thread"), TestUserSideTls4Thread, 0x1000, tlsHeap, 0));
   456 	TThreadId id = thread.Id();
   457 	
   458 	thread.Kill(101);
   459 
   460 	TRequestStatus status;
   461 	thread.Logon(status);
   462 	User::WaitForRequest(status);
   463 	
   464 	test_Equal(EExitKill, thread.ExitType());
   465 	test_Equal(101, thread.ExitReason());
   466 	
   467 	thread.Close();
   468 	tlsHeap->Close();
   469 	
   470 	// Check heap no longer exists
   471 	test(!HeapExists(tlsHeap));
   472 
   473 	// Check thread no longer exists
   474 	RThread thread2;
   475 	test_Equal(KErrNotFound, thread2.Open(id));
   476 	}
   477 
   478 #if 0
   479 class CTest : public CBase
   480 	{
   481 public:
   482 	static CTest* New(TInt aSize, TInt aTls, TInt aLinkedTls);
   483 	virtual ~CTest();
   484 public:
   485 	TAny* iAlloc;
   486 	TInt iTls;
   487 	TInt iLinkedTls;
   488 	};
   489 
   490 void TlsCleanup2(TAny* a)
   491 	{
   492 	delete ((CTest*)a);
   493 	}
   494 
   495 CTest::~CTest()
   496 	{
   497 	RDebug::Print(_L("~CTest %d %d"), iTls, iLinkedTls);
   498 	User::Free(iAlloc);
   499 	UserSvr::DllFreeTls(iTls);
   500 	if (iLinkedTls)
   501 		{
   502 		CTest* p = (CTest*)UserSvr::DllTls(iLinkedTls);
   503 		if (p)
   504 			delete p;
   505 		}
   506 	}
   507 
   508 CTest* CTest::New(TInt aSize, TInt aTls, TInt aLinkedTls)
   509 	{
   510 	CTest* p = new CTest;
   511 	test(p!=NULL);
   512 	p->iTls = aTls;
   513 	p->iAlloc = User::Alloc(aSize);
   514 	test(p->iAlloc!=NULL);
   515 	p->iLinkedTls = aLinkedTls;
   516 	test(UserSvr::DllSetTls(aTls, p, TlsCleanup2)==KErrNone);
   517 	return p;
   518 	}
   519 
   520 
   521 void TlsCleanupCheck(TAny*)
   522 	{
   523 	__UHEAP_MARKEND;
   524 	}
   525 
   526 void TlsCleanup1(TAny* a)
   527 	{
   528 	User::Free(a);
   529 	}
   530 
   531 TInt TlsCleanupThread1(TAny* a)
   532 	{
   533 	__UHEAP_MARK;
   534 	TInt n = (TInt)a;
   535 	TInt i;
   536 	TInt r = UserSvr::DllSetTls(0, NULL, TlsCleanupCheck);
   537 	if (r!=KErrNone)
   538 		return r;
   539 	for (i=0; i<n; ++i)
   540 		{
   541 		TAny* p = User::Alloc(64);
   542 		if (!p)
   543 			return KErrNoMemory;
   544 		r = UserSvr::DllSetTls(i+1, p, TlsCleanup1);
   545 		if (r!=KErrNone)
   546 			return r;
   547 		}
   548 	return KErrNone;
   549 	}
   550 
   551 TInt TlsCleanupThread2(TAny*)
   552 	{
   553 	__UHEAP_MARK;
   554 	TInt r = UserSvr::DllSetTls(0, NULL, TlsCleanupCheck);
   555 	if (r!=KErrNone)
   556 		return r;
   557 
   558 	CTest::New(256, 1, 2);
   559 	CTest::New(256, 2, 3);
   560 	CTest::New(256, 3, 0);
   561 	CTest::New(256, 6, 5);
   562 	CTest::New(256, 5, 4);
   563 	CTest::New(256, 4, 0);
   564 	CTest::New(256, 9, 8);
   565 	CTest::New(256, 8, 7);
   566 	CTest::New(256, 7, 9);
   567 	CTest::New(256, 10, 11);
   568 	CTest* p = CTest::New(256, 11, 12);
   569 	CTest::New(256, 12, 0);
   570 
   571 	delete p;
   572 
   573 	return KErrNone;
   574 	}
   575 
   576 void DisplayExitInfo(RThread t)
   577 	{
   578 	TInt exitType = t.ExitType();
   579 	TInt exitReason = t.ExitReason();
   580 	TBuf<32> exitCat = t.ExitCategory();
   581 	test.Printf(_L("Exit Info: %d,%d,%S\n"), exitType, exitReason, &exitCat);
   582 	}
   583 
   584 void DoTestCleanupHandler(TThreadFunction aFunc, TAny* aArg)
   585 	{
   586 	RThread t;
   587 	TInt r = t.Create(KNullDesC, aFunc, 0x1000, NULL, aArg);
   588 	test(r==KErrNone);
   589 	TRequestStatus s;
   590 	t.Logon(s);
   591 	t.Resume();
   592 	User::WaitForRequest(s);
   593 	DisplayExitInfo(t);
   594 	test(t.ExitType()==EExitKill);
   595 	test(t.ExitReason()==KErrNone);
   596 	test(s==KErrNone);
   597 	CLOSE_AND_WAIT(t);
   598 	}
   599 
   600 void TestCleanupHandler()
   601 	{
   602 	HEAP_MARK;
   603 
   604 	test.Start(_L("Test TLS cleanup handlers"));
   605 	DoTestCleanupHandler(TlsCleanupThread1, (TAny*)1 );
   606 	DoTestCleanupHandler(TlsCleanupThread1, (TAny*)2 );
   607 	DoTestCleanupHandler(TlsCleanupThread1, (TAny*)3 );
   608 	DoTestCleanupHandler(TlsCleanupThread2, NULL );
   609 
   610 	test.End();
   611 
   612 	HEAP_MARKEND;
   613 	}
   614 #endif
   615 
   616 void Benchmark()
   617 	{
   618 	const TInt KMaxEntries=(512*1024)/sizeof(STls); // limits TLS entries to 512K of storage
   619 	const TInt KMaxTime=500000; // limits time to half a second
   620 	
   621 	HEAP_MARK;
   622 
   623 	test.Start(_L("SetTls()"));//Note: much slower if done in reverse order
   624 	TInt count=0;
   625 	TTime start;
   626 	TTime finish;
   627 	TTime now;
   628 	start.HomeTime();
   629 	finish.HomeTime();
   630 	finish+=TTimeIntervalMicroSeconds(KMaxTime);
   631 	while (now.HomeTime(),now<finish && count<KMaxEntries)
   632 		{
   633 		test(UserSvr::DllSetTls(count,KCheckValue)==KErrNone);
   634 		count++;
   635 		}
   636 	TTimeIntervalMicroSeconds elapsed=now.MicroSecondsFrom(start);
   637 	TInt scount=(TInt)((count*500000.0)/elapsed.Int64()); // scale count up to 1/2 second
   638 	test.Printf(_L("     Done %d in 1/2 sec\n"),scount);
   639 	if (count==KMaxEntries)
   640 		test.Printf(_L("     (%d in %f sec)\n"),count,elapsed.Int64()/1000000.0);
   641 
   642 	TInt max=count;
   643 
   644 	test.Next(_L("Tls()"));
   645 	TInt i=0;
   646 	count=0;
   647 	finish.HomeTime();
   648 	finish+=TTimeIntervalMicroSeconds(KMaxTime);
   649 	while (now.HomeTime(),now<finish)
   650 		{
   651 		test(UserSvr::DllTls(i)==KCheckValue);
   652 		count++;
   653 		if (++i==max)
   654 			i=0;
   655 		}
   656 	elapsed=now.MicroSecondsFrom(start);
   657 	scount=(TInt)((count*500000.0)/elapsed.Int64()); // scale count up to 1/2 second
   658 	test.Printf(_L("     Done %d in 1/2 sec\n"),scount);
   659 
   660 	test.Next(_L("FreeTls()"));//Note: much faster if done in reverse order
   661 	count=0;
   662 	start.HomeTime();
   663 	finish.HomeTime();
   664 	finish+=TTimeIntervalMicroSeconds(KMaxTime);
   665 	while (now.HomeTime(),now<finish)
   666 		{
   667 		UserSvr::DllFreeTls(count++);
   668 		if (count==max)
   669 			break;
   670 		}
   671 	elapsed=now.MicroSecondsFrom(start);
   672 	scount=(TInt)((count*500000.0)/elapsed.Int64()); // scale count up to 1/2 second
   673 	test.Printf(_L("     Done %d in 1/2 sec\n"),scount);
   674 	if (count==max)
   675 		test.Printf(_L("     (%d in %f sec)\n"),count,elapsed.Int64()/1000000.0);
   676 	
   677 	while (count<max)
   678 		UserSvr::DllFreeTls(--max);
   679 
   680 	HEAP_MARKEND;
   681 	test.End();
   682 	}
   683 
   684 TInt E32Main()
   685 	{
   686 
   687 	test.Title();
   688 	test.Start(_L("Test"));
   689 
   690 	// Turn off lazy dll unloading
   691 	RLoader l;
   692 	test(l.Connect()==KErrNone);
   693 	test(l.CancelLazyDllUnload()==KErrNone);
   694 	l.Close();
   695 
   696 	Test();
   697 	test.Next(_L("Thread Test"));
   698 
   699 	HEAP_MARK;
   700 
   701 	RThread thread;
   702 	TInt r=thread.Create(_L("TLS test thread"),TestThread,KDefaultStackSize,0x1000,0x8000,NULL);
   703 	test(r==KErrNone);
   704 	TRequestStatus stat;
   705 	thread.Logon(stat);
   706 	thread.Resume();
   707 	User::WaitForRequest(stat);
   708 	test(stat==KErrNone);
   709 	test(thread.ExitCategory()==_L("Kill"));
   710 	test(thread.ExitType()==EExitKill); 
   711 	test(thread.ExitReason()==KErrNone); 
   712 	CLOSE_AND_WAIT(thread);
   713 	
   714 	HEAP_MARKEND;
   715 
   716 	if (TLSStoredOnUserHeap())
   717 		{
   718 		MainHeap = &User::Heap();
   719 		TestUserSideTls1();
   720 		TestUserSideTls2();
   721 		TestUserSideTls3();
   722 		TestUserSideTls4();		
   723 		}
   724 	
   725 	User::After(100);
   726 	
   727 	// On serial screen systems, WSERV may not yet have completed the disconnect
   728 	// from the second thread. This causes the kernel heap check to fail.
   729 	// So we wait here until WSERV can run.
   730 	test.Printf(_L("Wait for WSERV\n"));
   731 
   732 //	TestCleanupHandler();
   733 
   734 	test.Next(_L("Benchmark"));
   735 	Benchmark();
   736 	test.End();
   737 	return KErrNone;
   738 	}