os/kernelhwsrv/kerneltest/e32test/mmu/t_codepaging.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) 2006-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\mmu\t_codepaging.cpp
sl@0
    15
// This test relies on four dlls which it loads dynamically:
sl@0
    16
// - t_codepaging_dll		Very simple dll, contains a single function.  Used for testing state
sl@0
    17
// changes	of pages
sl@0
    18
// - t_codepaging_dll2	 	Contains 8 pages of data, used for testing the correct data is paged
sl@0
    19
// - t_codepaging_dll3		Statically links to t_codepaging_sll, used for testing ReadExportDir
sl@0
    20
// - t_codepaging_dll4		Large dll, used for testing code segment that span more than one page
sl@0
    21
// table
sl@0
    22
// - t_codepaging_dll5		Contains relocatable const data.
sl@0
    23
// - t_codepaging_dll6		Contains relocatable writable data.
sl@0
    24
// - t_codepaging_dll7		Statically linked to t_codepaging_dll5 to check dependent DLLs
sl@0
    25
// are initialised correctly.
sl@0
    26
// Suite of tests specifically to test the code paging portion of demand 
sl@0
    27
// paging.
sl@0
    28
// 002 Exercise ReadExportDir with one code seg mapped already into current process
sl@0
    29
// 003 Exercise ReadExportDir with one code seg mapped into different process
sl@0
    30
// 004 Check locking of code which then gets unloaded
sl@0
    31
// 004.01 Load test driver...
sl@0
    32
// 004.02 Load/unload dll
sl@0
    33
// 004.03 Load dll again
sl@0
    34
// 004.04 Get data from DLL
sl@0
    35
// 004.05 Lock DLL data
sl@0
    36
// 004.06 Check DLL data
sl@0
    37
// 004.07 Close DLL
sl@0
    38
// 004.08 Check DLL loaded at different address
sl@0
    39
// 004.09 Unlock DLL data
sl@0
    40
// 004.10 Check DLL loaded at original address
sl@0
    41
// 004.11 Cleanup
sl@0
    42
// 005 Test writing to paged code
sl@0
    43
// 005.01 Load DLL
sl@0
    44
// 005.02 Get data from DLL
sl@0
    45
// 005.03 Write to pages in DLL
sl@0
    46
// 006 Running tests on drive I:
sl@0
    47
// 007 Test accessing pages by executing code
sl@0
    48
// 008 Test accessing pages by reading code
sl@0
    49
// 009 Test accessing pages by reading code from another process via an alias
sl@0
    50
// 010 Test unmapping paged code
sl@0
    51
// 011 Test interactions between two processes
sl@0
    52
// 012 Test that the contents of a paged DLL are as expected
sl@0
    53
// 013 Test relocated const data in DLL
sl@0
    54
// 014 Test relocated writable data in DLL
sl@0
    55
// 015 Test relocated writable data in dependent DLL
sl@0
    56
// 016 Test relocated writable data in preloaded dependent DLL
sl@0
    57
// 017 Test relocated writable data in preloaded dependent DLL opened in other process
sl@0
    58
// 018 Test killing a thread while it is taking paging faults
sl@0
    59
// 019 Test unloading a library while another thread is executing it
sl@0
    60
// 020 Test random access to a large dll
sl@0
    61
// 021 Test accessing paged code from 2 processes at 1 priority level(s) for 5 seconds
sl@0
    62
// 022 Test accessing paged code from 5 processes at 1 priority level(s) for 10 seconds
sl@0
    63
// 023 Test accessing paged code from 10 processes at 1 priority level(s) for 20 seconds
sl@0
    64
// 024 Test accessing paged code from 5 processes at 2 priority level(s) for 10 seconds
sl@0
    65
// 025 Test accessing paged code from 50 processes at 1 priority level(s) for 2 seconds
sl@0
    66
// 026 Running tests on drive Z:
sl@0
    67
// 027 Test accessing pages by executing code
sl@0
    68
// 028 Test accessing pages by reading code
sl@0
    69
// 029 Test accessing pages by reading code from another process via an alias
sl@0
    70
// 030 Test unmapping paged code
sl@0
    71
// 031 Test interactions between two processes
sl@0
    72
// 032 Test that the contents of a paged DLL are as expected
sl@0
    73
// 033 Test relocated const data in DLL
sl@0
    74
// 034 Test relocated writable data in DLL
sl@0
    75
// 035 Test relocated writable data in dependent DLL
sl@0
    76
// 036 Test relocated writable data in preloaded dependent DLL
sl@0
    77
// 037 Test relocated writable data in preloaded dependent DLL opened in other process
sl@0
    78
// 038 Test killing a thread while it is taking paging faults
sl@0
    79
// 039 Test unloading a library while another thread is executing it
sl@0
    80
// 040 Test random access to a large dll
sl@0
    81
// 041 Test accessing paged code from 2 processes at 1 priority level(s) for 5 seconds
sl@0
    82
// 042 Test accessing paged code from 5 processes at 1 priority level(s) for 10 seconds
sl@0
    83
// 043 Test accessing paged code from 10 processes at 1 priority level(s) for 20 seconds
sl@0
    84
// 044 Test accessing paged code from 5 processes at 2 priority level(s) for 10 seconds
sl@0
    85
// 045 Test accessing paged code from 50 processes at 1 priority level(s) for 2 seconds
sl@0
    86
// 
sl@0
    87
//
sl@0
    88
sl@0
    89
//! @SYMTestCaseID			KBASE-T_CODEPAGING-0335
sl@0
    90
//! @SYMTestType			UT
sl@0
    91
//! @SYMPREQ				PREQ1110
sl@0
    92
//! @SYMTestCaseDesc		Demand Paging Code Paging tests.
sl@0
    93
//! @SYMTestActions			001 Code paging tests
sl@0
    94
//! @SYMTestExpectedResults All tests should pass.
sl@0
    95
//! @SYMTestPriority        High
sl@0
    96
//! @SYMTestStatus          Implemented
sl@0
    97
sl@0
    98
sl@0
    99
#define __E32TEST_EXTENSION__
sl@0
   100
#include <e32test.h>
sl@0
   101
#include <f32file.h>
sl@0
   102
#include <e32math.h>
sl@0
   103
#include <dptest.h>
sl@0
   104
sl@0
   105
#include "mmudetect.h"
sl@0
   106
#include "d_memorytest.h"
sl@0
   107
#include "d_demandpaging.h"
sl@0
   108
#include "t_codepaging_dll.h"
sl@0
   109
#include "paging_info.h"
sl@0
   110
sl@0
   111
class TPagingDriveInfo
sl@0
   112
	{
sl@0
   113
public:
sl@0
   114
	TChar iDriveLetter;
sl@0
   115
	TDriveInfo iDriveInfo;
sl@0
   116
	};
sl@0
   117
sl@0
   118
RArray<TPagingDriveInfo> SupportedDrives;
sl@0
   119
sl@0
   120
/// Page attributes, cut-n-paste'd from mmubase.h
sl@0
   121
enum TType
sl@0
   122
	{
sl@0
   123
//	EInvalid=0,			// No physical RAM exists for this page
sl@0
   124
//	EFixed=1,			// RAM fixed at boot time
sl@0
   125
//	EUnused=2,			// Page is unused
sl@0
   126
//	EChunk=3,
sl@0
   127
//	ECodeSeg=4,
sl@0
   128
//	EHwChunk=5,
sl@0
   129
//	EPageTable=6,
sl@0
   130
//	EPageDir=7,
sl@0
   131
//	EPtInfo=8,
sl@0
   132
//	EShadow=9,
sl@0
   133
sl@0
   134
	EPagedROM=10,
sl@0
   135
	EPagedCode=11,
sl@0
   136
	EPagedData=12,
sl@0
   137
	EPagedCache=13,
sl@0
   138
	EPagedFree=14,
sl@0
   139
	};
sl@0
   140
sl@0
   141
enum TState
sl@0
   142
	{
sl@0
   143
	EStateNormal 			= 0,	// no special state
sl@0
   144
	EStatePagedYoung 		= 1,
sl@0
   145
	EStatePagedOld 			= 2,
sl@0
   146
	EStatePagedDead 		= 3,	// Not possible on the flexible memory model.
sl@0
   147
	EStatePagedLocked 		= 4,
sl@0
   148
	EStatePagedOldestClean 	= 5,	// Flexible memory model only.
sl@0
   149
	EStatePagedOldestDirty 	= 6,	// Flexible memory model only.
sl@0
   150
	};
sl@0
   151
sl@0
   152
sl@0
   153
sl@0
   154
/// The possible states for a logical page of RAM loaded code
sl@0
   155
enum TPageState
sl@0
   156
	{
sl@0
   157
	EStateUnmapped,
sl@0
   158
	EStatePagedOut,
sl@0
   159
	EStateYoung,
sl@0
   160
	EStateOld,
sl@0
   161
	EStateOldestClean,
sl@0
   162
	EStateOldestDirty,
sl@0
   163
sl@0
   164
	ENumPageStates
sl@0
   165
	};
sl@0
   166
sl@0
   167
const TUint KPagedStateShift = 8;
sl@0
   168
const TUint KPagedStateMask = 0xff00;
sl@0
   169
sl@0
   170
sl@0
   171
/// The possible states for a physical page of RAM loaded code
sl@0
   172
enum TPhysState
sl@0
   173
	{
sl@0
   174
	EPhysNotPresent,
sl@0
   175
	EPhysYoung,
sl@0
   176
	EPhysOld,
sl@0
   177
	EPhysOldestClean,
sl@0
   178
	EPhysOldestDirty,
sl@0
   179
sl@0
   180
	ENumPhysStates
sl@0
   181
	};
sl@0
   182
sl@0
   183
/// Names of the logical page states
sl@0
   184
const char* StateNames[ENumPageStates] =
sl@0
   185
	{
sl@0
   186
	"Unmapped",
sl@0
   187
	"PagedOut",
sl@0
   188
	"Young",
sl@0
   189
	"Old",
sl@0
   190
	"OldestClean",
sl@0
   191
	"OldestDirty"
sl@0
   192
	};
sl@0
   193
sl@0
   194
/// Names of the physical page states
sl@0
   195
const char* PhysStateNames[ENumPhysStates] =
sl@0
   196
	{
sl@0
   197
	"NotPresent",
sl@0
   198
	"Young",
sl@0
   199
	"Old",
sl@0
   200
	"OldestClean",
sl@0
   201
	"OldestDirty"
sl@0
   202
	};
sl@0
   203
sl@0
   204
/// Array of physical page states indexed by logical page state
sl@0
   205
TPhysState PhysStateFromPageState[ENumPageStates] =
sl@0
   206
	{
sl@0
   207
	EPhysNotPresent,
sl@0
   208
	EPhysNotPresent,
sl@0
   209
	EPhysYoung,
sl@0
   210
	EPhysOld,
sl@0
   211
	EPhysOldestClean,
sl@0
   212
	EPhysOldestDirty,
sl@0
   213
	};
sl@0
   214
sl@0
   215
/// The expected logical page state bitmask for each state
sl@0
   216
TInt ExpectedPageState[ENumPageStates] =
sl@0
   217
	{
sl@0
   218
	0,
sl@0
   219
	EPageStatePageTablePresent | EPageStateInRamCode | EPageStatePaged,
sl@0
   220
	EPageStatePageTablePresent | EPageStateInRamCode | EPageStatePaged | EPageStatePtePresent | EPageStatePteValid,
sl@0
   221
	EPageStatePageTablePresent | EPageStateInRamCode | EPageStatePaged | EPageStatePtePresent,
sl@0
   222
	EPageStatePageTablePresent | EPageStateInRamCode | EPageStatePaged | EPageStatePtePresent,
sl@0
   223
	EPageStatePageTablePresent | EPageStateInRamCode | EPageStatePaged | EPageStatePtePresent
sl@0
   224
	};
sl@0
   225
sl@0
   226
/// Extra bits we expect to be set on the multiple memory model
sl@0
   227
TInt ExpectedPageStateMultipleExtra[ENumPageStates] =
sl@0
   228
	{
sl@0
   229
	EPageStateCodeChunkPresent,
sl@0
   230
	EPageStateCodeChunkPresent,
sl@0
   231
	EPageStateCodeChunkPresent | EPageStatePhysAddrPresent,
sl@0
   232
	EPageStateCodeChunkPresent | EPageStatePhysAddrPresent
sl@0
   233
	};
sl@0
   234
sl@0
   235
/// Mask for the bits of the page state related to the physicsal page that we check
sl@0
   236
TInt PhysStateMask = 0xffff;
sl@0
   237
sl@0
   238
/// The expected physical page state bitmask for each state
sl@0
   239
TInt ExpectedPhysState[ENumPhysStates] =
sl@0
   240
	{
sl@0
   241
	0,
sl@0
   242
	EPagedCode | (EStatePagedYoung<<8),
sl@0
   243
	EPagedCode | (EStatePagedOld<<8),
sl@0
   244
	EPagedCode | (EStatePagedOldestClean<<8),
sl@0
   245
	EPagedCode | (EStatePagedOldestDirty<<8)
sl@0
   246
	};
sl@0
   247
sl@0
   248
typedef void (*TFunc)(void);
sl@0
   249
typedef void (*TFunc1)(TInt aArg1);
sl@0
   250
typedef TFunc TTransitionTable[ENumPageStates][ENumPageStates];
sl@0
   251
sl@0
   252
void LoadLibrary();
sl@0
   253
void UnloadLibrary();
sl@0
   254
void AccessPage();
sl@0
   255
void MakeOld();
sl@0
   256
void MakeOldest();
sl@0
   257
void MakePagedOut();
sl@0
   258
sl@0
   259
TTransitionTable StateTransitions =
sl@0
   260
	{
sl@0
   261
// Current:			Next:	EStateUnmapped	EStatePagedOut	EStateYoung		EStateOld	EStateOldestClean	EStateOldestDirty	
sl@0
   262
/* EStateUnmapped 	*/	{	0,				LoadLibrary,	0,				0,			0,					0			},
sl@0
   263
/* EStatePagedOut	*/	{	UnloadLibrary,	0,				AccessPage,		0,			0,					0			},
sl@0
   264
/* EStateYoung		*/	{	UnloadLibrary,	MakePagedOut,	AccessPage,		MakeOld,	0,					0			},
sl@0
   265
/* EStateOld		*/	{	UnloadLibrary,	MakePagedOut,	AccessPage,		0,			MakeOldest,			MakeOldest	},
sl@0
   266
/* EStateOldestClean*/	{	UnloadLibrary,	MakePagedOut,	AccessPage,		0,			0,					0			},
sl@0
   267
/* EStateOldestDirty*/	{	UnloadLibrary,	MakePagedOut,	AccessPage,		0,			0,					0			},
sl@0
   268
	};
sl@0
   269
sl@0
   270
const TInt KMaxPathLen = 16;
sl@0
   271
typedef TPageState TStatePath[KMaxPathLen];
sl@0
   272
sl@0
   273
// Test paths through the possible states that excercises all transitions except those back to unmapped
sl@0
   274
// Doesn't consider dirty pages.
sl@0
   275
TStatePath TestPathNoOldest =
sl@0
   276
	{
sl@0
   277
	EStateUnmapped,
sl@0
   278
	EStatePagedOut,
sl@0
   279
	EStateYoung,
sl@0
   280
	EStateOld,
sl@0
   281
	EStateYoung,
sl@0
   282
	EStateOld,
sl@0
   283
	EStatePagedOut,
sl@0
   284
	EStateUnmapped,
sl@0
   285
	};
sl@0
   286
sl@0
   287
TStatePath TestPathOldest =
sl@0
   288
	{
sl@0
   289
	EStateUnmapped,
sl@0
   290
	EStatePagedOut,
sl@0
   291
	EStateYoung,
sl@0
   292
	EStateOld,
sl@0
   293
	EStateOldestClean,
sl@0
   294
	EStateYoung,
sl@0
   295
	EStateOld,
sl@0
   296
	EStateYoung,
sl@0
   297
	EStateOld,
sl@0
   298
	EStatePagedOut,
sl@0
   299
	EStateYoung,
sl@0
   300
	EStateOld,
sl@0
   301
	EStateOldestClean,
sl@0
   302
	EStatePagedOut,
sl@0
   303
	EStateUnmapped,
sl@0
   304
	};
sl@0
   305
sl@0
   306
TStatePath* TestPath = NULL;
sl@0
   307
sl@0
   308
/// The different ways of accessing paged code
sl@0
   309
enum TAccessMethod
sl@0
   310
	{
sl@0
   311
	EAccessExec,
sl@0
   312
	EAccessRead,
sl@0
   313
	EAccessAliasRead
sl@0
   314
	};
sl@0
   315
sl@0
   316
_LIT(KLibraryName, "t_codepaging_dll");
sl@0
   317
_LIT(KSearchPathTemplate, "?:\\sys\\bin");
sl@0
   318
sl@0
   319
// RTest stuff /////////////////////////////////////////////////////////////////
sl@0
   320
sl@0
   321
RTest test(_L("T_CODEPAGING"));
sl@0
   322
sl@0
   323
#define test_noError(x) { TInt _r = (x); if (_r < 0) HandleError(_r, __LINE__); }
sl@0
   324
#define test_notNull(x) { TAny* _a = (TAny*)(x); if (_a == NULL) HandleNull(__LINE__); }
sl@0
   325
#define test_equal(e, a) { TInt _e = TInt(e); TInt _a = TInt(a); if (_e != _a) HandleNotEqual(_e, _a, __LINE__); }
sl@0
   326
sl@0
   327
void HandleError(TInt aError, TInt aLine)
sl@0
   328
	{
sl@0
   329
	test.Printf(_L("Error %d\n"), aError);
sl@0
   330
	test.operator()(EFalse, aLine);
sl@0
   331
	}
sl@0
   332
sl@0
   333
void HandleNull(TInt aLine)
sl@0
   334
	{
sl@0
   335
	test.Printf(_L("Null value\n"));
sl@0
   336
	test.operator()(EFalse, aLine);
sl@0
   337
	}
sl@0
   338
sl@0
   339
void HandleNotEqual(TInt aExpected, TInt aActual, TInt aLine)
sl@0
   340
	{
sl@0
   341
	test.Printf(_L("Expected 0x%x but got 0x%x\n"), aExpected, aActual);
sl@0
   342
	test.operator()(EFalse, aLine);
sl@0
   343
	}
sl@0
   344
sl@0
   345
//  Server session /////////////////////////////////////////////////////////////
sl@0
   346
sl@0
   347
_LIT(KServerName, "t_codepaging_server");
sl@0
   348
sl@0
   349
class RTestSession : public RSessionBase
sl@0
   350
	{
sl@0
   351
public:
sl@0
   352
	enum TMessage
sl@0
   353
		{
sl@0
   354
		EKill,
sl@0
   355
		EExec,
sl@0
   356
		ESetCurrentDrive,
sl@0
   357
		EDesRead,
sl@0
   358
		ETestPageState,
sl@0
   359
		ETestStateTransition,
sl@0
   360
		EStartRandomAccessThread
sl@0
   361
		};
sl@0
   362
public:
sl@0
   363
	TInt Connect(TInt aProcessNum);
sl@0
   364
	inline void Kill()
sl@0
   365
		{ test_noError(RSessionBase::SendReceive(EKill,TIpcArgs())); }
sl@0
   366
	inline void Exec(TFunc aFunc)
sl@0
   367
		{ test_noError(RSessionBase::SendReceive(EExec,TIpcArgs((TInt)aFunc))); }
sl@0
   368
	inline void SetCurrentDrive(TUint16 aDrive)
sl@0
   369
		{ test_noError(RSessionBase::SendReceive(ESetCurrentDrive,TIpcArgs(aDrive))); }
sl@0
   370
	inline void DesRead(const TDesC8& aData)
sl@0
   371
		{ test_noError(RSessionBase::SendReceive(EDesRead,TIpcArgs(&aData))); }
sl@0
   372
	inline void TestPageState(TPageState aState, TPhysState aPhysState)
sl@0
   373
		{ test_noError(RSessionBase::SendReceive(ETestPageState,TIpcArgs(aState, aPhysState))); }
sl@0
   374
	inline void TestStateTransition(TPageState aState)
sl@0
   375
		{ test_noError(RSessionBase::SendReceive(ETestStateTransition,TIpcArgs(aState))); }
sl@0
   376
	inline void StartRandomAccessThread(TThreadPriority aPriority)
sl@0
   377
		{ test_noError(RSessionBase::SendReceive(EStartRandomAccessThread,TIpcArgs(aPriority))); }
sl@0
   378
	};
sl@0
   379
sl@0
   380
TInt RTestSession::Connect(TInt aProcessNum)
sl@0
   381
	{
sl@0
   382
	TBuf<32> name;
sl@0
   383
	name.AppendFormat(_L("%S-%d"), &KServerName, aProcessNum);
sl@0
   384
	return CreateSession(name,TVersion());
sl@0
   385
	}
sl@0
   386
sl@0
   387
sl@0
   388
// Global data /////////////////////////////////////////////////////////////////
sl@0
   389
sl@0
   390
TBool MovingMemoryModel;
sl@0
   391
TBool MultipleMemoryModel;
sl@0
   392
TBool FlexibleMemoryModel;
sl@0
   393
TBool HaveOldestLists;
sl@0
   394
TInt ProcessNum;
sl@0
   395
sl@0
   396
RTestSession OtherProcess;
sl@0
   397
sl@0
   398
RLibrary PagedLibrary;
sl@0
   399
TBool LibraryLoaded = EFalse;
sl@0
   400
sl@0
   401
TTestFunction Library_TestFunction = NULL;
sl@0
   402
sl@0
   403
TAccessMethod AccessMethod;
sl@0
   404
sl@0
   405
RLibrary LargeLibrary;
sl@0
   406
TBool LargeLibraryLoaded = EFalse;
sl@0
   407
const TUint8* LargeDataStart;
sl@0
   408
const TUint8* LargeDataEnd;
sl@0
   409
const TUint8* LargeDataPtr;
sl@0
   410
TInt PagesReadSinceLastAccess = 0;
sl@0
   411
sl@0
   412
TInt LiveListSize;
sl@0
   413
TInt PageSize;
sl@0
   414
sl@0
   415
TPageState State;
sl@0
   416
TPhysState PhysState;
sl@0
   417
sl@0
   418
TUint16 CurrentDrive;
sl@0
   419
TInt LocalDriveNumber;
sl@0
   420
sl@0
   421
RThread RandomAccessThread;
sl@0
   422
volatile TBool RandomAccessKill = EFalse;
sl@0
   423
sl@0
   424
TBool CanForcePageOut = ETrue;
sl@0
   425
sl@0
   426
// Utility functions ///////////////////////////////////////////////////////////
sl@0
   427
sl@0
   428
TPtrC16 GetMediaType(TInt aMediaType)
sl@0
   429
	{
sl@0
   430
	_LIT(KMediaNotPresent, "MediaNotPresent");
sl@0
   431
	_LIT(KMediaUnknown, "MediaUnknown");
sl@0
   432
	_LIT(KMediaFloppy, "MediaFloppy");
sl@0
   433
	_LIT(KMediaHardDisk, "MediaHardDisk");
sl@0
   434
	_LIT(KMediaCdRom, "MediaCdRom");
sl@0
   435
	_LIT(KMediaRam, "MediaRam");
sl@0
   436
	_LIT(KMediaFlash, "MediaFlash");
sl@0
   437
	_LIT(KMediaRom, "MediaRom");
sl@0
   438
	_LIT(KMediaRemote, "MediaRemote");
sl@0
   439
	_LIT(KMediaNANDFlash, "MediaNANDFlash");
sl@0
   440
	_LIT(KMediaUnKnown, "MediaUnKnown");
sl@0
   441
sl@0
   442
	switch(aMediaType)
sl@0
   443
		{
sl@0
   444
		case EMediaNotPresent:
sl@0
   445
			return KMediaNotPresent();
sl@0
   446
		case EMediaUnknown:
sl@0
   447
			return KMediaUnknown();
sl@0
   448
		case EMediaFloppy:
sl@0
   449
			return KMediaFloppy();
sl@0
   450
		case EMediaHardDisk:
sl@0
   451
			return KMediaHardDisk();
sl@0
   452
		case EMediaCdRom:
sl@0
   453
			return KMediaCdRom();
sl@0
   454
		case EMediaRam:
sl@0
   455
			return KMediaRam();
sl@0
   456
		case EMediaFlash:
sl@0
   457
			return KMediaFlash();
sl@0
   458
		case EMediaRom:
sl@0
   459
			return KMediaRom();
sl@0
   460
		case EMediaRemote:
sl@0
   461
			return KMediaRemote();
sl@0
   462
		case EMediaNANDFlash:
sl@0
   463
			return KMediaNANDFlash();
sl@0
   464
		default:
sl@0
   465
			return KMediaUnKnown();
sl@0
   466
		}
sl@0
   467
	}
sl@0
   468
sl@0
   469
// Get the list of pageable drives
sl@0
   470
void GetSupportedDrives(TBool aVerbose = EFalse)
sl@0
   471
	{
sl@0
   472
	if (aVerbose)
sl@0
   473
		{
sl@0
   474
		test.Printf(_L("Supported drives:\n"));
sl@0
   475
		test.Printf(_L("     Type             Attr     MedAttr  Filesystem\n"));
sl@0
   476
		}
sl@0
   477
		
sl@0
   478
	RFs fs;
sl@0
   479
	test_noError(fs.Connect());
sl@0
   480
sl@0
   481
	TDriveList driveList;
sl@0
   482
	TDriveInfo driveInfo;
sl@0
   483
sl@0
   484
	TInt r = fs.DriveList(driveList);
sl@0
   485
    test_noError(r);
sl@0
   486
sl@0
   487
	TBool NandPageableMediaFound = EFalse;
sl@0
   488
sl@0
   489
	for (TInt drvNum=0; drvNum<KMaxDrives; ++drvNum)
sl@0
   490
		{
sl@0
   491
	    if(!driveList[drvNum])
sl@0
   492
	        continue;   //-- skip unexisting drive
sl@0
   493
	
sl@0
   494
	    r = fs.Drive(driveInfo, drvNum);
sl@0
   495
	    test_noError(r);
sl@0
   496
sl@0
   497
sl@0
   498
		TChar ch;
sl@0
   499
		r = fs.DriveToChar(drvNum, ch);
sl@0
   500
		test_noError(r);
sl@0
   501
sl@0
   502
		TBuf<256> fileSystemName;
sl@0
   503
		r = fs.FileSystemName(fileSystemName, drvNum);
sl@0
   504
		test_noError(r);
sl@0
   505
	
sl@0
   506
		if ((driveInfo.iDriveAtt & KDriveAttPageable) && (driveInfo.iType == EMediaNANDFlash))
sl@0
   507
			NandPageableMediaFound = ETrue;
sl@0
   508
sl@0
   509
		TBool pageable = EFalse;
sl@0
   510
		if (driveInfo.iDriveAtt & KDriveAttPageable)
sl@0
   511
			pageable = ETrue;
sl@0
   512
sl@0
   513
		// If we've already found a pageable NAND drive, 
sl@0
   514
		// then assume the Z: drive is pageable too if it's got a composite file system
sl@0
   515
		_LIT(KCompositeName,"Composite");
sl@0
   516
		if ((fileSystemName == KCompositeName()) && NandPageableMediaFound)
sl@0
   517
			pageable = ETrue;
sl@0
   518
			
sl@0
   519
		if (pageable)
sl@0
   520
			{
sl@0
   521
			TChar ch;
sl@0
   522
			r = fs.DriveToChar(drvNum, ch);
sl@0
   523
			test_noError(r);
sl@0
   524
sl@0
   525
			TPagingDriveInfo pagingDriveInfo;
sl@0
   526
			pagingDriveInfo.iDriveLetter = ch;
sl@0
   527
			pagingDriveInfo.iDriveInfo = driveInfo;
sl@0
   528
sl@0
   529
			r = SupportedDrives.Append(pagingDriveInfo);
sl@0
   530
			test_noError(r);
sl@0
   531
			}
sl@0
   532
		
sl@0
   533
		if (aVerbose)
sl@0
   534
			{
sl@0
   535
			TPtrC16 mediaType = GetMediaType(driveInfo.iType);
sl@0
   536
			_LIT(KPageable, "pageable");
sl@0
   537
			test.Printf(_L("  %c: %16S %08x %08x %10S %S\n"), 
sl@0
   538
						(TInt) ch, &mediaType, driveInfo.iDriveAtt, driveInfo.iMediaAtt,
sl@0
   539
						&fileSystemName, (pageable ? &KPageable : &KNullDesC));
sl@0
   540
			}
sl@0
   541
		
sl@0
   542
		}
sl@0
   543
sl@0
   544
	fs.Close();
sl@0
   545
	}
sl@0
   546
sl@0
   547
TInt GetPageState(TAny* aPage)
sl@0
   548
	{
sl@0
   549
	TInt r = UserSvr::HalFunction(EHalGroupVM, EVMPageState, aPage, 0);
sl@0
   550
	test_noError(r);
sl@0
   551
	return r;
sl@0
   552
	}
sl@0
   553
sl@0
   554
// Force a page to be paged in or rejuvenated, to simulate aging of pages in the live list
sl@0
   555
void ForcePageIn()
sl@0
   556
	{
sl@0
   557
	// Find a page that's old or paged out
sl@0
   558
	do
sl@0
   559
		{
sl@0
   560
		LargeDataPtr += PageSize;
sl@0
   561
		if (LargeDataPtr >= LargeDataEnd)
sl@0
   562
			LargeDataPtr = LargeDataStart;
sl@0
   563
		}
sl@0
   564
	while (GetPageState((TAny*)LargeDataPtr) & EPageStatePteValid);
sl@0
   565
sl@0
   566
	// and read from it to make it young
sl@0
   567
	TUint32 value = *(volatile TUint8*)LargeDataPtr;
sl@0
   568
	(void)value;
sl@0
   569
	++PagesReadSinceLastAccess;
sl@0
   570
	}
sl@0
   571
sl@0
   572
void FlushAllPages()
sl@0
   573
	{
sl@0
   574
	test_noError(UserSvr::HalFunction(EHalGroupVM,EVMHalFlushCache,0,0));
sl@0
   575
	}
sl@0
   576
sl@0
   577
void TestCurrentState()
sl@0
   578
	{
sl@0
   579
	test_Value(State, State >= 0 && State < ENumPageStates);
sl@0
   580
	test_Value(PhysState, PhysState >= 0 && PhysState < ENumPhysStates);
sl@0
   581
	
sl@0
   582
	TInt stateBits = GetPageState((TAny*)Library_TestFunction);
sl@0
   583
	TInt expected = ExpectedPageState[State];
sl@0
   584
	if (MultipleMemoryModel)
sl@0
   585
		expected |= ExpectedPageStateMultipleExtra[State];
sl@0
   586
	TUint physStateIgnore = 0;
sl@0
   587
	if (FlexibleMemoryModel)
sl@0
   588
		{
sl@0
   589
		expected &= ~EPageStatePageTablePresent; // flexible memory model allocates page tables on demand
sl@0
   590
		physStateIgnore = 0xff; // flexible memory model doesn't have separate page types for code/data/ROM
sl@0
   591
		}
sl@0
   592
sl@0
   593
	test_equal(expected, stateBits & (~PhysStateMask))
sl@0
   594
	test_equal(ExpectedPhysState[PhysState] & ~physStateIgnore, stateBits & PhysStateMask & ~physStateIgnore)
sl@0
   595
	}
sl@0
   596
sl@0
   597
void TestPageState(TPageState aExpected, TPhysState aExpectedPhys)
sl@0
   598
	{
sl@0
   599
	RDebug::Printf("%d:  %-12s %-12s", ProcessNum, StateNames[aExpected], PhysStateNames[aExpectedPhys]);
sl@0
   600
	test_equal(State, aExpected);
sl@0
   601
	test_equal(PhysState, aExpectedPhys);
sl@0
   602
	TestCurrentState();
sl@0
   603
	}
sl@0
   604
sl@0
   605
TInt PathLength(const TStatePath& aPath)
sl@0
   606
	{
sl@0
   607
	TInt i = 1;
sl@0
   608
	while (aPath[i] != EStateUnmapped && i < KMaxPathLen)
sl@0
   609
		++i;
sl@0
   610
	return i + 1;
sl@0
   611
	}
sl@0
   612
sl@0
   613
TInt FindState(const TStatePath& aPath, TPageState aTarget)
sl@0
   614
	{
sl@0
   615
	TInt len = PathLength(aPath);
sl@0
   616
	TInt j;
sl@0
   617
	for (j = 1 ; j < len ; ++j)
sl@0
   618
		{
sl@0
   619
		if (aPath[j] == aTarget)
sl@0
   620
			return j;
sl@0
   621
		}
sl@0
   622
	return -1;
sl@0
   623
	}
sl@0
   624
sl@0
   625
TInt WriteByte(TAny* aArg)
sl@0
   626
	{
sl@0
   627
	TUint8* ptr = (TUint8*)aArg;
sl@0
   628
	*ptr = 23;
sl@0
   629
	return KErrNone;
sl@0
   630
	}
sl@0
   631
sl@0
   632
void StartOtherProcess(TInt aProcessNum, RTestSession& aSession)
sl@0
   633
	{
sl@0
   634
	RProcess me, other;
sl@0
   635
	TBuf<16> arg;
sl@0
   636
	arg.AppendNum(aProcessNum);
sl@0
   637
	test_noError(other.Create(me.FileName(), arg));
sl@0
   638
	TRequestStatus status;
sl@0
   639
	other.Rendezvous(status);
sl@0
   640
	other.Resume();
sl@0
   641
	User::WaitForRequest(status);
sl@0
   642
	test_noError(status.Int());
sl@0
   643
	test_equal(EExitPending, other.ExitType());
sl@0
   644
	test_noError(aSession.Connect(aProcessNum));
sl@0
   645
	other.Close();
sl@0
   646
	}
sl@0
   647
sl@0
   648
const TDesC& LibrarySearchPath(TUint16 aDrive)
sl@0
   649
	{
sl@0
   650
	static TBuf<32> path;
sl@0
   651
	path = KSearchPathTemplate;
sl@0
   652
	path[0] = aDrive;
sl@0
   653
	return path;
sl@0
   654
	}
sl@0
   655
sl@0
   656
const TDesC& LibraryName(TInt aLibraryNum, TUint16 aDrive)
sl@0
   657
	{
sl@0
   658
	// this gives dlls a different name on each drive so we can be sure we're loading the right one
sl@0
   659
	static TBuf<32> name;
sl@0
   660
	name = KLibraryName;
sl@0
   661
	if (aLibraryNum > 1)
sl@0
   662
		name.AppendNum(aLibraryNum);
sl@0
   663
	if (aDrive != 'Z')
sl@0
   664
		name.AppendFormat(_L("_%c"), aDrive);
sl@0
   665
	return name;
sl@0
   666
	}
sl@0
   667
sl@0
   668
const TDesC& LibraryFilename(TInt aLibraryNum, TUint16 aDrive)
sl@0
   669
	{
sl@0
   670
	static TBuf<40> filename;
sl@0
   671
	filename = LibrarySearchPath(aDrive);
sl@0
   672
	filename.AppendFormat(_L("\\%S.dll"), &LibraryName(aLibraryNum, aDrive));
sl@0
   673
	return filename;
sl@0
   674
	}
sl@0
   675
sl@0
   676
TInt LoadSpecificLibrary(RLibrary& aLibrary, TInt aLibraryNum, TUint16 aDrive)
sl@0
   677
	{
sl@0
   678
	const TDesC& name = LibraryName(aLibraryNum, aDrive);
sl@0
   679
	const TDesC& path = LibrarySearchPath(aDrive);
sl@0
   680
	return aLibrary.Load(name, path);
sl@0
   681
	}
sl@0
   682
sl@0
   683
TInt GetLocDrvNumber(TUint16 aDrive)
sl@0
   684
	{
sl@0
   685
	RFs fs;
sl@0
   686
	RFile file;
sl@0
   687
sl@0
   688
	TBuf<40> libname = LibraryFilename(1, aDrive);
sl@0
   689
	
sl@0
   690
	fs.Connect();
sl@0
   691
	TInt r=file.Open(fs,libname,EFileRead);
sl@0
   692
	if(r!=KErrNone)
sl@0
   693
		test.Printf(_L("%d: Error %d: could not open file %S\n"),ProcessNum, r, &libname);
sl@0
   694
	test(r==KErrNone);
sl@0
   695
sl@0
   696
	SBlockMapInfo info;
sl@0
   697
	TInt64 start=0;
sl@0
   698
	r=file.BlockMap(info,start, -1,ETestDebug);
sl@0
   699
sl@0
   700
	if (r!=KErrNone && r!=KErrCompletion)
sl@0
   701
		test.Printf(_L("Error %d: could not obtain block map\n"),r);
sl@0
   702
	test(r==KErrNone || r==KErrCompletion);
sl@0
   703
	TInt locDriveNumber=info.iLocalDriveNumber;
sl@0
   704
sl@0
   705
	file.Close();
sl@0
   706
	fs.Close();
sl@0
   707
	return locDriveNumber;
sl@0
   708
	}
sl@0
   709
sl@0
   710
void LoadLargeLibrary()
sl@0
   711
	{
sl@0
   712
	test(!LargeLibraryLoaded);
sl@0
   713
	test_noError(LoadSpecificLibrary(LargeLibrary, 4, CurrentDrive));
sl@0
   714
	TGetAddressOfDataFunction func = (TGetAddressOfDataFunction)LargeLibrary.Lookup(KGetAddressOfDataFunctionOrdinal);
sl@0
   715
	TInt size;
sl@0
   716
	LargeDataStart = (TUint8*)func(size);
sl@0
   717
	test_notNull(LargeDataStart);
sl@0
   718
	if (size < LiveListSize*PageSize)
sl@0
   719
		{
sl@0
   720
		// We need an area of paged data large enough to ensure we can cause a page of our choice to
sl@0
   721
		// be paged out.  If the size of the live list for testing is too small, we'll skip some tests
sl@0
   722
		CanForcePageOut = EFalse;
sl@0
   723
		}
sl@0
   724
	LargeDataEnd = LargeDataStart + size;
sl@0
   725
	LargeDataPtr = LargeDataStart;
sl@0
   726
 	LargeLibraryLoaded = ETrue;
sl@0
   727
	}
sl@0
   728
sl@0
   729
void UnloadLargeLibrary()
sl@0
   730
	{
sl@0
   731
	test(LargeLibraryLoaded);
sl@0
   732
	LargeLibrary.Close();
sl@0
   733
	LargeDataStart = NULL;
sl@0
   734
	LargeDataEnd = NULL;
sl@0
   735
	LargeDataPtr = NULL;
sl@0
   736
	LargeLibraryLoaded = EFalse;
sl@0
   737
	}
sl@0
   738
sl@0
   739
// Page in a page and keep aging it to see if it ever reaches an oldest list. 
sl@0
   740
TBool SetHaveOldestLists()
sl@0
   741
	{
sl@0
   742
	AccessMethod = EAccessExec;
sl@0
   743
	AccessPage();
sl@0
   744
	TInt pagedState = (GetPageState((TAny*)Library_TestFunction) & KPagedStateMask) >> KPagedStateShift;
sl@0
   745
	do	
sl@0
   746
		{
sl@0
   747
		ForcePageIn();
sl@0
   748
		pagedState = (GetPageState((TAny*)Library_TestFunction) & KPagedStateMask) >> KPagedStateShift;
sl@0
   749
		if (EStatePagedOldestClean == pagedState || EStatePagedOldestDirty == pagedState)
sl@0
   750
			break;
sl@0
   751
		}
sl@0
   752
	while (	PagesReadSinceLastAccess <= LiveListSize);
sl@0
   753
sl@0
   754
	HaveOldestLists = EStatePagedOldestClean == pagedState || EStatePagedOldestDirty == pagedState;
sl@0
   755
	return HaveOldestLists;
sl@0
   756
	}
sl@0
   757
sl@0
   758
void SetCurrentDrive(TUint16 aDrive)
sl@0
   759
	{
sl@0
   760
	if (LargeLibraryLoaded)
sl@0
   761
		UnloadLargeLibrary();
sl@0
   762
	CurrentDrive = aDrive;
sl@0
   763
	LocalDriveNumber = GetLocDrvNumber(aDrive);
sl@0
   764
	LoadLargeLibrary();
sl@0
   765
	if (!Library_TestFunction)
sl@0
   766
		{
sl@0
   767
		LoadLibrary();
sl@0
   768
		Library_TestFunction = (TTestFunction)PagedLibrary.Lookup(KTestFunctionOrdinal);
sl@0
   769
		test_notNull(Library_TestFunction);
sl@0
   770
		if (SetHaveOldestLists())
sl@0
   771
			TestPath = &TestPathOldest;
sl@0
   772
		else
sl@0
   773
			TestPath = &TestPathNoOldest;
sl@0
   774
		UnloadLibrary();
sl@0
   775
		FlushAllPages();
sl@0
   776
		}
sl@0
   777
	}
sl@0
   778
sl@0
   779
// State transition functions //////////////////////////////////////////////////
sl@0
   780
sl@0
   781
void LoadLibrary()
sl@0
   782
	{
sl@0
   783
	test_noError(LoadSpecificLibrary(PagedLibrary, 1, CurrentDrive));
sl@0
   784
	if (MovingMemoryModel)
sl@0
   785
		FlushAllPages(); // to make sure pages aren't already mapped
sl@0
   786
	LibraryLoaded = ETrue;
sl@0
   787
	}
sl@0
   788
sl@0
   789
void UnloadLibrary()
sl@0
   790
	{
sl@0
   791
	PagedLibrary.Close();
sl@0
   792
	LibraryLoaded = EFalse;
sl@0
   793
	}
sl@0
   794
sl@0
   795
void AccessPage()
sl@0
   796
	{
sl@0
   797
	switch (AccessMethod)
sl@0
   798
		{
sl@0
   799
		case EAccessExec:
sl@0
   800
			Library_TestFunction();
sl@0
   801
			break;
sl@0
   802
sl@0
   803
		case EAccessRead:
sl@0
   804
			{
sl@0
   805
			TUint8 x = *(volatile TUint8*)Library_TestFunction;
sl@0
   806
			(void)x;
sl@0
   807
			}
sl@0
   808
			break;
sl@0
   809
sl@0
   810
		case EAccessAliasRead:
sl@0
   811
			{
sl@0
   812
			TPtrC8 des((TUint8*)Library_TestFunction, 4);  // descriptor header must be in different page to data
sl@0
   813
			OtherProcess.DesRead(des);
sl@0
   814
			}
sl@0
   815
			break;
sl@0
   816
sl@0
   817
		}
sl@0
   818
	PagesReadSinceLastAccess = 0;
sl@0
   819
	}
sl@0
   820
sl@0
   821
void MakeOld()
sl@0
   822
	{
sl@0
   823
	TInt initialState = GetPageState((TAny*)Library_TestFunction);
sl@0
   824
	do	
sl@0
   825
		ForcePageIn();
sl@0
   826
	while (PagesReadSinceLastAccess <= LiveListSize &&
sl@0
   827
		   initialState == GetPageState((TAny*)Library_TestFunction));
sl@0
   828
	TUint pagedState = (GetPageState((TAny*)Library_TestFunction) & KPagedStateMask) >> KPagedStateShift;
sl@0
   829
	test_Equal(EStatePagedOld, pagedState);
sl@0
   830
	}
sl@0
   831
sl@0
   832
void MakeOldest()
sl@0
   833
	{
sl@0
   834
	TInt pagedState = (GetPageState((TAny*)Library_TestFunction) & KPagedStateMask) >> KPagedStateShift;
sl@0
   835
	do	
sl@0
   836
		{
sl@0
   837
		ForcePageIn();
sl@0
   838
		pagedState = (GetPageState((TAny*)Library_TestFunction) & KPagedStateMask) >> KPagedStateShift;
sl@0
   839
		if (EStatePagedOldestClean == pagedState ||	EStatePagedOldestDirty == pagedState)
sl@0
   840
			break;
sl@0
   841
		}
sl@0
   842
	while (PagesReadSinceLastAccess <= LiveListSize);
sl@0
   843
	test_Value(pagedState, EStatePagedOldestClean == pagedState || EStatePagedOldestDirty == pagedState);
sl@0
   844
	}
sl@0
   845
sl@0
   846
void MakePagedOut()
sl@0
   847
	{
sl@0
   848
	TInt finalListState1 = EStatePagedOld;
sl@0
   849
	TInt finalListState2 = EStatePagedOld;
sl@0
   850
	if (HaveOldestLists)
sl@0
   851
		{
sl@0
   852
		finalListState1 = EStatePagedOldestClean;
sl@0
   853
		finalListState2 = EStatePagedOldestDirty;
sl@0
   854
		}
sl@0
   855
sl@0
   856
	TInt pagedState = (GetPageState((TAny*)Library_TestFunction) & KPagedStateMask) >> KPagedStateShift;
sl@0
   857
	// Get the page onto the final list(s) so it can be detected when it is paged out.
sl@0
   858
	while (	pagedState != finalListState1 && pagedState != finalListState2 &&
sl@0
   859
			PagesReadSinceLastAccess <= LiveListSize)
sl@0
   860
		{
sl@0
   861
		ForcePageIn();
sl@0
   862
		pagedState = (GetPageState((TAny*)Library_TestFunction) & KPagedStateMask) >> KPagedStateShift;
sl@0
   863
		}
sl@0
   864
	// Now force the page off the paging lists.
sl@0
   865
	pagedState = GetPageState((TAny*)Library_TestFunction);
sl@0
   866
	do
sl@0
   867
		{
sl@0
   868
		ForcePageIn();
sl@0
   869
		}
sl@0
   870
	while (	PagesReadSinceLastAccess <= LiveListSize &&
sl@0
   871
			pagedState == GetPageState((TAny*)Library_TestFunction));
sl@0
   872
	}
sl@0
   873
sl@0
   874
// Test functions //////////////////////////////////////////////////////////////
sl@0
   875
sl@0
   876
void Initialise()
sl@0
   877
	{
sl@0
   878
	CurrentDrive = 'Z';
sl@0
   879
	
sl@0
   880
	TUint32 memModelAttrs = MemModelAttributes();
sl@0
   881
	MovingMemoryModel = ((memModelAttrs & EMemModelTypeMask) == EMemModelTypeMoving);
sl@0
   882
	MultipleMemoryModel = ((memModelAttrs & EMemModelTypeMask) == EMemModelTypeMultiple);
sl@0
   883
	FlexibleMemoryModel = ((memModelAttrs & EMemModelTypeMask) == EMemModelTypeFlexible);
sl@0
   884
sl@0
   885
	test_noError(UserSvr::HalFunction(EHalGroupKernel, EKernelHalPageSizeInBytes, &PageSize, 0));
sl@0
   886
	
sl@0
   887
	SVMCacheInfo info;
sl@0
   888
	test_noError(UserSvr::HalFunction(EHalGroupVM, EVMHalGetCacheSize, &info, 0));
sl@0
   889
	LiveListSize = info.iMaxSize / PageSize;
sl@0
   890
	}
sl@0
   891
sl@0
   892
void CopyDllFragmented(RFs& aFs, const TDesC& aSourceName, const TDesC& aDestName)
sl@0
   893
	{
sl@0
   894
	test.Printf(_L("  %S\n"), &aDestName);
sl@0
   895
sl@0
   896
	TInt r = aFs.MkDirAll(aDestName);
sl@0
   897
	test(r == KErrNone || r == KErrAlreadyExists);
sl@0
   898
sl@0
   899
	TBuf<40> tempName(aDestName);
sl@0
   900
	tempName.Append(_L(".tmp"));
sl@0
   901
sl@0
   902
	RFile in, out, temp;
sl@0
   903
	test_noError(in.Open(aFs, aSourceName, EFileRead));
sl@0
   904
	test_noError(out.Replace(aFs, aDestName, EFileWrite));
sl@0
   905
	test_noError(temp.Replace(aFs, tempName, EFileWrite));
sl@0
   906
sl@0
   907
	const TInt KBufferSize = 3333;
sl@0
   908
	TBuf8<KBufferSize> buffer;
sl@0
   909
	
sl@0
   910
	test_noError(temp.Write(buffer));
sl@0
   911
	test_noError(temp.Flush());
sl@0
   912
sl@0
   913
	TInt size;
sl@0
   914
	test_noError(in.Size(size));
sl@0
   915
	TInt pos = 0;
sl@0
   916
	while (pos < size)
sl@0
   917
		{
sl@0
   918
		test_noError(in.Read(buffer));
sl@0
   919
		test_noError(out.Write(buffer));
sl@0
   920
		test_noError(out.Flush());
sl@0
   921
		test_noError(temp.Write(buffer));
sl@0
   922
		test_noError(temp.Flush());
sl@0
   923
		pos += buffer.Length();
sl@0
   924
		}
sl@0
   925
	
sl@0
   926
	in.Close();
sl@0
   927
	out.Close();
sl@0
   928
	temp.Close();
sl@0
   929
	}
sl@0
   930
sl@0
   931
void CopyDllToSupportedDrives(RFs& aFs, CFileMan* aFileMan, TInt aLibraryNum)
sl@0
   932
	{
sl@0
   933
	TBuf<40> source = LibraryFilename(aLibraryNum, 'Z');
sl@0
   934
sl@0
   935
	test.Printf(_L("Copying %S to:\n"), &source);
sl@0
   936
	
sl@0
   937
	for (TInt i = 0 ; i < SupportedDrives.Count() ; ++i)
sl@0
   938
		{
sl@0
   939
		TUint8 drive = SupportedDrives[i].iDriveLetter;
sl@0
   940
		if (!(SupportedDrives[i].iDriveInfo.iMediaAtt & KMediaAttWriteProtected))
sl@0
   941
			{
sl@0
   942
			TBuf<40> dest = LibraryFilename(aLibraryNum, drive);
sl@0
   943
			CopyDllFragmented(aFs, source, dest);
sl@0
   944
			}
sl@0
   945
		}
sl@0
   946
	}
sl@0
   947
sl@0
   948
void CopyDllsToSupportedDrives()
sl@0
   949
	{
sl@0
   950
	RFs fs;
sl@0
   951
	test_noError(fs.Connect());
sl@0
   952
sl@0
   953
	CTrapCleanup* cleanup = CTrapCleanup::New();
sl@0
   954
	test_notNull(cleanup);
sl@0
   955
	
sl@0
   956
	CFileMan* fileMan = NULL;
sl@0
   957
	TRAPD(r, fileMan = CFileMan::NewL(fs));
sl@0
   958
	test_noError(r);
sl@0
   959
sl@0
   960
	for (TInt i = 1 ; i <= 7 ; ++i)
sl@0
   961
		CopyDllToSupportedDrives(fs, fileMan, i);
sl@0
   962
	
sl@0
   963
	delete fileMan;
sl@0
   964
	delete cleanup;	
sl@0
   965
	fs.Close();
sl@0
   966
	}
sl@0
   967
sl@0
   968
void TestStateTransition(TPageState aNext)
sl@0
   969
	{
sl@0
   970
	TPhysState nextPhys = PhysStateFromPageState[aNext];
sl@0
   971
	RDebug::Printf("%d:  %-12s            -> %-12s", ProcessNum, StateNames[State], StateNames[aNext]);
sl@0
   972
	TFunc func = StateTransitions[State][aNext];
sl@0
   973
	test_notNull(func);
sl@0
   974
	func();
sl@0
   975
	State = aNext;
sl@0
   976
	PhysState = nextPhys;
sl@0
   977
	TestCurrentState();
sl@0
   978
	}
sl@0
   979
sl@0
   980
void RunPathTest(const TStatePath& aPath, TInt aStart = 0, TInt aEnd = -1)
sl@0
   981
	{
sl@0
   982
	if (aEnd == -1)
sl@0
   983
		aEnd = PathLength(aPath) - 1;
sl@0
   984
sl@0
   985
	// Check we're already in the starting state
sl@0
   986
	TestPageState(aPath[aStart], PhysStateFromPageState[aPath[aStart]]);
sl@0
   987
sl@0
   988
	for (TInt i = aStart + 1 ; i <= aEnd ; ++i)
sl@0
   989
		TestStateTransition(aPath[i]);
sl@0
   990
	}
sl@0
   991
sl@0
   992
void RunUnmapTest(const TStatePath& aPath)
sl@0
   993
	{
sl@0
   994
	TInt len = PathLength(aPath);
sl@0
   995
	
sl@0
   996
	// Test an unmodified code paged page can be unmapped from all the possible 
sl@0
   997
	// states it can be in.
sl@0
   998
	TInt endState = EStateOld;
sl@0
   999
	if (HaveOldestLists)
sl@0
  1000
		endState = EStateOldestClean;
sl@0
  1001
		
sl@0
  1002
	for (TInt i = EStateUnmapped + 1; i <= endState; ++i)
sl@0
  1003
		{
sl@0
  1004
		TPageState target = (TPageState)i;
sl@0
  1005
		RDebug::Printf("\nUnmap from %s:\n", StateNames[target]);
sl@0
  1006
sl@0
  1007
		TStatePath path;
sl@0
  1008
		memcpy(path, aPath, sizeof(path));
sl@0
  1009
sl@0
  1010
		TInt j = FindState(path, target) + 1;
sl@0
  1011
		test_Value(j, j > 0 && j < len + 1);
sl@0
  1012
		path[j] = EStateUnmapped;
sl@0
  1013
		
sl@0
  1014
		RunPathTest(path, 0, j);
sl@0
  1015
		}
sl@0
  1016
	}
sl@0
  1017
sl@0
  1018
void GoToState(TPageState aState)
sl@0
  1019
	{
sl@0
  1020
	if (LibraryLoaded)
sl@0
  1021
		{
sl@0
  1022
		UnloadLibrary();
sl@0
  1023
		State = EStateUnmapped;
sl@0
  1024
		PhysState = PhysStateFromPageState[State];
sl@0
  1025
		}
sl@0
  1026
		
sl@0
  1027
	TInt i = FindState(*TestPath, aState);
sl@0
  1028
	test(i != -1);
sl@0
  1029
	RunPathTest(*TestPath, 0, i);
sl@0
  1030
	}
sl@0
  1031
sl@0
  1032
void RunMultiProcessTest()
sl@0
  1033
	{
sl@0
  1034
	TStatePath& testPath = *TestPath;
sl@0
  1035
	TInt len = PathLength(testPath);
sl@0
  1036
	
sl@0
  1037
	TInt endState = EStateOld;
sl@0
  1038
	if (HaveOldestLists)
sl@0
  1039
		endState = EStateOldestClean;
sl@0
  1040
	for (TInt i = EStateUnmapped; i <= endState; ++i)
sl@0
  1041
		{
sl@0
  1042
		TPageState target = (TPageState)i;
sl@0
  1043
		RDebug::Printf("\nTesting interaction with second process in state %s:\n", StateNames[target]);
sl@0
  1044
		
sl@0
  1045
		GoToState(target);
sl@0
  1046
		TPageState state2 = testPath[0];  // current state in other process
sl@0
  1047
		OtherProcess.TestPageState(state2, PhysStateFromPageState[state2]);
sl@0
  1048
		for (TInt i = 1 ; i < len ; ++i)
sl@0
  1049
			{
sl@0
  1050
			TPageState next2 = testPath[i];
sl@0
  1051
			OtherProcess.TestStateTransition(next2);
sl@0
  1052
			
sl@0
  1053
			// Update physical state if affected by transition in other process
sl@0
  1054
			if ((State == EStateYoung || State == EStateOld || State == EStateOldestClean) &&
sl@0
  1055
				(state2 != EStateUnmapped && next2 != EStateUnmapped))
sl@0
  1056
				PhysState = PhysStateFromPageState[next2];
sl@0
  1057
sl@0
  1058
			// Update logical state in this process if affected by transition in other process
sl@0
  1059
			if (State == EStateYoung && next2 == EStateOld)
sl@0
  1060
				State = EStateOld;
sl@0
  1061
			else if (State == EStateOld && next2 == EStateOldestClean)
sl@0
  1062
				State = EStateOldestClean;
sl@0
  1063
			else if ((State == EStateYoung || State == EStateOld || State == EStateOldestClean) &&
sl@0
  1064
					 (state2 == EStateOld  || state2 == EStateOldestClean) && next2 == EStatePagedOut)
sl@0
  1065
				State = EStatePagedOut;
sl@0
  1066
sl@0
  1067
			RDebug::Printf("%d:  %-12s %-12s", ProcessNum, StateNames[State], PhysStateNames[PhysState]);
sl@0
  1068
			TestCurrentState();
sl@0
  1069
			state2 = next2;
sl@0
  1070
			}
sl@0
  1071
		}
sl@0
  1072
sl@0
  1073
	if (LibraryLoaded)
sl@0
  1074
		{
sl@0
  1075
		UnloadLibrary();
sl@0
  1076
		State = EStateUnmapped;
sl@0
  1077
		PhysState = PhysStateFromPageState[State];
sl@0
  1078
		}	
sl@0
  1079
	}
sl@0
  1080
sl@0
  1081
void TestReadExportDir()
sl@0
  1082
	{
sl@0
  1083
	RLibrary library;
sl@0
  1084
	test_noError(LoadSpecificLibrary(library, 3, CurrentDrive));
sl@0
  1085
	TTestFunction func = (TTestFunction)library.Lookup(KTestFunctionOrdinal);
sl@0
  1086
	test_notNull(func);
sl@0
  1087
	test_noError(func());
sl@0
  1088
	library.Close();
sl@0
  1089
	}
sl@0
  1090
sl@0
  1091
void RunReadExportDirTest()
sl@0
  1092
	{
sl@0
  1093
	test.Next(_L("Exercise ReadExportDir with one code seg mapped already into current process"));
sl@0
  1094
	LoadLibrary();
sl@0
  1095
	TestReadExportDir();
sl@0
  1096
	UnloadLibrary();
sl@0
  1097
sl@0
  1098
	test.Next(_L("Exercise ReadExportDir with one code seg mapped into different process"));
sl@0
  1099
	OtherProcess.Exec(LoadLibrary);
sl@0
  1100
	TestReadExportDir();
sl@0
  1101
	OtherProcess.Exec(UnloadLibrary);
sl@0
  1102
	}
sl@0
  1103
sl@0
  1104
void RunWriteToPagedCodeTest()
sl@0
  1105
	{
sl@0
  1106
	test.Next(_L("Test writing to paged code"));
sl@0
  1107
sl@0
  1108
	RMemoryTestLdd memoryTest;
sl@0
  1109
	test(KErrNone==memoryTest.Open());
sl@0
  1110
sl@0
  1111
	FlushAllPages();
sl@0
  1112
	TUint8* ptr = (TUint8*)LargeDataStart;
sl@0
  1113
	while(ptr<LargeDataEnd)
sl@0
  1114
		{
sl@0
  1115
		TInt stateBits = GetPageState(ptr);
sl@0
  1116
		// write to paged out memory should cause exception...
sl@0
  1117
		test(KErrBadDescriptor==memoryTest.WriteMemory(ptr,0));
sl@0
  1118
		// page state should be unchanged...
sl@0
  1119
		test_equal(stateBits,GetPageState(ptr))
sl@0
  1120
		// page-in in memory...
sl@0
  1121
		TUint32 value = *(TUint32*)ptr;
sl@0
  1122
		// page state should be changed...
sl@0
  1123
		test(stateBits!=GetPageState(ptr));
sl@0
  1124
		// write to paged out memory should still cause exception...
sl@0
  1125
		test(KErrBadDescriptor==memoryTest.WriteMemory(ptr,~value));
sl@0
  1126
		// memory should be unchanged...
sl@0
  1127
		test(value==*(TUint32*)ptr);
sl@0
  1128
		ptr += PageSize;
sl@0
  1129
		}
sl@0
  1130
sl@0
  1131
	memoryTest.Close();
sl@0
  1132
	}
sl@0
  1133
sl@0
  1134
void RunPageLockingTest()
sl@0
  1135
	{
sl@0
  1136
	test.Next(_L("Check locking of code which then gets unloaded"));
sl@0
  1137
sl@0
  1138
	// load test driver...
sl@0
  1139
	test.Start(_L("Load test driver..."));
sl@0
  1140
	RDemandPagingTestLdd ldd;
sl@0
  1141
	TInt r = User::LoadLogicalDevice(KDemandPagingTestLddName);
sl@0
  1142
	test(r==KErrNone || r==KErrAlreadyExists);
sl@0
  1143
	test(ldd.Open()==KErrNone);
sl@0
  1144
sl@0
  1145
	// load once to get address that code will be loaded at...
sl@0
  1146
	test.Next(_L("Load/unload dll"));
sl@0
  1147
	RLibrary library;
sl@0
  1148
	test_noError(LoadSpecificLibrary(library, 5, CurrentDrive));
sl@0
  1149
	TGetAddressOfRelocatedDataFunction func = (TGetAddressOfRelocatedDataFunction)library.Lookup(KGetAddressOfDataFunctionOrdinal);
sl@0
  1150
	test_notNull(func);
sl@0
  1151
	library.Close();
sl@0
  1152
sl@0
  1153
	// load again and check it's at the same place...
sl@0
  1154
	test.Next(_L("Load dll again"));
sl@0
  1155
	test_noError(LoadSpecificLibrary(library, 5, CurrentDrive));
sl@0
  1156
	TGetAddressOfRelocatedDataFunction func2 = (TGetAddressOfRelocatedDataFunction)library.Lookup(KGetAddressOfDataFunctionOrdinal);
sl@0
  1157
	test_equal(func,func2);
sl@0
  1158
sl@0
  1159
	// get address of data in the DLL...
sl@0
  1160
	test.Next(_L("Get data from DLL"));
sl@0
  1161
	void* d;
sl@0
  1162
	void* c;
sl@0
  1163
	TInt size;
sl@0
  1164
	void** data = func(size,d,c);
sl@0
  1165
sl@0
  1166
	// lock pages...
sl@0
  1167
	test.Next(_L("Lock DLL data"));
sl@0
  1168
	r = ldd.Lock(data,size);
sl@0
  1169
	test_equal(r,1);
sl@0
  1170
sl@0
  1171
	// check data...
sl@0
  1172
	test.Next(_L("Check DLL data"));
sl@0
  1173
	for (TInt i = 0 ; i < size / 4 ; i+=2)
sl@0
  1174
		{
sl@0
  1175
		test_equal(c, data[i]);
sl@0
  1176
		test_equal(d, data[i+1]);
sl@0
  1177
		}
sl@0
  1178
sl@0
  1179
	// close library...
sl@0
  1180
	test.Next(_L("Close DLL"));
sl@0
  1181
	library.Close();
sl@0
  1182
	User::After(1000000);
sl@0
  1183
sl@0
  1184
	if(!FlexibleMemoryModel) // flexible memory model doesn't actually hog virtual address when locked (pinned)
sl@0
  1185
		{
sl@0
  1186
		// load again and check it's at a different place
sl@0
  1187
		// (because the locked memory is hogging the old place)...
sl@0
  1188
		test.Next(_L("Check DLL loaded at different address"));
sl@0
  1189
		test_noError(LoadSpecificLibrary(library, 5, CurrentDrive));
sl@0
  1190
		func2 = (TGetAddressOfRelocatedDataFunction)library.Lookup(KGetAddressOfDataFunctionOrdinal);
sl@0
  1191
		test(func!=func2);
sl@0
  1192
		library.Close();
sl@0
  1193
		User::After(1000000);
sl@0
  1194
sl@0
  1195
		// unlock pages...
sl@0
  1196
		test.Next(_L("Unlock DLL data"));
sl@0
  1197
		r = ldd.Unlock();
sl@0
  1198
		User::After(1000000);
sl@0
  1199
sl@0
  1200
		// load again and check it's back at the original place
sl@0
  1201
		// (because the locked memory now gone)...
sl@0
  1202
		test.Next(_L("Check DLL loaded at original address"));
sl@0
  1203
		test_noError(LoadSpecificLibrary(library, 5, CurrentDrive));
sl@0
  1204
		func2 = (TGetAddressOfRelocatedDataFunction)library.Lookup(KGetAddressOfDataFunctionOrdinal);
sl@0
  1205
		test(func==func2);
sl@0
  1206
		library.Close();
sl@0
  1207
		}
sl@0
  1208
sl@0
  1209
	// cleanup...
sl@0
  1210
	test.Next(_L("Cleanup"));
sl@0
  1211
	ldd.Close();
sl@0
  1212
sl@0
  1213
	test.End();
sl@0
  1214
	}
sl@0
  1215
sl@0
  1216
void TestContentsOfPagedDll()
sl@0
  1217
	{
sl@0
  1218
	test.Next(_L("Test that the contents of a paged DLL are as expected"));
sl@0
  1219
sl@0
  1220
	RLibrary library2;
sl@0
  1221
	test_noError(LoadSpecificLibrary(library2, 2, CurrentDrive));
sl@0
  1222
sl@0
  1223
	TGetAddressOfDataFunction func = (TGetAddressOfDataFunction)library2.Lookup(KGetAddressOfDataFunctionOrdinal);
sl@0
  1224
	test_notNull(func);
sl@0
  1225
sl@0
  1226
	TInt size;
sl@0
  1227
	TUint* data;
sl@0
  1228
	data = func(size);
sl@0
  1229
	test_notNull(data);
sl@0
  1230
sl@0
  1231
	// Data contents are psuedorandom numbers generated according to the following scheme
sl@0
  1232
	const TInt A = 1664525;
sl@0
  1233
	const TInt B = 1013904223;
sl@0
  1234
	TUint v = 23;
sl@0
  1235
	for (TInt i = 0 ; i < size / 4 ; ++i)
sl@0
  1236
		{
sl@0
  1237
		v = A * v + B;
sl@0
  1238
		test_equal(v, data[i]);
sl@0
  1239
		}
sl@0
  1240
sl@0
  1241
	library2.Close();
sl@0
  1242
	}
sl@0
  1243
sl@0
  1244
sl@0
  1245
void CheckRelocatableData(RLibrary& library)
sl@0
  1246
	{
sl@0
  1247
	TGetAddressOfRelocatedDataFunction func = (TGetAddressOfRelocatedDataFunction)library.Lookup(KGetAddressOfDataFunctionOrdinal);
sl@0
  1248
	test_notNull(func);
sl@0
  1249
	void* d;
sl@0
  1250
	void* c;
sl@0
  1251
	TInt size;
sl@0
  1252
	void** data = func(size,d,c);
sl@0
  1253
	test_equal(d, data);
sl@0
  1254
	for (TInt i = 0 ; i < size / 4 ; i+=2)
sl@0
  1255
		{
sl@0
  1256
		test_equal(c, data[i]);
sl@0
  1257
		test_equal(d, data[i+1]);
sl@0
  1258
		}
sl@0
  1259
	}
sl@0
  1260
sl@0
  1261
sl@0
  1262
void OtherProcessCheckRelocatableData()
sl@0
  1263
	{
sl@0
  1264
	RLibrary library;
sl@0
  1265
	test_noError(LoadSpecificLibrary(library, 7, CurrentDrive));
sl@0
  1266
	CheckRelocatableData(library);
sl@0
  1267
	library.Close();
sl@0
  1268
	}
sl@0
  1269
sl@0
  1270
sl@0
  1271
void TestContentsOfPagedDllWithRelocatedData()
sl@0
  1272
	{
sl@0
  1273
	test.Next(_L("Test relocated const data in DLL"));
sl@0
  1274
	PagingInfo::ResetBenchmarks();
sl@0
  1275
	RLibrary library;
sl@0
  1276
	test_noError(LoadSpecificLibrary(library, 5, CurrentDrive));
sl@0
  1277
	CheckRelocatableData(library);
sl@0
  1278
	library.Close();
sl@0
  1279
	PagingInfo::PrintBenchmarks();	// worst case fixups
sl@0
  1280
sl@0
  1281
	test.Next(_L("Test relocated writable data in DLL"));
sl@0
  1282
	test_noError(LoadSpecificLibrary(library, 6, CurrentDrive));
sl@0
  1283
	CheckRelocatableData(library);
sl@0
  1284
	library.Close();
sl@0
  1285
sl@0
  1286
	test.Next(_L("Test relocated writable data in dependent DLL"));
sl@0
  1287
	test_noError(LoadSpecificLibrary(library, 7, CurrentDrive));
sl@0
  1288
	CheckRelocatableData(library);
sl@0
  1289
	library.Close();
sl@0
  1290
sl@0
  1291
	test.Next(_L("Test relocated writable data in preloaded dependent DLL"));
sl@0
  1292
	RLibrary library2;
sl@0
  1293
	test_noError(LoadSpecificLibrary(library2, 6, CurrentDrive));
sl@0
  1294
	test_noError(LoadSpecificLibrary(library, 7, CurrentDrive));
sl@0
  1295
	CheckRelocatableData(library);
sl@0
  1296
	library.Close();
sl@0
  1297
	library2.Close();
sl@0
  1298
sl@0
  1299
	test.Next(_L("Test relocated writable data in preloaded dependent DLL opened in other process"));
sl@0
  1300
	test_noError(LoadSpecificLibrary(library2, 6, CurrentDrive));
sl@0
  1301
	OtherProcess.Exec(OtherProcessCheckRelocatableData);
sl@0
  1302
	library2.Close();
sl@0
  1303
	}
sl@0
  1304
sl@0
  1305
sl@0
  1306
TInt RandomAccessFunc(TAny* aArg)
sl@0
  1307
	{
sl@0
  1308
	const TUint8* dataStart = LargeDataStart;
sl@0
  1309
	const TUint8* dataEnd = LargeDataEnd;	
sl@0
  1310
	TInt size = dataEnd - dataStart;
sl@0
  1311
	TUint32 random = (User::FastCounter() << 8) | ProcessNum;
sl@0
  1312
	TInt i = 0;
sl@0
  1313
	while (!RandomAccessKill)
sl@0
  1314
		{
sl@0
  1315
		random = random*69069+1;
sl@0
  1316
		TInt offset = random % size;
sl@0
  1317
		TInt value = dataStart[offset];
sl@0
  1318
		if (offset != 0 && value != 0)
sl@0
  1319
			return KErrGeneral;
sl@0
  1320
		++i;
sl@0
  1321
		}
sl@0
  1322
sl@0
  1323
	RDebug::Printf("%d: Performed %d accesses", ProcessNum, i);
sl@0
  1324
	return KErrNone;
sl@0
  1325
	}
sl@0
  1326
sl@0
  1327
void StartRandomAccessThread(TThreadPriority aPriority)
sl@0
  1328
	{
sl@0
  1329
	RandomAccessKill = EFalse;
sl@0
  1330
	test_noError(RandomAccessThread.Create(_L("RandomAccessThread"), RandomAccessFunc, 4096, NULL, 0));
sl@0
  1331
	RDebug::Printf("%d: starting thread with priority %d", ProcessNum, aPriority);
sl@0
  1332
	RandomAccessThread.SetPriority(aPriority);
sl@0
  1333
	RandomAccessThread.Resume();
sl@0
  1334
	}
sl@0
  1335
sl@0
  1336
void KillRandomAccessThread()
sl@0
  1337
	{
sl@0
  1338
	test_equal(EExitPending, RandomAccessThread.ExitType());
sl@0
  1339
	TRequestStatus status;
sl@0
  1340
	RandomAccessThread.Logon(status);
sl@0
  1341
	RandomAccessKill = ETrue;
sl@0
  1342
	User::WaitForRequest(status);
sl@0
  1343
	test_equal(EExitKill, RandomAccessThread.ExitType());
sl@0
  1344
	test_equal(0, RandomAccessThread.ExitReason());
sl@0
  1345
	RandomAccessThread.Close();
sl@0
  1346
	PagedLibrary.Close();
sl@0
  1347
	}
sl@0
  1348
sl@0
  1349
void TestLargeDll(TInt aDelay)
sl@0
  1350
	{
sl@0
  1351
	test.Next(_L("Test random access to a large dll"));
sl@0
  1352
	StartRandomAccessThread(EPriorityLess);
sl@0
  1353
	User::After(aDelay * 1000000);
sl@0
  1354
	KillRandomAccessThread();
sl@0
  1355
	}
sl@0
  1356
sl@0
  1357
void TestKillThreadWhilePaging()
sl@0
  1358
	{
sl@0
  1359
 	test.Next(_L("Test killing a thread while it is taking paging faults"));
sl@0
  1360
	for (TInt i = 0 ; i < 50 ; ++i)
sl@0
  1361
		{
sl@0
  1362
		RDebug::Printf("  iteration %d", i);
sl@0
  1363
		StartRandomAccessThread(EPriorityLess);
sl@0
  1364
		User::After(10000);  // time for ~ 10 paging requests
sl@0
  1365
		test_equal(EExitPending, RandomAccessThread.ExitType());
sl@0
  1366
		TRequestStatus status;
sl@0
  1367
		RandomAccessThread.Logon(status);
sl@0
  1368
		RandomAccessThread.Terminate(666);
sl@0
  1369
		User::WaitForRequest(status);
sl@0
  1370
		test_equal(EExitTerminate, RandomAccessThread.ExitType());
sl@0
  1371
		test_equal(666, RandomAccessThread.ExitReason());
sl@0
  1372
		RandomAccessThread.Close();
sl@0
  1373
		PagedLibrary.Close();
sl@0
  1374
		}
sl@0
  1375
	}
sl@0
  1376
sl@0
  1377
void TestUnloadDllWhilePaging()
sl@0
  1378
	{
sl@0
  1379
 	test.Next(_L("Test unloading a library while another thread is accessing it"));
sl@0
  1380
	OtherProcess.Exec(UnloadLargeLibrary);
sl@0
  1381
	for (TInt i = 0 ; i < 50 ; ++i)
sl@0
  1382
		{
sl@0
  1383
		RDebug::Printf("  iteration %d", i);
sl@0
  1384
		StartRandomAccessThread(EPriorityLess);
sl@0
  1385
		User::After(10000);  // time for ~ 10 paging requests
sl@0
  1386
		test_equal(EExitPending, RandomAccessThread.ExitType());
sl@0
  1387
		TRequestStatus status;
sl@0
  1388
		RandomAccessThread.Logon(status);
sl@0
  1389
		UnloadLargeLibrary();
sl@0
  1390
		PagedLibrary.Close();
sl@0
  1391
		User::WaitForRequest(status);
sl@0
  1392
		test_equal(EExitPanic, RandomAccessThread.ExitType());
sl@0
  1393
		test_equal(3, RandomAccessThread.ExitReason());  // KERN-EXEC 3
sl@0
  1394
		RandomAccessThread.Close();
sl@0
  1395
		LoadLargeLibrary();
sl@0
  1396
		}
sl@0
  1397
	OtherProcess.Exec(LoadLargeLibrary);
sl@0
  1398
	}
sl@0
  1399
sl@0
  1400
void PrintElapsedTime(TTime& aStartTime)
sl@0
  1401
	{		
sl@0
  1402
	TTime timeNow;
sl@0
  1403
	timeNow.UniversalTime();
sl@0
  1404
	TTimeIntervalSeconds elapsed;
sl@0
  1405
	test_noError(timeNow.SecondsFrom(aStartTime, elapsed));
sl@0
  1406
	test.Printf(_L("%d seconds elapsed\n"), elapsed.Int());
sl@0
  1407
	}
sl@0
  1408
sl@0
  1409
void TestManyProcesses(TInt aCount, TInt aDelay, TInt aPriorities = 1)
sl@0
  1410
	{
sl@0
  1411
	TBuf<128> name;
sl@0
  1412
	name.AppendFormat(_L("Test accessing paged code from %d processes at %d priority level(s) for %d seconds"),
sl@0
  1413
					  aCount, aPriorities, aDelay);
sl@0
  1414
	test.Next(name);
sl@0
  1415
sl@0
  1416
	TTime startTime;
sl@0
  1417
	startTime.UniversalTime();
sl@0
  1418
sl@0
  1419
	// start subprocesses and let them initialise
sl@0
  1420
	RArray<RTestSession> processes;
sl@0
  1421
	TInt threadsAtEachPriority = aCount / aPriorities;
sl@0
  1422
	for (TInt i = 0 ; i < aCount ; ++i)
sl@0
  1423
		{
sl@0
  1424
		RTestSession sess;
sl@0
  1425
		StartOtherProcess(i + 3, sess);
sl@0
  1426
		test_noError(processes.Append(sess));
sl@0
  1427
		sess.SetCurrentDrive(CurrentDrive);
sl@0
  1428
		}
sl@0
  1429
	test.Printf(_L("Started subprocesses: "));
sl@0
  1430
	PrintElapsedTime(startTime);
sl@0
  1431
	
sl@0
  1432
	// then start random accesses to paged memory
sl@0
  1433
	for (TInt i = 0 ; i < aCount ; ++i)
sl@0
  1434
		{
sl@0
  1435
		TThreadPriority pri;
sl@0
  1436
		switch (i / threadsAtEachPriority)
sl@0
  1437
			{
sl@0
  1438
			case 0:  pri = EPriorityLess; break;
sl@0
  1439
			default: pri = EPriorityMuchLess; break;
sl@0
  1440
			}
sl@0
  1441
		processes[i].StartRandomAccessThread(pri);
sl@0
  1442
		}
sl@0
  1443
	test.Printf(_L("Started threads: "));
sl@0
  1444
	PrintElapsedTime(startTime);
sl@0
  1445
sl@0
  1446
	test_noError(PagingInfo::ResetAll(LocalDriveNumber,EMediaPagingStatsCode));
sl@0
  1447
	User::After(aDelay * 1000000);
sl@0
  1448
	test_noError(PagingInfo::PrintAll(LocalDriveNumber,EMediaPagingStatsCode));
sl@0
  1449
sl@0
  1450
	test.Printf(_L("Killing subprocesses: "));
sl@0
  1451
	PrintElapsedTime(startTime);
sl@0
  1452
		
sl@0
  1453
	for (TInt i = 0 ; i < aCount ; ++i)
sl@0
  1454
		{
sl@0
  1455
		processes[i].Exec(KillRandomAccessThread);
sl@0
  1456
		processes[i].Kill();
sl@0
  1457
		processes[i].Close();
sl@0
  1458
		}
sl@0
  1459
sl@0
  1460
	test.Printf(_L("Test finished: "));
sl@0
  1461
	PrintElapsedTime(startTime);
sl@0
  1462
sl@0
  1463
	processes.Close();
sl@0
  1464
	}
sl@0
  1465
sl@0
  1466
void TestCacheSize()
sl@0
  1467
	{
sl@0
  1468
	test.Next(_L("Test cache size within bounds"));
sl@0
  1469
	TUint sizeMin = 0;
sl@0
  1470
	TUint sizeMax = 0;
sl@0
  1471
	TUint currentSize = 0;
sl@0
  1472
	DPTest::CacheSize(sizeMin,sizeMax,currentSize);
sl@0
  1473
	test.Printf(_L("  minimum size == %d pages\n"), sizeMin >> 12);
sl@0
  1474
	test.Printf(_L("  maximum size == %d pages\n"), sizeMax >> 12);
sl@0
  1475
	test.Printf(_L("  current size == %d pages\n"), currentSize >> 12);
sl@0
  1476
	test(currentSize >= sizeMin);
sl@0
  1477
	test(currentSize <= sizeMax);
sl@0
  1478
	}
sl@0
  1479
sl@0
  1480
void RunUnalignedAliasAccessTest()
sl@0
  1481
	{
sl@0
  1482
	test.Next(_L("Test accesses to aliased non-word-aligned data"));
sl@0
  1483
	
sl@0
  1484
	for (TInt size = 0 ; size <= 28 ; ++ size)
sl@0
  1485
		{
sl@0
  1486
		test.Printf(_L("  size = %d:"), size);
sl@0
  1487
		for (TInt align = 0 ; align <= 3 ; ++align)
sl@0
  1488
			{
sl@0
  1489
			test.Printf(_L(" %d"), align);
sl@0
  1490
			TPtrC8 des(LargeDataStart + align, size);
sl@0
  1491
			FlushAllPages();
sl@0
  1492
			OtherProcess.DesRead(des);			
sl@0
  1493
			}
sl@0
  1494
		test.Printf(_L("\n"));
sl@0
  1495
		}
sl@0
  1496
	}
sl@0
  1497
sl@0
  1498
void TestCodeChunkCreated()
sl@0
  1499
	{
sl@0
  1500
	LoadLibrary();
sl@0
  1501
	TAny* func = (TAny*)PagedLibrary.Lookup(KTestFunctionOrdinal);
sl@0
  1502
	test_notNull(func);
sl@0
  1503
	FlushAllPages();
sl@0
  1504
	test(GetPageState(func) & EPageStateCodeChunkPresent);
sl@0
  1505
	UnloadLibrary();
sl@0
  1506
	FlushAllPages();
sl@0
  1507
	test(!(GetPageState(func) & EPageStateCodeChunkPresent));
sl@0
  1508
	}
sl@0
  1509
sl@0
  1510
void TestRepeatedLoading()
sl@0
  1511
	{
sl@0
  1512
	test.Next(_L("Test loading/unloading a DLL doesn't leak address space"));
sl@0
  1513
sl@0
  1514
	for (TInt dll = 1 ; dll <= 7 ; ++dll)
sl@0
  1515
		{
sl@0
  1516
		test.Printf(_L("  trying dll %d...\n"), dll);
sl@0
  1517
		
sl@0
  1518
		RLibrary library;
sl@0
  1519
		test_noError(LoadSpecificLibrary(library, dll, CurrentDrive));
sl@0
  1520
		TLibraryFunction func1 = library.Lookup(1);
sl@0
  1521
		library.Close();
sl@0
  1522
		
sl@0
  1523
		test_noError(LoadSpecificLibrary(library, dll, CurrentDrive));
sl@0
  1524
		TLibraryFunction func2 = library.Lookup(1);
sl@0
  1525
		library.Close();
sl@0
  1526
sl@0
  1527
		test_equal(func1, func2);
sl@0
  1528
		}
sl@0
  1529
	}
sl@0
  1530
sl@0
  1531
void RunDriveIndependantTests()
sl@0
  1532
	{
sl@0
  1533
	if (MultipleMemoryModel)
sl@0
  1534
		{
sl@0
  1535
		test.Next(_L("Test code chunk created and destroyed correctly"));
sl@0
  1536
		TestCodeChunkCreated();
sl@0
  1537
		}
sl@0
  1538
	
sl@0
  1539
	SetCurrentDrive('Z');
sl@0
  1540
sl@0
  1541
	if (CanForcePageOut)
sl@0
  1542
		{
sl@0
  1543
		test.Next(_L("Test accessing pages by executing code"));
sl@0
  1544
		AccessMethod = EAccessExec;
sl@0
  1545
		RunPathTest(*TestPath);
sl@0
  1546
sl@0
  1547
		test.Next(_L("Test accessing pages by reading code"));
sl@0
  1548
		AccessMethod = EAccessRead;
sl@0
  1549
		RunPathTest(*TestPath);
sl@0
  1550
sl@0
  1551
		if (!MovingMemoryModel)
sl@0
  1552
			{
sl@0
  1553
			test.Next(_L("Test accessing pages by reading code from another process via an alias"));
sl@0
  1554
			AccessMethod = EAccessAliasRead;
sl@0
  1555
			RunPathTest(*TestPath);
sl@0
  1556
			}
sl@0
  1557
sl@0
  1558
		test.Next(_L("Test unmapping paged code"));
sl@0
  1559
		AccessMethod = EAccessExec;
sl@0
  1560
		RunUnmapTest(*TestPath);
sl@0
  1561
sl@0
  1562
		if (!MovingMemoryModel)
sl@0
  1563
			{
sl@0
  1564
			test.Next(_L("Test interactions between two processes"));
sl@0
  1565
			RunMultiProcessTest();
sl@0
  1566
			}
sl@0
  1567
		}
sl@0
  1568
sl@0
  1569
	RunReadExportDirTest();
sl@0
  1570
	RunPageLockingTest();
sl@0
  1571
	RunWriteToPagedCodeTest();
sl@0
  1572
	RunUnalignedAliasAccessTest();
sl@0
  1573
	TestRepeatedLoading();
sl@0
  1574
	}
sl@0
  1575
sl@0
  1576
void RunPerDriveTests()
sl@0
  1577
	{
sl@0
  1578
	TestContentsOfPagedDll();
sl@0
  1579
	TestContentsOfPagedDllWithRelocatedData();
sl@0
  1580
	TestKillThreadWhilePaging();
sl@0
  1581
	TestUnloadDllWhilePaging();
sl@0
  1582
	
sl@0
  1583
	TestLargeDll(5);
sl@0
  1584
sl@0
  1585
	TestManyProcesses(2, 5, 1);
sl@0
  1586
	TestManyProcesses(5, 10, 1);
sl@0
  1587
	TestManyProcesses(10, 20, 1);
sl@0
  1588
	TestManyProcesses(5, 10, 2);
sl@0
  1589
	TestManyProcesses(50, 2, 1);
sl@0
  1590
	}
sl@0
  1591
sl@0
  1592
void RunAllTests()
sl@0
  1593
	{
sl@0
  1594
sl@0
  1595
	RunDriveIndependantTests();
sl@0
  1596
	
sl@0
  1597
	for (TInt i = 0 ; i < SupportedDrives.Count() ; ++i)
sl@0
  1598
		{
sl@0
  1599
		SetCurrentDrive(SupportedDrives[i].iDriveLetter);
sl@0
  1600
		OtherProcess.SetCurrentDrive(CurrentDrive);
sl@0
  1601
sl@0
  1602
		TBuf<32> message;
sl@0
  1603
		message.AppendFormat(_L("Running tests on drive %c:"), (TUint) SupportedDrives[i].iDriveLetter);
sl@0
  1604
		test.Next(message);		
sl@0
  1605
		RunPerDriveTests();
sl@0
  1606
		}
sl@0
  1607
	TestCacheSize();
sl@0
  1608
	}
sl@0
  1609
sl@0
  1610
// Server implementation ///////////////////////////////////////////////////////
sl@0
  1611
sl@0
  1612
class CTestSession : public CSession2
sl@0
  1613
	{
sl@0
  1614
public:
sl@0
  1615
	virtual void ServiceL(const RMessage2& aMessage);
sl@0
  1616
	};
sl@0
  1617
sl@0
  1618
void CTestSession::ServiceL(const RMessage2& aMessage)
sl@0
  1619
	{
sl@0
  1620
	TInt r = KErrNone;
sl@0
  1621
	switch (aMessage.Function())
sl@0
  1622
		{
sl@0
  1623
		case RTestSession::EKill:
sl@0
  1624
			CActiveScheduler::Stop();
sl@0
  1625
			break;
sl@0
  1626
sl@0
  1627
		case RTestSession::EExec:
sl@0
  1628
			((TFunc)aMessage.Int0())();		   
sl@0
  1629
			break;
sl@0
  1630
sl@0
  1631
		case RTestSession::ESetCurrentDrive:
sl@0
  1632
			SetCurrentDrive(aMessage.Int0());
sl@0
  1633
			break;
sl@0
  1634
sl@0
  1635
		case RTestSession::EDesRead:
sl@0
  1636
			{
sl@0
  1637
			TBuf8<32> buf;
sl@0
  1638
			if (buf.MaxSize() < aMessage.GetDesLength(0))
sl@0
  1639
				r = KErrArgument;
sl@0
  1640
			else
sl@0
  1641
				r = aMessage.Read(0, buf);
sl@0
  1642
			}
sl@0
  1643
			break;
sl@0
  1644
sl@0
  1645
		case RTestSession::ETestPageState:
sl@0
  1646
			TestPageState((TPageState)aMessage.Int0(), (TPhysState)aMessage.Int1());
sl@0
  1647
			break;
sl@0
  1648
			
sl@0
  1649
		case RTestSession::ETestStateTransition:
sl@0
  1650
			TestStateTransition((TPageState)aMessage.Int0());
sl@0
  1651
			break;
sl@0
  1652
sl@0
  1653
		case RTestSession::EStartRandomAccessThread:
sl@0
  1654
			StartRandomAccessThread((TThreadPriority)aMessage.Int0());
sl@0
  1655
			break;
sl@0
  1656
sl@0
  1657
		default:
sl@0
  1658
			r = KErrNotSupported;
sl@0
  1659
			break;
sl@0
  1660
		}
sl@0
  1661
	
sl@0
  1662
	aMessage.Complete(r);
sl@0
  1663
	}
sl@0
  1664
sl@0
  1665
class CTestServer : public CServer2
sl@0
  1666
	{
sl@0
  1667
public:
sl@0
  1668
	CTestServer() : CServer2(0) { }
sl@0
  1669
	virtual CSession2* NewSessionL(const TVersion& aVersion,const RMessage2& aMessage) const;
sl@0
  1670
 };
sl@0
  1671
sl@0
  1672
CSession2* CTestServer::NewSessionL(const TVersion& /*aVersion*/,const RMessage2& /*aMessage*/) const
sl@0
  1673
	{
sl@0
  1674
	return new (ELeave) CTestSession();
sl@0
  1675
	}
sl@0
  1676
sl@0
  1677
void DoStartServerL()
sl@0
  1678
	{
sl@0
  1679
	CActiveScheduler* activeScheduler = new CActiveScheduler;
sl@0
  1680
	test_notNull(activeScheduler);
sl@0
  1681
	CActiveScheduler::Install(activeScheduler);
sl@0
  1682
	CTestServer* server = new CTestServer();
sl@0
  1683
	test_notNull(server);
sl@0
  1684
	TBuf<32> name;
sl@0
  1685
	name.AppendFormat(_L("%S-%d"), &KServerName, ProcessNum);
sl@0
  1686
	test_noError(server->Start(name));
sl@0
  1687
	RProcess().Rendezvous(KErrNone);
sl@0
  1688
	CActiveScheduler::Start();
sl@0
  1689
	delete server;
sl@0
  1690
	delete activeScheduler;
sl@0
  1691
	}
sl@0
  1692
sl@0
  1693
void StartServer()
sl@0
  1694
	{
sl@0
  1695
	CTrapCleanup* cleanupStack = CTrapCleanup::New();
sl@0
  1696
	test_notNull(cleanupStack);
sl@0
  1697
	TRAPD(leaveError,DoStartServerL());	
sl@0
  1698
	test_noError(leaveError);
sl@0
  1699
	delete cleanupStack;
sl@0
  1700
	}
sl@0
  1701
sl@0
  1702
void SecondaryProcess()
sl@0
  1703
	{
sl@0
  1704
	TBuf<16> cmd;
sl@0
  1705
	User::CommandLine(cmd);
sl@0
  1706
	TLex lex(cmd);
sl@0
  1707
	lex.Val(ProcessNum);
sl@0
  1708
sl@0
  1709
	TBuf<32> name;
sl@0
  1710
	name.AppendFormat(_L("t_codepaging-%d"), ProcessNum);
sl@0
  1711
	RProcess me;
sl@0
  1712
	test_noError(me.RenameMe(name));
sl@0
  1713
	
sl@0
  1714
	GetSupportedDrives(EFalse);
sl@0
  1715
	Initialise();
sl@0
  1716
	SetCurrentDrive('Z');
sl@0
  1717
	StartServer();
sl@0
  1718
	}
sl@0
  1719
sl@0
  1720
void MainProcess()
sl@0
  1721
	{
sl@0
  1722
	ProcessNum = 1;
sl@0
  1723
		
sl@0
  1724
	test.Title();
sl@0
  1725
	test.Start(_L("Code paging tests"));
sl@0
  1726
	
sl@0
  1727
	TUint32 memModelAttributes=UserSvr::HalFunction(EHalGroupKernel, EKernelHalMemModelInfo, NULL, NULL);
sl@0
  1728
	TUint32 pagingPolicy = E32Loader::PagingPolicy();
sl@0
  1729
	TBool codePagingSupported = (memModelAttributes & EMemModelAttrCodePaging) != 0;
sl@0
  1730
	TBool pagingPolicyAllowsPaging = pagingPolicy != EKernelConfigCodePagingPolicyNoPaging;
sl@0
  1731
	test_Equal(codePagingSupported, pagingPolicyAllowsPaging);
sl@0
  1732
	if(!codePagingSupported)
sl@0
  1733
		{
sl@0
  1734
		test.Printf(_L("TESTS NOT RUN - Code paging not enabled on system.\n"));
sl@0
  1735
		test.End();
sl@0
  1736
		return;
sl@0
  1737
		}
sl@0
  1738
	
sl@0
  1739
	GetSupportedDrives(ETrue);
sl@0
  1740
	test(SupportedDrives.Count() > 0);
sl@0
  1741
sl@0
  1742
	// Turn off evil lazy dll unloading
sl@0
  1743
	RLoader l;
sl@0
  1744
	test(l.Connect()==KErrNone);
sl@0
  1745
	test(l.CancelLazyDllUnload()==KErrNone);
sl@0
  1746
	l.Close();
sl@0
  1747
sl@0
  1748
	CopyDllsToSupportedDrives();
sl@0
  1749
sl@0
  1750
	Initialise();
sl@0
  1751
sl@0
  1752
	StartOtherProcess(2, OtherProcess);
sl@0
  1753
sl@0
  1754
	RunAllTests();
sl@0
  1755
sl@0
  1756
	OtherProcess.Kill();
sl@0
  1757
	OtherProcess.Close();
sl@0
  1758
	test.End();
sl@0
  1759
	}
sl@0
  1760
sl@0
  1761
sl@0
  1762
TInt E32Main()
sl@0
  1763
	{
sl@0
  1764
	if (User::CommandLineLength() == 0)
sl@0
  1765
		MainProcess();
sl@0
  1766
	else
sl@0
  1767
		SecondaryProcess();
sl@0
  1768
	
sl@0
  1769
	return 0;
sl@0
  1770
	}