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\heap\t_kheap.cpp
16 // Test clean-up after kernel heap allocation failures.
18 // RProcess, RThread, RServer, RMutex, RChunk, RSemaphore, RTimer.
20 // - Tests allocation of kernel objects in low memory conditions and checks for
21 // leaks (OOM testing). The following objects are tested, with all
22 // combinations of attributes where applicable:
23 // - thread-relative timer.
24 // - local, global semaphore to the process, thread.
25 // - local, global mutex to the current process, thread.
26 // - server, handle to a file server session.
27 // - handle to a change notifier, a thread death notifier.
28 // - logical device driver, XIP and non-XIP (on hardware).
29 // - logical channel (hardware only excluding integrator).
31 // - chunks containg heaps (ie User::HeapChunk)
33 // - Test that the kernel correctly zeros memory on allocation and reallocation
34 // Platforms/Drives/Compatibility:
36 // Assumptions/Requirement/Pre-requisites:
37 // Failures and causes:
38 // Base Port information:
43 //! @SYMTestCaseID KBASE-T_KHEAP-0163
45 //! @SYMTestPriority High
46 //! @SYMTestActions Test allocation of Kernel objects in low memory conditions.
47 //! @SYMTestExpectedResults Test runs until this message is emitted: RTEST: SUCCESS : T_KHEAP test completed O.K.
49 #define __E32TEST_EXTENSION__
57 RTest test(_L("T_KHeap"));
58 RLoader LoaderSession;
61 _LIT(KTestLdd0FileName, "D_LDD.LDD");
62 _LIT(KTestLdd1FileName, "D_LDD_RAM.LDD");
63 _LIT(KTestLddName, "Test");
65 #include "../mmu/mmudetect.h"
66 #include "../mmu/d_memorytest.h"
69 TBool LargeChunkOK=EFalse;
70 const TInt KLargeChunk=0x80000000;
71 const TInt KOwnerThread=0x40000000;
72 const TInt KMaxKernelAllocations=1024;
73 _LIT(KName,"TestObj");
74 typedef TInt (*TTestFunction)(TInt);
78 RMemoryTestLdd TestLdd;
79 RKHeapDevice KHeapDevice;
83 User::SetDebugMask(0xefdfffff);
88 User::SetDebugMask(0x80000000);
94 TInt r=t.CreateLocal();
100 TInt TestLocalSem(TInt a)
102 TOwnerType ot=(TOwnerType)a;
104 TInt r=s.CreateLocal(0, ot);
110 TInt TestGlobalSem(TInt a)
112 TOwnerType ot=(TOwnerType)a;
114 TInt r=s.CreateGlobal(KName, 0, ot);
120 TInt TestLocalMutex(TInt a)
122 TOwnerType ot=(TOwnerType)a;
124 TInt r=m.CreateLocal(ot);
130 TInt TestGlobalMutex(TInt a)
132 TOwnerType ot=(TOwnerType)a;
134 TInt r=m.CreateGlobal(KName, ot);
140 TInt TestServer(TInt)
143 TInt r=s.CreateGlobal(KName);
149 TInt TestSession(TInt)
158 User::After(WaitABit); // allow asynchronous cleanup to happen
162 TInt TestChangeNotifier(TInt)
171 TInt TestUndertaker(TInt)
180 TInt TestLogicalDevice(TInt aDevice)
182 const TDesC* fileName = NULL;
183 const TDesC* objName = &KTestLddName();
187 fileName = &KTestLdd0FileName();
190 fileName = &KTestLdd1FileName();
195 TInt r = User::LoadLogicalDevice(*fileName);
196 test_KErrNone(LoaderSession.CancelLazyDllUnload()); // make sure transient loader session has been destroyed
199 r = User::FreeLogicalDevice(*objName);
205 TInt TestLogicalChannel(TInt)
214 TInt TestChunk(TInt att)
216 TChunkCreateInfo createInfo;
217 TInt maxSize = (att & KLargeChunk)? (33*1048576) : gPageSize;
218 createInfo.SetOwner((att & KOwnerThread)? EOwnerThread : EOwnerProcess);
220 if (att & TChunkCreate::EGlobal)
221 createInfo.SetGlobal(KName());
223 switch (att & (TChunkCreate::ENormal | TChunkCreate::EDoubleEnded | TChunkCreate::EDisconnected))
225 case TChunkCreate::ENormal:
226 createInfo.SetNormal(gPageSize, maxSize);
228 case TChunkCreate::EDoubleEnded:
229 createInfo.SetDoubleEnded(0, gPageSize, maxSize);
231 case TChunkCreate::EDisconnected:
232 createInfo.SetDisconnected(0, gPageSize, maxSize);
239 TInt r=c.Create(createInfo);
245 TInt TestHeap(TInt att)
249 RHeap* h = UserHeap::ChunkHeap(&KNullDesC(), 0x1000, 0x10000, 1, 4, att);
252 return h ? KErrNone : KErrNoMemory;
255 TInt r = c.CreateLocal(0, 0x100000);
258 RHeap* h = UserHeap::ChunkHeap(c, 0x1000, 1, 0, 4, att&1, (att&2) ? UserHeap::EChunkHeapDuplicate : 0);
263 return h ? KErrNone : KErrNoMemory;
266 TInt TestThreadFunction(TAny* a)
272 TInt TestThread(TInt att)
274 // bit 0 -> EOwnerThread
276 // bit 2 -> let it run
277 // bit 3 -> use own heap
280 TOwnerType ot=(att&1)?EOwnerThread:EOwnerProcess;
281 const TDesC* name=(att&2)?&KName():&KNullDesC();
287 r=t.Create(*name, TestThreadFunction, 0x1000, 0x1000, 0x10000, (TAny*)att, ot);
289 r=t.Create(*name, TestThreadFunction, 0x1000, NULL, (TAny*)att, ot);
292 UserSvr::HalFunction(EHalGroupKernel, EKernelHalSupervisorBarrier, 0, 0);
295 t.SetPriority(EPriorityMore);
301 t.Kill((att+1)*(att+1));
302 User::WaitForRequest(s);
303 if (s==KErrNoMemory) // if logon failed due to OOM ...
304 User::After(WaitABit); // ... allow thread to terminate before checking exit type
305 test(t.ExitType()==EExitKill);
309 test(r==(att+1)*(att+1));
313 User::After(WaitABit); // let supervisor run - can't use destruct notifier since it involves memory allocation
317 void DoTest(TTestFunction aFunc, TInt aParam)
319 test.Printf(_L("DoTest f=%08x p=%08x\n"),aFunc,aParam);
322 test_Equal(KErrNoMemory, (*aFunc)(aParam));
323 test_KErrNone(UserSvr::HalFunction(EHalGroupKernel, EKernelHalSupervisorBarrier, (TAny*)5000, 0));
327 test_KErrNone((*aFunc)(aParam));
328 test_KErrNone(UserSvr::HalFunction(EHalGroupKernel, EKernelHalSupervisorBarrier, (TAny*)5000, 0));
333 for (i=0; i<KMaxKernelAllocations && r==KErrNoMemory; i++)
338 test_KErrNone(UserSvr::HalFunction(EHalGroupKernel, EKernelHalSupervisorBarrier, (TAny*)5000, 0));
342 test.Printf(_L("Took %d tries\n"),i);
346 _LIT(KLddName, "ECOMM");
348 _LIT(KPddName, "EUART");
350 _LIT(KPddName, "ECDRV");
352 TInt LoadDeviceDrivers()
354 // Load ECOMM.LDD and all PDDs with name EUART?.PDD
360 TFileName n=KPddName();
362 for (i=-1; i<10; ++i)
368 r=User::LoadPhysicalDevice(n);
369 if (r==KErrNone || r==KErrAlreadyExists)
372 test.Printf(_L("Loaded PDD %S\n"),&n);
375 r=User::LoadLogicalDevice(KLddName);
376 if (r==KErrNone || r==KErrAlreadyExists)
379 test.Printf(_L("Loaded LDD %S\n"),&KLddName());
384 void TestKernAllocZerosMemory()
386 test.Next(_L("Kern::Alloc memory initialisation"));
387 test_KErrNone(TestLdd.Open());
389 TInt r=TestLdd.TestAllocZerosMemory();
392 test.Printf(_L("TestAllocZerosMemory returned %08x\n"), r);
395 r=TestLdd.TestReAllocZerosMemory();
398 test.Printf(_L("TestReAllocZerosMemory returned %08x\n"), r);
402 TInt TestCreateSharedChunk(TInt)
404 TInt r = KHeapDevice.CreateSharedChunk();
405 User::After(WaitABit); // let supervisor run - can't use destruct notifier since it involves memory allocation
409 TInt TestCreateHwChunk(TInt a)
411 TInt r = KHeapDevice.CreateHwChunk();
412 User::After(WaitABit); // let supervisor run - can't use destruct notifier since it involves memory allocation
417 GLDEF_C TInt E32Main()
419 // Test kernel alloc heaven with all out of memory possibilities
425 * Process tested by loader tests
427 * Library tested by loader tests
428 * Semaphore tested here
431 * Session tested here
432 * LDev tested by loader tests (to do)
433 * PDev tested by loader tests (to do)
435 * ChangeNot tested here
436 * Undertaker tested here
440 test.Start(_L("Testing kernel OOM handling"));
442 TInt factor = UserSvr::HalFunction(EHalGroupVariant, EVariantHalTimeoutExpansion, 0, 0);
447 WaitABit = 200000 * (TUint32)factor;
449 #ifdef __EPOC32__ // no WINS serial drivers yet
450 test.Next(_L("Load comms drivers"));
451 test(LoadDeviceDrivers()>=256);
453 test_KErrNone(UserHal::PageSizeInBytes(gPageSize));
455 // Keep a session to the loader
457 r = LoaderSession.Connect();
460 // Turn off lazy dll unloading
461 test_KErrNone(LoaderSession.CancelLazyDllUnload());
463 if (TestChunk(KLargeChunk) == KErrNone)
465 LargeChunkOK = ETrue;
467 test.Next(_L("Load/open d_kheap test driver"));
468 r = User::LoadLogicalDevice(KHeapTestDriverName);
469 test( r==KErrNone || r==KErrAlreadyExists);
470 if( KErrNone != (r=KHeapDevice.Open()) )
472 User::FreeLogicalDevice(KHeapTestDriverName);
473 test.Printf(_L("Could not open LDD"));
477 test.Next(_L("Timer"));
478 DoTest(TestTimer, 0);
479 test.Next(_L("Local semaphore"));
480 DoTest(TestLocalSem, EOwnerProcess);
481 test.Next(_L("Global semaphore"));
482 DoTest(TestGlobalSem, EOwnerProcess);
483 test.Next(_L("Local semaphore"));
484 DoTest(TestLocalSem, EOwnerThread);
485 test.Next(_L("Global semaphore"));
486 DoTest(TestGlobalSem, EOwnerThread);
487 test.Next(_L("Local mutex"));
488 DoTest(TestLocalMutex, EOwnerProcess);
489 test.Next(_L("Global mutex"));
490 DoTest(TestGlobalMutex, EOwnerProcess);
491 test.Next(_L("Local mutex"));
492 DoTest(TestLocalMutex, EOwnerThread);
493 test.Next(_L("Global mutex"));
494 DoTest(TestGlobalMutex, EOwnerThread);
495 test.Next(_L("Server"));
496 DoTest(TestServer, 0);
497 test.Next(_L("Session"));
498 DoTest(TestSession, 0);
499 test.Next(_L("Change notifier"));
500 DoTest(TestChangeNotifier, 0);
501 test.Next(_L("Undertaker"));
502 DoTest(TestUndertaker, 0);
503 test.Next(_L("Logical Device (XIP)"));
504 DoTest(TestLogicalDevice, 0);
506 test.Next(_L("Logical Device (Non-XIP)"));
507 //The first time a non-XIP LDD is loaded , Kernel permanently allocates some memory.
508 //The next line makes sure it happens before we start testing OOM condition.
509 TestLogicalDevice(1);
510 //Further non-XIP LDDs loadings must not leak the memory.
511 DoTest(TestLogicalDevice, 1);
513 // Temporary hack to avoid clash with debug output on Integrator
515 r = HAL::Get(HAL::EMachineUid, muid);
517 if (muid != HAL::EMachineUid_Integrator)
519 test.Next(_L("Logical Channel"));
520 r = User::LoadLogicalDevice(KHeapTestDriverName);
521 test(r==KErrNone || r==KErrAlreadyExists);
522 DoTest(TestLogicalChannel, 0);
526 TUint32 attlim=LargeChunkOK?0x100:0x80;
527 test.Next(_L("Chunk"));
528 for (att=0; att<attlim; ++att)
533 if (att&0x40) arg|=KOwnerThread;
534 if (att&0x80) arg|=KLargeChunk;
535 DoTest(TestChunk, arg);
538 test.Next(_L("Heap"));
539 for (att=0; att<8; ++att)
541 if (att==2 || att==3)
543 DoTest(TestHeap, att);
546 test.Next(_L("Thread"));
547 for (att=0; att<16; ++att)
549 DoTest(TestThread, att);
552 TestKernAllocZerosMemory();
554 test.Next(_L("Shared Chunk"));
555 DoTest(TestCreateSharedChunk, 0);
557 test.Next(_L("Hw Chunk"));
558 DoTest(TestCreateHwChunk, 0);
561 test.Next(_L("Close/unload d_kheap test driver"));
563 User::FreeLogicalDevice(KHeapTestDriverName);
564 LoaderSession.Close();
569 GLDEF_C TInt E32Main()
571 // _KHEAP_SETFAIL etc. not available in release mode, so don't test
576 test.Start(_L("No tests in release mode"));