First public contribution.
1 // Copyright (c) 2004-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\cppexceptions\t_unmap.cpp
19 #include <e32std_private.h>
21 #include <e32base_private.h>
26 #include <e32def_private.h>
30 _LIT(KTestName, "t_unmap");
31 _LIT(KTestThreadName, "t_unmap test thread");
32 _LIT(KNopThreadName, "nop [DLL unload checking] thread");
33 _LIT(KTUnmapPanic, "t_unmap");
34 _LIT(KThread, "Thread");
36 _LIT(KUnhandledExcCategory, "KERN-EXEC");
37 const TInt KUnhandledExcReason = 3;
41 EPanickingThread = 123456789
44 RTest test(KTestName);
46 RTest testThreadA(KTestThreadName);
47 RTest testThreadB(KTestThreadName);
48 RTest testThreadC(KTestThreadName);
49 RTest testThreadD(KTestThreadName);
50 RTest testThreadE(KTestThreadName);
51 RTest testThreadF(KTestThreadName);
52 RTest testThreadG(KTestThreadName);
53 RTest testThreadH(KTestThreadName);
55 RTest testThreadI(KTestThreadName);
56 RTest testThreadJ(KTestThreadName);
57 RTest testThreadK(KTestThreadName);
59 RSemaphore Thread1Semaphore;
60 RSemaphore Thread2Semaphore;
62 RSemaphore FinishedOpSemaphore;
64 RLibrary ThreadALibraryHandle;
65 RLibrary ThreadBLibraryHandle;
66 RLibrary ThreadCLibraryHandle;
67 RLibrary ThreadDLibraryHandle;
68 RLibrary ThreadELibraryHandle;
69 RLibrary ThreadFLibraryHandle;
70 RLibrary ThreadGLibraryHandle;
71 RLibrary ThreadHLibraryHandle;
72 RLibrary ThreadILibraryHandle;
73 RLibrary ThreadJLibraryHandle;
74 RLibrary ThreadKLibraryHandle;
76 TBool CheckKernelHeap;
92 TInt DoThreadAL(TAny*);
93 TInt DoThreadBL(TAny*);
94 TInt DoThreadCL(TAny*);
95 TInt DoThreadDL(TAny*);
96 TInt DoThreadEL(TAny*);
97 TInt DoThreadFL(TAny*);
98 TInt DoThreadGL(TAny*);
99 TInt DoThreadHL(TAny*);
100 TInt DoThreadIL(TAny*);
101 TInt DoThreadJL(TAny*);
102 TInt DoThreadKL(TAny*);
104 struct STestThreadInfo
106 TThreadFunction iThreadFn;
112 static STestThreadInfo const TheThreadArray[] =
114 { &ThreadA, EExitPanic, 0, 0 },
115 { &ThreadB, EExitKill, 0, 0 },
116 { &ThreadC, EExitPanic, 1, 0 },
117 { &ThreadD, EExitPanic, 2, 0 },
118 { &ThreadE, EExitKill, 2, 2 },
119 { &ThreadF, EExitPanic, 2, 1 },
120 { &ThreadG, EExitKill, 3, 1 },
121 { &ThreadH, EExitKill, 1, 1 },
122 { &ThreadI, EExitKill, 1, 3 },
123 { &ThreadJ, EExitPanic, 1, 2 },
124 { &ThreadK, EExitPanic, 1, 1 }
127 struct SNopThreadInfo
129 TLibraryFunction iFunc;
131 TInt32 iOriginalContents;
135 static SNopThreadInfo NopThreadInfo;
137 static const TInt TheThreadCount = (sizeof(TheThreadArray) / sizeof(STestThreadInfo));
139 static const TInt KHeapSize = 0x2000;
143 // Turn off lazy dll unloading
145 test(l.Connect()==KErrNone);
146 test(l.CancelLazyDllUnload()==KErrNone);
149 test.Start(_L("Check code seg unmapping over User::Leave()/C++ exceptions."));
153 CTrapCleanup* cleanup = CTrapCleanup::New();
154 TInt r = KErrNoMemory;
157 TRAP(r, TestThreads());
159 test.Printf(_L("Returned %d, expected %d\n"), r, KErrNone);
172 TInt NopThread(TAny*)
175 TInt32 current = *(TInt*)NopThreadInfo.iFunc;
176 if (current != NopThreadInfo.iOriginalContents)
177 current = *(TInt32*)NULL; // cause panic
179 TInt r = NopThreadInfo.iFunc();
186 void TestLoadWhileUnload();
192 test.Next(_L("Create synchronisation semaphores"));
193 TInt r = Thread1Semaphore.CreateLocal(0);
196 r = Thread2Semaphore.CreateLocal(0);
199 r = FinishedOpSemaphore.CreateLocal(0);
202 // Turn off JIT [threads can panic to test exit cleanup]
203 TBool jit = User::JustInTime();
204 User::SetJustInTime(EFalse);
208 // Do kernel heap checking
209 CheckKernelHeap = ETrue;
211 test.Next(_L("Run threads on their own"));
212 for (count = 0; count < TheThreadCount ; ++count)
214 // Set up descriptor for thread's name
215 TBuf16<7> name(KThread);
216 name.Append('A' + count);
220 TInt r = thread.Create(
222 TheThreadArray[count].iThreadFn,
230 // Set up notification of thread's death
231 TRequestStatus status;
232 thread.Logon(status);
236 r = library.Load(KLeavingDll);
239 // Remember the address of the NOP function
240 NopThreadInfo.iFunc = library.Lookup(2);
242 NopThreadInfo.iOriginalContents = *(TInt32*)NopThreadInfo.iFunc;
248 // Wait until it has an open handle to the library
249 FinishedOpSemaphore.Wait();
251 // Close our handle to the library
254 // Check library is still loaded
255 for (count2 = 0; count2 < TheThreadArray[count].iMappedSignals; ++count2)
257 // Tell it we're ready to go
258 Thread1Semaphore.Signal();
260 // Wait for it to finish next step
261 FinishedOpSemaphore.Wait();
263 // Create NOP thread to call NOP function to check DLL still loaded
265 r = nopThread.Create(
275 // Set up notification of thread's death
276 TRequestStatus nopStatus;
277 nopThread.Logon(nopStatus);
282 // Wait for it to die
283 User::WaitForRequest(nopStatus);
285 // Check the exit info
286 test(nopThread.ExitType() == EExitKill);
287 test(nopThread.ExitReason() == KErrNone);
289 // Close thread handle
290 CLOSE_AND_WAIT(nopThread);
293 // Check User::Leave() library unloading behaviour
294 for (count2 = 0; count2 < TheThreadArray[count].iLeaveSignals; ++count2)
296 // Tell it we're ready to go
297 Thread1Semaphore.Signal();
299 // Wait for it to finish next step
300 FinishedOpSemaphore.Wait();
302 // Create NOP thread to call NOP function to check whether DLL is still loaded
304 r = nopThread.Create(
314 // Set up notification of thread's death
315 TRequestStatus nopStatus;
316 nopThread.Logon(nopStatus);
321 // Wait for it to die
322 User::WaitForRequest(nopStatus);
324 // Check the exit info
325 #ifdef __LEAVE_EQUALS_THROW__
326 test(nopThread.ExitType() == EExitKill);
327 test(nopThread.ExitReason() == KErrGeneral);
328 #else //!__LEAVE_EQUALS_THROW__
329 test(nopThread.ExitType() == EExitPanic);
330 test(nopThread.ExitCategory() == KUnhandledExcCategory);
331 test(nopThread.ExitReason() == KUnhandledExcReason);
332 #endif //__LEAVE_EQUALS_THROW__
334 // Close thread handle
335 CLOSE_AND_WAIT(nopThread);
338 // Tell it we're ready to go again
339 Thread1Semaphore.Signal();
341 if (TheThreadArray[count].iExitType == EExitKill)
343 // Wait for it to finish last step
344 FinishedOpSemaphore.Wait();
346 User::After(100000); // let supervisor run
348 // Create NOP thread to call NOP function to check DLL is unloaded
350 r = nopThread.Create(
360 // Set up notification of thread's death
361 TRequestStatus nopStatus;
362 nopThread.Logon(nopStatus);
367 // Wait for it to die
368 User::WaitForRequest(nopStatus);
370 // Check the exit info
371 test(nopThread.ExitType() == EExitPanic);
372 test(nopThread.ExitCategory() == KUnhandledExcCategory);
373 test(nopThread.ExitReason() == KUnhandledExcReason);
375 // Close thread handle
376 CLOSE_AND_WAIT(nopThread);
378 // Let main thread die now
379 Thread1Semaphore.Signal();
382 // Wait for thread to exit
383 User::WaitForRequest(status);
385 // Check the exit type & category
386 test(thread.ExitType() == TheThreadArray[count].iExitType);
388 // Check category & reason, if appropriate
389 if (thread.ExitType() == EExitPanic)
391 test(thread.ExitCategory() == KTUnmapPanic);
392 test(thread.ExitReason() == EPanickingThread);
395 // Close thread handle
399 // Turn off kernel heap checking
400 CheckKernelHeap = EFalse;
402 test.Next(_L("Run threads against each other"));
403 for (count = 0; count < TheThreadCount ; ++count)
405 for (count2 = 0; count2 < TheThreadCount ; ++count2)
407 // Can't run the same threads back to back
413 // Set up descriptors for threads' names
414 _LIT(KFirstThread, " - 1");
415 _LIT(KSecondThread, " - 2");
416 TBuf16<11> name(KThread);
417 TBuf16<11> name2(KThread);
418 name.Append('A' + count);
419 name.Append(KFirstThread);
420 name2.Append('A' + count2);
421 name2.Append(KSecondThread);
425 TInt r = thread.Create(
427 TheThreadArray[count].iThreadFn,
438 TheThreadArray[count2].iThreadFn,
446 // Set up notification of threads' death
447 TRequestStatus status, status2;
448 thread.Logon(status);
449 thread2.Logon(status2);
454 // Wait until just before it's closed the library handle
455 FinishedOpSemaphore.Wait();
460 // Wait until just before it's closed the library handle
461 FinishedOpSemaphore.Wait();
463 // Tell first thread we're ready to go
464 TInt signals = TheThreadArray[count].iMappedSignals +
465 TheThreadArray[count].iLeaveSignals +
466 ((TheThreadArray[count].iExitType == EExitPanic) ? 1 : 2);
467 Thread1Semaphore.Signal(signals);
469 // Eat up 'FinishedOp' signals
471 FinishedOpSemaphore.Wait();
473 // Wait for it to finish
474 User::WaitForRequest(status);
476 // Check the exit type & category of the first thread
477 test(thread.ExitType() == TheThreadArray[count].iExitType);
479 // Check category & reason of the first thread, if appropriate
480 if (thread.ExitType() == EExitPanic)
482 test(thread.ExitCategory() == KTUnmapPanic);
483 test(thread.ExitReason() == EPanickingThread);
486 // Tell second thread we're ready to go
487 signals = TheThreadArray[count2].iMappedSignals +
488 TheThreadArray[count2].iLeaveSignals +
489 ((TheThreadArray[count2].iExitType == EExitPanic) ? 1 : 2);
490 Thread2Semaphore.Signal(signals);
492 // Eat up 'FinishedOp' signals
494 FinishedOpSemaphore.Wait();
496 // Wait for it to finish
497 User::WaitForRequest(status2);
499 // Check the exit type & category of the second thread
500 test(thread2.ExitType() == TheThreadArray[count2].iExitType);
502 // Check category & reason of the second thread, if appropriate
503 if (thread2.ExitType() == EExitPanic)
505 test(thread2.ExitCategory() == KTUnmapPanic);
506 test(thread2.ExitReason() == EPanickingThread);
509 // Close thread handles
510 CLOSE_AND_WAIT(thread);
511 CLOSE_AND_WAIT(thread2);
515 // Test two processes at once to deal with race conditions
516 test.Printf(_L("Create two processes at once to map the same library\n"));
517 RSemaphore procSem1, procSem2;
518 test(procSem1.CreateGlobal(KNullDesC, 0)==KErrNone);
519 test(procSem2.CreateGlobal(KNullDesC, 0)==KErrNone);
520 RProcess proc1, proc2;
521 test(proc1.Create(_L("T_UNMAP2"), KNullDesC)==KErrNone);
522 test(proc2.Create(_L("T_UNMAP2"), KNullDesC)==KErrNone);
523 test(proc1.SetParameter(1, procSem1)==KErrNone);
524 test(proc1.SetParameter(2, procSem2)==KErrNone);
525 test(proc2.SetParameter(1, procSem2)==KErrNone);
526 test(proc2.SetParameter(2, procSem1)==KErrNone);
527 TRequestStatus proc1stat, proc2stat;
528 proc1.Logon(proc1stat);
529 proc2.Logon(proc2stat);
530 test.Printf(_L("Start processes\n"));
533 test.Printf(_L("Wait for them to exit\n"));
534 User::WaitForRequest(proc1stat);
535 test(proc1.ExitType() == EExitKill);
536 test(proc1.ExitReason() == KErrNone);
537 User::WaitForRequest(proc2stat);
538 test(proc2.ExitType() == EExitKill);
539 test(proc2.ExitReason()==KErrNone);
540 CLOSE_AND_WAIT(proc1);
541 CLOSE_AND_WAIT(proc2);
545 // Test load while unload
546 TestLoadWhileUnload();
548 // Restore JIT setting
549 User::SetJustInTime(jit);
551 // Close synchronisation semaphores
552 Thread1Semaphore.Close();
553 Thread2Semaphore.Close();
554 FinishedOpSemaphore.Close();
559 // Test loading a library while another thread is unloading it in an unwind
560 void TestLoadWhileUnload()
562 // Set up descriptor for thread's name
563 TBuf16<7> name(KThread);
568 TInt r = thread.Create(
578 // Set up notification of thread's death
579 TRequestStatus status;
580 thread.Logon(status);
585 // Wait until it has an open handle to the library
586 FinishedOpSemaphore.Wait();
588 // Tell it to go ahead and leave
589 Thread1Semaphore.Signal();
591 // Wait for it to start unwinding
592 FinishedOpSemaphore.Wait();
594 // Tell it to go ahead and close the library handle
595 Thread1Semaphore.Signal();
597 // Wait for it to have closed the library
598 FinishedOpSemaphore.Wait();
602 r = library.Load(KLeavingDll);
605 // Remember the address of the NOP function
606 NopThreadInfo.iFunc = library.Lookup(2);
608 NopThreadInfo.iOriginalContents = *(TInt32*)NopThreadInfo.iFunc;
611 User::After(100000); // let supervisor run
613 // Check User::Leave() library unloading behaviour
614 for (TInt i = 0; i < 2; ++i)
616 // Create NOP thread to call NOP function to check whether DLL is still loaded
618 r = nopThread.Create(
628 // Set up notification of thread's death
629 TRequestStatus nopStatus;
630 nopThread.Logon(nopStatus);
635 // Wait for it to die
636 User::WaitForRequest(nopStatus);
638 // Check the exit info
639 test(nopThread.ExitType() == EExitKill);
640 test(nopThread.ExitReason() == KErrNone);
642 // Close thread handle
643 CLOSE_AND_WAIT(nopThread);
645 // Tell it we're ready to go
646 Thread1Semaphore.Signal();
648 // Wait for it to finish next step
650 FinishedOpSemaphore.Wait();
653 // Wait for thread to exit
654 User::WaitForRequest(status);
656 // Check the exit type & category
657 test(thread.ExitType() == EExitKill);
659 // Close thread handle
660 CLOSE_AND_WAIT(thread);
662 // Close our handle to the library
665 // Create NOP thread to call NOP function to check DLL is unloaded
667 r = nopThread.Create(
677 // Set up notification of thread's death
678 TRequestStatus nopStatus;
679 nopThread.Logon(nopStatus);
684 // Wait for it to die
685 User::WaitForRequest(nopStatus);
687 // Check the exit info
688 test(nopThread.ExitType() == EExitPanic);
689 test(nopThread.ExitCategory() == KUnhandledExcCategory);
690 test(nopThread.ExitReason() == KUnhandledExcReason);
692 // Close thread handle
693 CLOSE_AND_WAIT(nopThread);
697 // Cleanup operations
700 void Checkpoint(TAny* aSemaphore)
704 FinishedOpSemaphore.Signal();
705 static_cast<RSemaphore*>(aSemaphore)->Wait();
709 void DieDieDie(TAny* aSemaphore)
711 // Check-point before panicking
712 Checkpoint(aSemaphore);
714 User::Panic(KTUnmapPanic, EPanickingThread);
717 void PauseLeaving(TAny* aSemaphore)
719 Checkpoint(aSemaphore);
722 void TrapLeave(TAny* aSemaphore)
726 CleanupStack::PushL(TCleanupItem(&PauseLeaving, aSemaphore));
728 Checkpoint(aSemaphore);
730 User::Leave(KErrGeneral);
732 CleanupStack::Pop(); // pause op
736 Checkpoint(aSemaphore);
739 void TrapLeaveAndDie(TAny* aSemaphore)
743 CleanupStack::PushL(TCleanupItem(&DieDieDie, aSemaphore));
745 Checkpoint(aSemaphore);
747 User::Leave(KErrGeneral);
749 CleanupStack::Pop(); //DieDieDie op
754 void TrapLeaveAndClose_ThreadE(TAny* aSemaphore)
756 CleanupStack::Pop(&ThreadELibraryHandle);
760 CleanupStack::PushL(TCleanupItem(&PauseLeaving, aSemaphore));
762 CleanupClosePushL(ThreadELibraryHandle);
764 CleanupStack::PushL(TCleanupItem(&PauseLeaving, aSemaphore));
766 Checkpoint(aSemaphore);
768 User::Leave(KErrGeneral);
770 CleanupStack::Pop(); //pre-close pause op
772 CleanupStack::Pop(&ThreadELibraryHandle);
774 CleanupStack::Pop(); //post-close pause op
778 Checkpoint(aSemaphore);
781 void TrapLeaveCloseAndDie_ThreadF(TAny* aSemaphore)
783 CleanupStack::Pop(&ThreadFLibraryHandle);
787 CleanupStack::PushL(TCleanupItem(&DieDieDie, aSemaphore));
789 CleanupClosePushL(ThreadFLibraryHandle);
791 CleanupStack::PushL(TCleanupItem(&PauseLeaving, aSemaphore));
793 Checkpoint(aSemaphore);
795 User::Leave(KErrGeneral);
797 CleanupStack::Pop(); //pre-close pause op
799 CleanupStack::Pop(&ThreadFLibraryHandle);
801 CleanupStack::Pop(); //DieDieDie op
808 Here's a list of interesting things that could happen to a thread which
809 has an open handle to library on cleanup stack:
812 b) Closes handle normally
813 c) Leaves and panicks before closing handle
814 d) Recursively leaves and panicks before closing handle
815 e) Recursively leaves and closes handle in recursive leave
816 f) Recursively leaves and panicks in recursive leave, after closing handle
817 g) Recursively leaves and returns to first leave without closing handle; first leave closes handle
818 h) Leaves and closes handle
819 i) Leaves and closes handle, then recursively leaves
820 j) Leaves and closes handle, then recursively leaves and panicks in recursive leave
821 k) Leaves and panicks after closing handle, but before leave completes
823 Other ideas yet to be done:
825 l) TRAPs a leave, then closes handle
826 m) TRAPs a recusive leave, then closes handle
828 The thread functions below correspond to these.
830 These are the ways a library's code seg can be held open by a process:
832 a) Open handle to the library
833 b) Open reference to code seg because the last reference to the library was closed during a leave and
834 the process has not gone leave-idle
836 We then test both these by testing at extra points during the sequences above that
837 the code segments are either mapped or unmapped, as appropriate.
840 TInt ThreadA(TAny* aSemaphore)
848 new (&testThreadA) RTest(KNullDesC);
849 testThreadA.Start(KNullDesC);
851 CTrapCleanup* cleanup = CTrapCleanup::New();
852 TInt r = KErrNoMemory;
855 TRAP(r, DoThreadAL(aSemaphore));
857 // Check-point after closing the library handle
858 Checkpoint(aSemaphore);
860 testThreadA.Printf(_L("A: Returned %d, expected %d\n"), r, KErrNone);
861 testThreadA(r == KErrNone);
871 User::After(100000); // let supervisor run
879 TInt DoThreadAL(TAny* aSemaphore)
881 testThreadA.Printf(_L("A: Loading DLL.\n"));
882 User::LeaveIfError(ThreadALibraryHandle.Load(KLeavingDll));
884 testThreadA.Printf(_L("A: Pushing cleanup item to kill this thread!\n"));
885 CleanupStack::PushL(TCleanupItem(&DieDieDie, aSemaphore));
887 testThreadA.Printf(_L("A: Cleaning up Panic operation.\n"));
888 CleanupStack::PopAndDestroy(); // DieDieDie op
890 ThreadALibraryHandle.Close();
895 TInt ThreadB(TAny* aSemaphore)
903 new (&testThreadB) RTest(KNullDesC);
904 testThreadB.Start(KNullDesC);
906 CTrapCleanup* cleanup = CTrapCleanup::New();
907 TInt r = KErrNoMemory;
910 TRAP(r, DoThreadBL(aSemaphore));
912 // Check-point after closing the library handle
913 Checkpoint(aSemaphore);
915 testThreadB.Printf(_L("B: Returned %d, expected %d\n"), r, KErrNone);
916 testThreadB(r == KErrNone);
926 User::After(100000); // let supervisor run
934 TInt DoThreadBL(TAny* aSemaphore)
936 testThreadB.Printf(_L("B: Loading DLL.\n"));
937 User::LeaveIfError(ThreadBLibraryHandle.Load(KLeavingDll));
939 testThreadB.Printf(_L("B: Pushing handle to dynamically loaded DLL onto the cleanup stack.\n"));
940 CleanupClosePushL(ThreadBLibraryHandle);
942 // Check-point whilst holding the open library handle
943 Checkpoint(aSemaphore);
945 testThreadB.Printf(_L("B: Cleaning up DLL handle.\n"));
946 CleanupStack::PopAndDestroy(&ThreadBLibraryHandle);
951 TInt ThreadC(TAny* aSemaphore)
959 new (&testThreadC) RTest(KNullDesC);
960 testThreadC.Start(KNullDesC);
962 CTrapCleanup* cleanup = CTrapCleanup::New();
963 TInt r = KErrNoMemory;
966 TRAP(r, DoThreadCL(aSemaphore));
968 // Check-point after closing the library handle
969 Checkpoint(aSemaphore);
971 testThreadC.Printf(_L("C: Returned %d, expected %d\n"), r, KErrGeneral);
972 testThreadC(r == KErrGeneral);
984 User::After(100000); // let supervisor run
992 TInt DoThreadCL(TAny* aSemaphore)
994 testThreadC.Printf(_L("C: Loading DLL.\n"));
995 User::LeaveIfError(ThreadCLibraryHandle.Load(KLeavingDll));
997 testThreadC.Printf(_L("C: Pushing handle to dynamically loaded DLL onto the cleanup stack.\n"));
998 CleanupClosePushL(ThreadCLibraryHandle);
1000 testThreadC.Printf(_L("C: Pushing cleanup item to kill this thread before closing handle!\n"));
1001 CleanupStack::PushL(TCleanupItem(&DieDieDie, aSemaphore));
1003 testThreadC.Printf(_L("C: Looking up leaving function.\n"));
1004 TLibraryFunction leaving = ThreadCLibraryHandle.Lookup(1);
1005 User::LeaveIfNull((TAny*)leaving);
1007 // Check-point whilst holding the open library handle
1008 Checkpoint(aSemaphore);
1010 testThreadC.Printf(_L("C: Calling leaving function.\n"));
1013 testThreadC.Printf(_L("C: Cleaning up Panic operation.\n"));
1014 CleanupStack::Pop(aSemaphore); // DieDieDie op
1016 testThreadC.Printf(_L("C: Cleaning up DLL handle.\n"));
1017 CleanupStack::PopAndDestroy(&ThreadCLibraryHandle);
1022 TInt ThreadD(TAny* aSemaphore)
1025 if (CheckKernelHeap)
1030 new (&testThreadD) RTest(KNullDesC);
1031 testThreadD.Start(KNullDesC);
1033 CTrapCleanup* cleanup = CTrapCleanup::New();
1034 TInt r = KErrNoMemory;
1037 TRAP(r, DoThreadDL(aSemaphore));
1039 // Check-point after closing the library handle
1040 Checkpoint(aSemaphore);
1042 testThreadD.Printf(_L("D: Returned %d, expected %d\n"), r, KErrGeneral);
1043 testThreadD(r == KErrGeneral);
1051 testThreadD.Close();
1053 if (CheckKernelHeap)
1055 User::After(100000); // let supervisor run
1063 TInt DoThreadDL(TAny* aSemaphore)
1065 testThreadD.Printf(_L("D: Loading DLL.\n"));
1066 User::LeaveIfError(ThreadDLibraryHandle.Load(KLeavingDll));
1068 testThreadD.Printf(_L("D: Pushing handle to dynamically loaded DLL onto the cleanup stack.\n"));
1069 CleanupClosePushL(ThreadDLibraryHandle);
1071 testThreadD.Printf(_L("D: Pushing cleanup item to recursively leave and then kill this thread before closing handle!\n"));
1072 CleanupStack::PushL(TCleanupItem(&TrapLeaveAndDie, aSemaphore));
1074 testThreadD.Printf(_L("D: Looking up leaving function.\n"));
1075 TLibraryFunction leaving = ThreadDLibraryHandle.Lookup(1);
1076 User::LeaveIfNull((TAny*)leaving);
1078 // Check-point whilst holding the open library handle
1079 Checkpoint(aSemaphore);
1081 testThreadD.Printf(_L("D: Calling leaving function.\n"));
1084 testThreadD.Printf(_L("D: Cleaning up DLL handle.\n"));
1085 CleanupStack::PopAndDestroy(&ThreadDLibraryHandle);
1087 testThreadD.Printf(_L("D: Cleaning up recursive leave operation.\n"));
1088 CleanupStack::Pop(aSemaphore); // recursive leave op
1093 TInt ThreadE(TAny* aSemaphore)
1096 if (CheckKernelHeap)
1101 new (&testThreadE) RTest(KNullDesC);
1102 testThreadE.Start(KNullDesC);
1104 CTrapCleanup* cleanup = CTrapCleanup::New();
1105 TInt r = KErrNoMemory;
1108 TRAP(r, DoThreadEL(aSemaphore));
1110 // Check-point after closing the library handle
1111 Checkpoint(aSemaphore);
1113 testThreadE.Printf(_L("E: Returned %d, expected %d\n"), r, KErrGeneral);
1114 testThreadE(r == KErrGeneral);
1122 testThreadE.Close();
1124 if (CheckKernelHeap)
1126 User::After(100000); // let supervisor run
1134 TInt DoThreadEL(TAny* aSemaphore)
1136 testThreadE.Printf(_L("E: Loading DLL.\n"));
1137 User::LeaveIfError(ThreadELibraryHandle.Load(KLeavingDll));
1139 testThreadE.Printf(_L("E: Pushing handle to dynamically loaded DLL onto the cleanup stack.\n"));
1140 CleanupClosePushL(ThreadELibraryHandle);
1142 testThreadE.Printf(_L("E: Pushing cleanup item to recursively leave and then close the handle in the recursive leave\n"));
1143 CleanupStack::PushL(TCleanupItem(&TrapLeaveAndClose_ThreadE, aSemaphore));
1145 testThreadE.Printf(_L("E: Looking up leaving function.\n"));
1146 TLibraryFunction leaving = ThreadELibraryHandle.Lookup(1);
1147 User::LeaveIfNull((TAny*)leaving);
1149 // Check-point whilst holding the open library handle
1150 Checkpoint(aSemaphore);
1152 testThreadE.Printf(_L("E: Calling leaving function.\n"));
1155 testThreadE.Printf(_L("E: Cleaning up recursive leave operation.\n"));
1156 CleanupStack::Pop(aSemaphore); // recursive leave op
1158 // NB: library handle removed from cleanup stack
1163 TInt ThreadF(TAny* aSemaphore)
1166 if (CheckKernelHeap)
1171 new (&testThreadF) RTest(KNullDesC);
1172 testThreadF.Start(KNullDesC);
1174 CTrapCleanup* cleanup = CTrapCleanup::New();
1175 TInt r = KErrNoMemory;
1178 TRAP(r, DoThreadFL(aSemaphore));
1180 // Check-point after closing the library handle
1181 Checkpoint(aSemaphore);
1183 testThreadF.Printf(_L("F: Returned %d, expected %d\n"), r, KErrGeneral);
1184 testThreadF(r == KErrGeneral);
1192 testThreadF.Close();
1194 if (CheckKernelHeap)
1196 User::After(100000); // let supervisor run
1204 TInt DoThreadFL(TAny* aSemaphore)
1206 testThreadF.Printf(_L("F: Loading DLL.\n"));
1207 User::LeaveIfError(ThreadFLibraryHandle.Load(KLeavingDll));
1209 testThreadF.Printf(_L("F: Pushing handle to dynamically loaded DLL onto the cleanup stack.\n"));
1210 CleanupClosePushL(ThreadFLibraryHandle);
1212 testThreadF.Printf(_L("F: Pushing cleanup item to recursively leave and then panic in recursive leave after closing the library handle\n"));
1213 CleanupStack::PushL(TCleanupItem(&TrapLeaveCloseAndDie_ThreadF, aSemaphore));
1215 testThreadF.Printf(_L("F: Looking up leaving function.\n"));
1216 TLibraryFunction leaving = ThreadFLibraryHandle.Lookup(1);
1217 User::LeaveIfNull((TAny*)leaving);
1219 // Check-point whilst holding the open library handle
1220 Checkpoint(aSemaphore);
1222 testThreadF.Printf(_L("F: Calling leaving function.\n"));
1225 testThreadF.Printf(_L("F: Cleaning up recursive leave operation.\n"));
1226 CleanupStack::Pop(aSemaphore); // recursive leave op
1228 // NB: library handle removed from cleanup stack
1233 TInt ThreadG(TAny* aSemaphore)
1236 if (CheckKernelHeap)
1241 new (&testThreadG) RTest(KNullDesC);
1242 testThreadG.Start(KNullDesC);
1244 CTrapCleanup* cleanup = CTrapCleanup::New();
1245 TInt r = KErrNoMemory;
1248 TRAP(r, DoThreadGL(aSemaphore));
1250 // Check-point after closing the library handle
1251 Checkpoint(aSemaphore);
1253 testThreadG.Printf(_L("G: Returned %d, expected %d\n"), r, KErrGeneral);
1254 testThreadG(r == KErrGeneral);
1262 testThreadG.Close();
1264 if (CheckKernelHeap)
1266 User::After(100000); // let supervisor run
1274 TInt DoThreadGL(TAny* aSemaphore)
1276 testThreadG.Printf(_L("G: Loading DLL.\n"));
1277 User::LeaveIfError(ThreadGLibraryHandle.Load(KLeavingDll));
1279 testThreadG.Printf(_L("G: Pushing cleanup item to synchronise after closing library handle.\n"));
1280 CleanupStack::PushL(TCleanupItem(&PauseLeaving, aSemaphore));
1282 testThreadG.Printf(_L("G: Pushing handle to dynamically loaded DLL onto the cleanup stack.\n"));
1283 CleanupClosePushL(ThreadGLibraryHandle);
1285 testThreadG.Printf(_L("G: Pushing cleanup item to recursively leave, doing nothing, before closing handle\n"));
1286 CleanupStack::PushL(TCleanupItem(&TrapLeave, aSemaphore));
1288 testThreadG.Printf(_L("G: Looking up leaving function.\n"));
1289 TLibraryFunction leaving = ThreadGLibraryHandle.Lookup(1);
1290 User::LeaveIfNull((TAny*)leaving);
1292 // Check-point whilst holding the open library handle
1293 Checkpoint(aSemaphore);
1295 testThreadG.Printf(_L("G: Calling leaving function.\n"));
1298 testThreadG.Printf(_L("G: Cleaning up recursive leave operation.\n"));
1299 CleanupStack::Pop(aSemaphore); // trap leave op
1301 testThreadG.Printf(_L("G: Cleaning up DLL handle.\n"));
1302 CleanupStack::PopAndDestroy(&ThreadGLibraryHandle);
1307 TInt ThreadH(TAny* aSemaphore)
1310 if (CheckKernelHeap)
1315 new (&testThreadH) RTest(KNullDesC);
1316 testThreadH.Start(KNullDesC);
1318 CTrapCleanup* cleanup = CTrapCleanup::New();
1319 TInt r = KErrNoMemory;
1322 TRAP(r, DoThreadHL(aSemaphore));
1324 // Check-point after closing the library handle
1325 Checkpoint(aSemaphore);
1327 testThreadH.Printf(_L("H: Returned %d, expected %d\n"), r, KErrGeneral);
1328 testThreadH(r == KErrGeneral);
1336 testThreadH.Close();
1338 if (CheckKernelHeap)
1340 User::After(100000); // let supervisor run
1348 TInt DoThreadHL(TAny* aSemaphore)
1350 testThreadH.Printf(_L("H: Loading DLL.\n"));
1351 User::LeaveIfError(ThreadHLibraryHandle.Load(KLeavingDll));
1353 testThreadH.Printf(_L("H: Pushing cleanup item to synchronise after closing library handle.\n"));
1354 CleanupStack::PushL(TCleanupItem(&PauseLeaving, aSemaphore));
1356 testThreadH.Printf(_L("H: Pushing handle to dynamically loaded DLL onto the cleanup stack.\n"));
1357 CleanupClosePushL(ThreadHLibraryHandle);
1359 testThreadH.Printf(_L("H: Pushing cleanup item to synchronise during leave\n"));
1360 CleanupStack::PushL(TCleanupItem(&PauseLeaving, aSemaphore));
1362 testThreadH.Printf(_L("H: Looking up leaving function.\n"));
1363 TLibraryFunction leaving = ThreadHLibraryHandle.Lookup(1);
1364 User::LeaveIfNull((TAny*)leaving);
1366 // Check-point whilst holding the open library handle
1367 Checkpoint(aSemaphore);
1369 testThreadH.Printf(_L("H: Calling leaving function.\n"));
1372 testThreadH.Printf(_L("H: Cleaning up leave pausing operation.\n"));
1373 CleanupStack::Pop(aSemaphore); // pause leave op
1375 testThreadH.Printf(_L("H: Cleaning up DLL handle.\n"));
1376 CleanupStack::PopAndDestroy(&ThreadHLibraryHandle);
1381 TInt ThreadI(TAny* aSemaphore)
1384 if (CheckKernelHeap)
1389 new (&testThreadI) RTest(KNullDesC);
1390 testThreadI.Start(KNullDesC);
1392 CTrapCleanup* cleanup = CTrapCleanup::New();
1393 TInt r = KErrNoMemory;
1396 TRAP(r, DoThreadIL(aSemaphore));
1398 // Check-point after closing the library handle
1399 Checkpoint(aSemaphore);
1401 testThreadI.Printf(_L("I: Returned %d, expected %d\n"), r, KErrGeneral);
1402 testThreadI(r == KErrGeneral);
1410 testThreadI.Close();
1412 if (CheckKernelHeap)
1414 User::After(100000); // let supervisor run
1422 TInt DoThreadIL(TAny* aSemaphore)
1424 testThreadI.Printf(_L("I: Loading DLL.\n"));
1425 User::LeaveIfError(ThreadILibraryHandle.Load(KLeavingDll));
1427 testThreadI.Printf(_L("I: Pushing cleanup item to recursively leave, doing nothing, after closing handle\n"));
1428 CleanupStack::PushL(TCleanupItem(&TrapLeave, aSemaphore));
1430 testThreadI.Printf(_L("I: Pushing handle to dynamically loaded DLL onto the cleanup stack.\n"));
1431 CleanupClosePushL(ThreadILibraryHandle);
1433 testThreadI.Printf(_L("I: Pushing cleanup item to synchronise during leave\n"));
1434 CleanupStack::PushL(TCleanupItem(&PauseLeaving, aSemaphore));
1436 testThreadI.Printf(_L("I: Looking up leaving function.\n"));
1437 TLibraryFunction leaving = ThreadILibraryHandle.Lookup(1);
1438 User::LeaveIfNull((TAny*)leaving);
1440 // Check-point whilst holding the open library handle
1441 Checkpoint(aSemaphore);
1443 testThreadI.Printf(_L("I: Calling leaving function.\n"));
1446 testThreadI.Printf(_L("I: Cleaning up leave pausing operation.\n"));
1447 CleanupStack::Pop(aSemaphore); // pause leave op
1449 testThreadI.Printf(_L("I: Cleaning up DLL handle.\n"));
1450 CleanupStack::PopAndDestroy(&ThreadILibraryHandle);
1452 testThreadI.Printf(_L("I: Cleaning up recursive leave operation.\n"));
1453 CleanupStack::Pop(); // trap leave op
1458 TInt ThreadJ(TAny* aSemaphore)
1461 if (CheckKernelHeap)
1466 new (&testThreadJ) RTest(KNullDesC);
1467 testThreadJ.Start(KNullDesC);
1469 CTrapCleanup* cleanup = CTrapCleanup::New();
1470 TInt r = KErrNoMemory;
1473 TRAP(r, DoThreadJL(aSemaphore));
1475 // Check-point after closing the library handle
1476 Checkpoint(aSemaphore);
1478 testThreadJ.Printf(_L("J: Returned %d, expected %d\n"), r, KErrGeneral);
1479 testThreadJ(r == KErrGeneral);
1487 testThreadJ.Close();
1489 if (CheckKernelHeap)
1491 User::After(100000); // let supervisor run
1499 TInt DoThreadJL(TAny* aSemaphore)
1501 testThreadJ.Printf(_L("J: Loading DLL.\n"));
1502 User::LeaveIfError(ThreadJLibraryHandle.Load(KLeavingDll));
1504 testThreadJ.Printf(_L("J: Pushing cleanup item to recursively leave and panic, after closing handle\n"));
1505 CleanupStack::PushL(TCleanupItem(&TrapLeaveAndDie, aSemaphore));
1507 testThreadJ.Printf(_L("J: Pushing handle to dynamically loaded DLL onto the cleanup stack.\n"));
1508 CleanupClosePushL(ThreadJLibraryHandle);
1510 testThreadJ.Printf(_L("J: Pushing cleanup item to synchronise during leave\n"));
1511 CleanupStack::PushL(TCleanupItem(&PauseLeaving, aSemaphore));
1513 testThreadJ.Printf(_L("J: Looking up leaving function.\n"));
1514 TLibraryFunction leaving = ThreadJLibraryHandle.Lookup(1);
1515 User::LeaveIfNull((TAny*)leaving);
1517 // Check-point whilst holding the open library handle
1518 Checkpoint(aSemaphore);
1520 testThreadJ.Printf(_L("J: Calling leaving function.\n"));
1523 testThreadJ.Printf(_L("J: Cleaning up leave pausing operation.\n"));
1524 CleanupStack::Pop(aSemaphore); // pause leave op
1526 testThreadJ.Printf(_L("J: Cleaning up DLL handle.\n"));
1527 CleanupStack::PopAndDestroy(&ThreadJLibraryHandle);
1529 testThreadJ.Printf(_L("J: Cleaning up recursive leave operation.\n"));
1530 CleanupStack::Pop(); // leave and die op
1535 TInt ThreadK(TAny* aSemaphore)
1538 if (CheckKernelHeap)
1543 new (&testThreadK) RTest(KNullDesC);
1544 testThreadK.Start(KNullDesC);
1546 CTrapCleanup* cleanup = CTrapCleanup::New();
1547 TInt r = KErrNoMemory;
1550 TRAP(r, DoThreadKL(aSemaphore));
1552 // Check-point after closing the library handle
1553 Checkpoint(aSemaphore);
1555 testThreadK.Printf(_L("K: Returned %d, expected %d\n"), r, KErrGeneral);
1556 testThreadK(r == KErrGeneral);
1564 testThreadK.Close();
1566 if (CheckKernelHeap)
1568 User::After(100000); // let supervisor run
1576 TInt DoThreadKL(TAny* aSemaphore)
1578 testThreadK.Printf(_L("K: Loading DLL.\n"));
1579 User::LeaveIfError(ThreadKLibraryHandle.Load(KLeavingDll));
1581 testThreadK.Printf(_L("K: Pushing cleanup item to panic, after closing handle\n"));
1582 CleanupStack::PushL(TCleanupItem(&DieDieDie, aSemaphore));
1584 testThreadK.Printf(_L("K: Pushing handle to dynamically loaded DLL onto the cleanup stack.\n"));
1585 CleanupClosePushL(ThreadKLibraryHandle);
1587 testThreadK.Printf(_L("K: Pushing cleanup item to synchronise during leave\n"));
1588 CleanupStack::PushL(TCleanupItem(&PauseLeaving, aSemaphore));
1590 testThreadK.Printf(_L("K: Looking up leaving function.\n"));
1591 TLibraryFunction leaving = ThreadKLibraryHandle.Lookup(1);
1592 User::LeaveIfNull((TAny*)leaving);
1594 // Check-point whilst holding the open library handle
1595 Checkpoint(aSemaphore);
1597 testThreadK.Printf(_L("K: Calling leaving function.\n"));
1600 testThreadK.Printf(_L("K: Cleaning up leave pausing operation.\n"));
1601 CleanupStack::Pop(aSemaphore); // pause leave op
1603 testThreadK.Printf(_L("K: Cleaning up DLL handle.\n"));
1604 CleanupStack::PopAndDestroy(&ThreadKLibraryHandle);
1606 testThreadK.Printf(_L("K: Cleaning up panic operation.\n"));
1607 CleanupStack::Pop(); // die op