1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/kernelhwsrv/kerneltest/e32test/mmu/t_chunk.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,1434 @@
1.4 +// Copyright (c) 1995-2009 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of the License "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +// e32test\mmu\t_chunk.cpp
1.18 +// Overview:
1.19 +// Test RChunk class
1.20 +// API Information:
1.21 +// RChunk, RChangeNotifier, TFindChunk
1.22 +// Details:
1.23 +// - Test adjusting chunks: create a global chunk, adjust it, do some size
1.24 +// checks, verify Create() rounds up to chunk multiple, verify that adjust
1.25 +// request for size greater than MaxSize returns an error.
1.26 +// - Test creating chunks with small sizes (0 and 1), verify results are as expected.
1.27 +// - Create multiple local and global chunks, verify that Size,MaxSize,Name & FullName methods
1.28 +// are as expected.
1.29 +// Check Create method of global chunk if the name is already in use. Check the name can be
1.30 +// reused after the chunk is closed.
1.31 +// - Perform adjust tests on a chunk, verify results are as expected.
1.32 +// - Open and test global chunks with multiple references, verify results are as expected.
1.33 +// - Open and test local chunks, check TFindChunk::Next method, verify results are as expected.
1.34 +// - Check user thread is panicked if it creates or adjusts chunk with negative size or of an
1.35 +// invalid type or with an invalid name.
1.36 +// - Check the chunk is filled in with the appropriate clear value after creation, verify results
1.37 +// are as expected.
1.38 +// - Test sharing a chunk between threads, verify results are as expected.
1.39 +// - Create a thread to watch for notification of changes in free memory and
1.40 +// changes in out of memory status. Verify adjusting an RChunk generates
1.41 +// the expected notifications.
1.42 +// - Test finding a global chunk by name and verify results are as expected.
1.43 +// - Check read-only global chunks cannot be written to by other processes.
1.44 +// Platforms/Drives/Compatibility:
1.45 +// All.
1.46 +// Assumptions/Requirement/Pre-requisites:
1.47 +// Failures and causes:
1.48 +// Base Port information:
1.49 +//
1.50 +//
1.51 +
1.52 +#define __E32TEST_EXTENSION__
1.53 +
1.54 +#include <e32test.h>
1.55 +#include <e32panic.h>
1.56 +#include <e32svr.h>
1.57 +#include "mmudetect.h"
1.58 +#include "d_gobble.h"
1.59 +#include "freeram.h"
1.60 +
1.61 +const TInt KHeapSize=0x200;
1.62 +
1.63 +//const TInt KNumberOfChunks=10; can't have that many
1.64 +const TInt KNumberOfChunks=3;
1.65 +
1.66 +const TInt KChunkNum=5;
1.67 +const TInt KNormalReturn=194;
1.68 +
1.69 +#ifdef __WINS__
1.70 +const TInt KMinChunkSizeInBytesMinus1=0x0000ffff;
1.71 +const TUint KMinChunkSizeInBytesMask=0xffff0000;
1.72 +#elif defined (__X86__)
1.73 +const TInt KMinChunkSizeInBytesMinus1=0x003fffff;
1.74 +const TUint KMinChunkSizeInBytesMask=0xffc00000;
1.75 +#else
1.76 +const TInt KMinChunkSizeInBytesMinus1=0x000fffff;
1.77 +const TUint KMinChunkSizeInBytesMask=0xfff00000;
1.78 +#endif
1.79 +
1.80 +const TInt KMinPageSizeInBytesMinus1=0x00000fff;
1.81 +const TUint KMinPageSizeInBytesMask=0xfffff000;
1.82 +TInt gPageSize;
1.83 +
1.84 +LOCAL_D RTest test(_L("T_CHUNK"));
1.85 +LOCAL_D RTest t(_L("ShareThread"));
1.86 +LOCAL_D RChunk gChunk;
1.87 +
1.88 +LOCAL_D TPtr nullPtr(NULL,0);
1.89 +
1.90 +TUint32 MemModel;
1.91 +
1.92 +enum TDirective
1.93 + {
1.94 + ENormal,
1.95 + ECreateNegative,
1.96 + EAdjustNegative,
1.97 + ECreateInvalidType,
1.98 + ECreateInvalidName,
1.99 + ECreateNoName,
1.100 + };
1.101 +
1.102 +const TUint8 KDfltClearByte = 0x3;
1.103 +TBool CheckChunkCleared(RChunk& aRC, TInt aOffset=0, TUint8 aClearByte = KDfltClearByte)
1.104 + {
1.105 + TUint8* base = aRC.Base()+aOffset;
1.106 + TInt size = aRC.Size();
1.107 + test.Printf(_L("Testing chunk for 0x%x - size: %d!\n"), aClearByte, size);
1.108 + TBool ret=ETrue;
1.109 + for(TInt i = 0; i<size; i++)
1.110 + if(base[i] != aClearByte)
1.111 + ret=EFalse;
1.112 + memset((TAny*)base, 0x05, size);
1.113 + return ret;
1.114 + }
1.115 +
1.116 +TInt roundToPageSize(TInt aSize)
1.117 + {
1.118 +
1.119 + return(((aSize+KMinPageSizeInBytesMinus1)&KMinPageSizeInBytesMask));
1.120 + }
1.121 +
1.122 +TInt roundToChunkSize(TInt aSize)
1.123 + {
1.124 + if(MemModel==EMemModelTypeFlexible)
1.125 + return roundToPageSize(aSize);
1.126 + return(((aSize+KMinChunkSizeInBytesMinus1)&KMinChunkSizeInBytesMask));
1.127 + }
1.128 +
1.129 +TInt ThreadEntry2(TAny* /*aParam*/)
1.130 +//
1.131 +// Thread to read from shared chunk
1.132 +//
1.133 + {
1.134 + RChunk c;
1.135 + TInt r;
1.136 + r=c.OpenGlobal(_L("Marmalade"),ETrue);
1.137 + t(r==KErrNone);
1.138 + TUint8* base=c.Base();
1.139 + for (TInt8 i=0;i<10;i++)
1.140 + t(*base++==i); // check the chunk has 0-9
1.141 + c.Close();
1.142 + return(KErrNone);
1.143 + }
1.144 +
1.145 +TInt ThreadEntry(TAny* aDirective)
1.146 +//
1.147 +// Thread to create a Panic in a variety of ways
1.148 +//
1.149 + {
1.150 +
1.151 + switch((TUint)aDirective)
1.152 + {
1.153 + case ENormal:
1.154 + {
1.155 + return KNormalReturn;
1.156 + }
1.157 + case ECreateNegative:
1.158 + {
1.159 + gChunk.CreateLocal(0x10,-0x10);
1.160 + test(EFalse);
1.161 + }
1.162 + case EAdjustNegative:
1.163 + {
1.164 + gChunk.Adjust(-0x10);
1.165 + test(EFalse);
1.166 + }
1.167 + case ECreateInvalidType :
1.168 + {
1.169 + TChunkCreateInfo createInfo;
1.170 + createInfo.SetCode(gPageSize, gPageSize);
1.171 + _LIT(KChunkName, "Chunky");
1.172 + createInfo.SetGlobal(KChunkName);
1.173 + RChunk chunk;
1.174 + chunk.Create(createInfo);
1.175 + test(EFalse);
1.176 + }
1.177 + default:
1.178 + test(EFalse);
1.179 + }
1.180 + return(KErrNone);
1.181 + }
1.182 +
1.183 +//
1.184 +// Test the clear flags for the specified chunk.
1.185 +// Assumes chunk has one commited region from base to aBytes.
1.186 +//
1.187 +void TestClearChunk(RChunk& aChunk, TUint aBytes, TUint8 aClearByte)
1.188 + {
1.189 + test_Equal(ETrue, CheckChunkCleared(aChunk, 0, aClearByte));
1.190 + test_KErrNone(aChunk.Adjust(0));
1.191 + test_KErrNone(aChunk.Adjust(aBytes));
1.192 + test_Equal(ETrue, CheckChunkCleared(aChunk, 0, aClearByte));
1.193 + aChunk.Close();
1.194 + }
1.195 +
1.196 +
1.197 +//
1.198 +// Create the specified thread and verify the exit reason.
1.199 +//
1.200 +void TestThreadExit(TExitType aExitType, TInt aExitReason, TThreadFunction aFunc, TAny* aThreadParam)
1.201 + {
1.202 + RThread thread;
1.203 + test_KErrNone(thread.Create(_L("RChunkPanicThread"), aFunc, KDefaultStackSize,
1.204 + KHeapSize, KHeapSize, aThreadParam));
1.205 + // Disable JIT debugging.
1.206 + TBool justInTime=User::JustInTime();
1.207 + User::SetJustInTime(EFalse);
1.208 +
1.209 + TRequestStatus status;
1.210 + thread.Logon(status);
1.211 + thread.Resume();
1.212 + User::WaitForRequest(status);
1.213 + test_Equal(aExitType, thread.ExitType());
1.214 + test_Equal(aExitReason, status.Int());
1.215 + test_Equal(aExitReason, thread.ExitReason());
1.216 + if (aExitType == EExitPanic)
1.217 + test(thread.ExitCategory()==_L("USER"));
1.218 + CLOSE_AND_WAIT(thread);
1.219 +
1.220 + // Put JIT debugging back to previous status.
1.221 + User::SetJustInTime(justInTime);
1.222 + }
1.223 +
1.224 +
1.225 +//
1.226 +// Thread function to create a chunk with invalid attributes
1.227 +//
1.228 +TInt ChunkPanicThread(TAny* aCreateInfo)
1.229 + {
1.230 + // This should panic.
1.231 + RChunk chunk;
1.232 + chunk.Create((*(TChunkCreateInfo*) aCreateInfo));
1.233 + test(EFalse);
1.234 +
1.235 + return KErrGeneral; // Shouldn't reach here.
1.236 + }
1.237 +
1.238 +void testInitialise()
1.239 + {
1.240 + test.Next(_L("Load gobbler LDD"));
1.241 + TInt r = User::LoadLogicalDevice(KGobblerLddFileName);
1.242 + test(r==KErrNone || r==KErrAlreadyExists);
1.243 +
1.244 + // get system info...
1.245 + MemModel = UserSvr::HalFunction(EHalGroupKernel, EKernelHalMemModelInfo, NULL, NULL) & EMemModelTypeMask;
1.246 +
1.247 + test_KErrNone(UserHal::PageSizeInBytes(gPageSize));
1.248 + }
1.249 +
1.250 +
1.251 +void test1()
1.252 +//
1.253 +// Test creating chunks with silly sizes
1.254 +//
1.255 + {
1.256 +
1.257 + __KHEAP_MARK;
1.258 + RChunk chunk;
1.259 + TInt r;
1.260 + test.Start(_L("Create global chunks"));
1.261 + r=chunk.CreateGlobal(_L("Fopp"),1,1);
1.262 + test(r==KErrNone);
1.263 + chunk.Close();
1.264 + r=chunk.CreateGlobal(_L("Fopp"),0,0);
1.265 + test(r==KErrArgument);
1.266 +
1.267 + __KHEAP_CHECK(0);
1.268 +
1.269 + test.Next(_L("Create local chunks"));
1.270 + r=chunk.CreateLocal(1,1);
1.271 + test(r==KErrNone);
1.272 + chunk.Close();
1.273 + r=chunk.CreateLocal(0,0);
1.274 + test(r==KErrArgument);
1.275 + test.End();
1.276 + __KHEAP_MARKEND;
1.277 + }
1.278 +
1.279 +
1.280 +void test2(TInt aSize)
1.281 +//
1.282 +// Test local/global chunk creation
1.283 +//
1.284 + {
1.285 +
1.286 + RChunk lchunk[KNumberOfChunks];
1.287 + RChunk gchunk[KNumberOfChunks];
1.288 + RChunk chunk;
1.289 +
1.290 + __KHEAP_MARK;
1.291 + test.Start(_L("Create multiple local and global chunks"));
1.292 +
1.293 + TInt i;
1.294 + TBuf<0x40> name;
1.295 + TFullName fullname;
1.296 + for (i=0; i<KNumberOfChunks; i++)
1.297 + {
1.298 + TInt r;
1.299 + // create a local chunk
1.300 + r=lchunk[i].CreateLocal(aSize,aSize);
1.301 + test(r==KErrNone);
1.302 + r=lchunk[i].MaxSize();
1.303 + test(r==roundToChunkSize(aSize));
1.304 + test(lchunk[i].Size()==roundToPageSize(aSize)); // was 0
1.305 + test(lchunk[i].Name().Left(6)==_L("Local-"));
1.306 +
1.307 + fullname=RProcess().Name();
1.308 + fullname+=_L("::");
1.309 + fullname+=lchunk[i].Name();
1.310 + test(lchunk[i].FullName().CompareF(fullname)==0);
1.311 +
1.312 + // create a global chunk
1.313 + name.Format(_L("Chunk%d"),i);
1.314 + r=gchunk[i].CreateGlobal(name,aSize,aSize);
1.315 + test(r==KErrNone);
1.316 + test(gchunk[i].MaxSize()==roundToChunkSize(aSize));
1.317 + test(gchunk[i].Size()==roundToPageSize(aSize)); // was 0
1.318 + test(gchunk[i].Name()==name);
1.319 + }
1.320 +
1.321 + // make room for another chunk
1.322 + lchunk[KNumberOfChunks-1].Close();
1.323 + gchunk[KNumberOfChunks-1].Close();
1.324 +
1.325 +// Try to create a global chunk with a duplicate name
1.326 + test.Next(_L("Create a chunk with a duplicate name"));
1.327 + TInt r=chunk.CreateGlobal(_L("Chunk0"),aSize,aSize);
1.328 + test(r==KErrAlreadyExists);
1.329 +
1.330 + test.Next(_L("Close all chunks"));
1.331 + for (i=0; i<KNumberOfChunks-1; i++)
1.332 + {
1.333 + lchunk[i].Close();
1.334 + gchunk[i].Close();
1.335 + }
1.336 +
1.337 + test.Next(_L("Reuse a name"));
1.338 + r=chunk.CreateGlobal(_L("Chunk1"),aSize,aSize);
1.339 + test(r==KErrNone);
1.340 + test(chunk.MaxSize()==roundToChunkSize(aSize));
1.341 + test(chunk.Size()==roundToPageSize(aSize));
1.342 + test(chunk.Name()==_L("Chunk1"));
1.343 + chunk.Close();
1.344 +
1.345 + test.End();
1.346 + __KHEAP_MARKEND;
1.347 + }
1.348 +
1.349 +void test3_2(RChunk& aChunk, TInt aSize)
1.350 +//
1.351 +// Perform Adjust tests on aChunk
1.352 +//
1.353 + {
1.354 +
1.355 + TInt r;
1.356 + test.Start(_L("Adjust to full size"));
1.357 + r=aChunk.Adjust(aSize);
1.358 + test(r==KErrNone);
1.359 + test(aChunk.Size()==roundToPageSize(aSize));
1.360 + test(aChunk.MaxSize()==roundToChunkSize(aSize));
1.361 +
1.362 + test.Next(_L("Adjust a chunk to half size"));
1.363 + r=aChunk.Adjust(aSize/2);
1.364 + test(r==KErrNone);
1.365 + test(aChunk.Size()==roundToPageSize(aSize/2));
1.366 + test(aChunk.MaxSize()==roundToChunkSize(aSize));
1.367 +
1.368 + test.Next(_L("Adjust to same size"));
1.369 + r=aChunk.Adjust(aSize/2);
1.370 + test(r==KErrNone);
1.371 + test(aChunk.Size()==roundToPageSize(aSize/2));
1.372 + test(aChunk.MaxSize()==roundToChunkSize(aSize));
1.373 +
1.374 + test.Next(_L("Adjusting to size=0"));
1.375 + r=aChunk.Adjust(0);
1.376 + test(r==KErrNone);
1.377 + test(aChunk.Size()==0);
1.378 + test(aChunk.MaxSize()==roundToChunkSize(aSize));
1.379 +
1.380 + test.Next(_L("Adjust back to half size"));
1.381 + r=aChunk.Adjust(aSize/2);
1.382 + test(r==KErrNone);
1.383 + test(aChunk.Size()==roundToPageSize(aSize/2));
1.384 + test(aChunk.MaxSize()==roundToChunkSize(aSize));
1.385 +
1.386 + test.End();
1.387 + }
1.388 +
1.389 +
1.390 +void test3(TInt aSize)
1.391 +//
1.392 +// Test Adjust size of chunk
1.393 +//
1.394 + {
1.395 +
1.396 + RChunk chunk;
1.397 + __KHEAP_MARK;
1.398 + TInt r;
1.399 +// Run Adjust tests with a local chunk
1.400 + test.Start(_L("Local Chunk.Adjust()"));
1.401 + r=chunk.CreateLocal(aSize,aSize);
1.402 + test3_2(chunk, aSize);
1.403 + chunk.Close();
1.404 +// Run Adjust tests with a global chunk
1.405 + test.Next(_L("Global Chunk.Adjust()"));
1.406 + r=chunk.CreateGlobal(_L("Fopp"),aSize,aSize);
1.407 + test(KErrNone==r);
1.408 + test3_2(chunk,aSize);
1.409 + chunk.Close();
1.410 + test.End();
1.411 + __KHEAP_MARKEND;
1.412 + }
1.413 +
1.414 +void test4(TInt aSize)
1.415 +//
1.416 +// Test OpenGlobal
1.417 +//
1.418 + {
1.419 +
1.420 + RChunk chunk[KChunkNum];
1.421 + RChunk c1, c2, c3;
1.422 + TName name;
1.423 +
1.424 + __KHEAP_MARK;
1.425 + TInt i,r;
1.426 + for (i=0; i<KChunkNum; i++)
1.427 + {
1.428 + name.Format(_L("Chunk%d"), i);
1.429 + r=chunk[i].CreateGlobal(name,aSize,aSize);
1.430 + }
1.431 +
1.432 + test.Start(_L("Open Global chunks"));
1.433 + r=c1.OpenGlobal(_L("Chunk1"),EFalse); // 2nd ref to this chunk
1.434 + test(r==KErrNone);
1.435 + r=c2.OpenGlobal(_L("Chunk3"),EFalse); // 2nd ref to this chunk
1.436 + test(r==KErrNone);
1.437 + r=c3.OpenGlobal(_L("Chunk4"),EFalse); // 2nd ref to this chunk
1.438 + test(r==KErrNone);
1.439 + c3.Close();
1.440 +
1.441 + test.Next(_L("Attempt Open non-existant chunk"));
1.442 + r=c3.OpenGlobal(_L("Non Existant Chunk"),EFalse);
1.443 + test(r==KErrNotFound);
1.444 +
1.445 + for (i=0; i<KChunkNum; i++)
1.446 + {
1.447 + test.Printf(_L("Closing chunk %d\n"),i);
1.448 + chunk[i].Close();
1.449 + }
1.450 +
1.451 + test.Next(_L("Test chunks with multiple references are still valid"));
1.452 + r=c1.Adjust(aSize/2);
1.453 + test(r==KErrNone);
1.454 + test(c1.MaxSize()==roundToChunkSize(aSize));
1.455 + test(c1.Size()==roundToPageSize(aSize/2));
1.456 + test(c1.Name()==_L("Chunk1"));
1.457 +
1.458 + r=c2.Adjust(aSize/2);
1.459 + test(r==KErrNone);
1.460 + test(c2.MaxSize()==roundToChunkSize(aSize));
1.461 + test(c2.Size()==roundToPageSize(aSize/2));
1.462 + test(c2.Name()==_L("Chunk3"));
1.463 +
1.464 +// Open another reference to a chunk
1.465 + r=c3.OpenGlobal(_L("Chunk3"),EFalse);
1.466 + test(r==KErrNone);
1.467 + test(c3.Base()==c2.Base());
1.468 + test(c3.Size()==c2.Size());
1.469 + test(c2.Size()!=aSize);
1.470 +// Adjust with one reference
1.471 + r=c3.Adjust(aSize);
1.472 + test(r==KErrNone);
1.473 +// Test sizes from the other
1.474 + test(c2.Size()==roundToPageSize(aSize));
1.475 + test(c2.MaxSize()==roundToChunkSize(aSize));
1.476 +
1.477 + c1.Close();
1.478 + c2.Close();
1.479 + c3.Close();
1.480 +
1.481 + test.Next(_L("And check the heap..."));
1.482 + test.End();
1.483 + __KHEAP_MARKEND;
1.484 + }
1.485 +
1.486 +void test5(TInt aSize)
1.487 +//
1.488 +// Test Open
1.489 +//
1.490 + {
1.491 +
1.492 + RChunk chunk[2*KNumberOfChunks];
1.493 + RChunk c1;
1.494 +
1.495 + test.Start(_L("Creating Local and Global Chunks"));
1.496 + __KHEAP_MARK;
1.497 + TInt i,r;
1.498 + TBuf<0x40> b;
1.499 +
1.500 +// Create KNumberOfChunks Global chunks
1.501 + for (i=0; i<KNumberOfChunks; i++)
1.502 + {
1.503 + b.Format(_L("Chunk%d"), i);
1.504 + r=chunk[i].CreateGlobal(b,aSize,aSize);
1.505 + test(chunk[i].Name()==b);
1.506 + test(r==KErrNone);
1.507 +
1.508 + b.Format(_L("This is chunk %d"), i);
1.509 + b.Append(TChar(0));
1.510 + chunk[i].Adjust(aSize);
1.511 + Mem::Copy(chunk[i].Base(), b.Ptr(), b.Size());
1.512 + test(chunk[i].MaxSize()==roundToChunkSize(aSize));
1.513 + test(chunk[i].Size()==roundToPageSize(aSize));
1.514 + }
1.515 +
1.516 + test.Next(_L("Find and Open the Chunks"));
1.517 + TFindChunk find;
1.518 + TFullName name;
1.519 + for (i=0; i<KNumberOfChunks; i++)
1.520 + {
1.521 + test.Printf(_L("Opening chunk %d\n"),i);
1.522 + find.Find(chunk[i].FullName());
1.523 + r = find.Next(name);
1.524 + test(r==KErrNone);
1.525 + c1.Open(find);
1.526 + b=TPtrC((TText*)c1.Base());
1.527 + name.Format(_L("This is chunk %d"), i);
1.528 + test(b==name);
1.529 + c1.Close();
1.530 + }
1.531 +
1.532 + test.Next(_L("Close chunks"));
1.533 + for (i=0; i<KNumberOfChunks; i++)
1.534 + chunk[i].Close();
1.535 +
1.536 + test.End();
1.537 + __KHEAP_MARKEND;
1.538 + }
1.539 +
1.540 +
1.541 +void test7(TInt aSize)
1.542 +//
1.543 +// Deliberately cause RChunk panics
1.544 +//
1.545 + {
1.546 + __KHEAP_MARK;
1.547 +
1.548 +// ENormal
1.549 + test.Start(_L("Test panic thread"));
1.550 + TestThreadExit(EExitKill, KNormalReturn, ThreadEntry, (TAny*)ENormal);
1.551 +
1.552 +// ECreateNegative
1.553 + test.Next(_L("Create Chunk with a negative size"));
1.554 + TestThreadExit(EExitPanic, EChkCreateMaxSizeNegative, ThreadEntry, (TAny*) ECreateNegative);
1.555 +
1.556 +// EAdjustNegative
1.557 + test.Next(_L("Adjust a Chunk to Size = -0x10"));
1.558 + gChunk.CreateLocal(aSize,aSize);
1.559 + TestThreadExit(EExitPanic, EChkAdjustNewSizeNegative, ThreadEntry, (TAny*) EAdjustNegative);
1.560 + gChunk.Close();
1.561 +
1.562 +// ECreateInvalidType
1.563 + test.Next(_L("Create chunk of invalid type"));
1.564 + TestThreadExit(EExitPanic, EChkCreateInvalidType, ThreadEntry, (TAny*) ECreateInvalidType);
1.565 +
1.566 + test.End();
1.567 +
1.568 + __KHEAP_MARKEND;
1.569 + }
1.570 +
1.571 +
1.572 +void testClear(TInt aSize)
1.573 + {
1.574 + __KHEAP_MARK;
1.575 + test.Start(_L("Test clearing memory (Platform Security)"));
1.576 +
1.577 + RChunk c1,c2,c3,c4,c5,c6,c7,c8,c9,c10;
1.578 + TInt r;
1.579 +
1.580 + TBuf<0x40> b;
1.581 +
1.582 + b.Copy(_L("Chunk"));
1.583 +
1.584 + r=c1.CreateGlobal(b,aSize,aSize);
1.585 + test(r==KErrNone);
1.586 +
1.587 + test((TBool)ETrue==CheckChunkCleared(c1));
1.588 + c1.Close();
1.589 +
1.590 + r=c2.CreateLocal(aSize,aSize,EOwnerProcess);
1.591 + test(r==KErrNone);
1.592 +
1.593 + test((TBool)ETrue==CheckChunkCleared(c2));
1.594 + c2.Close();
1.595 +
1.596 + r=c3.CreateLocalCode(aSize,aSize,EOwnerProcess);
1.597 + test(r==KErrNone);
1.598 +
1.599 + test((TBool)ETrue==CheckChunkCleared(c3));
1.600 + c3.Close();
1.601 +
1.602 + r=c4.CreateDoubleEndedLocal(0x1000,0x1000+aSize,0x100000);
1.603 + test(r==KErrNone);
1.604 +
1.605 + test((TBool)ETrue==CheckChunkCleared(c4,c4.Bottom()));
1.606 + c4.Close();
1.607 +
1.608 + r=c5.CreateDoubleEndedGlobal(b,0x1000,0x1000+aSize,0x100000,EOwnerProcess);
1.609 + test(r==KErrNone);
1.610 +
1.611 + test((TBool)ETrue==CheckChunkCleared(c5,c5.Bottom()));
1.612 + c5.Close();
1.613 +
1.614 + r=c6.CreateDisconnectedLocal(0x1000,0x1000+aSize,0x100000);
1.615 + test(r==KErrNone);
1.616 +
1.617 + test((TBool)ETrue==CheckChunkCleared(c6,0x1000));
1.618 + c6.Close();
1.619 +
1.620 + r=c7.CreateDisconnectedGlobal(b,0x1000,0x1000+aSize,0x100000,EOwnerProcess);
1.621 + test(r==KErrNone);
1.622 +
1.623 + test((TBool)ETrue==CheckChunkCleared(c7,0x1000));
1.624 + c7.Close();
1.625 +
1.626 + test.Next(_L("Test setting the clear byte of RChunk::Create()"));
1.627 +
1.628 + TChunkCreateInfo createInfo;
1.629 + createInfo.SetNormal(aSize, aSize);
1.630 + test_KErrNone(c10.Create(createInfo));
1.631 + TestClearChunk(c10, aSize, KDfltClearByte);
1.632 +
1.633 + createInfo.SetClearByte(0x0);
1.634 + test_KErrNone(c8.Create(createInfo));
1.635 + TestClearChunk(c8, aSize, 0x0);
1.636 +
1.637 + createInfo.SetClearByte(0xff);
1.638 + test_KErrNone(c9.Create(createInfo));
1.639 + TestClearChunk(c9, aSize, 0xff);
1.640 +
1.641 + test.End();
1.642 + __KHEAP_MARKEND;
1.643 + }
1.644 +
1.645 +void testShare()
1.646 +//
1.647 +// Test sharing a chunk between threads
1.648 +//
1.649 + {
1.650 + test.Start(_L("Test chunk sharing between threads"));
1.651 +
1.652 + test.Next(_L("Create chunk Marmalade"));
1.653 + TInt r=0;
1.654 + RChunk chunk;
1.655 + TInt size=0x1000;
1.656 + TInt maxSize=0x5000;
1.657 + r=0;
1.658 + r=chunk.CreateGlobal(_L("Marmalade"),size,maxSize);
1.659 + test(r==KErrNone);
1.660 + test.Next(_L("Write 0-9 to it"));
1.661 + TUint8* base=chunk.Base();
1.662 + for (TInt8 j=0;j<10;j++)
1.663 + *base++=j; // write 0 - 9 to the chunk
1.664 +
1.665 + RThread t;
1.666 + TRequestStatus stat;
1.667 + test.Next(_L("Create reader thread"));
1.668 + r=t.Create(_L("RChunkShareThread"), ThreadEntry2, KDefaultStackSize,KHeapSize,KHeapSize,NULL);
1.669 + test(r==KErrNone);
1.670 + t.Logon(stat);
1.671 + test.Next(_L("Resume reader thread"));
1.672 + t.Resume();
1.673 + User::WaitForRequest(stat);
1.674 + CLOSE_AND_WAIT(t);
1.675 + chunk.Close();
1.676 +
1.677 + test.End();
1.678 + }
1.679 +
1.680 +void FindChunks()
1.681 + { // taken from some code written by SteveG
1.682 + test.Start(_L("Finding chunks...\n"));
1.683 +
1.684 + TFullName name=_L("*");
1.685 + TFindChunk find(name);
1.686 + TInt i=0;
1.687 +
1.688 +
1.689 + while (find.Next(name)==KErrNone)
1.690 + {
1.691 + RChunk chunk;
1.692 + test.Printf(_L("Chunk name %S\n"),&name);
1.693 + TInt err=chunk.Open(find);
1.694 + if (err)
1.695 + test.Printf(_L("Error %d opening chunk"),err);
1.696 + else
1.697 + {
1.698 + TBuf<16> access;
1.699 + if (chunk.IsWritable())
1.700 + access=_L("ReadWrite");
1.701 + else if (chunk.IsReadable())
1.702 + access=_L("ReadOnly");
1.703 + else
1.704 + access=_L("No Access");
1.705 + test.Printf(_L("Chunk size %08x bytes, %S\n"),chunk.Size(),&access);
1.706 + chunk.Close();
1.707 + i++;
1.708 + }
1.709 + User::After(1000000);
1.710 + }
1.711 + test.End();
1.712 + }
1.713 +
1.714 +void testAdjustChunk()
1.715 + {
1.716 + test.Start(_L("Test adjusting chunks"));
1.717 +
1.718 + RChunk hermione;
1.719 +
1.720 + test.Next(_L("Create global chunk"));
1.721 + TInt r=hermione.CreateGlobal(_L("Hermione"),0x1000,0x100000);
1.722 + test(r==KErrNone);
1.723 + TUint32* base=(TUint32*)hermione.Base();
1.724 + TUint32* top=(TUint32*)(hermione.Base()+hermione.Size());
1.725 + TUint32* i;
1.726 +
1.727 + test.Printf(_L("Base = %08x, Top = %08x\n"),base,top);
1.728 + test.Next(_L("Check I can write to all of it"));
1.729 + for (i=base;i<top;i++)
1.730 + *i=0xdeaddead;
1.731 +
1.732 + test.Next(_L("Adjust the chunk"));
1.733 + r=hermione.Adjust(0x1400);
1.734 + test(r==KErrNone);
1.735 +
1.736 + base=(TUint32*)hermione.Base();
1.737 + top=(TUint32*)(hermione.Base()+hermione.Size());
1.738 + test.Printf(_L("Base = %08x, Top = %08x\n"),base,top);
1.739 + test.Next(_L("Check I can write to all of the bigger chunk"));
1.740 + for (i=base;i<top;i++)
1.741 + *i=0xdeaddead;
1.742 +
1.743 + hermione.Close();
1.744 +
1.745 + test.Next(_L("Do some size checks"));
1.746 + RChunk wibble;
1.747 + r=wibble.CreateGlobal(_L("Wibble"),0x1,gPageSize*8);
1.748 + test(r==KErrNone);
1.749 + test.Next(_L("Check create rounds up to page multiple"));
1.750 + test(wibble.Size()==(TInt)gPageSize);
1.751 + test.Next(_L("Check create rounds up to chunk multiple"));
1.752 + test(wibble.MaxSize()==roundToChunkSize(gPageSize*8));
1.753 +
1.754 + test.Next(_L("Check adjust rounds up to page multiple"));
1.755 + r=wibble.Adjust((gPageSize*6)-12);
1.756 + test(r==KErrNone);
1.757 + test(wibble.Size()==gPageSize*6);
1.758 +
1.759 + test.Next(_L("Different number, same size"));
1.760 + r=wibble.Adjust((gPageSize*6)-18);
1.761 + test(r==KErrNone);
1.762 + test(wibble.Size()==gPageSize*6);
1.763 +
1.764 + test.Next(_L("Check adjust > MaxSize returns error"));
1.765 + r=wibble.Adjust(wibble.MaxSize()+gPageSize);
1.766 + test(r==KErrArgument);
1.767 +
1.768 + wibble.Close();
1.769 + test.End();
1.770 + }
1.771 +
1.772 +TInt NotifierCount=0;
1.773 +TInt OOMCount=0;
1.774 +RChangeNotifier Notifier;
1.775 +RThread NtfThrd;
1.776 +_LIT(KNotifierThreadName,"NotifierThread");
1.777 +
1.778 +TInt NotifierThread(TAny*)
1.779 + {
1.780 + TInt r=Notifier.Create();
1.781 + while (r==KErrNone)
1.782 + {
1.783 + TRequestStatus s;
1.784 + r=Notifier.Logon(s);
1.785 + if (r!=KErrNone)
1.786 + break;
1.787 + User::WaitForRequest(s);
1.788 + if (s.Int()&EChangesFreeMemory)
1.789 + ++NotifierCount;
1.790 + if (s.Int()&EChangesOutOfMemory)
1.791 + ++OOMCount;
1.792 + }
1.793 + Notifier.Close();
1.794 + return r;
1.795 + }
1.796 +
1.797 +
1.798 +void WaitForNotifier()
1.799 + {
1.800 + User::After(500000); // wait for notifier
1.801 + }
1.802 +
1.803 +
1.804 +void CheckNotifierCount(TInt aLevel, TInt aOom)
1.805 + {
1.806 + WaitForNotifier();
1.807 + if (NtfThrd.ExitType()!=EExitPending)
1.808 + {
1.809 + TExitCategoryName exitCat=NtfThrd.ExitCategory();
1.810 + test.Printf(_L("Thread exited: %d,%d,%S"),NtfThrd.ExitType(),NtfThrd.ExitReason(),&exitCat);
1.811 + test(0);
1.812 + }
1.813 + TInt c1=NotifierCount;
1.814 + TInt c2=OOMCount;
1.815 + if (c1!=aLevel || c2!=aOom)
1.816 + {
1.817 + test.Printf(_L("Count %d,%d Expected %d,%d"),c1,c2,aLevel,aOom);
1.818 + test(0);
1.819 + }
1.820 + }
1.821 +
1.822 +void testNotifiers()
1.823 + {
1.824 + RGobbler gobbler;
1.825 + TInt r = gobbler.Open();
1.826 + test(r==KErrNone);
1.827 + TUint32 taken = gobbler.GobbleRAM(128*1024*1024);
1.828 + test.Printf(_L("Gobbled: %dK\n"), taken/1024);
1.829 + test.Printf(_L("Free RAM 0x%08X bytes\n"),FreeRam());
1.830 +
1.831 + test.Next(_L("Create thread"));
1.832 + r=NtfThrd.Create(KNotifierThreadName,NotifierThread,KDefaultStackSize,NULL,NULL);
1.833 + test(r==KErrNone);
1.834 + NtfThrd.SetPriority(EPriorityMore);
1.835 + NtfThrd.Resume();
1.836 + test.Next(_L("Check for initial notifier"));
1.837 + CheckNotifierCount(1,1);
1.838 + TInt free=FreeRam();
1.839 + test.Printf(_L("Free RAM: %dK\n"),free/1024);
1.840 + test(free>=1048576);
1.841 + test.Next(_L("Set thresholds"));
1.842 + r=UserSvr::SetMemoryThresholds(65536,524288); // low=64K good=512K
1.843 + test(r==KErrNone);
1.844 + test.Next(_L("Create chunk"));
1.845 + // Chunk must not be paged otherwise it will not effect the amount
1.846 + // of free ram reported plus on h4 swap size is less than the total ram.
1.847 + TChunkCreateInfo createInfo;
1.848 + createInfo.SetNormal(0, free+2097152);
1.849 + createInfo.SetPaging(TChunkCreateInfo::EUnpaged);
1.850 + RChunk c;
1.851 + test_KErrNone(c.Create(createInfo));
1.852 + const TInt KBufferSpace = 768*1024; // 768K buffer
1.853 + CheckNotifierCount(1,1);
1.854 + test.Next(_L("Leave 768K"));
1.855 + r=c.Adjust(free-KBufferSpace); // leave 768K
1.856 + test(r==KErrNone);
1.857 + CheckNotifierCount(1,1); // shouldn't get notifier
1.858 + TInt free2=FreeRam();
1.859 + test.Printf(_L("Free RAM: %dK\n"),free2/1024);
1.860 + test(free2<=KBufferSpace);
1.861 + TInt free3=free-(KBufferSpace-free2); // this accounts for space used by page tables
1.862 + test.Next(_L("Leave 32K"));
1.863 + r=c.Adjust(free3-32768); // leave 32K
1.864 + test(r==KErrNone);
1.865 + CheckNotifierCount(2,1); // should get notifier
1.866 + test.Next(_L("Leave 28K"));
1.867 + r=c.Adjust(free3-28672); // leave 28K
1.868 + test(r==KErrNone);
1.869 + CheckNotifierCount(2,1); // shouldn't get another notifier
1.870 + test.Next(_L("Ask for too much"));
1.871 + r=c.Adjust(free3+4096); // try to get more than available
1.872 + test(r==KErrNoMemory);
1.873 + CheckNotifierCount(2,2); // should get another notifier
1.874 + test.Next(_L("Leave 128K"));
1.875 + r=c.Adjust(free3-131072); // leave 128K
1.876 + test(r==KErrNone);
1.877 + CheckNotifierCount(2,2); // shouldn't get another notifier
1.878 + test.Next(_L("Leave 640K"));
1.879 + r=c.Adjust(free3-655360); // leave 640K
1.880 + test(r==KErrNone);
1.881 + CheckNotifierCount(3,2); // should get another notifier
1.882 + test.Next(_L("Leave 1M"));
1.883 + r=c.Adjust(free3-1048576); // leave 1M
1.884 + test(r==KErrNone);
1.885 + CheckNotifierCount(3,2); // shouldn't get another notifier
1.886 + test.Next(_L("Ask for too much"));
1.887 + r=c.Adjust(free3+4096); // try to get more than available
1.888 + test(r==KErrNoMemory);
1.889 +
1.890 + TInt notifierCount = 3;
1.891 + if(MemModel==EMemModelTypeFlexible)
1.892 + {
1.893 + // on flexible memory model, we get memory changed notifiers
1.894 + // on failed memory allocation; this hack lets the test code
1.895 + // pass this as acceptable behaviour...
1.896 + WaitForNotifier();
1.897 + notifierCount = NotifierCount; // expect whatever we actually got
1.898 + }
1.899 +
1.900 + CheckNotifierCount(notifierCount,3); // should get another notifier
1.901 + test.Next(_L("Leave 1M"));
1.902 + r=c.Adjust(free3-1048576); // leave 1M
1.903 + test(r==KErrNone);
1.904 + CheckNotifierCount(notifierCount,3); // shouldn't get another notifier
1.905 +
1.906 + c.Close();
1.907 + TRequestStatus s;
1.908 + NtfThrd.Logon(s);
1.909 + NtfThrd.Kill(0);
1.910 + User::WaitForRequest(s);
1.911 + CLOSE_AND_WAIT(NtfThrd);
1.912 + Notifier.Close();
1.913 + gobbler.Close();
1.914 + }
1.915 +
1.916 +
1.917 +// TestFullAddressSpace is used to stress the memory allocation mechanism(beyond the 1GB limit).
1.918 +// However, the memory model can introduce limitations in the total amount of memory a single
1.919 +// process is allowed to allocate. To make the test more generic before closing the reserved
1.920 +// chunks for this test we trigger the creation of a new process. This process executes
1.921 +// t_chunk again, passing argument "extended". The result is that more chunks will be created
1.922 +// through another call to TestFullAddressSpace, with the parameter extendedFlag set to true.
1.923 +// Eventually the total amount of allocated space will overcome the 1Gb limit in any case.
1.924 +
1.925 +void TestFullAddressSpace(TBool extendedFlag )
1.926 + {
1.927 + test.Start(_L("Fill process address space with chunks\n"));
1.928 + RChunk chunk[2][11];
1.929 + TInt total = 0;
1.930 + TInt i;
1.931 + TInt j;
1.932 + TInt r;
1.933 +
1.934 + for(j=0; j<=1; j++)
1.935 + {
1.936 + if(!j)
1.937 + test.Next(_L("Creating local chunks"));
1.938 + else
1.939 + test.Next(_L("Creating global chunks"));
1.940 + for(i=10; i>=0; --i)
1.941 + {
1.942 + TInt size = 1<<(20+i);
1.943 +
1.944 + if(!j)
1.945 + r = chunk[j][i].CreateDisconnectedLocal(0,0,size);
1.946 + else
1.947 + r = chunk[j][i].CreateDisconnectedGlobal(KNullDesC,0,0,size);
1.948 + TBuf<128> text;
1.949 + text.AppendFormat(_L("Create %dMB chunk returns %d"),1<<i,r);
1.950 + test.Next(text);
1.951 + if(r!=KErrNoMemory)
1.952 + {
1.953 + test(r==KErrNone);
1.954 + // commit memory to each 1MB region,
1.955 + // this excercises page table allocation
1.956 + volatile TUint8* base = (TUint8*)chunk[j][i].Base();
1.957 + for(TInt o=0; o<size; o+=1<<20)
1.958 + {
1.959 + r = chunk[j][i].Commit(o,1);
1.960 + test(r==KErrNone);
1.961 + // access the commited memory...
1.962 + base[o] = (TUint8)(o&0xff);
1.963 + test(base[o]==(TUint8)(o&0xff));
1.964 + base[o] = (TUint8)~(o&0xff);
1.965 + test(base[o]==(TUint8)~(o&0xff));
1.966 + }
1.967 + total += 1<<i;
1.968 + }
1.969 + }
1.970 + }
1.971 +
1.972 + if (extendedFlag == EFalse)
1.973 + {
1.974 +
1.975 + test.Printf(_L("Total chunk size created was %d MB\n\n"),total);
1.976 +
1.977 + if(total<1024)
1.978 + {
1.979 + _LIT(KOtherProcessName,"t_chunk");
1.980 + _LIT(KProcessArgs,"extended");
1.981 +
1.982 + RProcess process;
1.983 + r=process.Create(KOtherProcessName,KProcessArgs );
1.984 + test.Printf(_L("Creating new process( t_chunk extended) returns %d\n"),r );
1.985 + test( r == KErrNone);
1.986 +
1.987 + TRequestStatus status;
1.988 + process.Logon(status);
1.989 + process.Resume();
1.990 +
1.991 + User::WaitForRequest(status);
1.992 +
1.993 + test(process.ExitType() == EExitKill);
1.994 + test(process.ExitReason() == 0);
1.995 + process.Close();
1.996 + }
1.997 +
1.998 + }
1.999 + else
1.1000 + test.Printf(_L("Total chunk size created by the new process was %d MB\n"),total);
1.1001 +
1.1002 + for(j=0; j<=1; j++)
1.1003 + for(i=10; i>=0; --i)
1.1004 + chunk[j][i].Close();
1.1005 + test.End();
1.1006 + }
1.1007 +
1.1008 +
1.1009 +#ifdef __WINS__
1.1010 +void TestExecLocalCode()
1.1011 + {
1.1012 + RChunk c;
1.1013 + TInt size = 10 * 1024;
1.1014 + TInt rc = c.CreateLocalCode(size, size, EOwnerProcess);
1.1015 + test_KErrNone(rc);
1.1016 + TUint8 *p = c.Base();
1.1017 + TUint32 (*func)() = (TUint32 (*)())p;
1.1018 + test.Printf(_L("Create small function in the new code chunk\n"));
1.1019 + *p++ = 0xB8; // mov eax, 0x12345678
1.1020 + *p++ = 0x78;
1.1021 + *p++ = 0x56;
1.1022 + *p++ = 0x34;
1.1023 + *p++ = 0x12;
1.1024 + *p = 0xC3; // ret
1.1025 + test.Printf(_L("Going to call the new function\n"));
1.1026 + TUint32 res = (*func)();
1.1027 + test_Equal(0x12345678, res);
1.1028 + c.Close();
1.1029 + }
1.1030 +#endif // __WINS__
1.1031 +
1.1032 +
1.1033 +_LIT(KChunkName, "CloseChunk");
1.1034 +
1.1035 +struct TRequestData
1.1036 + {
1.1037 + RSemaphore requestSem;
1.1038 + RSemaphore completionSem;
1.1039 + RSemaphore nextItSem;
1.1040 + };
1.1041 +
1.1042 +TInt CloseThread(TAny* data)
1.1043 + {
1.1044 + TRequestData* reqData = (TRequestData*)data;
1.1045 + ASSERT(reqData);
1.1046 +
1.1047 + for(;;)
1.1048 + {
1.1049 + // Wait for a request to open and close the chunk.
1.1050 + reqData->requestSem.Wait();
1.1051 +
1.1052 + // Try to open the chunk (may have already been closed by another thread).
1.1053 + RChunk chunk;
1.1054 + TInt r = chunk.OpenGlobal(KChunkName, EFalse, EOwnerThread);
1.1055 + if (r != KErrNone)
1.1056 + {
1.1057 + // The chunk was already closed...
1.1058 + r = (r == KErrNotFound) ? KErrNone : r; // Ensure no debug output for expected failures.
1.1059 +
1.1060 + if(r != KErrNone)
1.1061 + {
1.1062 + test.Printf(_L("CloseThread RChunk::OpenGlobal Err: %d\n"), r);
1.1063 + test_KErrNone(r);
1.1064 + }
1.1065 + }
1.1066 + else
1.1067 + {
1.1068 + // Close the chunk.
1.1069 + chunk.Close();
1.1070 + }
1.1071 +
1.1072 + // Tell our parent we have completed this iteration and wait for the next.
1.1073 + reqData->completionSem.Signal();
1.1074 + reqData->nextItSem.Wait();
1.1075 + }
1.1076 + }
1.1077 +
1.1078 +void TestClosure()
1.1079 + {
1.1080 + const TUint KCloseThreads = 50;
1.1081 + RThread thread[KCloseThreads];
1.1082 + TRequestStatus dead[KCloseThreads];
1.1083 +
1.1084 + // We need three semaphores or we risk signal stealing if one thread gets ahead of the
1.1085 + // others and starts a second iteration before the other threads have been signalled
1.1086 + // and have begun their first iteration. Such a situation results in deadlock so we
1.1087 + // force all threads to finish the iteration first using the nextItSem semaphore to
1.1088 + // ensure we can only move to the next iteration once every thread has completed the
1.1089 + // current iteration.
1.1090 + TRequestData reqData;
1.1091 + test_KErrNone(reqData.requestSem.CreateLocal(0));
1.1092 + test_KErrNone(reqData.completionSem.CreateLocal(0));
1.1093 + test_KErrNone(reqData.nextItSem.CreateLocal(0));
1.1094 +
1.1095 + TUint i = 0;
1.1096 +
1.1097 + // Create thread pool. We do this rather than create 50 threads
1.1098 + // over and over again for 800 times - the kernel's garbage collection
1.1099 + // does not keep up and we run out of backing store.
1.1100 + for (; i < KCloseThreads; i++)
1.1101 + {
1.1102 + test_KErrNone(thread[i].Create(KNullDesC, CloseThread, KDefaultStackSize, NULL, (TAny*)&reqData));
1.1103 + thread[i].Logon(dead[i]);
1.1104 + thread[i].SetPriority(EPriorityMuchLess);
1.1105 + thread[i].Resume();
1.1106 + }
1.1107 +
1.1108 + for (TUint delay = 200; delay < 1000; delay++)
1.1109 + {
1.1110 + test.Printf(_L("Closure delay %dus\r"), delay);
1.1111 +
1.1112 + // Create a global chunk.
1.1113 + RChunk chunk;
1.1114 + test_KErrNone(chunk.CreateGlobal(KChunkName, gPageSize, gPageSize));
1.1115 +
1.1116 + // Release the threads so they can try to close the handle.
1.1117 + reqData.requestSem.Signal(KCloseThreads);
1.1118 +
1.1119 + // Wait for the delay then close the handle ourselves.
1.1120 + User::AfterHighRes(delay);
1.1121 + chunk.Close();
1.1122 +
1.1123 + // Wait for the threads to complete then release them for the next iteration.
1.1124 + for (i = 0; i < KCloseThreads; i++)
1.1125 + {
1.1126 + reqData.completionSem.Wait();
1.1127 + }
1.1128 + reqData.nextItSem.Signal(KCloseThreads);
1.1129 +
1.1130 + // Ensure garbage collection is complete to prevent the kernel's
1.1131 + // garbage collection from being overwhelmed and causing the
1.1132 + // backing store to be exhausted.
1.1133 + UserSvr::HalFunction(EHalGroupKernel, EKernelHalSupervisorBarrier, 0, 0);
1.1134 + }
1.1135 +
1.1136 + // Kill thread pool.
1.1137 + for (i = 0; i < KCloseThreads; i++)
1.1138 + {
1.1139 + thread[i].Kill(KErrNone);
1.1140 + User::WaitForRequest(dead[i]);
1.1141 + test(KErrNone == thread[i].ExitReason());
1.1142 + test_Equal(EExitKill, thread[i].ExitType());
1.1143 + thread[i].Close();
1.1144 + }
1.1145 +
1.1146 + reqData.requestSem.Close();
1.1147 + reqData.completionSem.Close();
1.1148 + reqData.nextItSem.Close();
1.1149 +
1.1150 + // Ensure garbage collection is complete to prevent false positive
1.1151 + // kernel memory leaks.
1.1152 + UserSvr::HalFunction(EHalGroupKernel, EKernelHalSupervisorBarrier, 0, 0);
1.1153 + }
1.1154 +
1.1155 +
1.1156 +/**Returns true if argument is found in the command line*/
1.1157 +TBool IsInCommandLine(const TDesC& aArg)
1.1158 + {
1.1159 + TBuf<64> c;
1.1160 + User::CommandLine(c);
1.1161 + if (c.FindF(aArg) >= 0)
1.1162 + return ETrue;
1.1163 + return EFalse;
1.1164 + }
1.1165 +
1.1166 +_LIT(KTestChunkReadOnly, "TestReadOnlyChunk");
1.1167 +_LIT(KTestSemaphoreReadOnly, "TestReadOnlySemaphore");
1.1168 +_LIT(KTestParamRo, "restro");
1.1169 +_LIT(KTestParamRw, "restrw");
1.1170 +_LIT(KTestParamWait, "restwait");
1.1171 +_LIT(KTestParamWritableChunk, "restwritable");
1.1172 +
1.1173 +enum TTestProcessParameters
1.1174 + {
1.1175 + ETestRw = 0x1,
1.1176 + ETestWait = 0x2,
1.1177 + ETestWritableChunk = 0x4,
1.1178 + };
1.1179 +
1.1180 +void TestReadOnlyProcess(TUint aParams)
1.1181 + {
1.1182 + TInt r;
1.1183 + RChunk chunk;
1.1184 + RSemaphore sem;
1.1185 +
1.1186 + test.Start(_L("Open global chunk"));
1.1187 + r = chunk.OpenGlobal(KTestChunkReadOnly, EFalse);
1.1188 + test_KErrNone(r);
1.1189 +
1.1190 + test(chunk.IsReadable());
1.1191 + r = chunk.Adjust(1);
1.1192 + if (aParams & ETestWritableChunk)
1.1193 + {
1.1194 + test(chunk.IsWritable());
1.1195 + test_KErrNone(r);
1.1196 + }
1.1197 + else
1.1198 + {
1.1199 + test(!chunk.IsWritable());
1.1200 + test_Equal(KErrAccessDenied, r);
1.1201 + }
1.1202 +
1.1203 + if (aParams & ETestWait)
1.1204 + {
1.1205 + RProcess::Rendezvous(KErrNone);
1.1206 + test.Next(_L("Wait on semaphore"));
1.1207 + r = sem.OpenGlobal(KTestSemaphoreReadOnly);
1.1208 + test_KErrNone(r);
1.1209 + sem.Wait();
1.1210 + }
1.1211 +
1.1212 + test.Next(_L("Read"));
1.1213 + TUint8 read = *(volatile TUint8*) chunk.Base();
1.1214 + (void) read;
1.1215 +
1.1216 + if (aParams & ETestRw)
1.1217 + {
1.1218 + test.Next(_L("Write"));
1.1219 + TUint8* write = chunk.Base();
1.1220 + *write = 0x3d;
1.1221 + }
1.1222 +
1.1223 + chunk.Close();
1.1224 + if (aParams & ETestWait)
1.1225 + {
1.1226 + sem.Close();
1.1227 + }
1.1228 + test.End();
1.1229 + }
1.1230 +
1.1231 +void TestReadOnly()
1.1232 + {
1.1233 + TInt r;
1.1234 + RChunk chunk;
1.1235 + RProcess process1;
1.1236 + RProcess process2;
1.1237 + RSemaphore sem;
1.1238 + TRequestStatus rs;
1.1239 + TRequestStatus rv;
1.1240 +
1.1241 + // Assumption is made that any memory model from Flexible onwards that supports
1.1242 + // read-only memory also supports read-only chunks
1.1243 + if (MemModelType() < EMemModelTypeFlexible || !HaveWriteProt())
1.1244 + {
1.1245 + test.Printf(_L("Memory model is not expected to support Read-Only Chunks\n"));
1.1246 + return;
1.1247 + }
1.1248 +
1.1249 + TBool jit = User::JustInTime();
1.1250 + User::SetJustInTime(EFalse);
1.1251 +
1.1252 + test.Start(_L("Create writable global chunk"));
1.1253 + TChunkCreateInfo info;
1.1254 + info.SetNormal(0, 1234567);
1.1255 + info.SetGlobal(KTestChunkReadOnly);
1.1256 + r = chunk.Create(info);
1.1257 + test_KErrNone(r);
1.1258 + test(chunk.IsReadable());
1.1259 + test(chunk.IsWritable());
1.1260 +
1.1261 + test.Next(_L("Adjust size"));
1.1262 + r = chunk.Adjust(1); // add one page
1.1263 + test_KErrNone(r);
1.1264 +
1.1265 + test.Next(_L("Attempt read/write 1"));
1.1266 + r = process1.Create(RProcess().FileName(), KTestParamWritableChunk);
1.1267 + test_KErrNone(r);
1.1268 + process1.Logon(rs);
1.1269 + process1.Resume();
1.1270 + User::WaitForRequest(rs);
1.1271 + test_Equal(EExitKill, process1.ExitType());
1.1272 + test_KErrNone(process1.ExitReason());
1.1273 + CLOSE_AND_WAIT(process1);
1.1274 + CLOSE_AND_WAIT(chunk);
1.1275 +
1.1276 + test.Next(_L("Create read-only global chunk"));
1.1277 + info.SetReadOnly();
1.1278 + r = chunk.Create(info);
1.1279 + test_KErrNone(r);
1.1280 + test(chunk.IsReadable());
1.1281 + test(chunk.IsWritable());
1.1282 + // To keep in sync with the 'process2' process
1.1283 + r = sem.CreateGlobal(KTestSemaphoreReadOnly, 0);
1.1284 + test_KErrNone(r);
1.1285 +
1.1286 + test.Next(_L("Attempt read 1"));
1.1287 + r = process1.Create(RProcess().FileName(), KTestParamRo);
1.1288 + test_KErrNone(r);
1.1289 + process1.Logon(rs);
1.1290 + process1.Resume();
1.1291 + User::WaitForRequest(rs);
1.1292 + test_Equal(EExitPanic, process1.ExitType());
1.1293 + test_Equal(3, process1.ExitReason()); // KERN-EXEC 3 assumed
1.1294 + CLOSE_AND_WAIT(process1);
1.1295 + // Create second process before commiting memory and make it wait
1.1296 + r = process2.Create(RProcess().FileName(), KTestParamWait);
1.1297 + test_KErrNone(r)
1.1298 + process2.Rendezvous(rv);
1.1299 + process2.Resume();
1.1300 + User::WaitForRequest(rv);
1.1301 +
1.1302 + test.Next(_L("Adjust size"));
1.1303 + r = chunk.Adjust(1); // add one page
1.1304 + test_KErrNone(r);
1.1305 +
1.1306 + test.Next(_L("Attempt read 2"));
1.1307 + r = process1.Create(RProcess().FileName(), KTestParamRo);
1.1308 + test_KErrNone(r);
1.1309 + process1.Logon(rs);
1.1310 + process1.Resume();
1.1311 + User::WaitForRequest(rs);
1.1312 + test_Equal(EExitKill, process1.ExitType());
1.1313 + test_KErrNone(process1.ExitReason());
1.1314 + CLOSE_AND_WAIT(process1);
1.1315 +
1.1316 + test.Next(_L("Attempt read/write 1"));
1.1317 + r = process1.Create(RProcess().FileName(), KTestParamRw);
1.1318 + test_KErrNone(r);
1.1319 + process1.Logon(rs);
1.1320 + process1.Resume();
1.1321 + User::WaitForRequest(rs);
1.1322 + test_Equal(EExitPanic, process1.ExitType());
1.1323 + test_Equal(3, process1.ExitReason()); // KERN-EXEC 3 assumed
1.1324 + CLOSE_AND_WAIT(process1);
1.1325 + // Controlling process is not affected
1.1326 + TUint8* write = chunk.Base();
1.1327 + *write = 0x77;
1.1328 +
1.1329 + test.Next(_L("Attempt read/write 2"));
1.1330 + test_Equal(EExitPending, process2.ExitType());
1.1331 + process2.Logon(rs);
1.1332 + sem.Signal();
1.1333 + User::WaitForRequest(rs);
1.1334 + test_Equal(EExitPanic, process2.ExitType());
1.1335 + test_Equal(3, process2.ExitReason()); // KERN-EXEC 3 assumed
1.1336 + CLOSE_AND_WAIT(process2);
1.1337 +
1.1338 + chunk.Close();
1.1339 + sem.Close();
1.1340 + test.End();
1.1341 + User::SetJustInTime(jit);
1.1342 + }
1.1343 +
1.1344 +TInt E32Main()
1.1345 +//
1.1346 +// Test RChunk class
1.1347 +//
1.1348 + {
1.1349 + test.Title();
1.1350 + if (!HaveVirtMem())
1.1351 + {
1.1352 + test.Printf(_L("This test requires an MMU\n"));
1.1353 + return KErrNone;
1.1354 + }
1.1355 + testInitialise();
1.1356 +
1.1357 + // Turn off lazy dll unloading so the kernel heap checking isn't affected.
1.1358 + RLoader l;
1.1359 + test(l.Connect()==KErrNone);
1.1360 + test(l.CancelLazyDllUnload()==KErrNone);
1.1361 + l.Close();
1.1362 +
1.1363 + _LIT(KExtended,"extended");
1.1364 +
1.1365 + if (IsInCommandLine(KExtended))
1.1366 + {
1.1367 + __KHEAP_MARK;
1.1368 + test.Printf(_L("t_chunk extended was called. Ready to call TestFullAddressSpace(Etrue) \n"));
1.1369 + TestFullAddressSpace(ETrue);
1.1370 + __KHEAP_MARKEND;
1.1371 + }
1.1372 + else if (IsInCommandLine(KTestParamRo))
1.1373 + {
1.1374 + test_KErrNone(User::RenameProcess(KTestParamRo));
1.1375 + TestReadOnlyProcess(0);
1.1376 + }
1.1377 + else if (IsInCommandLine(KTestParamRw))
1.1378 + {
1.1379 + test_KErrNone(User::RenameProcess(KTestParamRw));
1.1380 + TestReadOnlyProcess(ETestRw);
1.1381 + }
1.1382 + else if (IsInCommandLine(KTestParamWait))
1.1383 + {
1.1384 + test_KErrNone(User::RenameProcess(KTestParamWait));
1.1385 + TestReadOnlyProcess(ETestRw | ETestWait);
1.1386 + }
1.1387 + else if (IsInCommandLine(KTestParamWritableChunk))
1.1388 + {
1.1389 + test_KErrNone(User::RenameProcess(KTestParamWritableChunk));
1.1390 + TestReadOnlyProcess(ETestWritableChunk | ETestRw);
1.1391 + }
1.1392 + else
1.1393 + {
1.1394 + __KHEAP_MARK;
1.1395 + test.Start(_L("Testing.."));
1.1396 + testAdjustChunk();
1.1397 + test.Next(_L("Test1"));
1.1398 + test1();
1.1399 + test.Next(_L("Test2"));
1.1400 + test2(0x80);
1.1401 + test.Next(_L("Test3"));
1.1402 + test3(0x7000);
1.1403 + test.Next(_L("Test4"));
1.1404 + test4(0x7000);
1.1405 + test.Next(_L("Test5"));
1.1406 + test5(0x80);
1.1407 + test.Next(_L("Test7"));
1.1408 + test7(0x80);
1.1409 + test.Next(_L("Test chunk data clearing attributes"));
1.1410 + testClear(0x500);
1.1411 + testClear(07000);
1.1412 + test.Next(_L("Test9"));
1.1413 + testShare();
1.1414 + test.Next(_L("Test memory notifiers"));
1.1415 + testNotifiers();
1.1416 + test.Next(_L("FindChunks"));
1.1417 + FindChunks();
1.1418 +
1.1419 + test.Next(_L("Test full address space"));
1.1420 + TestFullAddressSpace(EFalse);
1.1421 +
1.1422 +#ifdef __WINS__
1.1423 + test.Next(_L("Test execution of code in a local code chunk on emulator"));
1.1424 + TestExecLocalCode();
1.1425 +#endif // __WINS__
1.1426 +
1.1427 + test.Next(_L("Test for race conditions in chunk closure"));
1.1428 + TestClosure();
1.1429 + test.Next(_L("Read-only chunks"));
1.1430 + TestReadOnly();
1.1431 + test.End();
1.1432 + __KHEAP_MARKEND;
1.1433 + }
1.1434 +
1.1435 + test.Close();
1.1436 + return(KErrNone);
1.1437 + }