First public contribution.
1 // Copyright (c) 1995-2009 Nokia Corporation and/or its subsidiary(-ies).
2 // All rights reserved.
3 // This component and the accompanying materials are made available
4 // under the terms of the License "Eclipse Public License v1.0"
5 // which accompanies this distribution, and is available
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
14 // e32test\mmu\t_chunk.cpp
18 // RChunk, RChangeNotifier, TFindChunk
20 // - Test adjusting chunks: create a global chunk, adjust it, do some size
21 // checks, verify Create() rounds up to chunk multiple, verify that adjust
22 // request for size greater than MaxSize returns an error.
23 // - Test creating chunks with small sizes (0 and 1), verify results are as expected.
24 // - Create multiple local and global chunks, verify that Size,MaxSize,Name & FullName methods
26 // Check Create method of global chunk if the name is already in use. Check the name can be
27 // reused after the chunk is closed.
28 // - Perform adjust tests on a chunk, verify results are as expected.
29 // - Open and test global chunks with multiple references, verify results are as expected.
30 // - Open and test local chunks, check TFindChunk::Next method, verify results are as expected.
31 // - Check user thread is panicked if it creates or adjusts chunk with negative size or of an
32 // invalid type or with an invalid name.
33 // - Check the chunk is filled in with the appropriate clear value after creation, verify results
35 // - Test sharing a chunk between threads, verify results are as expected.
36 // - Create a thread to watch for notification of changes in free memory and
37 // changes in out of memory status. Verify adjusting an RChunk generates
38 // the expected notifications.
39 // - Test finding a global chunk by name and verify results are as expected.
40 // - Check read-only global chunks cannot be written to by other processes.
41 // Platforms/Drives/Compatibility:
43 // Assumptions/Requirement/Pre-requisites:
44 // Failures and causes:
45 // Base Port information:
49 #define __E32TEST_EXTENSION__
54 #include "mmudetect.h"
58 const TInt KHeapSize=0x200;
60 //const TInt KNumberOfChunks=10; can't have that many
61 const TInt KNumberOfChunks=3;
63 const TInt KChunkNum=5;
64 const TInt KNormalReturn=194;
67 const TInt KMinChunkSizeInBytesMinus1=0x0000ffff;
68 const TUint KMinChunkSizeInBytesMask=0xffff0000;
69 #elif defined (__X86__)
70 const TInt KMinChunkSizeInBytesMinus1=0x003fffff;
71 const TUint KMinChunkSizeInBytesMask=0xffc00000;
73 const TInt KMinChunkSizeInBytesMinus1=0x000fffff;
74 const TUint KMinChunkSizeInBytesMask=0xfff00000;
77 const TInt KMinPageSizeInBytesMinus1=0x00000fff;
78 const TUint KMinPageSizeInBytesMask=0xfffff000;
81 LOCAL_D RTest test(_L("T_CHUNK"));
82 LOCAL_D RTest t(_L("ShareThread"));
83 LOCAL_D RChunk gChunk;
85 LOCAL_D TPtr nullPtr(NULL,0);
99 const TUint8 KDfltClearByte = 0x3;
100 TBool CheckChunkCleared(RChunk& aRC, TInt aOffset=0, TUint8 aClearByte = KDfltClearByte)
102 TUint8* base = aRC.Base()+aOffset;
103 TInt size = aRC.Size();
104 test.Printf(_L("Testing chunk for 0x%x - size: %d!\n"), aClearByte, size);
106 for(TInt i = 0; i<size; i++)
107 if(base[i] != aClearByte)
109 memset((TAny*)base, 0x05, size);
113 TInt roundToPageSize(TInt aSize)
116 return(((aSize+KMinPageSizeInBytesMinus1)&KMinPageSizeInBytesMask));
119 TInt roundToChunkSize(TInt aSize)
121 if(MemModel==EMemModelTypeFlexible)
122 return roundToPageSize(aSize);
123 return(((aSize+KMinChunkSizeInBytesMinus1)&KMinChunkSizeInBytesMask));
126 TInt ThreadEntry2(TAny* /*aParam*/)
128 // Thread to read from shared chunk
133 r=c.OpenGlobal(_L("Marmalade"),ETrue);
135 TUint8* base=c.Base();
136 for (TInt8 i=0;i<10;i++)
137 t(*base++==i); // check the chunk has 0-9
142 TInt ThreadEntry(TAny* aDirective)
144 // Thread to create a Panic in a variety of ways
148 switch((TUint)aDirective)
152 return KNormalReturn;
154 case ECreateNegative:
156 gChunk.CreateLocal(0x10,-0x10);
159 case EAdjustNegative:
161 gChunk.Adjust(-0x10);
164 case ECreateInvalidType :
166 TChunkCreateInfo createInfo;
167 createInfo.SetCode(gPageSize, gPageSize);
168 _LIT(KChunkName, "Chunky");
169 createInfo.SetGlobal(KChunkName);
171 chunk.Create(createInfo);
181 // Test the clear flags for the specified chunk.
182 // Assumes chunk has one commited region from base to aBytes.
184 void TestClearChunk(RChunk& aChunk, TUint aBytes, TUint8 aClearByte)
186 test_Equal(ETrue, CheckChunkCleared(aChunk, 0, aClearByte));
187 test_KErrNone(aChunk.Adjust(0));
188 test_KErrNone(aChunk.Adjust(aBytes));
189 test_Equal(ETrue, CheckChunkCleared(aChunk, 0, aClearByte));
195 // Create the specified thread and verify the exit reason.
197 void TestThreadExit(TExitType aExitType, TInt aExitReason, TThreadFunction aFunc, TAny* aThreadParam)
200 test_KErrNone(thread.Create(_L("RChunkPanicThread"), aFunc, KDefaultStackSize,
201 KHeapSize, KHeapSize, aThreadParam));
202 // Disable JIT debugging.
203 TBool justInTime=User::JustInTime();
204 User::SetJustInTime(EFalse);
206 TRequestStatus status;
207 thread.Logon(status);
209 User::WaitForRequest(status);
210 test_Equal(aExitType, thread.ExitType());
211 test_Equal(aExitReason, status.Int());
212 test_Equal(aExitReason, thread.ExitReason());
213 if (aExitType == EExitPanic)
214 test(thread.ExitCategory()==_L("USER"));
215 CLOSE_AND_WAIT(thread);
217 // Put JIT debugging back to previous status.
218 User::SetJustInTime(justInTime);
223 // Thread function to create a chunk with invalid attributes
225 TInt ChunkPanicThread(TAny* aCreateInfo)
227 // This should panic.
229 chunk.Create((*(TChunkCreateInfo*) aCreateInfo));
232 return KErrGeneral; // Shouldn't reach here.
235 void testInitialise()
237 test.Next(_L("Load gobbler LDD"));
238 TInt r = User::LoadLogicalDevice(KGobblerLddFileName);
239 test(r==KErrNone || r==KErrAlreadyExists);
241 // get system info...
242 MemModel = UserSvr::HalFunction(EHalGroupKernel, EKernelHalMemModelInfo, NULL, NULL) & EMemModelTypeMask;
244 test_KErrNone(UserHal::PageSizeInBytes(gPageSize));
250 // Test creating chunks with silly sizes
257 test.Start(_L("Create global chunks"));
258 r=chunk.CreateGlobal(_L("Fopp"),1,1);
261 r=chunk.CreateGlobal(_L("Fopp"),0,0);
262 test(r==KErrArgument);
266 test.Next(_L("Create local chunks"));
267 r=chunk.CreateLocal(1,1);
270 r=chunk.CreateLocal(0,0);
271 test(r==KErrArgument);
277 void test2(TInt aSize)
279 // Test local/global chunk creation
283 RChunk lchunk[KNumberOfChunks];
284 RChunk gchunk[KNumberOfChunks];
288 test.Start(_L("Create multiple local and global chunks"));
293 for (i=0; i<KNumberOfChunks; i++)
296 // create a local chunk
297 r=lchunk[i].CreateLocal(aSize,aSize);
299 r=lchunk[i].MaxSize();
300 test(r==roundToChunkSize(aSize));
301 test(lchunk[i].Size()==roundToPageSize(aSize)); // was 0
302 test(lchunk[i].Name().Left(6)==_L("Local-"));
304 fullname=RProcess().Name();
306 fullname+=lchunk[i].Name();
307 test(lchunk[i].FullName().CompareF(fullname)==0);
309 // create a global chunk
310 name.Format(_L("Chunk%d"),i);
311 r=gchunk[i].CreateGlobal(name,aSize,aSize);
313 test(gchunk[i].MaxSize()==roundToChunkSize(aSize));
314 test(gchunk[i].Size()==roundToPageSize(aSize)); // was 0
315 test(gchunk[i].Name()==name);
318 // make room for another chunk
319 lchunk[KNumberOfChunks-1].Close();
320 gchunk[KNumberOfChunks-1].Close();
322 // Try to create a global chunk with a duplicate name
323 test.Next(_L("Create a chunk with a duplicate name"));
324 TInt r=chunk.CreateGlobal(_L("Chunk0"),aSize,aSize);
325 test(r==KErrAlreadyExists);
327 test.Next(_L("Close all chunks"));
328 for (i=0; i<KNumberOfChunks-1; i++)
334 test.Next(_L("Reuse a name"));
335 r=chunk.CreateGlobal(_L("Chunk1"),aSize,aSize);
337 test(chunk.MaxSize()==roundToChunkSize(aSize));
338 test(chunk.Size()==roundToPageSize(aSize));
339 test(chunk.Name()==_L("Chunk1"));
346 void test3_2(RChunk& aChunk, TInt aSize)
348 // Perform Adjust tests on aChunk
353 test.Start(_L("Adjust to full size"));
354 r=aChunk.Adjust(aSize);
356 test(aChunk.Size()==roundToPageSize(aSize));
357 test(aChunk.MaxSize()==roundToChunkSize(aSize));
359 test.Next(_L("Adjust a chunk to half size"));
360 r=aChunk.Adjust(aSize/2);
362 test(aChunk.Size()==roundToPageSize(aSize/2));
363 test(aChunk.MaxSize()==roundToChunkSize(aSize));
365 test.Next(_L("Adjust to same size"));
366 r=aChunk.Adjust(aSize/2);
368 test(aChunk.Size()==roundToPageSize(aSize/2));
369 test(aChunk.MaxSize()==roundToChunkSize(aSize));
371 test.Next(_L("Adjusting to size=0"));
374 test(aChunk.Size()==0);
375 test(aChunk.MaxSize()==roundToChunkSize(aSize));
377 test.Next(_L("Adjust back to half size"));
378 r=aChunk.Adjust(aSize/2);
380 test(aChunk.Size()==roundToPageSize(aSize/2));
381 test(aChunk.MaxSize()==roundToChunkSize(aSize));
387 void test3(TInt aSize)
389 // Test Adjust size of chunk
396 // Run Adjust tests with a local chunk
397 test.Start(_L("Local Chunk.Adjust()"));
398 r=chunk.CreateLocal(aSize,aSize);
399 test3_2(chunk, aSize);
401 // Run Adjust tests with a global chunk
402 test.Next(_L("Global Chunk.Adjust()"));
403 r=chunk.CreateGlobal(_L("Fopp"),aSize,aSize);
405 test3_2(chunk,aSize);
411 void test4(TInt aSize)
417 RChunk chunk[KChunkNum];
423 for (i=0; i<KChunkNum; i++)
425 name.Format(_L("Chunk%d"), i);
426 r=chunk[i].CreateGlobal(name,aSize,aSize);
429 test.Start(_L("Open Global chunks"));
430 r=c1.OpenGlobal(_L("Chunk1"),EFalse); // 2nd ref to this chunk
432 r=c2.OpenGlobal(_L("Chunk3"),EFalse); // 2nd ref to this chunk
434 r=c3.OpenGlobal(_L("Chunk4"),EFalse); // 2nd ref to this chunk
438 test.Next(_L("Attempt Open non-existant chunk"));
439 r=c3.OpenGlobal(_L("Non Existant Chunk"),EFalse);
440 test(r==KErrNotFound);
442 for (i=0; i<KChunkNum; i++)
444 test.Printf(_L("Closing chunk %d\n"),i);
448 test.Next(_L("Test chunks with multiple references are still valid"));
449 r=c1.Adjust(aSize/2);
451 test(c1.MaxSize()==roundToChunkSize(aSize));
452 test(c1.Size()==roundToPageSize(aSize/2));
453 test(c1.Name()==_L("Chunk1"));
455 r=c2.Adjust(aSize/2);
457 test(c2.MaxSize()==roundToChunkSize(aSize));
458 test(c2.Size()==roundToPageSize(aSize/2));
459 test(c2.Name()==_L("Chunk3"));
461 // Open another reference to a chunk
462 r=c3.OpenGlobal(_L("Chunk3"),EFalse);
464 test(c3.Base()==c2.Base());
465 test(c3.Size()==c2.Size());
466 test(c2.Size()!=aSize);
467 // Adjust with one reference
470 // Test sizes from the other
471 test(c2.Size()==roundToPageSize(aSize));
472 test(c2.MaxSize()==roundToChunkSize(aSize));
478 test.Next(_L("And check the heap..."));
483 void test5(TInt aSize)
489 RChunk chunk[2*KNumberOfChunks];
492 test.Start(_L("Creating Local and Global Chunks"));
497 // Create KNumberOfChunks Global chunks
498 for (i=0; i<KNumberOfChunks; i++)
500 b.Format(_L("Chunk%d"), i);
501 r=chunk[i].CreateGlobal(b,aSize,aSize);
502 test(chunk[i].Name()==b);
505 b.Format(_L("This is chunk %d"), i);
507 chunk[i].Adjust(aSize);
508 Mem::Copy(chunk[i].Base(), b.Ptr(), b.Size());
509 test(chunk[i].MaxSize()==roundToChunkSize(aSize));
510 test(chunk[i].Size()==roundToPageSize(aSize));
513 test.Next(_L("Find and Open the Chunks"));
516 for (i=0; i<KNumberOfChunks; i++)
518 test.Printf(_L("Opening chunk %d\n"),i);
519 find.Find(chunk[i].FullName());
523 b=TPtrC((TText*)c1.Base());
524 name.Format(_L("This is chunk %d"), i);
529 test.Next(_L("Close chunks"));
530 for (i=0; i<KNumberOfChunks; i++)
538 void test7(TInt aSize)
540 // Deliberately cause RChunk panics
546 test.Start(_L("Test panic thread"));
547 TestThreadExit(EExitKill, KNormalReturn, ThreadEntry, (TAny*)ENormal);
550 test.Next(_L("Create Chunk with a negative size"));
551 TestThreadExit(EExitPanic, EChkCreateMaxSizeNegative, ThreadEntry, (TAny*) ECreateNegative);
554 test.Next(_L("Adjust a Chunk to Size = -0x10"));
555 gChunk.CreateLocal(aSize,aSize);
556 TestThreadExit(EExitPanic, EChkAdjustNewSizeNegative, ThreadEntry, (TAny*) EAdjustNegative);
559 // ECreateInvalidType
560 test.Next(_L("Create chunk of invalid type"));
561 TestThreadExit(EExitPanic, EChkCreateInvalidType, ThreadEntry, (TAny*) ECreateInvalidType);
569 void testClear(TInt aSize)
572 test.Start(_L("Test clearing memory (Platform Security)"));
574 RChunk c1,c2,c3,c4,c5,c6,c7,c8,c9,c10;
581 r=c1.CreateGlobal(b,aSize,aSize);
584 test((TBool)ETrue==CheckChunkCleared(c1));
587 r=c2.CreateLocal(aSize,aSize,EOwnerProcess);
590 test((TBool)ETrue==CheckChunkCleared(c2));
593 r=c3.CreateLocalCode(aSize,aSize,EOwnerProcess);
596 test((TBool)ETrue==CheckChunkCleared(c3));
599 r=c4.CreateDoubleEndedLocal(0x1000,0x1000+aSize,0x100000);
602 test((TBool)ETrue==CheckChunkCleared(c4,c4.Bottom()));
605 r=c5.CreateDoubleEndedGlobal(b,0x1000,0x1000+aSize,0x100000,EOwnerProcess);
608 test((TBool)ETrue==CheckChunkCleared(c5,c5.Bottom()));
611 r=c6.CreateDisconnectedLocal(0x1000,0x1000+aSize,0x100000);
614 test((TBool)ETrue==CheckChunkCleared(c6,0x1000));
617 r=c7.CreateDisconnectedGlobal(b,0x1000,0x1000+aSize,0x100000,EOwnerProcess);
620 test((TBool)ETrue==CheckChunkCleared(c7,0x1000));
623 test.Next(_L("Test setting the clear byte of RChunk::Create()"));
625 TChunkCreateInfo createInfo;
626 createInfo.SetNormal(aSize, aSize);
627 test_KErrNone(c10.Create(createInfo));
628 TestClearChunk(c10, aSize, KDfltClearByte);
630 createInfo.SetClearByte(0x0);
631 test_KErrNone(c8.Create(createInfo));
632 TestClearChunk(c8, aSize, 0x0);
634 createInfo.SetClearByte(0xff);
635 test_KErrNone(c9.Create(createInfo));
636 TestClearChunk(c9, aSize, 0xff);
644 // Test sharing a chunk between threads
647 test.Start(_L("Test chunk sharing between threads"));
649 test.Next(_L("Create chunk Marmalade"));
655 r=chunk.CreateGlobal(_L("Marmalade"),size,maxSize);
657 test.Next(_L("Write 0-9 to it"));
658 TUint8* base=chunk.Base();
659 for (TInt8 j=0;j<10;j++)
660 *base++=j; // write 0 - 9 to the chunk
664 test.Next(_L("Create reader thread"));
665 r=t.Create(_L("RChunkShareThread"), ThreadEntry2, KDefaultStackSize,KHeapSize,KHeapSize,NULL);
668 test.Next(_L("Resume reader thread"));
670 User::WaitForRequest(stat);
678 { // taken from some code written by SteveG
679 test.Start(_L("Finding chunks...\n"));
681 TFullName name=_L("*");
682 TFindChunk find(name);
686 while (find.Next(name)==KErrNone)
689 test.Printf(_L("Chunk name %S\n"),&name);
690 TInt err=chunk.Open(find);
692 test.Printf(_L("Error %d opening chunk"),err);
696 if (chunk.IsWritable())
697 access=_L("ReadWrite");
698 else if (chunk.IsReadable())
699 access=_L("ReadOnly");
701 access=_L("No Access");
702 test.Printf(_L("Chunk size %08x bytes, %S\n"),chunk.Size(),&access);
706 User::After(1000000);
711 void testAdjustChunk()
713 test.Start(_L("Test adjusting chunks"));
717 test.Next(_L("Create global chunk"));
718 TInt r=hermione.CreateGlobal(_L("Hermione"),0x1000,0x100000);
720 TUint32* base=(TUint32*)hermione.Base();
721 TUint32* top=(TUint32*)(hermione.Base()+hermione.Size());
724 test.Printf(_L("Base = %08x, Top = %08x\n"),base,top);
725 test.Next(_L("Check I can write to all of it"));
726 for (i=base;i<top;i++)
729 test.Next(_L("Adjust the chunk"));
730 r=hermione.Adjust(0x1400);
733 base=(TUint32*)hermione.Base();
734 top=(TUint32*)(hermione.Base()+hermione.Size());
735 test.Printf(_L("Base = %08x, Top = %08x\n"),base,top);
736 test.Next(_L("Check I can write to all of the bigger chunk"));
737 for (i=base;i<top;i++)
742 test.Next(_L("Do some size checks"));
744 r=wibble.CreateGlobal(_L("Wibble"),0x1,gPageSize*8);
746 test.Next(_L("Check create rounds up to page multiple"));
747 test(wibble.Size()==(TInt)gPageSize);
748 test.Next(_L("Check create rounds up to chunk multiple"));
749 test(wibble.MaxSize()==roundToChunkSize(gPageSize*8));
751 test.Next(_L("Check adjust rounds up to page multiple"));
752 r=wibble.Adjust((gPageSize*6)-12);
754 test(wibble.Size()==gPageSize*6);
756 test.Next(_L("Different number, same size"));
757 r=wibble.Adjust((gPageSize*6)-18);
759 test(wibble.Size()==gPageSize*6);
761 test.Next(_L("Check adjust > MaxSize returns error"));
762 r=wibble.Adjust(wibble.MaxSize()+gPageSize);
763 test(r==KErrArgument);
769 TInt NotifierCount=0;
771 RChangeNotifier Notifier;
773 _LIT(KNotifierThreadName,"NotifierThread");
775 TInt NotifierThread(TAny*)
777 TInt r=Notifier.Create();
784 User::WaitForRequest(s);
785 if (s.Int()&EChangesFreeMemory)
787 if (s.Int()&EChangesOutOfMemory)
795 void WaitForNotifier()
797 User::After(500000); // wait for notifier
801 void CheckNotifierCount(TInt aLevel, TInt aOom)
804 if (NtfThrd.ExitType()!=EExitPending)
806 TExitCategoryName exitCat=NtfThrd.ExitCategory();
807 test.Printf(_L("Thread exited: %d,%d,%S"),NtfThrd.ExitType(),NtfThrd.ExitReason(),&exitCat);
810 TInt c1=NotifierCount;
812 if (c1!=aLevel || c2!=aOom)
814 test.Printf(_L("Count %d,%d Expected %d,%d"),c1,c2,aLevel,aOom);
822 TInt r = gobbler.Open();
824 TUint32 taken = gobbler.GobbleRAM(128*1024*1024);
825 test.Printf(_L("Gobbled: %dK\n"), taken/1024);
826 test.Printf(_L("Free RAM 0x%08X bytes\n"),FreeRam());
828 test.Next(_L("Create thread"));
829 r=NtfThrd.Create(KNotifierThreadName,NotifierThread,KDefaultStackSize,NULL,NULL);
831 NtfThrd.SetPriority(EPriorityMore);
833 test.Next(_L("Check for initial notifier"));
834 CheckNotifierCount(1,1);
836 test.Printf(_L("Free RAM: %dK\n"),free/1024);
838 test.Next(_L("Set thresholds"));
839 r=UserSvr::SetMemoryThresholds(65536,524288); // low=64K good=512K
841 test.Next(_L("Create chunk"));
842 // Chunk must not be paged otherwise it will not effect the amount
843 // of free ram reported plus on h4 swap size is less than the total ram.
844 TChunkCreateInfo createInfo;
845 createInfo.SetNormal(0, free+2097152);
846 createInfo.SetPaging(TChunkCreateInfo::EUnpaged);
848 test_KErrNone(c.Create(createInfo));
849 const TInt KBufferSpace = 768*1024; // 768K buffer
850 CheckNotifierCount(1,1);
851 test.Next(_L("Leave 768K"));
852 r=c.Adjust(free-KBufferSpace); // leave 768K
854 CheckNotifierCount(1,1); // shouldn't get notifier
855 TInt free2=FreeRam();
856 test.Printf(_L("Free RAM: %dK\n"),free2/1024);
857 test(free2<=KBufferSpace);
858 TInt free3=free-(KBufferSpace-free2); // this accounts for space used by page tables
859 test.Next(_L("Leave 32K"));
860 r=c.Adjust(free3-32768); // leave 32K
862 CheckNotifierCount(2,1); // should get notifier
863 test.Next(_L("Leave 28K"));
864 r=c.Adjust(free3-28672); // leave 28K
866 CheckNotifierCount(2,1); // shouldn't get another notifier
867 test.Next(_L("Ask for too much"));
868 r=c.Adjust(free3+4096); // try to get more than available
869 test(r==KErrNoMemory);
870 CheckNotifierCount(2,2); // should get another notifier
871 test.Next(_L("Leave 128K"));
872 r=c.Adjust(free3-131072); // leave 128K
874 CheckNotifierCount(2,2); // shouldn't get another notifier
875 test.Next(_L("Leave 640K"));
876 r=c.Adjust(free3-655360); // leave 640K
878 CheckNotifierCount(3,2); // should get another notifier
879 test.Next(_L("Leave 1M"));
880 r=c.Adjust(free3-1048576); // leave 1M
882 CheckNotifierCount(3,2); // shouldn't get another notifier
883 test.Next(_L("Ask for too much"));
884 r=c.Adjust(free3+4096); // try to get more than available
885 test(r==KErrNoMemory);
887 TInt notifierCount = 3;
888 if(MemModel==EMemModelTypeFlexible)
890 // on flexible memory model, we get memory changed notifiers
891 // on failed memory allocation; this hack lets the test code
892 // pass this as acceptable behaviour...
894 notifierCount = NotifierCount; // expect whatever we actually got
897 CheckNotifierCount(notifierCount,3); // should get another notifier
898 test.Next(_L("Leave 1M"));
899 r=c.Adjust(free3-1048576); // leave 1M
901 CheckNotifierCount(notifierCount,3); // shouldn't get another notifier
907 User::WaitForRequest(s);
908 CLOSE_AND_WAIT(NtfThrd);
914 // TestFullAddressSpace is used to stress the memory allocation mechanism(beyond the 1GB limit).
915 // However, the memory model can introduce limitations in the total amount of memory a single
916 // process is allowed to allocate. To make the test more generic before closing the reserved
917 // chunks for this test we trigger the creation of a new process. This process executes
918 // t_chunk again, passing argument "extended". The result is that more chunks will be created
919 // through another call to TestFullAddressSpace, with the parameter extendedFlag set to true.
920 // Eventually the total amount of allocated space will overcome the 1Gb limit in any case.
922 void TestFullAddressSpace(TBool extendedFlag )
924 test.Start(_L("Fill process address space with chunks\n"));
934 test.Next(_L("Creating local chunks"));
936 test.Next(_L("Creating global chunks"));
939 TInt size = 1<<(20+i);
942 r = chunk[j][i].CreateDisconnectedLocal(0,0,size);
944 r = chunk[j][i].CreateDisconnectedGlobal(KNullDesC,0,0,size);
946 text.AppendFormat(_L("Create %dMB chunk returns %d"),1<<i,r);
951 // commit memory to each 1MB region,
952 // this excercises page table allocation
953 volatile TUint8* base = (TUint8*)chunk[j][i].Base();
954 for(TInt o=0; o<size; o+=1<<20)
956 r = chunk[j][i].Commit(o,1);
958 // access the commited memory...
959 base[o] = (TUint8)(o&0xff);
960 test(base[o]==(TUint8)(o&0xff));
961 base[o] = (TUint8)~(o&0xff);
962 test(base[o]==(TUint8)~(o&0xff));
969 if (extendedFlag == EFalse)
972 test.Printf(_L("Total chunk size created was %d MB\n\n"),total);
976 _LIT(KOtherProcessName,"t_chunk");
977 _LIT(KProcessArgs,"extended");
980 r=process.Create(KOtherProcessName,KProcessArgs );
981 test.Printf(_L("Creating new process( t_chunk extended) returns %d\n"),r );
982 test( r == KErrNone);
984 TRequestStatus status;
985 process.Logon(status);
988 User::WaitForRequest(status);
990 test(process.ExitType() == EExitKill);
991 test(process.ExitReason() == 0);
997 test.Printf(_L("Total chunk size created by the new process was %d MB\n"),total);
1000 for(i=10; i>=0; --i)
1001 chunk[j][i].Close();
1007 void TestExecLocalCode()
1010 TInt size = 10 * 1024;
1011 TInt rc = c.CreateLocalCode(size, size, EOwnerProcess);
1013 TUint8 *p = c.Base();
1014 TUint32 (*func)() = (TUint32 (*)())p;
1015 test.Printf(_L("Create small function in the new code chunk\n"));
1016 *p++ = 0xB8; // mov eax, 0x12345678
1022 test.Printf(_L("Going to call the new function\n"));
1023 TUint32 res = (*func)();
1024 test_Equal(0x12345678, res);
1030 _LIT(KChunkName, "CloseChunk");
1034 RSemaphore requestSem;
1035 RSemaphore completionSem;
1036 RSemaphore nextItSem;
1039 TInt CloseThread(TAny* data)
1041 TRequestData* reqData = (TRequestData*)data;
1046 // Wait for a request to open and close the chunk.
1047 reqData->requestSem.Wait();
1049 // Try to open the chunk (may have already been closed by another thread).
1051 TInt r = chunk.OpenGlobal(KChunkName, EFalse, EOwnerThread);
1054 // The chunk was already closed...
1055 r = (r == KErrNotFound) ? KErrNone : r; // Ensure no debug output for expected failures.
1059 test.Printf(_L("CloseThread RChunk::OpenGlobal Err: %d\n"), r);
1069 // Tell our parent we have completed this iteration and wait for the next.
1070 reqData->completionSem.Signal();
1071 reqData->nextItSem.Wait();
1077 const TUint KCloseThreads = 50;
1078 RThread thread[KCloseThreads];
1079 TRequestStatus dead[KCloseThreads];
1081 // We need three semaphores or we risk signal stealing if one thread gets ahead of the
1082 // others and starts a second iteration before the other threads have been signalled
1083 // and have begun their first iteration. Such a situation results in deadlock so we
1084 // force all threads to finish the iteration first using the nextItSem semaphore to
1085 // ensure we can only move to the next iteration once every thread has completed the
1086 // current iteration.
1087 TRequestData reqData;
1088 test_KErrNone(reqData.requestSem.CreateLocal(0));
1089 test_KErrNone(reqData.completionSem.CreateLocal(0));
1090 test_KErrNone(reqData.nextItSem.CreateLocal(0));
1094 // Create thread pool. We do this rather than create 50 threads
1095 // over and over again for 800 times - the kernel's garbage collection
1096 // does not keep up and we run out of backing store.
1097 for (; i < KCloseThreads; i++)
1099 test_KErrNone(thread[i].Create(KNullDesC, CloseThread, KDefaultStackSize, NULL, (TAny*)&reqData));
1100 thread[i].Logon(dead[i]);
1101 thread[i].SetPriority(EPriorityMuchLess);
1105 for (TUint delay = 200; delay < 1000; delay++)
1107 test.Printf(_L("Closure delay %dus\r"), delay);
1109 // Create a global chunk.
1111 test_KErrNone(chunk.CreateGlobal(KChunkName, gPageSize, gPageSize));
1113 // Release the threads so they can try to close the handle.
1114 reqData.requestSem.Signal(KCloseThreads);
1116 // Wait for the delay then close the handle ourselves.
1117 User::AfterHighRes(delay);
1120 // Wait for the threads to complete then release them for the next iteration.
1121 for (i = 0; i < KCloseThreads; i++)
1123 reqData.completionSem.Wait();
1125 reqData.nextItSem.Signal(KCloseThreads);
1127 // Ensure garbage collection is complete to prevent the kernel's
1128 // garbage collection from being overwhelmed and causing the
1129 // backing store to be exhausted.
1130 UserSvr::HalFunction(EHalGroupKernel, EKernelHalSupervisorBarrier, 0, 0);
1133 // Kill thread pool.
1134 for (i = 0; i < KCloseThreads; i++)
1136 thread[i].Kill(KErrNone);
1137 User::WaitForRequest(dead[i]);
1138 test(KErrNone == thread[i].ExitReason());
1139 test_Equal(EExitKill, thread[i].ExitType());
1143 reqData.requestSem.Close();
1144 reqData.completionSem.Close();
1145 reqData.nextItSem.Close();
1147 // Ensure garbage collection is complete to prevent false positive
1148 // kernel memory leaks.
1149 UserSvr::HalFunction(EHalGroupKernel, EKernelHalSupervisorBarrier, 0, 0);
1153 /**Returns true if argument is found in the command line*/
1154 TBool IsInCommandLine(const TDesC& aArg)
1157 User::CommandLine(c);
1158 if (c.FindF(aArg) >= 0)
1163 _LIT(KTestChunkReadOnly, "TestReadOnlyChunk");
1164 _LIT(KTestSemaphoreReadOnly, "TestReadOnlySemaphore");
1165 _LIT(KTestParamRo, "restro");
1166 _LIT(KTestParamRw, "restrw");
1167 _LIT(KTestParamWait, "restwait");
1168 _LIT(KTestParamWritableChunk, "restwritable");
1170 enum TTestProcessParameters
1174 ETestWritableChunk = 0x4,
1177 void TestReadOnlyProcess(TUint aParams)
1183 test.Start(_L("Open global chunk"));
1184 r = chunk.OpenGlobal(KTestChunkReadOnly, EFalse);
1187 test(chunk.IsReadable());
1188 r = chunk.Adjust(1);
1189 if (aParams & ETestWritableChunk)
1191 test(chunk.IsWritable());
1196 test(!chunk.IsWritable());
1197 test_Equal(KErrAccessDenied, r);
1200 if (aParams & ETestWait)
1202 RProcess::Rendezvous(KErrNone);
1203 test.Next(_L("Wait on semaphore"));
1204 r = sem.OpenGlobal(KTestSemaphoreReadOnly);
1209 test.Next(_L("Read"));
1210 TUint8 read = *(volatile TUint8*) chunk.Base();
1213 if (aParams & ETestRw)
1215 test.Next(_L("Write"));
1216 TUint8* write = chunk.Base();
1221 if (aParams & ETestWait)
1238 // Assumption is made that any memory model from Flexible onwards that supports
1239 // read-only memory also supports read-only chunks
1240 if (MemModelType() < EMemModelTypeFlexible || !HaveWriteProt())
1242 test.Printf(_L("Memory model is not expected to support Read-Only Chunks\n"));
1246 TBool jit = User::JustInTime();
1247 User::SetJustInTime(EFalse);
1249 test.Start(_L("Create writable global chunk"));
1250 TChunkCreateInfo info;
1251 info.SetNormal(0, 1234567);
1252 info.SetGlobal(KTestChunkReadOnly);
1253 r = chunk.Create(info);
1255 test(chunk.IsReadable());
1256 test(chunk.IsWritable());
1258 test.Next(_L("Adjust size"));
1259 r = chunk.Adjust(1); // add one page
1262 test.Next(_L("Attempt read/write 1"));
1263 r = process1.Create(RProcess().FileName(), KTestParamWritableChunk);
1267 User::WaitForRequest(rs);
1268 test_Equal(EExitKill, process1.ExitType());
1269 test_KErrNone(process1.ExitReason());
1270 CLOSE_AND_WAIT(process1);
1271 CLOSE_AND_WAIT(chunk);
1273 test.Next(_L("Create read-only global chunk"));
1275 r = chunk.Create(info);
1277 test(chunk.IsReadable());
1278 test(chunk.IsWritable());
1279 // To keep in sync with the 'process2' process
1280 r = sem.CreateGlobal(KTestSemaphoreReadOnly, 0);
1283 test.Next(_L("Attempt read 1"));
1284 r = process1.Create(RProcess().FileName(), KTestParamRo);
1288 User::WaitForRequest(rs);
1289 test_Equal(EExitPanic, process1.ExitType());
1290 test_Equal(3, process1.ExitReason()); // KERN-EXEC 3 assumed
1291 CLOSE_AND_WAIT(process1);
1292 // Create second process before commiting memory and make it wait
1293 r = process2.Create(RProcess().FileName(), KTestParamWait);
1295 process2.Rendezvous(rv);
1297 User::WaitForRequest(rv);
1299 test.Next(_L("Adjust size"));
1300 r = chunk.Adjust(1); // add one page
1303 test.Next(_L("Attempt read 2"));
1304 r = process1.Create(RProcess().FileName(), KTestParamRo);
1308 User::WaitForRequest(rs);
1309 test_Equal(EExitKill, process1.ExitType());
1310 test_KErrNone(process1.ExitReason());
1311 CLOSE_AND_WAIT(process1);
1313 test.Next(_L("Attempt read/write 1"));
1314 r = process1.Create(RProcess().FileName(), KTestParamRw);
1318 User::WaitForRequest(rs);
1319 test_Equal(EExitPanic, process1.ExitType());
1320 test_Equal(3, process1.ExitReason()); // KERN-EXEC 3 assumed
1321 CLOSE_AND_WAIT(process1);
1322 // Controlling process is not affected
1323 TUint8* write = chunk.Base();
1326 test.Next(_L("Attempt read/write 2"));
1327 test_Equal(EExitPending, process2.ExitType());
1330 User::WaitForRequest(rs);
1331 test_Equal(EExitPanic, process2.ExitType());
1332 test_Equal(3, process2.ExitReason()); // KERN-EXEC 3 assumed
1333 CLOSE_AND_WAIT(process2);
1338 User::SetJustInTime(jit);
1343 // Test RChunk class
1349 test.Printf(_L("This test requires an MMU\n"));
1354 // Turn off lazy dll unloading so the kernel heap checking isn't affected.
1356 test(l.Connect()==KErrNone);
1357 test(l.CancelLazyDllUnload()==KErrNone);
1360 _LIT(KExtended,"extended");
1362 if (IsInCommandLine(KExtended))
1365 test.Printf(_L("t_chunk extended was called. Ready to call TestFullAddressSpace(Etrue) \n"));
1366 TestFullAddressSpace(ETrue);
1369 else if (IsInCommandLine(KTestParamRo))
1371 test_KErrNone(User::RenameProcess(KTestParamRo));
1372 TestReadOnlyProcess(0);
1374 else if (IsInCommandLine(KTestParamRw))
1376 test_KErrNone(User::RenameProcess(KTestParamRw));
1377 TestReadOnlyProcess(ETestRw);
1379 else if (IsInCommandLine(KTestParamWait))
1381 test_KErrNone(User::RenameProcess(KTestParamWait));
1382 TestReadOnlyProcess(ETestRw | ETestWait);
1384 else if (IsInCommandLine(KTestParamWritableChunk))
1386 test_KErrNone(User::RenameProcess(KTestParamWritableChunk));
1387 TestReadOnlyProcess(ETestWritableChunk | ETestRw);
1392 test.Start(_L("Testing.."));
1394 test.Next(_L("Test1"));
1396 test.Next(_L("Test2"));
1398 test.Next(_L("Test3"));
1400 test.Next(_L("Test4"));
1402 test.Next(_L("Test5"));
1404 test.Next(_L("Test7"));
1406 test.Next(_L("Test chunk data clearing attributes"));
1409 test.Next(_L("Test9"));
1411 test.Next(_L("Test memory notifiers"));
1413 test.Next(_L("FindChunks"));
1416 test.Next(_L("Test full address space"));
1417 TestFullAddressSpace(EFalse);
1420 test.Next(_L("Test execution of code in a local code chunk on emulator"));
1421 TestExecLocalCode();
1424 test.Next(_L("Test for race conditions in chunk closure"));
1426 test.Next(_L("Read-only chunks"));