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