--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/kerneltest/e32test/dll/t_tls.cpp Mon Oct 19 15:55:17 2009 +0100
@@ -0,0 +1,738 @@
+// Copyright (c) 1996-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of the License "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+// e32test\dll\t_tls.cpp
+// Overview:
+// Test and benchmark TLS (Thread Local Storage) functions
+// API Information:
+// UserSvr
+// Details:
+// - Use the UserSvr methods: DllTls, DllSetTls and DllFreeTls to test
+// the thread local storage. Verify the expected results. Verify that
+// the heap was not corrupted by any of the tests.
+// - In a separate thread, use the UserSvr methods: DllTls, DllSetTls and
+// DllFreeTls to test the thread local storage. Verify the expected results.
+// - Test the TLS cleanup handlers and verify results are as expected. Verify
+// that the heap was not corrupted by any of the tests.
+// - Benchmark how many DllSetTls, DllTls and DllFreeTls operations can be
+// performed in 1/2 second.
+// Platforms/Drives/Compatibility:
+// All.
+// Assumptions/Requirement/Pre-requisites:
+// Failures and causes:
+// Base Port information:
+// Tests and benchmarks Tls functions
+// 14/10/96 Modified scheme on Arm release
+// SetTls - 352 ~1300
+// Tls - 3510 ~1600
+// 15/10/96 Array scheme on Arm release
+// Set Tls - ~1900
+// Tls - ~2550
+//
+//
+
+#define __E32TEST_EXTENSION__
+
+#include <e32test.h>
+#include <e32svr.h>
+#include <f32dbg.h>
+#include <e32def.h>
+#include <e32def_private.h>
+#include "u32std.h"
+
+// Can't tell whether allocations will be on the kernel or user heap, so perform all heap check
+// operations on both
+#define HEAP_MARK __UHEAP_MARK; __KHEAP_MARK
+#define HEAP_MARKEND __UHEAP_MARKEND; __KHEAP_MARKEND
+#define HEAP_RESET __UHEAP_RESET; __KHEAP_RESET
+#define HEAP_CHECK(x) __UHEAP_CHECK(x); __KHEAP_CHECK(x)
+#define HEAP_FAILNEXT(x) __UHEAP_FAILNEXT(x); __KHEAP_FAILNEXT(x)
+
+TInt const KCheckHandle=67338721;
+TUint8* const KCheckValue=(TUint8*)8525124;
+
+LOCAL_D RTest test(_L("T_TLS"));
+
+_LIT(KTestDllName, "t_tlsdll");
+const TInt KTestDllOrdSet = 1;
+const TInt KTestDllOrdGet = 2;
+const TInt KTestDllOrdFree = 3;
+
+typedef TInt (*TTestDllSetFn)(TAny*);
+typedef TAny* (*TTestDllGetFn)();
+typedef void (*TTestDllFreeFn)();
+
+TInt TestDllSetTls(RLibrary aLib, TAny* aValue)
+ {
+ TTestDllSetFn f = (TTestDllSetFn)aLib.Lookup(KTestDllOrdSet);
+ return (*f)(aValue);
+ }
+
+TAny* TestDllGetTls(RLibrary aLib)
+ {
+ TTestDllGetFn f = (TTestDllGetFn)aLib.Lookup(KTestDllOrdGet);
+ return (*f)();
+ }
+
+void TestDllFreeTls(RLibrary aLib)
+ {
+ TTestDllFreeFn f = (TTestDllFreeFn)aLib.Lookup(KTestDllOrdFree);
+ (*f)();
+ }
+
+#define DISPLAY_PROGRESS test.Printf(_L("Line %d\n"), __LINE__)
+
+void Test()
+ {
+ test.Start(_L("Stuff without Setting"));
+
+ HEAP_MARK;
+
+ test(UserSvr::DllTls(KCheckHandle)==NULL);
+ UserSvr::DllFreeTls(KCheckHandle);
+ test(UserSvr::DllTls(KCheckHandle)==NULL);
+ test(UserSvr::DllTls(0)==NULL);
+ UserSvr::DllFreeTls(0);
+ test(UserSvr::DllTls(0)==NULL);
+
+ HEAP_CHECK(0);
+
+ test.Next(_L("Set"));
+ test(UserSvr::DllSetTls(KCheckHandle,KCheckValue)==KErrNone);
+ test.Next(_L("Get"));
+ test(UserSvr::DllTls(KCheckHandle)==KCheckValue);
+ test.Next(_L("Free"));
+ UserSvr::DllFreeTls(KCheckHandle);
+ test(UserSvr::DllTls(KCheckHandle)==NULL);
+
+ HEAP_CHECK(0);
+
+ test.Next(_L("Set lots"));
+ TInt i=0;
+ for(;i<1000;i+=3)
+ {
+ test(UserSvr::DllSetTls(KCheckHandle+i,KCheckValue-i)==KErrNone);
+ test(UserSvr::DllTls(KCheckHandle+i)==KCheckValue-i);
+ }
+ for(i=999;i>0;i-=3)
+ {
+ test(UserSvr::DllTls(KCheckHandle+i)==KCheckValue-i);
+ UserSvr::DllFreeTls(KCheckHandle+i);
+ test(UserSvr::DllTls(KCheckHandle+i)==NULL);
+ }
+ test(UserSvr::DllTls(KCheckHandle+i)==KCheckValue-i);
+ UserSvr::DllFreeTls(KCheckHandle+i);
+ test(UserSvr::DllTls(KCheckHandle+i)==NULL);
+
+ HEAP_MARKEND;
+
+
+ test.Next(_L("Test with DLL ID"));
+
+ HEAP_MARK;
+
+ test(UserSvr::DllTls(KCheckHandle, 1)==0);
+ test(UserSvr::DllTls(KCheckHandle, 2)==0);
+ DISPLAY_PROGRESS;
+#ifdef _DEBUG
+ HEAP_FAILNEXT(1);
+ DISPLAY_PROGRESS;
+ test(UserSvr::DllSetTls(KCheckHandle, 1, KCheckValue)==KErrNoMemory);
+#endif
+ test(UserSvr::DllSetTls(KCheckHandle, 1, KCheckValue)==KErrNone);
+ test(UserSvr::DllTls(KCheckHandle, 1)==KCheckValue);
+ test(UserSvr::DllTls(KCheckHandle, 2)==0);
+ DISPLAY_PROGRESS;
+ HEAP_FAILNEXT(1);
+ DISPLAY_PROGRESS;
+ test(UserSvr::DllSetTls(KCheckHandle, 3, KCheckValue)==KErrNone);
+
+#ifdef _DEBUG
+ RSemaphore s;
+ test(s.CreateLocal(0)==KErrNoMemory);
+#endif
+
+ HEAP_RESET;
+
+ test(UserSvr::DllTls(KCheckHandle, 1)==0);
+ test(UserSvr::DllTls(KCheckHandle, 2)==0);
+ test(UserSvr::DllTls(KCheckHandle, 3)==KCheckValue);
+ UserSvr::DllFreeTls(KCheckHandle);
+
+ DISPLAY_PROGRESS;
+ HEAP_MARKEND;
+ DISPLAY_PROGRESS;
+
+ test.Next(_L("Test reloading DLL"));
+
+ RLibrary l;
+ TInt r = l.Load(KTestDllName);
+ test(r==KErrNone);
+ for (i=0; i<2; ++i)
+ {
+ test.Printf(_L("i=%d\n"),i);
+ test(TestDllGetTls(l)==0);
+ test(TestDllSetTls(l, KCheckValue)==KErrNone);
+ test(TestDllGetTls(l)==KCheckValue);
+ if (i==0)
+ {
+ TestDllFreeTls(l);
+ test(TestDllGetTls(l)==0);
+ }
+ l.Close();
+ r = l.Load(KTestDllName);
+ test(r==KErrNone);
+ test(TestDllGetTls(l)==0);
+ TestDllFreeTls(l);
+ }
+ l.Close();
+
+ test.End();
+ }
+
+TInt TestThread(TAny*)
+ {
+ RTest test(_L("T_TLS Thread"));
+ test.Start(_L("Stuff without Setting"));
+ test(UserSvr::DllTls(KCheckHandle)==NULL);
+ UserSvr::DllFreeTls(KCheckHandle);
+ test(UserSvr::DllTls(KCheckHandle)==NULL);
+ test(UserSvr::DllTls(0)==NULL);
+ UserSvr::DllFreeTls(0);
+ test(UserSvr::DllTls(0)==NULL);
+ test.Next(_L("Set"));
+ test(UserSvr::DllSetTls(KCheckHandle,KCheckValue)==KErrNone);
+ test.Next(_L("Get"));
+ test(UserSvr::DllTls(KCheckHandle)==KCheckValue);
+ test.Next(_L("Free"));
+ UserSvr::DllFreeTls(KCheckHandle);
+ test(UserSvr::DllTls(KCheckHandle)==NULL);
+ test.Next(_L("Set lots"));
+ TInt i=0;
+ for(;i<1000;i+=3)
+ {
+ test(UserSvr::DllSetTls(KCheckHandle+i,KCheckValue-i)==KErrNone);
+ test(UserSvr::DllTls(KCheckHandle+i)==KCheckValue-i);
+ }
+ for(i=999;i>=0;i-=3)
+ {
+ test(UserSvr::DllTls(KCheckHandle+i)==KCheckValue-i);
+ UserSvr::DllFreeTls(KCheckHandle+i);
+ test(UserSvr::DllTls(KCheckHandle+i)==NULL);
+ }
+
+ test.Close();
+ return KErrNone;
+ }
+
+TInt HeapSize(RHeap* aHeap = NULL)
+ {
+ if (!aHeap)
+ aHeap = &User::Heap();
+ TInt size;
+ aHeap->AllocSize(size);
+ return size;
+ }
+
+TBool TLSStoredOnUserHeap()
+ {
+ TInt initCount = HeapSize();
+ TInt i;
+ const TInt KMax = 2;
+ for(i = 0 ; i < KMax ; ++i)
+ test(UserSvr::DllSetTls(KCheckHandle+i,KCheckValue-i) == KErrNone);
+ TInt finalCount = HeapSize();
+ for(i = 0 ; i < KMax ; ++i)
+ UserSvr::DllFreeTls(KCheckHandle+i);
+ return initCount != finalCount;
+ }
+
+class RDummyAllocator : public RAllocator
+ {
+public:
+ TInt AccessCount() { return iAccessCount; }
+ };
+
+RHeap* MainHeap = NULL;
+
+TInt HeapAccessCount(TAny* aHeap)
+ {
+ RDummyAllocator* heap = (RDummyAllocator*)aHeap;
+ return heap->AccessCount();
+ }
+
+TBool HeapExists(RHeap* aHeap)
+ {
+ RThread thread;
+ test_KErrNone(thread.Create(_L("HeapExistsThread"), HeapAccessCount, 0x1000, MainHeap, (TAny*)aHeap));
+ TRequestStatus status;
+ thread.Logon(status);
+ thread.Resume();
+ User::WaitForRequest(status);
+
+ TInt r;
+ if (thread.ExitType() == EExitKill)
+ {
+ r = thread.ExitReason();
+ test_NotNegative(r);
+ }
+ else
+ {
+ test_Equal(EExitPanic, thread.ExitType());
+ test_Equal(3, thread.ExitReason());
+ r = 0;
+ }
+ thread.Close();
+
+ return r != 0;
+ }
+
+TInt TestUserSideTls1Thread(TAny*)
+ {
+ // Ensure TLS uses initial heap
+ if (UserSvr::DllSetTls(KCheckHandle,KCheckValue) != KErrNone)
+ return __LINE__;
+ UserSvr::DllFreeTls(KCheckHandle);
+
+ RHeap* tlsHeap = &User::Heap();
+ TInt tlsInitSize = HeapSize(tlsHeap);
+
+ // Switch heap
+ RHeap* newHeap = User::ChunkHeap(NULL, 0x1000, 0x1000);
+ if (!newHeap)
+ return __LINE__;
+ TInt newInitSize = HeapSize(newHeap);
+ User::SwitchHeap(newHeap);
+ tlsHeap->Close();
+
+ // Allocate more TLS data
+ for(TInt i = 0 ; i < 100 ; ++i)
+ {
+ if (UserSvr::DllSetTls(KCheckHandle+i,KCheckValue-i) != KErrNone)
+ return __LINE__;
+ }
+
+ // Test TLS data was allocated on original heap
+ if (!(HeapSize(tlsHeap) > tlsInitSize))
+ return __LINE__;
+ if (HeapSize(newHeap) != newInitSize)
+ return __LINE__;
+
+ return KErrNone;
+ }
+
+void TestUserSideTls1()
+ {
+ test.Next(_L("Test user-side TLS behaviour when switching heaps"));
+
+ RThread thread;
+ test_KErrNone(thread.Create(_L("TestUserSideTls1Thread"), TestUserSideTls1Thread, 0x1000, 0x1000, 0x1000, 0));
+
+ TRequestStatus status;
+ thread.Logon(status);
+ thread.Resume();
+ User::WaitForRequest(status);
+
+ test_Equal(EExitKill, thread.ExitType());
+ test_Equal(KErrNone, thread.ExitReason());
+ thread.Close();
+ }
+
+TInt TestUserSideTls2Thread(TAny*)
+ {
+ // Allocate some TLS data
+ for(TInt i = 0 ; i < 100 ; ++i)
+ {
+ if (UserSvr::DllSetTls(KCheckHandle+i,KCheckValue-i) != KErrNone)
+ return __LINE__;
+ }
+
+ // Exit normally
+ return KErrNone;
+ }
+
+void TestUserSideTls2()
+ {
+ test.Next(_L("Test user-side TLS data cleanup on thread exit"));
+
+ RHeap* tlsHeap = User::ChunkHeap(NULL, 0x1000, 0x1000);
+ test_NotNull(tlsHeap);
+ TInt initSize = HeapSize(tlsHeap);
+
+ RThread thread;
+ test_KErrNone(thread.Create(_L("TestUserSideTls2Thread"), TestUserSideTls2Thread, 0x1000, tlsHeap, 0));
+ TThreadId id = thread.Id();
+
+ TRequestStatus status;
+ thread.Logon(status);
+ thread.Resume();
+ User::WaitForRequest(status);
+
+ test_Equal(EExitKill, thread.ExitType());
+ test_Equal(KErrNone, thread.ExitReason());
+ thread.Close();
+
+ // Check TLS data freed
+ test_Equal(initSize, HeapSize(tlsHeap));
+ tlsHeap->Close();
+
+ // Check heap no longer exists
+ test(!HeapExists(tlsHeap));
+
+ // Check thread no longer exists
+ RThread thread2;
+ test_Equal(KErrNotFound, thread2.Open(id));
+ }
+
+TInt TestUserSideTls3Thread(TAny*)
+ {
+ // Allocate some TLS data
+ for(TInt i = 0 ; i < 100 ; ++i)
+ {
+ if (UserSvr::DllSetTls(KCheckHandle+i,KCheckValue-i) != KErrNone)
+ return __LINE__;
+ }
+
+ // Panic
+ User::Panic(_L("Test"), 999);
+ return KErrNone;
+ }
+
+void TestUserSideTls3()
+ {
+ test.Next(_L("Test user-side TLS data cleanup on thread panic"));
+
+ RHeap* tlsHeap = User::ChunkHeap(NULL, 0x1000, 0x1000);
+ test_NotNull(tlsHeap);
+
+ RThread thread;
+ test_KErrNone(thread.Create(_L("TestUserSideTls3Thread"), TestUserSideTls3Thread, 0x1000, tlsHeap, 0));
+ TThreadId id = thread.Id();
+
+ TRequestStatus status;
+ thread.Logon(status);
+ thread.Resume();
+ User::WaitForRequest(status);
+
+ test_Equal(EExitPanic, thread.ExitType());
+ test_Equal(999, thread.ExitReason());
+
+ thread.Close();
+ tlsHeap->Close();
+
+ // Check heap no longer exists
+ test(!HeapExists(tlsHeap));
+
+ // Check thread no longer exists
+ RThread thread2;
+ test_Equal(KErrNotFound, thread2.Open(id));
+ }
+
+TInt TestUserSideTls4Thread(TAny*)
+ {
+ // Shouldn't ever run
+ return KErrGeneral;
+ }
+
+void TestUserSideTls4()
+ {
+ test.Next(_L("Test user-side TLS data cleanup on early thread kill"));
+
+ RHeap* tlsHeap = User::ChunkHeap(NULL, 0x1000, 0x1000);
+ test_NotNull(tlsHeap);
+
+ RThread thread;
+ test_KErrNone(thread.Create(_L("TestUserSideTls4Thread"), TestUserSideTls4Thread, 0x1000, tlsHeap, 0));
+ TThreadId id = thread.Id();
+
+ thread.Kill(101);
+
+ TRequestStatus status;
+ thread.Logon(status);
+ User::WaitForRequest(status);
+
+ test_Equal(EExitKill, thread.ExitType());
+ test_Equal(101, thread.ExitReason());
+
+ thread.Close();
+ tlsHeap->Close();
+
+ // Check heap no longer exists
+ test(!HeapExists(tlsHeap));
+
+ // Check thread no longer exists
+ RThread thread2;
+ test_Equal(KErrNotFound, thread2.Open(id));
+ }
+
+#if 0
+class CTest : public CBase
+ {
+public:
+ static CTest* New(TInt aSize, TInt aTls, TInt aLinkedTls);
+ virtual ~CTest();
+public:
+ TAny* iAlloc;
+ TInt iTls;
+ TInt iLinkedTls;
+ };
+
+void TlsCleanup2(TAny* a)
+ {
+ delete ((CTest*)a);
+ }
+
+CTest::~CTest()
+ {
+ RDebug::Print(_L("~CTest %d %d"), iTls, iLinkedTls);
+ User::Free(iAlloc);
+ UserSvr::DllFreeTls(iTls);
+ if (iLinkedTls)
+ {
+ CTest* p = (CTest*)UserSvr::DllTls(iLinkedTls);
+ if (p)
+ delete p;
+ }
+ }
+
+CTest* CTest::New(TInt aSize, TInt aTls, TInt aLinkedTls)
+ {
+ CTest* p = new CTest;
+ test(p!=NULL);
+ p->iTls = aTls;
+ p->iAlloc = User::Alloc(aSize);
+ test(p->iAlloc!=NULL);
+ p->iLinkedTls = aLinkedTls;
+ test(UserSvr::DllSetTls(aTls, p, TlsCleanup2)==KErrNone);
+ return p;
+ }
+
+
+void TlsCleanupCheck(TAny*)
+ {
+ __UHEAP_MARKEND;
+ }
+
+void TlsCleanup1(TAny* a)
+ {
+ User::Free(a);
+ }
+
+TInt TlsCleanupThread1(TAny* a)
+ {
+ __UHEAP_MARK;
+ TInt n = (TInt)a;
+ TInt i;
+ TInt r = UserSvr::DllSetTls(0, NULL, TlsCleanupCheck);
+ if (r!=KErrNone)
+ return r;
+ for (i=0; i<n; ++i)
+ {
+ TAny* p = User::Alloc(64);
+ if (!p)
+ return KErrNoMemory;
+ r = UserSvr::DllSetTls(i+1, p, TlsCleanup1);
+ if (r!=KErrNone)
+ return r;
+ }
+ return KErrNone;
+ }
+
+TInt TlsCleanupThread2(TAny*)
+ {
+ __UHEAP_MARK;
+ TInt r = UserSvr::DllSetTls(0, NULL, TlsCleanupCheck);
+ if (r!=KErrNone)
+ return r;
+
+ CTest::New(256, 1, 2);
+ CTest::New(256, 2, 3);
+ CTest::New(256, 3, 0);
+ CTest::New(256, 6, 5);
+ CTest::New(256, 5, 4);
+ CTest::New(256, 4, 0);
+ CTest::New(256, 9, 8);
+ CTest::New(256, 8, 7);
+ CTest::New(256, 7, 9);
+ CTest::New(256, 10, 11);
+ CTest* p = CTest::New(256, 11, 12);
+ CTest::New(256, 12, 0);
+
+ delete p;
+
+ return KErrNone;
+ }
+
+void DisplayExitInfo(RThread t)
+ {
+ TInt exitType = t.ExitType();
+ TInt exitReason = t.ExitReason();
+ TBuf<32> exitCat = t.ExitCategory();
+ test.Printf(_L("Exit Info: %d,%d,%S\n"), exitType, exitReason, &exitCat);
+ }
+
+void DoTestCleanupHandler(TThreadFunction aFunc, TAny* aArg)
+ {
+ RThread t;
+ TInt r = t.Create(KNullDesC, aFunc, 0x1000, NULL, aArg);
+ test(r==KErrNone);
+ TRequestStatus s;
+ t.Logon(s);
+ t.Resume();
+ User::WaitForRequest(s);
+ DisplayExitInfo(t);
+ test(t.ExitType()==EExitKill);
+ test(t.ExitReason()==KErrNone);
+ test(s==KErrNone);
+ CLOSE_AND_WAIT(t);
+ }
+
+void TestCleanupHandler()
+ {
+ HEAP_MARK;
+
+ test.Start(_L("Test TLS cleanup handlers"));
+ DoTestCleanupHandler(TlsCleanupThread1, (TAny*)1 );
+ DoTestCleanupHandler(TlsCleanupThread1, (TAny*)2 );
+ DoTestCleanupHandler(TlsCleanupThread1, (TAny*)3 );
+ DoTestCleanupHandler(TlsCleanupThread2, NULL );
+
+ test.End();
+
+ HEAP_MARKEND;
+ }
+#endif
+
+void Benchmark()
+ {
+ const TInt KMaxEntries=(512*1024)/sizeof(STls); // limits TLS entries to 512K of storage
+ const TInt KMaxTime=500000; // limits time to half a second
+
+ HEAP_MARK;
+
+ test.Start(_L("SetTls()"));//Note: much slower if done in reverse order
+ TInt count=0;
+ TTime start;
+ TTime finish;
+ TTime now;
+ start.HomeTime();
+ finish.HomeTime();
+ finish+=TTimeIntervalMicroSeconds(KMaxTime);
+ while (now.HomeTime(),now<finish && count<KMaxEntries)
+ {
+ test(UserSvr::DllSetTls(count,KCheckValue)==KErrNone);
+ count++;
+ }
+ TTimeIntervalMicroSeconds elapsed=now.MicroSecondsFrom(start);
+ TInt scount=(TInt)((count*500000.0)/elapsed.Int64()); // scale count up to 1/2 second
+ test.Printf(_L(" Done %d in 1/2 sec\n"),scount);
+ if (count==KMaxEntries)
+ test.Printf(_L(" (%d in %f sec)\n"),count,elapsed.Int64()/1000000.0);
+
+ TInt max=count;
+
+ test.Next(_L("Tls()"));
+ TInt i=0;
+ count=0;
+ finish.HomeTime();
+ finish+=TTimeIntervalMicroSeconds(KMaxTime);
+ while (now.HomeTime(),now<finish)
+ {
+ test(UserSvr::DllTls(i)==KCheckValue);
+ count++;
+ if (++i==max)
+ i=0;
+ }
+ elapsed=now.MicroSecondsFrom(start);
+ scount=(TInt)((count*500000.0)/elapsed.Int64()); // scale count up to 1/2 second
+ test.Printf(_L(" Done %d in 1/2 sec\n"),scount);
+
+ test.Next(_L("FreeTls()"));//Note: much faster if done in reverse order
+ count=0;
+ start.HomeTime();
+ finish.HomeTime();
+ finish+=TTimeIntervalMicroSeconds(KMaxTime);
+ while (now.HomeTime(),now<finish)
+ {
+ UserSvr::DllFreeTls(count++);
+ if (count==max)
+ break;
+ }
+ elapsed=now.MicroSecondsFrom(start);
+ scount=(TInt)((count*500000.0)/elapsed.Int64()); // scale count up to 1/2 second
+ test.Printf(_L(" Done %d in 1/2 sec\n"),scount);
+ if (count==max)
+ test.Printf(_L(" (%d in %f sec)\n"),count,elapsed.Int64()/1000000.0);
+
+ while (count<max)
+ UserSvr::DllFreeTls(--max);
+
+ HEAP_MARKEND;
+ test.End();
+ }
+
+TInt E32Main()
+ {
+
+ test.Title();
+ test.Start(_L("Test"));
+
+ // Turn off lazy dll unloading
+ RLoader l;
+ test(l.Connect()==KErrNone);
+ test(l.CancelLazyDllUnload()==KErrNone);
+ l.Close();
+
+ Test();
+ test.Next(_L("Thread Test"));
+
+ HEAP_MARK;
+
+ RThread thread;
+ TInt r=thread.Create(_L("TLS test thread"),TestThread,KDefaultStackSize,0x1000,0x8000,NULL);
+ test(r==KErrNone);
+ TRequestStatus stat;
+ thread.Logon(stat);
+ thread.Resume();
+ User::WaitForRequest(stat);
+ test(stat==KErrNone);
+ test(thread.ExitCategory()==_L("Kill"));
+ test(thread.ExitType()==EExitKill);
+ test(thread.ExitReason()==KErrNone);
+ CLOSE_AND_WAIT(thread);
+
+ HEAP_MARKEND;
+
+ if (TLSStoredOnUserHeap())
+ {
+ MainHeap = &User::Heap();
+ TestUserSideTls1();
+ TestUserSideTls2();
+ TestUserSideTls3();
+ TestUserSideTls4();
+ }
+
+ User::After(100);
+
+ // On serial screen systems, WSERV may not yet have completed the disconnect
+ // from the second thread. This causes the kernel heap check to fail.
+ // So we wait here until WSERV can run.
+ test.Printf(_L("Wait for WSERV\n"));
+
+// TestCleanupHandler();
+
+ test.Next(_L("Benchmark"));
+ Benchmark();
+ test.End();
+ return KErrNone;
+ }