os/kernelhwsrv/kerneltest/e32test/cppexceptions/t_unmap.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) 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".
     7 //
     8 // Initial Contributors:
     9 // Nokia Corporation - initial contribution.
    10 //
    11 // Contributors:
    12 //
    13 // Description:
    14 // e32test\cppexceptions\t_unmap.cpp
    15 // 
    16 //
    17 
    18 #include <e32std.h>
    19 #include <e32std_private.h>
    20 #include <e32base.h>
    21 #include <e32base_private.h>
    22 #include <e32test.h>
    23 #include <e32svr.h>
    24 #include <f32dbg.h>
    25 #include <e32def.h>
    26 #include <e32def_private.h>
    27 
    28 #include "d_unmap.h"
    29 
    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");
    35 
    36 _LIT(KUnhandledExcCategory, "KERN-EXEC");
    37 const TInt KUnhandledExcReason = 3;
    38 
    39 enum TUnmapPanic
    40 	{
    41 	EPanickingThread = 123456789
    42 	};
    43 
    44 RTest test(KTestName);
    45 
    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);
    54 
    55 RTest testThreadI(KTestThreadName);
    56 RTest testThreadJ(KTestThreadName);
    57 RTest testThreadK(KTestThreadName);
    58 
    59 RSemaphore Thread1Semaphore;
    60 RSemaphore Thread2Semaphore;
    61 
    62 RSemaphore FinishedOpSemaphore;
    63 
    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;
    75 
    76 TBool CheckKernelHeap;
    77 
    78 void TestThreads();
    79 
    80 TInt ThreadA(TAny*);
    81 TInt ThreadB(TAny*);
    82 TInt ThreadC(TAny*);
    83 TInt ThreadD(TAny*);
    84 TInt ThreadE(TAny*);
    85 TInt ThreadF(TAny*);
    86 TInt ThreadG(TAny*);
    87 TInt ThreadH(TAny*);
    88 TInt ThreadI(TAny*);
    89 TInt ThreadJ(TAny*);
    90 TInt ThreadK(TAny*);
    91 
    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*);
   103 
   104 struct STestThreadInfo
   105 	{
   106 	TThreadFunction	iThreadFn;
   107 	TExitType		iExitType;
   108 	TInt			iMappedSignals;
   109 	TInt			iLeaveSignals;
   110 	};
   111 
   112 static STestThreadInfo const TheThreadArray[] =
   113 	{
   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 }
   125 	};
   126 
   127 struct SNopThreadInfo
   128 	{
   129 	TLibraryFunction iFunc;
   130 #ifdef __WINS__
   131 	TInt32 iOriginalContents;
   132 #endif
   133 	};
   134 
   135 static SNopThreadInfo NopThreadInfo;
   136 
   137 static const TInt TheThreadCount = (sizeof(TheThreadArray) / sizeof(STestThreadInfo));
   138 
   139 static const TInt KHeapSize = 0x2000;
   140 
   141 TInt E32Main()
   142    	{
   143 	// Turn off lazy dll unloading
   144 	RLoader l;
   145 	test(l.Connect()==KErrNone);
   146 	test(l.CancelLazyDllUnload()==KErrNone);
   147 	l.Close();
   148 	
   149 	test.Start(_L("Check code seg unmapping over User::Leave()/C++ exceptions."));
   150 
   151 	__UHEAP_MARK;
   152    	//
   153    	CTrapCleanup* cleanup = CTrapCleanup::New();
   154    	TInt r = KErrNoMemory;
   155    	if (cleanup)
   156    		{
   157 		TRAP(r, TestThreads());
   158 
   159 		test.Printf(_L("Returned %d, expected %d\n"), r, KErrNone);
   160 		test(r == KErrNone);
   161    		}
   162 
   163 	delete cleanup;
   164    	//
   165    	__UHEAP_MARKEND;
   166 
   167 	test.End();
   168 
   169    	return r;
   170    	}
   171 
   172 TInt NopThread(TAny*)
   173 	{
   174 #ifdef __WINS__
   175 	TInt32 current = *(TInt*)NopThreadInfo.iFunc;
   176 	if (current != NopThreadInfo.iOriginalContents)
   177 		current = *(TInt32*)NULL; // cause panic
   178 #endif
   179 	TInt r = NopThreadInfo.iFunc();
   180 	if (r)
   181 		return KErrNone;
   182 	else
   183 		return KErrGeneral;
   184 	}
   185 
   186 void TestLoadWhileUnload();
   187 
   188 void TestThreads()
   189 	{
   190 	__KHEAP_MARK;
   191 
   192 	test.Next(_L("Create synchronisation semaphores"));
   193 	TInt r = Thread1Semaphore.CreateLocal(0);
   194 	test(r == KErrNone);
   195 
   196 	r = Thread2Semaphore.CreateLocal(0);
   197 	test(r == KErrNone);
   198 
   199 	r = FinishedOpSemaphore.CreateLocal(0);
   200 	test(r == KErrNone);
   201 
   202 	// Turn off JIT [threads can panic to test exit cleanup]
   203 	TBool jit = User::JustInTime();
   204 	User::SetJustInTime(EFalse);
   205 
   206 	TInt count, count2;
   207 	
   208 	// Do kernel heap checking
   209 	CheckKernelHeap = ETrue;
   210 
   211 	test.Next(_L("Run threads on their own"));
   212 	for (count = 0; count < TheThreadCount ; ++count)
   213 		{
   214 		// Set up descriptor for thread's name
   215 		TBuf16<7> name(KThread);
   216 		name.Append('A' + count);
   217 
   218 		// Create thread
   219 		RThread thread;
   220 		TInt r = thread.Create(
   221 			name,
   222 			TheThreadArray[count].iThreadFn,
   223 			KDefaultStackSize,
   224 			KHeapSize,
   225 			KHeapSize,
   226 			&Thread1Semaphore
   227 		);
   228 		test(r == KErrNone);
   229 
   230 		// Set up notification of thread's death
   231 		TRequestStatus status;
   232 		thread.Logon(status);
   233 
   234 		// Load library
   235 		RLibrary library;
   236 		r = library.Load(KLeavingDll);
   237 		test(r == KErrNone);
   238 
   239 		// Remember the address of the NOP function
   240 		NopThreadInfo.iFunc = library.Lookup(2);
   241 #ifdef __WINS__
   242 		NopThreadInfo.iOriginalContents = *(TInt32*)NopThreadInfo.iFunc;
   243 #endif
   244 
   245 		// Run thread
   246 		thread.Resume();
   247 
   248 		// Wait until it has an open handle to the library
   249 		FinishedOpSemaphore.Wait();
   250 
   251 		// Close our handle to the library
   252 		library.Close();
   253 
   254 		// Check library is still loaded
   255 		for (count2 = 0; count2 < TheThreadArray[count].iMappedSignals; ++count2)
   256 			{
   257 			// Tell it we're ready to go
   258 			Thread1Semaphore.Signal();
   259 
   260 			// Wait for it to finish next step
   261 			FinishedOpSemaphore.Wait();
   262 
   263 			// Create NOP thread to call NOP function to check DLL still loaded
   264 			RThread nopThread;
   265 			r = nopThread.Create(
   266 				KNopThreadName,
   267 				NopThread,
   268 				KDefaultStackSize,
   269 				KHeapSize,
   270 				KHeapSize,
   271 				NULL
   272 			);
   273 			test(r == KErrNone);
   274 
   275 			// Set up notification of thread's death
   276 			TRequestStatus nopStatus;
   277 			nopThread.Logon(nopStatus);
   278 
   279 			// Run thread
   280 			nopThread.Resume();
   281 
   282 			// Wait for it to die
   283 			User::WaitForRequest(nopStatus);
   284 
   285 			// Check the exit info
   286 			test(nopThread.ExitType() == EExitKill);
   287 			test(nopThread.ExitReason() == KErrNone);
   288 
   289 			// Close thread handle
   290 			CLOSE_AND_WAIT(nopThread);
   291 			}
   292 
   293 		// Check User::Leave() library unloading behaviour
   294 		for (count2 = 0; count2 < TheThreadArray[count].iLeaveSignals; ++count2)
   295 			{
   296 			// Tell it we're ready to go
   297 			Thread1Semaphore.Signal();
   298 
   299 			// Wait for it to finish next step
   300 			FinishedOpSemaphore.Wait();
   301 
   302 			// Create NOP thread to call NOP function to check whether DLL is still loaded
   303 			RThread nopThread;
   304 			r = nopThread.Create(
   305 				KNopThreadName,
   306 				NopThread,
   307 				KDefaultStackSize,
   308 				KHeapSize,
   309 				KHeapSize,
   310 				NULL
   311 			);
   312 			test(r == KErrNone);
   313 
   314 			// Set up notification of thread's death
   315 			TRequestStatus nopStatus;
   316 			nopThread.Logon(nopStatus);
   317 
   318 			// Run thread
   319 			nopThread.Resume();
   320 
   321 			// Wait for it to die
   322 			User::WaitForRequest(nopStatus);
   323 
   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__
   333 
   334 			// Close thread handle
   335 			CLOSE_AND_WAIT(nopThread);
   336 			}
   337 
   338 		// Tell it we're ready to go again
   339 		Thread1Semaphore.Signal();
   340 
   341 		if (TheThreadArray[count].iExitType == EExitKill)
   342 			{
   343 			// Wait for it to finish last step
   344 			FinishedOpSemaphore.Wait();
   345 
   346 			User::After(100000);	// let supervisor run
   347 
   348 			// Create NOP thread to call NOP function to check DLL is unloaded
   349 			RThread nopThread;
   350 			r = nopThread.Create(
   351 				KNopThreadName,
   352 				NopThread,
   353 				KDefaultStackSize,
   354 				KHeapSize,
   355 				KHeapSize,
   356 				NULL
   357 			);
   358 			test(r == KErrNone);
   359 
   360 			// Set up notification of thread's death
   361 			TRequestStatus nopStatus;
   362 			nopThread.Logon(nopStatus);
   363 
   364 			// Run thread
   365 			nopThread.Resume();
   366 
   367 			// Wait for it to die
   368 			User::WaitForRequest(nopStatus);
   369 
   370 			// Check the exit info
   371 			test(nopThread.ExitType() == EExitPanic);
   372 			test(nopThread.ExitCategory() == KUnhandledExcCategory);
   373 			test(nopThread.ExitReason() == KUnhandledExcReason);
   374 
   375 			// Close thread handle
   376 			CLOSE_AND_WAIT(nopThread);
   377 
   378 			// Let main thread die now
   379 			Thread1Semaphore.Signal();
   380 			}
   381 
   382 		// Wait for thread to exit
   383 		User::WaitForRequest(status);
   384 
   385 		// Check the exit type & category
   386 		test(thread.ExitType() == TheThreadArray[count].iExitType);
   387 
   388 		// Check category & reason, if appropriate
   389 		if (thread.ExitType() == EExitPanic)
   390 			{
   391 			test(thread.ExitCategory() == KTUnmapPanic);
   392 			test(thread.ExitReason() == EPanickingThread);
   393 			}
   394 
   395 		// Close thread handle
   396 		thread.Close();
   397 		}
   398 
   399 	// Turn off kernel heap checking
   400 	CheckKernelHeap = EFalse;
   401 
   402 	test.Next(_L("Run threads against each other"));
   403 	for (count = 0; count < TheThreadCount ; ++count)
   404 		{
   405 		for (count2 = 0; count2 < TheThreadCount ; ++count2)
   406 			{
   407 			// Can't run the same threads back to back
   408 			if (count == count2)
   409 				{
   410 				continue;
   411 				}
   412 
   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);
   422 
   423 			// Create threads
   424 			RThread thread;
   425 			TInt r = thread.Create(
   426 				name,
   427 				TheThreadArray[count].iThreadFn,
   428 				KDefaultStackSize,
   429 				KHeapSize,
   430 				KHeapSize,
   431 				&Thread1Semaphore
   432 			);
   433 			test(r == KErrNone);
   434 
   435 			RThread thread2;
   436 			r = thread2.Create(
   437 				name2,
   438 				TheThreadArray[count2].iThreadFn,
   439 				KDefaultStackSize,
   440 				KHeapSize,
   441 				KHeapSize,
   442 				&Thread2Semaphore
   443 			);
   444 			test(r == KErrNone);
   445 
   446 			// Set up notification of threads' death
   447 			TRequestStatus status, status2;
   448 			thread.Logon(status);
   449 			thread2.Logon(status2);
   450 
   451 			// Run first thread
   452 			thread.Resume();
   453 
   454 			// Wait until just before it's closed the library handle
   455 			FinishedOpSemaphore.Wait();
   456 
   457 			// Run second thread
   458 			thread2.Resume();
   459 
   460 			// Wait until just before it's closed the library handle
   461 			FinishedOpSemaphore.Wait();
   462 
   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);
   468 
   469 			// Eat up 'FinishedOp' signals
   470 			while(--signals>0)
   471 				FinishedOpSemaphore.Wait();
   472 
   473 			// Wait for it to finish
   474 			User::WaitForRequest(status);
   475 
   476 			// Check the exit type & category of the first thread
   477 			test(thread.ExitType() == TheThreadArray[count].iExitType);
   478 
   479 			// Check category & reason of the first thread, if appropriate
   480 			if (thread.ExitType() == EExitPanic)
   481 				{
   482 				test(thread.ExitCategory() == KTUnmapPanic);
   483 				test(thread.ExitReason() == EPanickingThread);
   484 				}
   485 
   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);
   491 
   492 			// Eat up 'FinishedOp' signals
   493 			while(--signals>0)
   494 				FinishedOpSemaphore.Wait();
   495 
   496 			// Wait for it to finish
   497 			User::WaitForRequest(status2);
   498 
   499 			// Check the exit type & category of the second thread
   500 			test(thread2.ExitType() == TheThreadArray[count2].iExitType);
   501 
   502 			// Check category & reason of the second thread, if appropriate
   503 			if (thread2.ExitType() == EExitPanic)
   504 				{
   505 				test(thread2.ExitCategory() == KTUnmapPanic);
   506 				test(thread2.ExitReason() == EPanickingThread);
   507 				}
   508 
   509 			// Close thread handles
   510 			CLOSE_AND_WAIT(thread);
   511 			CLOSE_AND_WAIT(thread2);
   512 			}
   513 		}
   514 
   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"));
   531 	proc1.Resume();
   532 	proc2.Resume();
   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);
   542 	procSem1.Close();
   543 	procSem2.Close();
   544 
   545 	// Test load while unload
   546 	TestLoadWhileUnload();
   547 
   548 	// Restore JIT setting
   549 	User::SetJustInTime(jit);
   550 
   551 	// Close synchronisation semaphores
   552 	Thread1Semaphore.Close();
   553 	Thread2Semaphore.Close();
   554 	FinishedOpSemaphore.Close();
   555 
   556 	__KHEAP_MARKEND;
   557 	}
   558 
   559 // Test loading a library while another thread is unloading it in an unwind
   560 void TestLoadWhileUnload()
   561 	{
   562 	// Set up descriptor for thread's name
   563 	TBuf16<7> name(KThread);
   564 	name.Append('H');
   565 
   566 	// Create thread
   567 	RThread thread;
   568 	TInt r = thread.Create(
   569 		name,
   570 		ThreadH,
   571 		KDefaultStackSize,
   572 		KHeapSize,
   573 		KHeapSize,
   574 		&Thread1Semaphore
   575 	);
   576 	test(r == KErrNone);
   577 
   578 	// Set up notification of thread's death
   579 	TRequestStatus status;
   580 	thread.Logon(status);
   581 
   582 	// Run thread
   583 	thread.Resume();
   584 
   585 	// Wait until it has an open handle to the library
   586 	FinishedOpSemaphore.Wait();
   587 
   588 	// Tell it to go ahead and leave
   589 	Thread1Semaphore.Signal();
   590 
   591 	// Wait for it to start unwinding
   592 	FinishedOpSemaphore.Wait();
   593 
   594 	// Tell it to go ahead and close the library handle
   595 	Thread1Semaphore.Signal();
   596 
   597 	// Wait for it to have closed the library
   598 	FinishedOpSemaphore.Wait();
   599 
   600 	// Load library
   601 	RLibrary library;
   602 	r = library.Load(KLeavingDll);
   603 	test(r == KErrNone);
   604 
   605 	// Remember the address of the NOP function
   606 	NopThreadInfo.iFunc = library.Lookup(2);
   607 #ifdef __WINS__
   608 	NopThreadInfo.iOriginalContents = *(TInt32*)NopThreadInfo.iFunc;
   609 #endif
   610 
   611 	User::After(100000);	// let supervisor run
   612 
   613 	// Check User::Leave() library unloading behaviour
   614 	for (TInt i = 0; i < 2; ++i)
   615 		{
   616 		// Create NOP thread to call NOP function to check whether DLL is still loaded
   617 		RThread nopThread;
   618 		r = nopThread.Create(
   619 			KNopThreadName,
   620 			NopThread,
   621 			KDefaultStackSize,
   622 			KHeapSize,
   623 			KHeapSize,
   624 			NULL
   625 		);
   626 		test(r == KErrNone);
   627 
   628 		// Set up notification of thread's death
   629 		TRequestStatus nopStatus;
   630 		nopThread.Logon(nopStatus);
   631 
   632 		// Run thread
   633 		nopThread.Resume();
   634 
   635 		// Wait for it to die
   636 		User::WaitForRequest(nopStatus);
   637 
   638 		// Check the exit info
   639 		test(nopThread.ExitType() == EExitKill);
   640 		test(nopThread.ExitReason() == KErrNone);
   641 
   642 		// Close thread handle
   643 		CLOSE_AND_WAIT(nopThread);
   644 
   645 		// Tell it we're ready to go
   646 		Thread1Semaphore.Signal();
   647 
   648 		// Wait for it to finish next step
   649 		if (i==0)
   650 			FinishedOpSemaphore.Wait();
   651 		}
   652 
   653 	// Wait for thread to exit
   654 	User::WaitForRequest(status);
   655 
   656 	// Check the exit type & category
   657 	test(thread.ExitType() == EExitKill);
   658 
   659 	// Close thread handle
   660 	CLOSE_AND_WAIT(thread);
   661 
   662 	// Close our handle to the library
   663 	library.Close();
   664 
   665 	// Create NOP thread to call NOP function to check DLL is unloaded
   666 	RThread nopThread;
   667 	r = nopThread.Create(
   668 		KNopThreadName,
   669 		NopThread,
   670 		KDefaultStackSize,
   671 		KHeapSize,
   672 		KHeapSize,
   673 		NULL
   674 	);
   675 	test(r == KErrNone);
   676 
   677 	// Set up notification of thread's death
   678 	TRequestStatus nopStatus;
   679 	nopThread.Logon(nopStatus);
   680 
   681 	// Run thread
   682 	nopThread.Resume();
   683 
   684 	// Wait for it to die
   685 	User::WaitForRequest(nopStatus);
   686 
   687 	// Check the exit info
   688 	test(nopThread.ExitType() == EExitPanic);
   689 	test(nopThread.ExitCategory() == KUnhandledExcCategory);
   690 	test(nopThread.ExitReason() == KUnhandledExcReason);
   691 
   692 	// Close thread handle
   693 	CLOSE_AND_WAIT(nopThread);
   694 	}	
   695 
   696 //
   697 // Cleanup operations
   698 //
   699 
   700 void Checkpoint(TAny* aSemaphore)
   701 	{
   702 	if(aSemaphore)
   703 		{
   704 		FinishedOpSemaphore.Signal();
   705 		static_cast<RSemaphore*>(aSemaphore)->Wait();
   706 		}
   707 	}
   708 
   709 void DieDieDie(TAny* aSemaphore)
   710 	{
   711 	// Check-point before panicking
   712 	Checkpoint(aSemaphore);
   713 	
   714 	User::Panic(KTUnmapPanic, EPanickingThread);
   715 	}
   716 
   717 void PauseLeaving(TAny* aSemaphore)
   718 	{
   719 	Checkpoint(aSemaphore);
   720 	}
   721 
   722 void TrapLeave(TAny* aSemaphore)
   723 	{
   724 	TRAP_IGNORE(
   725 		{
   726 		CleanupStack::PushL(TCleanupItem(&PauseLeaving, aSemaphore));
   727 
   728 		Checkpoint(aSemaphore);
   729 
   730 		User::Leave(KErrGeneral);
   731 
   732 		CleanupStack::Pop(); // pause op
   733 		}
   734 	);
   735 
   736 	Checkpoint(aSemaphore);
   737 	}
   738 
   739 void TrapLeaveAndDie(TAny* aSemaphore)
   740 	{
   741 	TRAP_IGNORE(
   742 		{
   743 		CleanupStack::PushL(TCleanupItem(&DieDieDie, aSemaphore));
   744 
   745 		Checkpoint(aSemaphore);
   746 
   747 		User::Leave(KErrGeneral);
   748 
   749 		CleanupStack::Pop(); //DieDieDie op
   750 		}
   751 	);
   752 	}
   753 
   754 void TrapLeaveAndClose_ThreadE(TAny* aSemaphore)
   755 	{
   756 	CleanupStack::Pop(&ThreadELibraryHandle);
   757 
   758 	TRAP_IGNORE(
   759 		{
   760 		CleanupStack::PushL(TCleanupItem(&PauseLeaving, aSemaphore));
   761 
   762 		CleanupClosePushL(ThreadELibraryHandle);
   763 
   764 		CleanupStack::PushL(TCleanupItem(&PauseLeaving, aSemaphore));
   765 
   766 		Checkpoint(aSemaphore);
   767 
   768 		User::Leave(KErrGeneral);
   769 
   770 		CleanupStack::Pop(); //pre-close pause op
   771 
   772 		CleanupStack::Pop(&ThreadELibraryHandle);
   773 
   774 		CleanupStack::Pop(); //post-close pause op
   775 		}
   776 	);
   777 
   778 	Checkpoint(aSemaphore);
   779 	}
   780 
   781 void TrapLeaveCloseAndDie_ThreadF(TAny* aSemaphore)
   782 	{
   783 	CleanupStack::Pop(&ThreadFLibraryHandle);
   784 
   785 	TRAP_IGNORE(
   786 		{
   787 		CleanupStack::PushL(TCleanupItem(&DieDieDie, aSemaphore));
   788 
   789 		CleanupClosePushL(ThreadFLibraryHandle);
   790 
   791 		CleanupStack::PushL(TCleanupItem(&PauseLeaving, aSemaphore));
   792 
   793 		Checkpoint(aSemaphore);
   794 
   795 		User::Leave(KErrGeneral);
   796 
   797 		CleanupStack::Pop(); //pre-close pause op
   798 
   799 		CleanupStack::Pop(&ThreadFLibraryHandle);
   800 
   801 		CleanupStack::Pop(); //DieDieDie op
   802 		}
   803 	);
   804 	}
   805 
   806 
   807 /**
   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:
   810 
   811 a)	Panicks
   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
   822 
   823 Other ideas yet to be done:
   824 
   825 l)	TRAPs a leave, then closes handle
   826 m)	TRAPs a recusive leave, then closes handle
   827 
   828 The thread functions below correspond to these.
   829 
   830 These are the ways a library's code seg can be held open by a process:
   831 
   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
   835 
   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.
   838 */
   839 
   840 TInt ThreadA(TAny* aSemaphore)
   841 	{
   842 	__UHEAP_MARK;
   843 	if (CheckKernelHeap)
   844 		{
   845 		__KHEAP_MARK;
   846 		}
   847 
   848 	new (&testThreadA) RTest(KNullDesC);
   849 	testThreadA.Start(KNullDesC);
   850    	//
   851    	CTrapCleanup* cleanup = CTrapCleanup::New();
   852    	TInt r = KErrNoMemory;
   853    	if (cleanup)
   854    		{
   855 		TRAP(r, DoThreadAL(aSemaphore));
   856 
   857 		// Check-point after closing the library handle
   858 		Checkpoint(aSemaphore);
   859 
   860 		testThreadA.Printf(_L("A: Returned %d, expected %d\n"), r, KErrNone);
   861 		testThreadA(r == KErrNone);
   862    		}
   863 
   864 	delete cleanup;
   865    	//
   866 	testThreadA.End();
   867 	testThreadA.Close();
   868 
   869 	if (CheckKernelHeap)
   870 		{
   871 		User::After(100000);	// let supervisor run
   872 		__KHEAP_MARKEND;
   873 		}
   874    	__UHEAP_MARKEND;
   875 
   876    	return r;
   877 	}
   878 
   879 TInt DoThreadAL(TAny* aSemaphore)
   880 	{
   881 	testThreadA.Printf(_L("A: Loading DLL.\n"));
   882 	User::LeaveIfError(ThreadALibraryHandle.Load(KLeavingDll));
   883 
   884     testThreadA.Printf(_L("A: Pushing cleanup item to kill this thread!\n"));
   885 	CleanupStack::PushL(TCleanupItem(&DieDieDie, aSemaphore));
   886 
   887 	testThreadA.Printf(_L("A: Cleaning up Panic operation.\n"));
   888 	CleanupStack::PopAndDestroy(); // DieDieDie op
   889 
   890 	ThreadALibraryHandle.Close();
   891 
   892 	return KErrNone;
   893 	}
   894 
   895 TInt ThreadB(TAny* aSemaphore)
   896 	{
   897 	__UHEAP_MARK;
   898 	if (CheckKernelHeap)
   899 		{
   900 		__KHEAP_MARK;
   901 		}
   902 
   903 	new (&testThreadB) RTest(KNullDesC);
   904 	testThreadB.Start(KNullDesC);
   905    	//
   906    	CTrapCleanup* cleanup = CTrapCleanup::New();
   907    	TInt r = KErrNoMemory;
   908    	if (cleanup)
   909    		{
   910 		TRAP(r, DoThreadBL(aSemaphore));
   911 
   912 		// Check-point after closing the library handle
   913 		Checkpoint(aSemaphore);
   914 
   915 		testThreadB.Printf(_L("B: Returned %d, expected %d\n"), r, KErrNone);
   916 		testThreadB(r == KErrNone);
   917    		}
   918 
   919 	delete cleanup;
   920    	//
   921 	testThreadB.End();
   922 	testThreadB.Close();
   923 
   924 	if (CheckKernelHeap)
   925 		{
   926 		User::After(100000);	// let supervisor run
   927 		__KHEAP_MARKEND;
   928 		}
   929    	__UHEAP_MARKEND;
   930 
   931 	return r;
   932 	}
   933 
   934 TInt DoThreadBL(TAny* aSemaphore)
   935 	{
   936     testThreadB.Printf(_L("B: Loading DLL.\n"));
   937 	User::LeaveIfError(ThreadBLibraryHandle.Load(KLeavingDll));
   938 
   939     testThreadB.Printf(_L("B: Pushing handle to dynamically loaded DLL onto the cleanup stack.\n"));
   940 	CleanupClosePushL(ThreadBLibraryHandle);
   941 
   942 	// Check-point whilst holding the open library handle
   943 	Checkpoint(aSemaphore);
   944 	
   945 	testThreadB.Printf(_L("B: Cleaning up DLL handle.\n"));
   946 	CleanupStack::PopAndDestroy(&ThreadBLibraryHandle);
   947 
   948 	return KErrNone;
   949 	}
   950 
   951 TInt ThreadC(TAny* aSemaphore)
   952 	{
   953 	__UHEAP_MARK;
   954 	if (CheckKernelHeap)
   955 		{
   956 		__KHEAP_MARK;
   957 		}
   958 
   959 	new (&testThreadC) RTest(KNullDesC);
   960 	testThreadC.Start(KNullDesC);
   961    	//
   962    	CTrapCleanup* cleanup = CTrapCleanup::New();
   963    	TInt r = KErrNoMemory;
   964    	if (cleanup)
   965    		{
   966 		TRAP(r, DoThreadCL(aSemaphore));
   967 
   968 		// Check-point after closing the library handle
   969 		Checkpoint(aSemaphore);
   970 
   971 		testThreadC.Printf(_L("C: Returned %d, expected %d\n"), r, KErrGeneral);
   972 		testThreadC(r == KErrGeneral);
   973 
   974 		r = KErrNone;
   975    		}
   976 
   977 	delete cleanup;
   978    	//
   979 	testThreadC.End();
   980 	testThreadC.Close();
   981 
   982 	if (CheckKernelHeap)
   983 		{
   984 		User::After(100000);	// let supervisor run
   985 		__KHEAP_MARKEND;
   986 		}
   987    	__UHEAP_MARKEND;
   988 
   989 	return r;
   990 	}
   991 
   992 TInt DoThreadCL(TAny* aSemaphore)
   993 	{
   994     testThreadC.Printf(_L("C: Loading DLL.\n"));
   995 	User::LeaveIfError(ThreadCLibraryHandle.Load(KLeavingDll));
   996 
   997     testThreadC.Printf(_L("C: Pushing handle to dynamically loaded DLL onto the cleanup stack.\n"));
   998 	CleanupClosePushL(ThreadCLibraryHandle);
   999 
  1000 	testThreadC.Printf(_L("C: Pushing cleanup item to kill this thread before closing handle!\n"));
  1001 	CleanupStack::PushL(TCleanupItem(&DieDieDie, aSemaphore));
  1002 
  1003     testThreadC.Printf(_L("C: Looking up leaving function.\n"));
  1004 	TLibraryFunction leaving = ThreadCLibraryHandle.Lookup(1);
  1005 	User::LeaveIfNull((TAny*)leaving);
  1006 
  1007 	// Check-point whilst holding the open library handle
  1008 	Checkpoint(aSemaphore);
  1009 	
  1010 	testThreadC.Printf(_L("C: Calling leaving function.\n"));
  1011 	(*leaving)();
  1012 
  1013 	testThreadC.Printf(_L("C: Cleaning up Panic operation.\n"));
  1014 	CleanupStack::Pop(aSemaphore); // DieDieDie op
  1015 
  1016 	testThreadC.Printf(_L("C: Cleaning up DLL handle.\n"));
  1017 	CleanupStack::PopAndDestroy(&ThreadCLibraryHandle);
  1018 
  1019 	return KErrNone;
  1020 	}
  1021 
  1022 TInt ThreadD(TAny* aSemaphore)
  1023 	{
  1024 	__UHEAP_MARK;
  1025 	if (CheckKernelHeap)
  1026 		{
  1027 		__KHEAP_MARK;
  1028 		}
  1029 
  1030 	new (&testThreadD) RTest(KNullDesC);
  1031 	testThreadD.Start(KNullDesC);
  1032    	//
  1033    	CTrapCleanup* cleanup = CTrapCleanup::New();
  1034    	TInt r = KErrNoMemory;
  1035    	if (cleanup)
  1036    		{
  1037 		TRAP(r, DoThreadDL(aSemaphore));
  1038 
  1039 		// Check-point after closing the library handle
  1040 		Checkpoint(aSemaphore);
  1041 
  1042 		testThreadD.Printf(_L("D: Returned %d, expected %d\n"), r, KErrGeneral);
  1043 		testThreadD(r == KErrGeneral);
  1044 
  1045 		r = KErrNone;
  1046    		}
  1047 
  1048 	delete cleanup;
  1049    	//
  1050 	testThreadD.End();
  1051 	testThreadD.Close();
  1052 
  1053 	if (CheckKernelHeap)
  1054 		{
  1055 		User::After(100000);	// let supervisor run
  1056 		__KHEAP_MARKEND;
  1057 		}
  1058    	__UHEAP_MARKEND;
  1059 
  1060 	return r;
  1061 	}
  1062 
  1063 TInt DoThreadDL(TAny* aSemaphore)
  1064 	{
  1065     testThreadD.Printf(_L("D: Loading DLL.\n"));
  1066 	User::LeaveIfError(ThreadDLibraryHandle.Load(KLeavingDll));
  1067 
  1068     testThreadD.Printf(_L("D: Pushing handle to dynamically loaded DLL onto the cleanup stack.\n"));
  1069 	CleanupClosePushL(ThreadDLibraryHandle);
  1070 
  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));
  1073 
  1074     testThreadD.Printf(_L("D: Looking up leaving function.\n"));
  1075 	TLibraryFunction leaving = ThreadDLibraryHandle.Lookup(1);
  1076 	User::LeaveIfNull((TAny*)leaving);
  1077 
  1078 	// Check-point whilst holding the open library handle
  1079 	Checkpoint(aSemaphore);
  1080 
  1081 	testThreadD.Printf(_L("D: Calling leaving function.\n"));
  1082 	(*leaving)();
  1083 
  1084 	testThreadD.Printf(_L("D: Cleaning up DLL handle.\n"));
  1085 	CleanupStack::PopAndDestroy(&ThreadDLibraryHandle);
  1086 
  1087 	testThreadD.Printf(_L("D: Cleaning up recursive leave operation.\n"));
  1088 	CleanupStack::Pop(aSemaphore); // recursive leave op
  1089 
  1090 	return KErrNone;
  1091 	}
  1092 
  1093 TInt ThreadE(TAny* aSemaphore)
  1094 	{
  1095 	__UHEAP_MARK;
  1096 	if (CheckKernelHeap)
  1097 		{
  1098 		__KHEAP_MARK;
  1099 		}
  1100 
  1101 	new (&testThreadE) RTest(KNullDesC);
  1102 	testThreadE.Start(KNullDesC);
  1103    	//
  1104    	CTrapCleanup* cleanup = CTrapCleanup::New();
  1105    	TInt r = KErrNoMemory;
  1106    	if (cleanup)
  1107    		{
  1108 		TRAP(r, DoThreadEL(aSemaphore));
  1109 
  1110 		// Check-point after closing the library handle
  1111 		Checkpoint(aSemaphore);
  1112 
  1113 		testThreadE.Printf(_L("E: Returned %d, expected %d\n"), r, KErrGeneral);
  1114 		testThreadE(r == KErrGeneral);
  1115 
  1116 		r = KErrNone;
  1117    		}
  1118 
  1119 	delete cleanup;
  1120    	//
  1121 	testThreadE.End();
  1122 	testThreadE.Close();
  1123 
  1124 	if (CheckKernelHeap)
  1125 		{
  1126 		User::After(100000);	// let supervisor run
  1127 		__KHEAP_MARKEND;
  1128 		}
  1129    	__UHEAP_MARKEND;
  1130 
  1131 	return r;
  1132 	}
  1133 
  1134 TInt DoThreadEL(TAny* aSemaphore)
  1135 	{
  1136     testThreadE.Printf(_L("E: Loading DLL.\n"));
  1137 	User::LeaveIfError(ThreadELibraryHandle.Load(KLeavingDll));
  1138 
  1139     testThreadE.Printf(_L("E: Pushing handle to dynamically loaded DLL onto the cleanup stack.\n"));
  1140 	CleanupClosePushL(ThreadELibraryHandle);
  1141 
  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));
  1144 
  1145     testThreadE.Printf(_L("E: Looking up leaving function.\n"));
  1146 	TLibraryFunction leaving = ThreadELibraryHandle.Lookup(1);
  1147 	User::LeaveIfNull((TAny*)leaving);
  1148 
  1149 	// Check-point whilst holding the open library handle
  1150 	Checkpoint(aSemaphore);
  1151 
  1152 	testThreadE.Printf(_L("E: Calling leaving function.\n"));
  1153 	(*leaving)();
  1154 
  1155 	testThreadE.Printf(_L("E: Cleaning up recursive leave operation.\n"));
  1156 	CleanupStack::Pop(aSemaphore); // recursive leave op
  1157 
  1158 	// NB: library handle removed from cleanup stack
  1159 
  1160 	return KErrNone;
  1161 	}
  1162 
  1163 TInt ThreadF(TAny* aSemaphore)
  1164 	{
  1165 	__UHEAP_MARK;
  1166 	if (CheckKernelHeap)
  1167 		{
  1168 		__KHEAP_MARK;
  1169 		}
  1170 
  1171 	new (&testThreadF) RTest(KNullDesC);
  1172 	testThreadF.Start(KNullDesC);
  1173    	//
  1174    	CTrapCleanup* cleanup = CTrapCleanup::New();
  1175    	TInt r = KErrNoMemory;
  1176    	if (cleanup)
  1177    		{
  1178 		TRAP(r, DoThreadFL(aSemaphore));
  1179 
  1180 		// Check-point after closing the library handle
  1181 		Checkpoint(aSemaphore);
  1182 
  1183 		testThreadF.Printf(_L("F: Returned %d, expected %d\n"), r, KErrGeneral);
  1184 		testThreadF(r == KErrGeneral);
  1185 
  1186 		r = KErrNone;
  1187    		}
  1188 
  1189 	delete cleanup;
  1190    	//
  1191 	testThreadF.End();
  1192 	testThreadF.Close();
  1193 
  1194 	if (CheckKernelHeap)
  1195 		{
  1196 		User::After(100000);	// let supervisor run
  1197 		__KHEAP_MARKEND;
  1198 		}
  1199    	__UHEAP_MARKEND;
  1200 
  1201 	return r;
  1202 	}
  1203 
  1204 TInt DoThreadFL(TAny* aSemaphore)
  1205 	{
  1206     testThreadF.Printf(_L("F: Loading DLL.\n"));
  1207 	User::LeaveIfError(ThreadFLibraryHandle.Load(KLeavingDll));
  1208 
  1209     testThreadF.Printf(_L("F: Pushing handle to dynamically loaded DLL onto the cleanup stack.\n"));
  1210 	CleanupClosePushL(ThreadFLibraryHandle);
  1211 
  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));
  1214 
  1215     testThreadF.Printf(_L("F: Looking up leaving function.\n"));
  1216 	TLibraryFunction leaving = ThreadFLibraryHandle.Lookup(1);
  1217 	User::LeaveIfNull((TAny*)leaving);
  1218 
  1219 	// Check-point whilst holding the open library handle
  1220 	Checkpoint(aSemaphore);
  1221 
  1222 	testThreadF.Printf(_L("F: Calling leaving function.\n"));
  1223 	(*leaving)();
  1224 
  1225 	testThreadF.Printf(_L("F: Cleaning up recursive leave operation.\n"));
  1226 	CleanupStack::Pop(aSemaphore); // recursive leave op
  1227 
  1228 	// NB: library handle removed from cleanup stack
  1229 
  1230 	return KErrNone;
  1231 	}
  1232 
  1233 TInt ThreadG(TAny* aSemaphore)
  1234 	{
  1235 	__UHEAP_MARK;
  1236 	if (CheckKernelHeap)
  1237 		{
  1238 		__KHEAP_MARK;
  1239 		}
  1240 
  1241 	new (&testThreadG) RTest(KNullDesC);
  1242 	testThreadG.Start(KNullDesC);
  1243    	//
  1244    	CTrapCleanup* cleanup = CTrapCleanup::New();
  1245    	TInt r = KErrNoMemory;
  1246    	if (cleanup)
  1247    		{
  1248 		TRAP(r, DoThreadGL(aSemaphore));
  1249 
  1250 		// Check-point after closing the library handle
  1251 		Checkpoint(aSemaphore);
  1252 
  1253 		testThreadG.Printf(_L("G: Returned %d, expected %d\n"), r, KErrGeneral);
  1254 		testThreadG(r == KErrGeneral);
  1255 
  1256 		r = KErrNone;
  1257    		}
  1258 
  1259 	delete cleanup;
  1260    	//
  1261 	testThreadG.End();
  1262 	testThreadG.Close();
  1263 
  1264 	if (CheckKernelHeap)
  1265 		{
  1266 		User::After(100000);	// let supervisor run
  1267 		__KHEAP_MARKEND;
  1268 		}
  1269    	__UHEAP_MARKEND;
  1270 
  1271 	return r;
  1272 	}
  1273 
  1274 TInt DoThreadGL(TAny* aSemaphore)
  1275 	{
  1276     testThreadG.Printf(_L("G: Loading DLL.\n"));
  1277 	User::LeaveIfError(ThreadGLibraryHandle.Load(KLeavingDll));
  1278 
  1279     testThreadG.Printf(_L("G: Pushing cleanup item to synchronise after closing library handle.\n"));
  1280 	CleanupStack::PushL(TCleanupItem(&PauseLeaving, aSemaphore));
  1281 
  1282     testThreadG.Printf(_L("G: Pushing handle to dynamically loaded DLL onto the cleanup stack.\n"));
  1283 	CleanupClosePushL(ThreadGLibraryHandle);
  1284 
  1285 	testThreadG.Printf(_L("G: Pushing cleanup item to recursively leave, doing nothing, before closing handle\n"));
  1286 	CleanupStack::PushL(TCleanupItem(&TrapLeave, aSemaphore));
  1287 
  1288     testThreadG.Printf(_L("G: Looking up leaving function.\n"));
  1289 	TLibraryFunction leaving = ThreadGLibraryHandle.Lookup(1);
  1290 	User::LeaveIfNull((TAny*)leaving);
  1291 
  1292 	// Check-point whilst holding the open library handle
  1293 	Checkpoint(aSemaphore);
  1294 
  1295 	testThreadG.Printf(_L("G: Calling leaving function.\n"));
  1296 	(*leaving)();
  1297 
  1298 	testThreadG.Printf(_L("G: Cleaning up recursive leave operation.\n"));
  1299 	CleanupStack::Pop(aSemaphore); // trap leave op
  1300 
  1301 	testThreadG.Printf(_L("G: Cleaning up DLL handle.\n"));
  1302 	CleanupStack::PopAndDestroy(&ThreadGLibraryHandle);
  1303 
  1304 	return KErrNone;
  1305 	}
  1306 
  1307 TInt ThreadH(TAny* aSemaphore)
  1308 	{
  1309 	__UHEAP_MARK;
  1310 	if (CheckKernelHeap)
  1311 		{
  1312 		__KHEAP_MARK;
  1313 		}
  1314 
  1315 	new (&testThreadH) RTest(KNullDesC);
  1316 	testThreadH.Start(KNullDesC);
  1317    	//
  1318    	CTrapCleanup* cleanup = CTrapCleanup::New();
  1319    	TInt r = KErrNoMemory;
  1320    	if (cleanup)
  1321    		{
  1322 		TRAP(r, DoThreadHL(aSemaphore));
  1323 
  1324 		// Check-point after closing the library handle
  1325 		Checkpoint(aSemaphore);
  1326 
  1327 		testThreadH.Printf(_L("H: Returned %d, expected %d\n"), r, KErrGeneral);
  1328 		testThreadH(r == KErrGeneral);
  1329 
  1330 		r = KErrNone;
  1331    		}
  1332 
  1333 	delete cleanup;
  1334    	//
  1335 	testThreadH.End();
  1336 	testThreadH.Close();
  1337 
  1338 	if (CheckKernelHeap)
  1339 		{
  1340 		User::After(100000);	// let supervisor run
  1341 		__KHEAP_MARKEND;
  1342 		}
  1343    	__UHEAP_MARKEND;
  1344 
  1345 	return r;
  1346 	}
  1347 
  1348 TInt DoThreadHL(TAny* aSemaphore)
  1349 	{
  1350     testThreadH.Printf(_L("H: Loading DLL.\n"));
  1351 	User::LeaveIfError(ThreadHLibraryHandle.Load(KLeavingDll));
  1352 
  1353     testThreadH.Printf(_L("H: Pushing cleanup item to synchronise after closing library handle.\n"));
  1354 	CleanupStack::PushL(TCleanupItem(&PauseLeaving, aSemaphore));
  1355 
  1356     testThreadH.Printf(_L("H: Pushing handle to dynamically loaded DLL onto the cleanup stack.\n"));
  1357 	CleanupClosePushL(ThreadHLibraryHandle);
  1358 
  1359 	testThreadH.Printf(_L("H: Pushing cleanup item to synchronise during leave\n"));
  1360 	CleanupStack::PushL(TCleanupItem(&PauseLeaving, aSemaphore));
  1361 
  1362     testThreadH.Printf(_L("H: Looking up leaving function.\n"));
  1363 	TLibraryFunction leaving = ThreadHLibraryHandle.Lookup(1);
  1364 	User::LeaveIfNull((TAny*)leaving);
  1365 
  1366 	// Check-point whilst holding the open library handle
  1367 	Checkpoint(aSemaphore);
  1368 
  1369 	testThreadH.Printf(_L("H: Calling leaving function.\n"));
  1370 	(*leaving)();
  1371 
  1372 	testThreadH.Printf(_L("H: Cleaning up leave pausing operation.\n"));
  1373 	CleanupStack::Pop(aSemaphore); // pause leave op
  1374 
  1375 	testThreadH.Printf(_L("H: Cleaning up DLL handle.\n"));
  1376 	CleanupStack::PopAndDestroy(&ThreadHLibraryHandle);
  1377 
  1378 	return KErrNone;
  1379 	}
  1380 
  1381 TInt ThreadI(TAny* aSemaphore)
  1382 	{
  1383 	__UHEAP_MARK;
  1384 	if (CheckKernelHeap)
  1385 		{
  1386 		__KHEAP_MARK;
  1387 		}
  1388 
  1389 	new (&testThreadI) RTest(KNullDesC);
  1390 	testThreadI.Start(KNullDesC);
  1391    	//
  1392    	CTrapCleanup* cleanup = CTrapCleanup::New();
  1393    	TInt r = KErrNoMemory;
  1394    	if (cleanup)
  1395    		{
  1396 		TRAP(r, DoThreadIL(aSemaphore));
  1397 
  1398 		// Check-point after closing the library handle
  1399 		Checkpoint(aSemaphore);
  1400 
  1401 		testThreadI.Printf(_L("I: Returned %d, expected %d\n"), r, KErrGeneral);
  1402 		testThreadI(r == KErrGeneral);
  1403 
  1404 		r = KErrNone;
  1405    		}
  1406 
  1407 	delete cleanup;
  1408    	//
  1409 	testThreadI.End();
  1410 	testThreadI.Close();
  1411 
  1412 	if (CheckKernelHeap)
  1413 		{
  1414 		User::After(100000);	// let supervisor run
  1415 		__KHEAP_MARKEND;
  1416 		}
  1417    	__UHEAP_MARKEND;
  1418 
  1419 	return r;
  1420 	}
  1421 
  1422 TInt DoThreadIL(TAny* aSemaphore)
  1423 	{
  1424     testThreadI.Printf(_L("I: Loading DLL.\n"));
  1425 	User::LeaveIfError(ThreadILibraryHandle.Load(KLeavingDll));
  1426 
  1427 	testThreadI.Printf(_L("I: Pushing cleanup item to recursively leave, doing nothing, after closing handle\n"));
  1428 	CleanupStack::PushL(TCleanupItem(&TrapLeave, aSemaphore));
  1429 
  1430     testThreadI.Printf(_L("I: Pushing handle to dynamically loaded DLL onto the cleanup stack.\n"));
  1431 	CleanupClosePushL(ThreadILibraryHandle);
  1432 
  1433 	testThreadI.Printf(_L("I: Pushing cleanup item to synchronise during leave\n"));
  1434 	CleanupStack::PushL(TCleanupItem(&PauseLeaving, aSemaphore));
  1435 
  1436     testThreadI.Printf(_L("I: Looking up leaving function.\n"));
  1437 	TLibraryFunction leaving = ThreadILibraryHandle.Lookup(1);
  1438 	User::LeaveIfNull((TAny*)leaving);
  1439 
  1440 	// Check-point whilst holding the open library handle
  1441 	Checkpoint(aSemaphore);
  1442 
  1443 	testThreadI.Printf(_L("I: Calling leaving function.\n"));
  1444 	(*leaving)();
  1445 
  1446 	testThreadI.Printf(_L("I: Cleaning up leave pausing operation.\n"));
  1447 	CleanupStack::Pop(aSemaphore); // pause leave op
  1448 
  1449 	testThreadI.Printf(_L("I: Cleaning up DLL handle.\n"));
  1450 	CleanupStack::PopAndDestroy(&ThreadILibraryHandle);
  1451 
  1452 	testThreadI.Printf(_L("I: Cleaning up recursive leave operation.\n"));
  1453 	CleanupStack::Pop(); // trap leave op
  1454 
  1455 	return KErrNone;
  1456 	}
  1457 
  1458 TInt ThreadJ(TAny* aSemaphore)
  1459 	{
  1460 	__UHEAP_MARK;
  1461 	if (CheckKernelHeap)
  1462 		{
  1463 		__KHEAP_MARK;
  1464 		}
  1465 
  1466 	new (&testThreadJ) RTest(KNullDesC);
  1467 	testThreadJ.Start(KNullDesC);
  1468    	//
  1469    	CTrapCleanup* cleanup = CTrapCleanup::New();
  1470    	TInt r = KErrNoMemory;
  1471    	if (cleanup)
  1472    		{
  1473 		TRAP(r, DoThreadJL(aSemaphore));
  1474 
  1475 		// Check-point after closing the library handle
  1476 		Checkpoint(aSemaphore);
  1477 
  1478 		testThreadJ.Printf(_L("J: Returned %d, expected %d\n"), r, KErrGeneral);
  1479 		testThreadJ(r == KErrGeneral);
  1480 
  1481 		r = KErrNone;
  1482    		}
  1483 
  1484 	delete cleanup;
  1485    	//
  1486 	testThreadJ.End();
  1487 	testThreadJ.Close();
  1488 
  1489 	if (CheckKernelHeap)
  1490 		{
  1491 		User::After(100000);	// let supervisor run
  1492 		__KHEAP_MARKEND;
  1493 		}
  1494    	__UHEAP_MARKEND;
  1495 
  1496 	return r;
  1497 	}
  1498 
  1499 TInt DoThreadJL(TAny* aSemaphore)
  1500 	{
  1501     testThreadJ.Printf(_L("J: Loading DLL.\n"));
  1502 	User::LeaveIfError(ThreadJLibraryHandle.Load(KLeavingDll));
  1503 
  1504 	testThreadJ.Printf(_L("J: Pushing cleanup item to recursively leave and panic, after closing handle\n"));
  1505 	CleanupStack::PushL(TCleanupItem(&TrapLeaveAndDie, aSemaphore));
  1506 
  1507     testThreadJ.Printf(_L("J: Pushing handle to dynamically loaded DLL onto the cleanup stack.\n"));
  1508 	CleanupClosePushL(ThreadJLibraryHandle);
  1509 
  1510 	testThreadJ.Printf(_L("J: Pushing cleanup item to synchronise during leave\n"));
  1511 	CleanupStack::PushL(TCleanupItem(&PauseLeaving, aSemaphore));
  1512 
  1513     testThreadJ.Printf(_L("J: Looking up leaving function.\n"));
  1514 	TLibraryFunction leaving = ThreadJLibraryHandle.Lookup(1);
  1515 	User::LeaveIfNull((TAny*)leaving);
  1516 
  1517 	// Check-point whilst holding the open library handle
  1518 	Checkpoint(aSemaphore);
  1519 
  1520 	testThreadJ.Printf(_L("J: Calling leaving function.\n"));
  1521 	(*leaving)();
  1522 
  1523 	testThreadJ.Printf(_L("J: Cleaning up leave pausing operation.\n"));
  1524 	CleanupStack::Pop(aSemaphore); // pause leave op
  1525 
  1526 	testThreadJ.Printf(_L("J: Cleaning up DLL handle.\n"));
  1527 	CleanupStack::PopAndDestroy(&ThreadJLibraryHandle);
  1528 
  1529 	testThreadJ.Printf(_L("J: Cleaning up recursive leave operation.\n"));
  1530 	CleanupStack::Pop(); // leave and die op
  1531 
  1532 	return KErrNone;
  1533 	}
  1534 
  1535 TInt ThreadK(TAny* aSemaphore)
  1536 	{
  1537 	__UHEAP_MARK;
  1538 	if (CheckKernelHeap)
  1539 		{
  1540 		__KHEAP_MARK;
  1541 		}
  1542 
  1543 	new (&testThreadK) RTest(KNullDesC);
  1544 	testThreadK.Start(KNullDesC);
  1545    	//
  1546    	CTrapCleanup* cleanup = CTrapCleanup::New();
  1547    	TInt r = KErrNoMemory;
  1548    	if (cleanup)
  1549    		{
  1550 		TRAP(r, DoThreadKL(aSemaphore));
  1551 
  1552 		// Check-point after closing the library handle
  1553 		Checkpoint(aSemaphore);
  1554 
  1555 		testThreadK.Printf(_L("K: Returned %d, expected %d\n"), r, KErrGeneral);
  1556 		testThreadK(r == KErrGeneral);
  1557 
  1558 		r = KErrNone;
  1559    		}
  1560 
  1561 	delete cleanup;
  1562    	//
  1563 	testThreadK.End();
  1564 	testThreadK.Close();
  1565 
  1566 	if (CheckKernelHeap)
  1567 		{
  1568 		User::After(100000);	// let supervisor run
  1569 		__KHEAP_MARKEND;
  1570 		}
  1571    	__UHEAP_MARKEND;
  1572 
  1573 	return r;
  1574 	}
  1575 
  1576 TInt DoThreadKL(TAny* aSemaphore)
  1577 	{
  1578     testThreadK.Printf(_L("K: Loading DLL.\n"));
  1579 	User::LeaveIfError(ThreadKLibraryHandle.Load(KLeavingDll));
  1580 
  1581 	testThreadK.Printf(_L("K: Pushing cleanup item to panic, after closing handle\n"));
  1582 	CleanupStack::PushL(TCleanupItem(&DieDieDie, aSemaphore));
  1583 
  1584     testThreadK.Printf(_L("K: Pushing handle to dynamically loaded DLL onto the cleanup stack.\n"));
  1585 	CleanupClosePushL(ThreadKLibraryHandle);
  1586 
  1587 	testThreadK.Printf(_L("K: Pushing cleanup item to synchronise during leave\n"));
  1588 	CleanupStack::PushL(TCleanupItem(&PauseLeaving, aSemaphore));
  1589 
  1590     testThreadK.Printf(_L("K: Looking up leaving function.\n"));
  1591 	TLibraryFunction leaving = ThreadKLibraryHandle.Lookup(1);
  1592 	User::LeaveIfNull((TAny*)leaving);
  1593 
  1594 	// Check-point whilst holding the open library handle
  1595 	Checkpoint(aSemaphore);
  1596 
  1597 	testThreadK.Printf(_L("K: Calling leaving function.\n"));
  1598 	(*leaving)();
  1599 
  1600 	testThreadK.Printf(_L("K: Cleaning up leave pausing operation.\n"));
  1601 	CleanupStack::Pop(aSemaphore); // pause leave op
  1602 
  1603 	testThreadK.Printf(_L("K: Cleaning up DLL handle.\n"));
  1604 	CleanupStack::PopAndDestroy(&ThreadKLibraryHandle);
  1605 
  1606 	testThreadK.Printf(_L("K: Cleaning up panic operation.\n"));
  1607 	CleanupStack::Pop(); // die op
  1608 
  1609 	return KErrNone;
  1610 	}