kerneltest/e32test/cppexceptions/t_unmap.cpp
changeset 0 a41df078684a
child 293 0659d0e1a03c
equal deleted inserted replaced
-1:000000000000 0:a41df078684a
       
     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 	}