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".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
14 // e32test\dll\t_tls.cpp
16 // Test and benchmark TLS (Thread Local Storage) functions
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:
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
38 // 15/10/96 Array scheme on Arm release
44 #define __E32TEST_EXTENSION__
50 #include <e32def_private.h>
53 // Can't tell whether allocations will be on the kernel or user heap, so perform all heap check
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)
61 TInt const KCheckHandle=67338721;
62 TUint8* const KCheckValue=(TUint8*)8525124;
64 LOCAL_D RTest test(_L("T_TLS"));
66 _LIT(KTestDllName, "t_tlsdll");
67 const TInt KTestDllOrdSet = 1;
68 const TInt KTestDllOrdGet = 2;
69 const TInt KTestDllOrdFree = 3;
71 typedef TInt (*TTestDllSetFn)(TAny*);
72 typedef TAny* (*TTestDllGetFn)();
73 typedef void (*TTestDllFreeFn)();
75 TInt TestDllSetTls(RLibrary aLib, TAny* aValue)
77 TTestDllSetFn f = (TTestDllSetFn)aLib.Lookup(KTestDllOrdSet);
81 TAny* TestDllGetTls(RLibrary aLib)
83 TTestDllGetFn f = (TTestDllGetFn)aLib.Lookup(KTestDllOrdGet);
87 void TestDllFreeTls(RLibrary aLib)
89 TTestDllFreeFn f = (TTestDllFreeFn)aLib.Lookup(KTestDllOrdFree);
93 #define DISPLAY_PROGRESS test.Printf(_L("Line %d\n"), __LINE__)
97 test.Start(_L("Stuff without Setting"));
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);
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);
120 test.Next(_L("Set lots"));
124 test(UserSvr::DllSetTls(KCheckHandle+i,KCheckValue-i)==KErrNone);
125 test(UserSvr::DllTls(KCheckHandle+i)==KCheckValue-i);
129 test(UserSvr::DllTls(KCheckHandle+i)==KCheckValue-i);
130 UserSvr::DllFreeTls(KCheckHandle+i);
131 test(UserSvr::DllTls(KCheckHandle+i)==NULL);
133 test(UserSvr::DllTls(KCheckHandle+i)==KCheckValue-i);
134 UserSvr::DllFreeTls(KCheckHandle+i);
135 test(UserSvr::DllTls(KCheckHandle+i)==NULL);
140 test.Next(_L("Test with DLL ID"));
144 test(UserSvr::DllTls(KCheckHandle, 1)==0);
145 test(UserSvr::DllTls(KCheckHandle, 2)==0);
150 test(UserSvr::DllSetTls(KCheckHandle, 1, KCheckValue)==KErrNoMemory);
152 test(UserSvr::DllSetTls(KCheckHandle, 1, KCheckValue)==KErrNone);
153 test(UserSvr::DllTls(KCheckHandle, 1)==KCheckValue);
154 test(UserSvr::DllTls(KCheckHandle, 2)==0);
158 test(UserSvr::DllSetTls(KCheckHandle, 3, KCheckValue)==KErrNone);
162 test(s.CreateLocal(0)==KErrNoMemory);
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);
176 test.Next(_L("Test reloading DLL"));
179 TInt r = l.Load(KTestDllName);
183 test.Printf(_L("i=%d\n"),i);
184 test(TestDllGetTls(l)==0);
185 test(TestDllSetTls(l, KCheckValue)==KErrNone);
186 test(TestDllGetTls(l)==KCheckValue);
190 test(TestDllGetTls(l)==0);
193 r = l.Load(KTestDllName);
195 test(TestDllGetTls(l)==0);
203 TInt TestThread(TAny*)
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"));
224 test(UserSvr::DllSetTls(KCheckHandle+i,KCheckValue-i)==KErrNone);
225 test(UserSvr::DllTls(KCheckHandle+i)==KCheckValue-i);
229 test(UserSvr::DllTls(KCheckHandle+i)==KCheckValue-i);
230 UserSvr::DllFreeTls(KCheckHandle+i);
231 test(UserSvr::DllTls(KCheckHandle+i)==NULL);
238 TInt HeapSize(RHeap* aHeap = NULL)
241 aHeap = &User::Heap();
243 aHeap->AllocSize(size);
247 TBool TLSStoredOnUserHeap()
249 TInt initCount = HeapSize();
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;
260 class RDummyAllocator : public RAllocator
263 TInt AccessCount() { return iAccessCount; }
266 RHeap* MainHeap = NULL;
268 TInt HeapAccessCount(TAny* aHeap)
270 RDummyAllocator* heap = (RDummyAllocator*)aHeap;
271 return heap->AccessCount();
274 TBool HeapExists(RHeap* aHeap)
277 test_KErrNone(thread.Create(_L("HeapExistsThread"), HeapAccessCount, 0x1000, MainHeap, (TAny*)aHeap));
278 TRequestStatus status;
279 thread.Logon(status);
281 User::WaitForRequest(status);
284 if (thread.ExitType() == EExitKill)
286 r = thread.ExitReason();
291 test_Equal(EExitPanic, thread.ExitType());
292 test_Equal(3, thread.ExitReason());
300 TInt TestUserSideTls1Thread(TAny*)
302 // Ensure TLS uses initial heap
303 if (UserSvr::DllSetTls(KCheckHandle,KCheckValue) != KErrNone)
305 UserSvr::DllFreeTls(KCheckHandle);
307 RHeap* tlsHeap = &User::Heap();
308 TInt tlsInitSize = HeapSize(tlsHeap);
311 RHeap* newHeap = User::ChunkHeap(NULL, 0x1000, 0x1000);
314 TInt newInitSize = HeapSize(newHeap);
315 User::SwitchHeap(newHeap);
318 // Allocate more TLS data
319 for(TInt i = 0 ; i < 100 ; ++i)
321 if (UserSvr::DllSetTls(KCheckHandle+i,KCheckValue-i) != KErrNone)
325 // Test TLS data was allocated on original heap
326 if (!(HeapSize(tlsHeap) > tlsInitSize))
328 if (HeapSize(newHeap) != newInitSize)
334 void TestUserSideTls1()
336 test.Next(_L("Test user-side TLS behaviour when switching heaps"));
339 test_KErrNone(thread.Create(_L("TestUserSideTls1Thread"), TestUserSideTls1Thread, 0x1000, 0x1000, 0x1000, 0));
341 TRequestStatus status;
342 thread.Logon(status);
344 User::WaitForRequest(status);
346 test_Equal(EExitKill, thread.ExitType());
347 test_Equal(KErrNone, thread.ExitReason());
351 TInt TestUserSideTls2Thread(TAny*)
353 // Allocate some TLS data
354 for(TInt i = 0 ; i < 100 ; ++i)
356 if (UserSvr::DllSetTls(KCheckHandle+i,KCheckValue-i) != KErrNone)
364 void TestUserSideTls2()
366 test.Next(_L("Test user-side TLS data cleanup on thread exit"));
368 RHeap* tlsHeap = User::ChunkHeap(NULL, 0x1000, 0x1000);
369 test_NotNull(tlsHeap);
370 TInt initSize = HeapSize(tlsHeap);
373 test_KErrNone(thread.Create(_L("TestUserSideTls2Thread"), TestUserSideTls2Thread, 0x1000, tlsHeap, 0));
374 TThreadId id = thread.Id();
376 TRequestStatus status;
377 thread.Logon(status);
379 User::WaitForRequest(status);
381 test_Equal(EExitKill, thread.ExitType());
382 test_Equal(KErrNone, thread.ExitReason());
385 // Check TLS data freed
386 test_Equal(initSize, HeapSize(tlsHeap));
389 // Check heap no longer exists
390 test(!HeapExists(tlsHeap));
392 // Check thread no longer exists
394 test_Equal(KErrNotFound, thread2.Open(id));
397 TInt TestUserSideTls3Thread(TAny*)
399 // Allocate some TLS data
400 for(TInt i = 0 ; i < 100 ; ++i)
402 if (UserSvr::DllSetTls(KCheckHandle+i,KCheckValue-i) != KErrNone)
407 User::Panic(_L("Test"), 999);
411 void TestUserSideTls3()
413 test.Next(_L("Test user-side TLS data cleanup on thread panic"));
415 RHeap* tlsHeap = User::ChunkHeap(NULL, 0x1000, 0x1000);
416 test_NotNull(tlsHeap);
419 test_KErrNone(thread.Create(_L("TestUserSideTls3Thread"), TestUserSideTls3Thread, 0x1000, tlsHeap, 0));
420 TThreadId id = thread.Id();
422 TRequestStatus status;
423 thread.Logon(status);
425 User::WaitForRequest(status);
427 test_Equal(EExitPanic, thread.ExitType());
428 test_Equal(999, thread.ExitReason());
433 // Check heap no longer exists
434 test(!HeapExists(tlsHeap));
436 // Check thread no longer exists
438 test_Equal(KErrNotFound, thread2.Open(id));
441 TInt TestUserSideTls4Thread(TAny*)
443 // Shouldn't ever run
447 void TestUserSideTls4()
449 test.Next(_L("Test user-side TLS data cleanup on early thread kill"));
451 RHeap* tlsHeap = User::ChunkHeap(NULL, 0x1000, 0x1000);
452 test_NotNull(tlsHeap);
455 test_KErrNone(thread.Create(_L("TestUserSideTls4Thread"), TestUserSideTls4Thread, 0x1000, tlsHeap, 0));
456 TThreadId id = thread.Id();
460 TRequestStatus status;
461 thread.Logon(status);
462 User::WaitForRequest(status);
464 test_Equal(EExitKill, thread.ExitType());
465 test_Equal(101, thread.ExitReason());
470 // Check heap no longer exists
471 test(!HeapExists(tlsHeap));
473 // Check thread no longer exists
475 test_Equal(KErrNotFound, thread2.Open(id));
479 class CTest : public CBase
482 static CTest* New(TInt aSize, TInt aTls, TInt aLinkedTls);
490 void TlsCleanup2(TAny* a)
497 RDebug::Print(_L("~CTest %d %d"), iTls, iLinkedTls);
499 UserSvr::DllFreeTls(iTls);
502 CTest* p = (CTest*)UserSvr::DllTls(iLinkedTls);
508 CTest* CTest::New(TInt aSize, TInt aTls, TInt aLinkedTls)
510 CTest* p = new CTest;
513 p->iAlloc = User::Alloc(aSize);
514 test(p->iAlloc!=NULL);
515 p->iLinkedTls = aLinkedTls;
516 test(UserSvr::DllSetTls(aTls, p, TlsCleanup2)==KErrNone);
521 void TlsCleanupCheck(TAny*)
526 void TlsCleanup1(TAny* a)
531 TInt TlsCleanupThread1(TAny* a)
536 TInt r = UserSvr::DllSetTls(0, NULL, TlsCleanupCheck);
541 TAny* p = User::Alloc(64);
544 r = UserSvr::DllSetTls(i+1, p, TlsCleanup1);
551 TInt TlsCleanupThread2(TAny*)
554 TInt r = UserSvr::DllSetTls(0, NULL, TlsCleanupCheck);
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);
576 void DisplayExitInfo(RThread t)
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);
584 void DoTestCleanupHandler(TThreadFunction aFunc, TAny* aArg)
587 TInt r = t.Create(KNullDesC, aFunc, 0x1000, NULL, aArg);
592 User::WaitForRequest(s);
594 test(t.ExitType()==EExitKill);
595 test(t.ExitReason()==KErrNone);
600 void TestCleanupHandler()
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 );
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
623 test.Start(_L("SetTls()"));//Note: much slower if done in reverse order
630 finish+=TTimeIntervalMicroSeconds(KMaxTime);
631 while (now.HomeTime(),now<finish && count<KMaxEntries)
633 test(UserSvr::DllSetTls(count,KCheckValue)==KErrNone);
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);
644 test.Next(_L("Tls()"));
648 finish+=TTimeIntervalMicroSeconds(KMaxTime);
649 while (now.HomeTime(),now<finish)
651 test(UserSvr::DllTls(i)==KCheckValue);
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);
660 test.Next(_L("FreeTls()"));//Note: much faster if done in reverse order
664 finish+=TTimeIntervalMicroSeconds(KMaxTime);
665 while (now.HomeTime(),now<finish)
667 UserSvr::DllFreeTls(count++);
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);
675 test.Printf(_L(" (%d in %f sec)\n"),count,elapsed.Int64()/1000000.0);
678 UserSvr::DllFreeTls(--max);
688 test.Start(_L("Test"));
690 // Turn off lazy dll unloading
692 test(l.Connect()==KErrNone);
693 test(l.CancelLazyDllUnload()==KErrNone);
697 test.Next(_L("Thread Test"));
702 TInt r=thread.Create(_L("TLS test thread"),TestThread,KDefaultStackSize,0x1000,0x8000,NULL);
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);
716 if (TLSStoredOnUserHeap())
718 MainHeap = &User::Heap();
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"));
732 // TestCleanupHandler();
734 test.Next(_L("Benchmark"));