sl@0: // Copyright (c) 1995-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of the License "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // e32test\thread\t_thread.cpp sl@0: // Overview: sl@0: // Tests the RThread class sl@0: // API Information: sl@0: // RThread, RUndertaker sl@0: // Details: sl@0: // - Create a thread, verify its priority, change the priority and verify results. sl@0: // - Verify naming and renaming threads works as expected. sl@0: // - Test logging on, resuming and closing a thread. Verify results are as expected. sl@0: // - Test creating threads with a variety of invalid parameters. Verify results. sl@0: // - Test the RUndertaker methods: create some threads, logon to the undertaker, sl@0: // verify results upon killing a thread and setting the thread handle. sl@0: // - Check kernel allocation when creating threads and undertakers. Verify the sl@0: // heap has not been corrupted. sl@0: // - Run a thread multiple times, panic within the thread, panic external to the sl@0: // thread and exit a thread in a variety of ways. Verify results are as expected. sl@0: // - Create a semaphore and some threads, verify the threads can wait on and signal sl@0: // the semaphore. sl@0: // - Test unclosed but completed threads. sl@0: // - Suspend and resume some threads in a variety of ways, verify results are as sl@0: // expected. sl@0: // - Test thread duplication. sl@0: // - Test opening a thread using an full name, perform various tests by finding, sl@0: // killing, closing, recreating etc. Verify the results are as expected. sl@0: // - Test creating a thread using a duplicate name then reuse the thread with a sl@0: // valid name. Verify results are as expected. sl@0: // - Verify that a panicked thread releases an existing mutex. sl@0: // - Test thread ID: attempt to open a nonexistent thread by ID, verify different sl@0: // threads have different IDs, verify open by ID works as expected. sl@0: // - Test RThread::StackInfo(), print results and verify results are as expected. sl@0: // Platforms/Drives/Compatibility: sl@0: // All. sl@0: // Assumptions/Requirement/Pre-requisites: sl@0: // Failures and causes: sl@0: // Base Port information: sl@0: // sl@0: // sl@0: sl@0: #define __E32TEST_EXTENSION__ sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include "../misc/prbs.h" sl@0: sl@0: const TInt KNumThreads=20; sl@0: sl@0: const TInt KExitPanicNum=999; sl@0: const TInt KHeapSize=0x200; sl@0: const TInt KThreadReturnValue=9999; sl@0: const TInt KTerminationReason=1234; sl@0: const TInt KKillReason=4321; sl@0: enum TInstruction {ENormal,EInstrPanic,EWait}; sl@0: sl@0: const TInt KWaitTime=800000; sl@0: sl@0: class TReadInfo sl@0: { sl@0: public: sl@0: TDesC* tdesc; sl@0: TPtrC* tptrc; sl@0: TDes* tdes; sl@0: TPtr* tptr; sl@0: HBufC* hbufc; sl@0: TBufC<0x20>* tbufc; sl@0: TBuf<0x20>* tbuf; sl@0: TPtr* tptrdes; sl@0: TAny* anAddress; sl@0: }; sl@0: sl@0: LOCAL_D RTest test(_L("T_THREAD")); sl@0: LOCAL_D RTest rtest(_L("Read thread tests")); sl@0: LOCAL_D RTest wtest(_L("Write thread tests")); sl@0: sl@0: #define rtest(x) rtest(x,__LINE__) sl@0: #define wtest(x) wtest(x,__LINE__) sl@0: sl@0: LOCAL_C TInt LoopyThread(TAny*) sl@0: { sl@0: sl@0: FOREVER sl@0: User::AfterHighRes(1000); sl@0: } sl@0: sl@0: LOCAL_D void testUndertaker(TOwnerType anOwnerType) sl@0: // sl@0: // Test RThreadWatcher sl@0: // sl@0: { sl@0: sl@0: RThread thread1; sl@0: TInt r; sl@0: test.Start(_L("Test the RUndertaker class")); sl@0: test.Next(_L("Create a thread")); sl@0: // if (anOwnerType==EOwnerThread) sl@0: // User::SetDebugMask(0x8000867c); sl@0: r=thread1.Create(_L("Loopy1"),LoopyThread,KDefaultStackSize,KHeapSize,KHeapSize,(TAny*)NULL,anOwnerType); sl@0: test(r==KErrNone); sl@0: thread1.Resume(); sl@0: sl@0: TRequestStatus stat1; sl@0: TInt threadHandle1; sl@0: RThread w1; sl@0: RUndertaker u1; sl@0: test.Next(_L("Create an RUndertaker")); sl@0: r=u1.Create(); sl@0: test(r==KErrNone); sl@0: test.Next(_L("Logon to RUndertaker")); sl@0: r=u1.Logon(stat1,threadHandle1); sl@0: test(r==KErrNone); sl@0: test.Next(_L("Logon again & check we're rejected")); sl@0: r=u1.Logon(stat1,threadHandle1); sl@0: test(r==KErrInUse); sl@0: test.Next(_L("Cancel logon to RUndertaker")); sl@0: r=u1.LogonCancel(); sl@0: test(r==KErrNone); sl@0: test(stat1==KErrCancel); sl@0: sl@0: test.Next(_L("Logon to RUndertaker again")); sl@0: u1.Logon(stat1,threadHandle1); sl@0: sl@0: test.Next(_L("Create another thread")); sl@0: RThread thread2; sl@0: r=thread2.Create(_L("Loopy2"),LoopyThread,KDefaultStackSize,KHeapSize,KHeapSize,(TAny*)NULL,anOwnerType); sl@0: test(r==KErrNone); sl@0: thread2.Resume(); sl@0: sl@0: TRequestStatus stat2; sl@0: TInt threadHandle2; sl@0: RThread w2; sl@0: RUndertaker u2; sl@0: test.Next(_L("Create another RUndertaker")); sl@0: r=u2.Create(); sl@0: test(r==KErrNone); sl@0: test.Next(_L("Logon to RUndertaker")); sl@0: r=u2.Logon(stat2,threadHandle2); sl@0: test(r==KErrNone); sl@0: sl@0: test.Next(_L("Create yet another thread")); sl@0: RThread thread3; sl@0: r=thread3.Create(_L("Loopy3"),LoopyThread,KDefaultStackSize,KHeapSize,KHeapSize,(TAny*)NULL,anOwnerType); sl@0: test(r==KErrNone); sl@0: thread3.Resume(); sl@0: sl@0: test.Next(_L("Kill the first thread & check the undertakers")); sl@0: thread1.Kill(0x489); sl@0: thread1.Close(); sl@0: sl@0: User::WaitForRequest(stat1); sl@0: User::WaitForRequest(stat2); sl@0: test(stat1==KErrDied); sl@0: test(stat2==KErrDied); sl@0: sl@0: RThread keep1; sl@0: RThread keep2; sl@0: test.Next(_L("Set the RThread handles")); sl@0: keep1.SetHandle(threadHandle1); sl@0: keep2.SetHandle(threadHandle2); sl@0: sl@0: test.Next(_L("Test the exit reasons")); sl@0: test(keep1.ExitReason()==0x489); sl@0: test(keep2.ExitReason()==0x489); sl@0: // test.Printf(_L("Thread name %S\n"),&(w1.Name())); sl@0: sl@0: test.Next(_L("Logon again with both watchers")); sl@0: r=u1.Logon(stat1,threadHandle1); sl@0: test(r==KErrNone); sl@0: r=u2.Logon(stat2,threadHandle2); sl@0: test(r==KErrNone); sl@0: sl@0: test.Next(_L("Kill the 3rd thread & check the undertakers")); sl@0: thread3.Kill(0x999); sl@0: thread3.Close(); sl@0: sl@0: User::WaitForRequest(stat1); sl@0: User::WaitForRequest(stat2); sl@0: test(stat1==KErrDied); sl@0: test(stat2==KErrDied); sl@0: sl@0: test.Next(_L("Set the RThread handles")); sl@0: w1.SetHandle(threadHandle1); sl@0: w2.SetHandle(threadHandle2); sl@0: sl@0: test.Next(_L("Test the exit reasons")); sl@0: test(w1.ExitReason()==0x999); sl@0: test(w2.ExitReason()==0x999); sl@0: // test.Printf(_L("Thread name %S\n"),&(w1.Name())); sl@0: w1.Close(); sl@0: CLOSE_AND_WAIT(w2); sl@0: sl@0: test.Next(_L("Logon again with both undertakers")); sl@0: r=u1.Logon(stat1,threadHandle1); sl@0: test(r==KErrNone); sl@0: r=u2.Logon(stat2,threadHandle2); sl@0: test(r==KErrNone); sl@0: sl@0: test.Next(_L("Kill the 2nd thread & check the undertakers")); sl@0: thread2.Kill(0x707); sl@0: thread2.Close(); sl@0: sl@0: User::WaitForRequest(stat1); sl@0: User::WaitForRequest(stat2); sl@0: test(stat1==KErrDied); sl@0: test(stat2==KErrDied); sl@0: sl@0: test.Next(_L("Set the RThread handles")); sl@0: w1.SetHandle(threadHandle1); sl@0: w2.SetHandle(threadHandle2); sl@0: sl@0: test.Next(_L("Test the exit reasons")); sl@0: test(w1.ExitReason()==0x707); sl@0: test(w2.ExitReason()==0x707); sl@0: // test.Printf(_L("Thread name %S\n"),&(w1.Name())); sl@0: sl@0: test.Next(_L("Check kernel allocation")); sl@0: test.Next(_L("Please wait while I create & close masses of threads")); sl@0: RThread t[KNumThreads]; sl@0: TInt j; sl@0: for (j=0; j name; sl@0: name.Format(_L("LoopyThread%d"),j); sl@0: test(t[j].Create(name, LoopyThread, KDefaultStackSize, KHeapSize, KHeapSize, (TAny*)NULL,anOwnerType)==KErrNone); sl@0: } sl@0: for (j=0; jInt(); sl@0: test_Equal(s, KRequestPending); sl@0: } sl@0: if (aR) sl@0: { sl@0: aT.Rendezvous(*aR); sl@0: TInt s = aR->Int(); sl@0: test_Equal(s, KRequestPending); sl@0: aT.Resume(); sl@0: User::WaitForRequest(*aR); sl@0: s = aR->Int(); sl@0: test_KErrNone(s); sl@0: } sl@0: return r; sl@0: } sl@0: sl@0: sl@0: LOCAL_D TInt test4Thread(TAny *aSem) sl@0: // sl@0: // Wait to be released on the semaphore. sl@0: // Then release the semaphore. sl@0: // sl@0: { sl@0: sl@0: RSemaphore& sem=(*(RSemaphore*)aSem); sl@0: sem.Wait(); sl@0: sem.Signal(); sl@0: return(KErrNone); sl@0: } sl@0: sl@0: TInt BadPriority(TAny* aThread) sl@0: { sl@0: ((RThread*)aThread)->SetPriority(EPriorityNull); sl@0: return KErrNone; sl@0: } sl@0: sl@0: _LIT(KLitRomString,"RomStringRomStringRomStringRomStringRomStringRomStringRomString"); sl@0: sl@0: LOCAL_C TInt BadFullNameThread(TAny* aPar) sl@0: { sl@0: RThread thread; sl@0: sl@0: switch ((TInt)aPar) sl@0: { sl@0: case 0: sl@0: { sl@0: HBufC* hBuf = HBufC::New(5);//Size 5 is not sufficient. thread.FullName should panic. sl@0: test(NULL != hBuf); sl@0: RBuf rBuf(hBuf); sl@0: thread.FullName(rBuf); sl@0: rBuf.Close(); sl@0: } sl@0: return(KErrNone); sl@0: sl@0: case 1: sl@0: { sl@0: TPtr ptr((TText*)(KLitRomString.iBuf), KLitRomString.iTypeLength); sl@0: // Passing descriptor whose data is in ROM. This may behave in different ways sl@0: // on differrent platforms. Here, we just check that Kernel is safe. sl@0: thread.FullName(ptr); sl@0: } sl@0: return(KErrNone); sl@0: } sl@0: return(KErrArgument); sl@0: } sl@0: sl@0: sl@0: LOCAL_D void test1() sl@0: // sl@0: // Test 1 sl@0: // sl@0: { sl@0: sl@0: __UHEAP_MARK; sl@0: RThread thread; sl@0: TRequestStatus stat; sl@0: TInt r; sl@0: sl@0: test.Start(_L("Close without create")); sl@0: thread.Close(); sl@0: sl@0: test.Next(_L("Create ENormal")); sl@0: r = StartInstructionThread(thread, _L("Thread"), ENormal, EOwnerProcess, 0, 0); sl@0: test_KErrNone(r); sl@0: sl@0: test.Next(_L("Test priorities")); sl@0: test(thread.Priority()==EPriorityNormal); sl@0: thread.SetPriority(EPriorityRealTime); // WINS will commute this to EPriorityMuchMore sl@0: #if defined(__EPOC32__) sl@0: test(thread.Priority()==EPriorityRealTime); sl@0: #endif sl@0: thread.SetPriority(EPriorityMuchMore); sl@0: test(thread.Priority()==EPriorityMuchMore); sl@0: // thread.SetPriority(EPriorityNull); sl@0: RThread badThread; sl@0: r = badThread.Create(_L("Bad Priority"),BadPriority,KDefaultStackSize,KHeapSize,KHeapSize,&thread); sl@0: test(r==KErrNone); sl@0: badThread.Logon(stat); sl@0: test(stat==KRequestPending); sl@0: badThread.Resume(); sl@0: User::WaitForRequest(stat); sl@0: test(stat==EBadPriority); sl@0: test(badThread.ExitCategory()==_L("KERN-EXEC")); sl@0: test(badThread.ExitReason()==EBadPriority); sl@0: test(badThread.ExitType()==EExitPanic); sl@0: CLOSE_AND_WAIT(badThread); sl@0: test(thread.Priority()==EPriorityMuchMore); sl@0: sl@0: #if defined(__EPOC32__) sl@0: test.Next(_L("Test setting process priority from thread")); sl@0: test(thread.ProcessPriority()==EPriorityForeground); sl@0: thread.SetProcessPriority(EPriorityHigh); sl@0: test(thread.ProcessPriority()==EPriorityHigh); sl@0: test(RProcess().Priority()==EPriorityHigh); sl@0: thread.SetProcessPriority(EPriorityForeground); sl@0: test(thread.ProcessPriority()==EPriorityForeground); sl@0: test(RProcess().Priority()==EPriorityForeground); sl@0: #endif sl@0: sl@0: TBuf<0x100> name; sl@0: test.Next(_L("Test thread name")); sl@0: test(thread.Name()==_L("Thread")); sl@0: test.Next(_L("Get owning process name")); sl@0: RProcess p; sl@0: test(thread.Process(p)==KErrNone); sl@0: name=p.Name(); sl@0: name.Append(_L("::")); sl@0: name.Append(thread.Name()); sl@0: test.Next(_L("Test fullname - via TFullName RHandleBase::FullName")); sl@0: test(thread.FullName().CompareF(name)==0); sl@0: sl@0: test.Next(_L("Test fullname - via void RHandleBase::FullName(TDes& aName)")); sl@0: HBufC* hBuf = HBufC::New(100); sl@0: test(NULL != hBuf); sl@0: TPtr ptr = hBuf->Des(); sl@0: thread.FullName(ptr); sl@0: test(ptr.CompareF(name)==0); sl@0: RBuf rBuf(hBuf); sl@0: thread.FullName(rBuf); sl@0: test(rBuf.CompareF(name)==0); sl@0: rBuf.Close(); sl@0: sl@0: test.Next(_L("Test void RHandleBase::FullName(TDes& aName) when aName is too short")); sl@0: TInt aaa=badThread.Create(_L("BadFullNameThread1"),BadFullNameThread,KDefaultStackSize,KHeapSize,KHeapSize,(TAny*)0); sl@0: test(aaa==KErrNone); sl@0: badThread.Logon(stat); sl@0: test(badThread.ExitType()==EExitPending); sl@0: badThread.Resume(); sl@0: User::WaitForRequest(stat); sl@0: test(badThread.ExitCategory()==_L("KERN-EXEC")); sl@0: test(badThread.ExitReason()==EKUDesSetLengthOverflow); sl@0: test(badThread.ExitType()==EExitPanic); sl@0: CLOSE_AND_WAIT(badThread); sl@0: sl@0: test.Next(_L("Test void RHandleBase::FullName(TDes& aName) where aName has data in ROM ")); sl@0: aaa=badThread.Create(_L("BadFullNameThread2"),BadFullNameThread,KDefaultStackSize,KHeapSize,KHeapSize,(TAny*)1); sl@0: test(aaa==KErrNone); sl@0: badThread.Logon(stat); sl@0: test(badThread.ExitType()==EExitPending); sl@0: badThread.Resume(); sl@0: User::WaitForRequest(stat); sl@0: test.Printf(_L("BadFullNameThread2 exited with ExitReason=%d and ExitType=%d\n"),badThread.ExitReason(),badThread.ExitType()); sl@0: CLOSE_AND_WAIT(badThread); sl@0: sl@0: test.Next(_L("Rename current thread")); sl@0: test(User::RenameThread(_L("renamed"))==KErrNone); sl@0: name=p.Name(); sl@0: name.Append(_L("::")); sl@0: RThread me; sl@0: name.Append(me.Name()); sl@0: test(me.Name()==_L("renamed")); sl@0: test(me.FullName().CompareF(name)==0); sl@0: sl@0: test.Next(_L("Test running exit types")); sl@0: test(thread.ExitType()==EExitPending); sl@0: test(thread.ExitReason()==0); sl@0: // no getters for iUserHeap and iFrame sl@0: test(thread.ExitCategory()==KNullDesC); sl@0: sl@0: test.Next(_L("Test logging on")); sl@0: thread.Logon(stat); sl@0: RThread t; sl@0: test(t.RequestCount()==0); sl@0: test(stat==KRequestPending); sl@0: r=thread.LogonCancel(stat); // this generates a signal sl@0: test(r==KErrNone); sl@0: test(stat==KErrNone); sl@0: test(t.RequestCount()==1); // the request count is 1 due to the signal generated by LogonCancel sl@0: test(thread.RequestCount()==0); sl@0: sl@0: test.Next(_L("Resuming thread")); sl@0: thread.Resume(); sl@0: test.Next(_L("Absorb cancel")); sl@0: User::WaitForRequest(stat); sl@0: test.Next(_L("Test LogonCancel on dead thread is ok")); sl@0: r=thread.LogonCancel(stat); sl@0: test(r==KErrGeneral); sl@0: test.Next(_L("Close thread")); sl@0: CLOSE_AND_WAIT(thread); sl@0: test.Next(_L("Close again")); sl@0: thread.Close(); sl@0: thread.Close(); sl@0: thread.Close(); sl@0: thread.Close(); sl@0: __UHEAP_MARKEND; sl@0: test.End(); sl@0: } sl@0: sl@0: sl@0: LOCAL_D void test2(TOwnerType anOwnerType) sl@0: // sl@0: // Test 2 sl@0: // sl@0: { sl@0: sl@0: __UHEAP_MARK; sl@0: RThread thread; sl@0: TRequestStatus stat; sl@0: TRequestStatus rstat; sl@0: TInt r; sl@0: sl@0: test.Start(_L("Run thread 10 times")); sl@0: for (TInt xx=0;xx<10;xx++) sl@0: { sl@0: test.Printf(_L("\r%02d"),xx); sl@0: r = StartInstructionThread(thread, _L("Thread1"), ENormal, anOwnerType, &stat, 0); sl@0: test_KErrNone(r); sl@0: thread.Resume(); sl@0: User::WaitForRequest(stat); sl@0: CLOSE_AND_WAIT(thread); sl@0: } sl@0: test.Printf(_L("\n")); sl@0: sl@0: test.Next(_L("Panic within thread")); sl@0: r = StartInstructionThread(thread, _L("Thread2"), EInstrPanic, anOwnerType, &stat, 0); sl@0: test_KErrNone(r); sl@0: test(thread.ExitType()==EExitPending); sl@0: thread.Resume(); sl@0: User::WaitForRequest(stat); sl@0: test(thread.ExitCategory()==_L("Hello")); sl@0: test(thread.ExitReason()==KExitPanicNum); sl@0: test(thread.ExitType()==EExitPanic); sl@0: CLOSE_AND_WAIT(thread); sl@0: sl@0: test.Next(_L("Panic external to thread")); sl@0: TInt ijk; sl@0: TUint seed[2] = { 0xadf85458, 0 }; sl@0: TUint maxcount = 0; sl@0: for (ijk=0; ijk<8192; ++ijk) sl@0: { sl@0: if (!(ijk&255)) sl@0: test.Printf(_L("%d\n"), ijk); sl@0: r = StartInstructionThread(thread, _L("Thread3"), EWait, anOwnerType, &stat, 0); sl@0: test_KErrNone(r); sl@0: __e32_atomic_store_ord32(&IFLAG, 0); sl@0: thread.Resume(); sl@0: thread.SetPriority(EPriorityMore); sl@0: if (maxcount==0) sl@0: { sl@0: while (__e32_atomic_load_acq32(&IFLAG)==0 && --maxcount!=0) sl@0: { sl@0: } sl@0: maxcount = 0u - maxcount; sl@0: test.Printf(_L("maxcount=%u\n"), maxcount); sl@0: } sl@0: else sl@0: { sl@0: TUint random = Random(seed); sl@0: random %= maxcount; sl@0: ++random; sl@0: while (__e32_atomic_load_acq32(&IFLAG)==0 && --random!=0) sl@0: { sl@0: } sl@0: } sl@0: thread.Panic(_L("panic"), 123); sl@0: User::WaitForRequest(stat); sl@0: test(thread.ExitCategory()==_L("panic")); sl@0: test(thread.ExitReason()==123); sl@0: test(thread.ExitType()==EExitPanic); sl@0: CLOSE_AND_WAIT(thread); sl@0: } sl@0: sl@0: test.Next(_L("Internal exit")); sl@0: r = StartInstructionThread(thread, _L("Thread4"), ENormal, anOwnerType, &stat, 0); sl@0: test_KErrNone(r); sl@0: test(thread.ExitType()==EExitPending); sl@0: thread.Resume(); sl@0: User::WaitForRequest(stat); sl@0: test(thread.ExitCategory()==_L("Kill")); sl@0: test(thread.ExitReason()==KThreadReturnValue); sl@0: test(thread.ExitType()==EExitKill); sl@0: CLOSE_AND_WAIT(thread); sl@0: sl@0: test.Next(_L("External terminate")); sl@0: r = StartInstructionThread(thread, _L("Thread5"), EWait, anOwnerType, &stat, &rstat); sl@0: test_KErrNone(r); sl@0: test.Next(_L("Terminate")); sl@0: thread.Terminate(KTerminationReason); sl@0: test.Next(_L("Wait")); sl@0: User::WaitForRequest(stat); sl@0: test(thread.ExitCategory()==_L("Terminate")); sl@0: test(thread.ExitReason()==KTerminationReason); sl@0: test(thread.ExitType()==EExitTerminate); sl@0: test.Next(_L("Close")); sl@0: CLOSE_AND_WAIT(thread); sl@0: sl@0: test.Next(_L("External kill")); sl@0: r = StartInstructionThread(thread, _L("Thread6"), EWait, anOwnerType, &stat, &rstat); sl@0: test_KErrNone(r); sl@0: thread.Suspend(); sl@0: thread.Resume(); sl@0: thread.Kill(KKillReason); sl@0: User::WaitForRequest(stat); sl@0: test(thread.ExitCategory()==_L("Kill")); sl@0: test(thread.ExitReason()==KKillReason); sl@0: test(thread.ExitType()==EExitKill); sl@0: test.Next(_L("Kill again")); sl@0: thread.Kill(KErrNone); sl@0: thread.Kill(KErrNone); sl@0: thread.Kill(KErrNone); sl@0: CLOSE_AND_WAIT(thread); sl@0: test.End(); sl@0: __UHEAP_MARKEND; sl@0: } sl@0: sl@0: LOCAL_D void test3() sl@0: // sl@0: // Test 3. sl@0: // sl@0: { sl@0: sl@0: test.Start(_L("Read across thread")); sl@0: TReadInfo info; sl@0: TPtrC des1=_L("tdesc"); sl@0: info.tdesc=(&des1); sl@0: TPtrC ptr1=_L("tptrc"); sl@0: info.tptrc=&ptr1; sl@0: TBuf<0x20> tdes(_L("tdes")); sl@0: info.tdes=&tdes; sl@0: TBuf<0x20> tptrbuf(_L("tptr")); sl@0: TPtr tptr((TText*)tptrbuf.Ptr(),tptrbuf.Length(),tptrbuf.MaxLength()); sl@0: info.tptr=&tptr; sl@0: TBuf<0x20> hbufc(_L("hbufc")); sl@0: HBufC *pH=hbufc.Alloc(); sl@0: test(pH!=NULL); sl@0: info.hbufc=pH; sl@0: TBufC<0x20> tbufc(_L("tbufc")); sl@0: info.tbufc=&tbufc; sl@0: TBuf<0x20> tbuf(_L("tbuf")); sl@0: info.tbuf=&tbuf; sl@0: TBufC<0x20> tptrdes(_L("tptrdes")); sl@0: TPtr des=tptrdes.Des(); sl@0: info.tptrdes=&des; sl@0: TBuf<0x10> b(_L("Hello")); sl@0: info.anAddress=(&b); sl@0: info.anAddress= info.anAddress; //prevents warning (var set but never used) sl@0: delete pH; sl@0: test.End(); sl@0: } sl@0: sl@0: LOCAL_D void test4() sl@0: // sl@0: // Test 4. sl@0: // sl@0: { sl@0: sl@0: test.Start(_L("Create sempahore")); sl@0: RSemaphore sem; sl@0: TInt r=sem.CreateLocal(0); sl@0: test(r==KErrNone); sl@0: // sl@0: test.Next(_L("Create thread 1")); sl@0: RThread t; sl@0: r=t.Create(_L("Thread1"),test4Thread,KDefaultStackSize,KHeapSize,KHeapSize,&sem); sl@0: test(r==KErrNone); sl@0: t.Resume(); sl@0: t.Close(); sl@0: // sl@0: test.Next(_L("Create thread 2")); sl@0: r=t.Create(_L("Thread2"),test4Thread,KDefaultStackSize,KHeapSize,KHeapSize,&sem); sl@0: test(r==KErrNone); sl@0: t.Resume(); sl@0: t.Close(); sl@0: // sl@0: test.Next(_L("Create thread 3")); sl@0: r=t.Create(_L("Thread3"),test4Thread,KDefaultStackSize,KHeapSize,KHeapSize,&sem); sl@0: test(r==KErrNone); sl@0: t.Resume(); sl@0: t.Close(); sl@0: // sl@0: test.Next(_L("Release threads")); sl@0: sem.Signal(3); sl@0: // sl@0: test.Next(_L("Wait 1")); sl@0: sem.Wait(); sl@0: // sl@0: test.Next(_L("Wait 2")); sl@0: sem.Wait(); sl@0: // sl@0: test.Next(_L("Wait 2")); sl@0: sem.Wait(); sl@0: sem.Close(); sl@0: // sl@0: test.End(); sl@0: } sl@0: sl@0: TInt MinimalThread(TAny*) sl@0: // sl@0: // Minimal thread, used in test 5 sl@0: // sl@0: { sl@0: return(KErrNone); sl@0: } sl@0: sl@0: LOCAL_D void test5() sl@0: // sl@0: // Test 5 - tests unclosed but completed threads sl@0: // sl@0: { sl@0: sl@0: test.Start(_L("Start thread")); sl@0: RThread thread1; sl@0: test(thread1.Create(_L("Test Thread1"),MinimalThread,KDefaultStackSize,KHeapSize,KHeapSize,NULL)==KErrNone); sl@0: TRequestStatus stat1; sl@0: thread1.Logon(stat1); sl@0: thread1.Resume(); sl@0: User::WaitForRequest(stat1); sl@0: test(thread1.ExitType()==EExitKill); sl@0: // 'missing' thread1.Close(); sl@0: sl@0: test.Next(_L("Start another thread")); sl@0: RThread thread2; sl@0: test(thread2.Create(_L("Test Thread2"),MinimalThread,KDefaultStackSize,KHeapSize,KHeapSize,NULL)==KErrNone); sl@0: TRequestStatus stat2; sl@0: thread2.Logon(stat2); sl@0: thread2.Resume(); sl@0: User::WaitForRequest(stat2); //Goes wrong here in build 48 sl@0: test(thread2.ExitType()==EExitKill); sl@0: sl@0: test.Next(_L("Close both threads")); sl@0: CLOSE_AND_WAIT(thread2); sl@0: CLOSE_AND_WAIT(thread1); sl@0: sl@0: test.End(); sl@0: } sl@0: sl@0: LOCAL_D TInt test6Thread(TAny *anArg) sl@0: // sl@0: // sl@0: // sl@0: { sl@0: ((RSemaphore*)anArg)->Wait(); sl@0: RThread t; sl@0: RThread dup; sl@0: dup.Duplicate(t); sl@0: dup.Panic(_L("Test"),0); sl@0: sl@0: return KErrNone; sl@0: } sl@0: sl@0: void test6() sl@0: // sl@0: // Test thread duplication sl@0: // sl@0: { sl@0: sl@0: test.Start(_L("Create thread")); sl@0: RSemaphore sem; sl@0: TInt r=sem.CreateLocal(0); sl@0: test(r==KErrNone); sl@0: sl@0: RThread t; sl@0: t.Create(_L("test6thread"),test6Thread,KDefaultStackSize,KHeapSize,KHeapSize,&sem); sl@0: test.Next(_L("Resume thread")); sl@0: TRequestStatus stat; sl@0: t.Logon(stat); sl@0: t.Resume(); sl@0: sem.Signal(); sl@0: User::WaitForRequest(stat); sl@0: test.Next(_L("Close thread")); sl@0: t.Close(); sl@0: sem.Close(); sl@0: test.End(); sl@0: } sl@0: sl@0: RSemaphore gsem; sl@0: enum TThreadProgress { EBeforeStart, EStarted, EWaiting, EDoneWaiting, EFinished }; sl@0: TThreadProgress progress=EBeforeStart; sl@0: LOCAL_D TInt test7thread(TAny * /*anArg*/) sl@0: // sl@0: // sl@0: // sl@0: { sl@0: sl@0: progress=EStarted; sl@0: progress=EWaiting; sl@0: gsem.Wait(); sl@0: progress=EDoneWaiting; sl@0: gsem.Wait(); sl@0: progress=EFinished; sl@0: return KErrNone; sl@0: } sl@0: sl@0: void test7() sl@0: // sl@0: // Suspend/ Resume tests sl@0: // sl@0: { sl@0: sl@0: TInt r=gsem.CreateLocal(0); sl@0: test(r==KErrNone); sl@0: test.Start(_L("Create thread")); sl@0: RThread t; sl@0: r=t.Create(_L("test7thread"), test7thread, KDefaultStackSize,KHeapSize,KHeapSize,NULL); sl@0: test(r==KErrNone); sl@0: TRequestStatus stat; sl@0: t.Logon(stat); sl@0: test.Next(_L("Resume thread")); sl@0: t.Resume(); sl@0: User::After(KWaitTime); // wait a bit; sl@0: test.Next(_L("Make thread wait on a semaphore")); sl@0: test(progress==EWaiting); sl@0: test.Next(_L("Suspend waiting thread")); sl@0: t.Suspend(); sl@0: test.Next(_L("Signal the semaphore")); sl@0: gsem.Signal(); sl@0: User::After(KWaitTime); sl@0: test.Next(_L("Test thread still suspended")); sl@0: test(progress==EWaiting); sl@0: test.Next(_L("resume thread")); sl@0: t.Resume(); sl@0: test.Next(_L("Test the thread no longer waiting on the semaphore")); sl@0: User::After(KWaitTime); sl@0: test(progress==EDoneWaiting); sl@0: test.Next(_L("Wait for thread to finish")); sl@0: gsem.Signal(); sl@0: User::WaitForRequest(stat); sl@0: test(stat==KErrNone); sl@0: test(progress==EFinished); sl@0: CLOSE_AND_WAIT(t); sl@0: sl@0: RThread tt; sl@0: progress=EBeforeStart; sl@0: test.Next(_L("Create Thread")); sl@0: r=tt.Create(_L("test7thread"), test7thread, KDefaultStackSize,KHeapSize,KHeapSize,NULL); sl@0: test(r==KErrNone); sl@0: tt.Logon(stat); sl@0: test.Next(_L("Suspend thread without starting it")); sl@0: tt.Suspend(); sl@0: tt.Suspend(); sl@0: test.Next(_L("Resume and test suspend/resume balance")); sl@0: tt.Resume(); sl@0: tt.Resume(); sl@0: User::After(KWaitTime); sl@0: test(progress==EBeforeStart); sl@0: tt.Resume(); sl@0: test.Next(_L("test thread is suspended on semaphore")); sl@0: User::After(KWaitTime); sl@0: test(progress==EWaiting); sl@0: test.Next(_L("suspend thread")); sl@0: tt.Suspend(); sl@0: tt.Suspend(); sl@0: test.Next(_L("resume thread")); sl@0: tt.Resume(); sl@0: tt.Resume(); sl@0: test.Next(_L("test thread still suspended on semaphore")); sl@0: User::After(KWaitTime); sl@0: test(progress==EWaiting); sl@0: test.Next(_L("Suspend, Suspend, Signal semaphore, Suspend")); sl@0: tt.Suspend(); sl@0: tt.Suspend(); sl@0: gsem.Signal(); sl@0: tt.Suspend(); sl@0: test.Next(_L("test thread still suspended on semaphore")); sl@0: User::After(KWaitTime); sl@0: test(progress==EWaiting); sl@0: test.Next(_L("Resume thread, checking suspend/resume balance")); sl@0: tt.Resume(); sl@0: User::After(KWaitTime); sl@0: test(progress==EWaiting); sl@0: tt.Resume(); sl@0: User::After(KWaitTime); sl@0: test(progress==EWaiting); sl@0: tt.Resume(); sl@0: User::After(KWaitTime); sl@0: test(progress==EDoneWaiting); sl@0: test.Next(_L("Resume an executing thread")); sl@0: tt.Resume(); sl@0: tt.Resume(); sl@0: // test.Next(_L("Suspend and check balance")); sl@0: // tt.Suspend(); sl@0: // tt.Suspend(); sl@0: test.Next(_L("Wait for thread to finish")); sl@0: gsem.Signal(); sl@0: User::After(KWaitTime); sl@0: test(progress==EFinished); sl@0: User::WaitForRequest(stat); sl@0: CLOSE_AND_WAIT(tt); sl@0: sl@0: // sl@0: test.Next(_L("Create Thread")); sl@0: r=tt.Create(_L("test7thread"), test7thread, KDefaultStackSize,KHeapSize,KHeapSize,NULL); sl@0: test(r==KErrNone); sl@0: tt.Logon(stat); sl@0: test.Next(_L("Resume")); sl@0: tt.Resume(); sl@0: test.Next(_L("Hang thread on semaphore")); sl@0: User::After(KWaitTime); sl@0: test(progress==EWaiting); sl@0: test.Next(_L("Suspend then Resume thread")); sl@0: tt.Suspend(); sl@0: tt.Suspend(); sl@0: tt.Resume(); sl@0: User::After(KWaitTime); sl@0: test(progress==EWaiting); sl@0: tt.Resume(); sl@0: test.Next(_L("Check still hanging on semaphore")); sl@0: User::After(KWaitTime); sl@0: test(progress==EWaiting); sl@0: test.Next(_L("Signal Semaphore")); sl@0: gsem.Signal(); sl@0: test.Next(_L("Test thread executing again")); sl@0: User::After(KWaitTime); sl@0: test(progress==EDoneWaiting); sl@0: test.Next(_L("Hang thread on another semaphore, and suspend")); sl@0: tt.Suspend(); sl@0: test.Next(_L("Signal semaphore, and suspend again")); sl@0: gsem.Signal(); sl@0: User::After(KWaitTime); sl@0: test(progress==EDoneWaiting); sl@0: tt.Suspend(); sl@0: test.Next(_L("Resume the thread")); sl@0: tt.Resume(); sl@0: User::After(KWaitTime); sl@0: test(progress==EDoneWaiting); sl@0: tt.Resume(); sl@0: test.Next(_L("Wait for thread to finish")); sl@0: User::After(KWaitTime); sl@0: test(progress==EFinished); sl@0: User::WaitForRequest(stat); sl@0: CLOSE_AND_WAIT(tt); sl@0: test.End(); sl@0: } sl@0: sl@0: #if 0 sl@0: RSemaphore Sem; sl@0: LOCAL_D TInt test8thread(TAny* aPtr) sl@0: // sl@0: // sl@0: // sl@0: { sl@0: sl@0: typedef TBuf<0x20> TTestBuf; sl@0: typedef volatile TTestBuf* TTestBufPtr; sl@0: volatile TTestBufPtr& pB=*(volatile TTestBufPtr*)aPtr; sl@0: if ((TUint)pB != 0xc90fdaa2) sl@0: return KErrGeneral; sl@0: Sem.Wait(); sl@0: TDesC* pD=(TDesC*)pB; sl@0: test(*pD==_L("Everything's just hunky-dory")); sl@0: delete (TTestBufPtr*)pB; sl@0: __UHEAP_MARKEND; sl@0: return KErrNone; sl@0: } sl@0: #endif sl@0: sl@0: void test8() sl@0: // sl@0: // Get Heap sl@0: // sl@0: { sl@0: // !!! RThread::SetInitialParameter no longer exists sl@0: sl@0: /* sl@0: typedef TBuf<0x20> TTestBuf; sl@0: TTestBuf* buf=(TTestBuf*)0xc90fdaa2; sl@0: sl@0: test.Start(_L("Create thread")); sl@0: RThread thread; sl@0: TInt r=thread.Create(_L("test8thread"),test8thread,KDefaultStackSize,KHeapSize,KHeapSize,NULL); sl@0: test(r==KErrNone); sl@0: r=Sem.CreateLocal(0); sl@0: test(r==KErrNone); sl@0: test.Next(_L("Set parameter")); sl@0: r=thread.SetInitialParameter(&buf); sl@0: test(r==KErrNone); sl@0: TRequestStatus stat; sl@0: thread.Logon(stat); sl@0: thread.SetPriority(EPriorityMore); sl@0: test.Next(_L("Resume thread")); sl@0: thread.Resume(); sl@0: test.Next(_L("Set initial parameter NULL")); sl@0: r=thread.SetInitialParameter(NULL); sl@0: test(thread.ExitType()==EExitPending); sl@0: sl@0: test.Next(_L("Get heap")); sl@0: RHeap* heap; sl@0: heap=thread.Heap(); sl@0: test.Next(_L("Alloc inside heap")); sl@0: __RHEAP_MARK(heap); sl@0: buf=(TTestBuf*)heap->Alloc(sizeof(TTestBuf)); sl@0: test(buf!=NULL); sl@0: new(buf) TTestBuf; sl@0: *buf=(_L("Everything's just hunky-dory")); sl@0: sl@0: Sem.Signal(); sl@0: User::WaitForRequest(stat); sl@0: test(stat==KErrNone); sl@0: test(thread.ExitType()==EExitKill); sl@0: test(thread.ExitReason()==KErrNone); sl@0: sl@0: test.Next(_L("Close")); sl@0: thread.Close(); sl@0: Sem.Close(); sl@0: test.End(); sl@0: */ sl@0: } sl@0: sl@0: TInt Thread(TAny* /*aAny*/) sl@0: { sl@0: sl@0: RTest test(_L("Any old thread")); sl@0: test.Next(_L("Find remote thread")); sl@0: // find the main thread sl@0: TFullName name; sl@0: name=RProcess().Name(); sl@0: name.Append(_L("::*")); sl@0: TFindThread ft; sl@0: ft.Find(name); sl@0: TInt r=ft.Next(name); sl@0: test(r==KErrNone); sl@0: RThread t; sl@0: t.Open(ft); sl@0: sl@0: t.Close(); sl@0: return KErrNone; sl@0: } sl@0: sl@0: void test9() sl@0: { sl@0: sl@0: test.Start(_L("Test create a NULL TPtr")); sl@0: TPtr p(NULL, 10, 10); sl@0: test.Next(_L("Create and run remote thread")); sl@0: RThread t; sl@0: TInt r; sl@0: r=t.Create(_L("Any Old Thread"), Thread, 0x2000, 0x2000, 0x2000, (TAny *)&p); sl@0: test(KErrNone==r); sl@0: TRequestStatus stat; sl@0: t.Logon(stat); sl@0: t.Resume(); sl@0: test.Next(_L("Wait for thread to complete")); sl@0: User::WaitForRequest(stat); sl@0: test(stat==KErrNone); sl@0: test(t.ExitCategory()==_L("Kill")); sl@0: test(t.ExitReason()==KErrNone); sl@0: test(t.ExitType()==EExitKill); sl@0: CLOSE_AND_WAIT(t); sl@0: test.End(); sl@0: } sl@0: sl@0: sl@0: sl@0: TInt FoghornLeghorn(TAny* aMutex) sl@0: // sl@0: // Thread function sl@0: // sl@0: { sl@0: sl@0: ((RSemaphore*)aMutex)->Wait(); sl@0: RThread thread; sl@0: TInt r=thread.Create(_L("I say * boy"),FoghornLeghorn,KDefaultStackSize,NULL,aMutex); sl@0: test(r==KErrBadName); sl@0: return KErrNone; sl@0: } sl@0: sl@0: void testOpen() sl@0: { sl@0: sl@0: test.Start(_L("Create Foghorn Leghorn")); sl@0: RSemaphore fogMut; sl@0: fogMut.CreateLocal(0); sl@0: RThread foghorn; sl@0: TInt r=foghorn.Create(_L("Foghorn Leghorn"),FoghornLeghorn,KDefaultStackSize,KHeapSize,KHeapSize,&fogMut); sl@0: test(r==KErrNone); sl@0: test.Next(_L("Logon")); sl@0: TRequestStatus stat; sl@0: foghorn.Logon(stat); sl@0: test(stat==KRequestPending); sl@0: test.Next(_L("Resume Foghorn Leghorn")); sl@0: foghorn.Resume(); sl@0: test.Next(_L("Get full name")); sl@0: TFindThread find(_L("*Foghorn Leghorn")); sl@0: TFullName name; sl@0: r=find.Next(name); sl@0: test(r==KErrNone); sl@0: test.Next(_L("Open another handle using full name")); sl@0: RThread leghorn; sl@0: r=leghorn.Open(name); sl@0: test(r==KErrNone); sl@0: test.Next(_L("Kill using second handle")); sl@0: leghorn.Kill(34523); sl@0: User::WaitForRequest(stat); sl@0: test(stat==34523); sl@0: test.Next(_L("Close handles")); sl@0: foghorn.Close(); sl@0: CLOSE_AND_WAIT(leghorn); sl@0: sl@0: test.Next(_L("Again! - Create Foghorn Leghorn")); sl@0: r=foghorn.Create(_L("Foghorn Leghorn"),FoghornLeghorn,KDefaultStackSize,KHeapSize,KHeapSize,&fogMut); sl@0: test(r==KErrNone); sl@0: test.Next(_L("Logon")); sl@0: foghorn.Logon(stat); sl@0: test(stat==KRequestPending); sl@0: test.Next(_L("Resume Foghorn Leghorn")); sl@0: foghorn.Resume(); sl@0: test.Next(_L("Get full name")); sl@0: find.Find(_L("*Foghorn Leghorn")); sl@0: r=find.Next(name); sl@0: test(r==KErrNone); sl@0: test.Next(_L("Open another handle using full name")); sl@0: r=leghorn.Open(name); sl@0: test(r==KErrNone); sl@0: test.Next(_L("Kill using second handle")); sl@0: leghorn.Kill(67857); sl@0: User::WaitForRequest(stat); sl@0: test(stat==67857); sl@0: test.Next(_L("Close handles")); sl@0: foghorn.Close(); sl@0: CLOSE_AND_WAIT(leghorn); sl@0: sl@0: test.Next(_L("Create Foghorn Leghorn")); sl@0: r=foghorn.Create(_L("Foghorn Leghorn"),FoghornLeghorn,KDefaultStackSize,KHeapSize,KHeapSize,&fogMut); sl@0: test(r==KErrNone); sl@0: test.Next(_L("Logon")); sl@0: foghorn.Logon(stat); sl@0: test(stat==KRequestPending); sl@0: test.Next(_L("Resume Foghorn Leghorn")); sl@0: foghorn.Resume(); sl@0: test.Next(_L("Now close it")); sl@0: foghorn.Close(); sl@0: sl@0: test.Next(_L("Get full name")); sl@0: find.Find(_L("*Foghorn Leghorn")); sl@0: r=find.Next(name); sl@0: test(r==KErrNone); sl@0: test.Next(_L("Open using full name")); sl@0: r=leghorn.Open(name); sl@0: test(r==KErrNone); sl@0: test.Next(_L("Kill")); sl@0: leghorn.Kill(67857); sl@0: User::WaitForRequest(stat); sl@0: test(stat==67857); sl@0: test.Next(_L("Close")); sl@0: CLOSE_AND_WAIT(leghorn); sl@0: sl@0: test.Next(_L("Start and get it to try to start a new thread")); sl@0: r=foghorn.Create(_L("Foghorn Leghorn"),FoghornLeghorn,KDefaultStackSize,KHeapSize,KHeapSize,&fogMut); sl@0: test(r==KErrNone); sl@0: foghorn.Logon(stat); sl@0: test(stat==KRequestPending); sl@0: foghorn.Resume(); sl@0: fogMut.Signal(); sl@0: User::WaitForRequest(stat); sl@0: test(stat==KErrNone); sl@0: test(foghorn.ExitCategory()==_L("Kill")); sl@0: test(foghorn.ExitReason()==KErrNone); sl@0: test(foghorn.ExitType()==EExitKill); sl@0: test.Next(_L("Close")); sl@0: CLOSE_AND_WAIT(foghorn); sl@0: fogMut.Close(); sl@0: sl@0: test.End(); sl@0: } sl@0: sl@0: TInt Bunny(TAny*) sl@0: // sl@0: // Thread function sl@0: // sl@0: { sl@0: sl@0: FOREVER sl@0: ; sl@0: } sl@0: sl@0: void testReuse() sl@0: { sl@0: sl@0: test.Start(_L("Create thread with duplicate name")); sl@0: RThread thread; sl@0: TFullName name=thread.Name(); sl@0: TInt r=thread.Create(name,Bunny,KDefaultStackSize,KHeapSize,KHeapSize,NULL); sl@0: test(r==KErrAlreadyExists); sl@0: // thread.Resume(); handle will be invalid since create failed sl@0: test.Next(_L("Create with a good name")); sl@0: r=thread.Create(_L("Bugs Bunny"),Bunny,KDefaultStackSize,KHeapSize,KHeapSize,NULL); sl@0: test(r==KErrNone); sl@0: TRequestStatus stat; sl@0: thread.Logon(stat); sl@0: test.Next(_L("Resume")); sl@0: thread.Resume(); sl@0: test.Next(_L("Kill")); sl@0: thread.Kill(15); sl@0: User::WaitForRequest(stat); sl@0: test(stat==15); sl@0: CLOSE_AND_WAIT(thread); sl@0: sl@0: test.End(); sl@0: } sl@0: sl@0: sl@0: TInt HongKongPhooey(TAny * /*aAny*/) sl@0: { sl@0: sl@0: RMutex m; sl@0: m.OpenGlobal(_L("Test Mutex")); sl@0: m.Wait(); sl@0: User::Panic(_L("Hello"),900); sl@0: return KErrNone; sl@0: } sl@0: sl@0: void testReleaseMutex() sl@0: // sl@0: // Bug HA-187 sl@0: // sl@0: { sl@0: TInt r; sl@0: test.Start(_L("Create a global Mutex")); sl@0: RMutex m; sl@0: r=m.CreateGlobal(_L("Test Mutex")); sl@0: test.Next(_L("Create a thread")); sl@0: RThread number1SuperGuy; sl@0: r=number1SuperGuy.Create(_L("Hong Kong Phooey"), HongKongPhooey, KDefaultStackSize,KHeapSize,KHeapSize,NULL); sl@0: test(r==KErrNone); sl@0: TRequestStatus s; sl@0: number1SuperGuy.Logon(s); sl@0: test.Next(_L("Resume Thread")); sl@0: number1SuperGuy.Resume(); sl@0: test.Next(_L("Wait on Mutex and Panic")); sl@0: User::WaitForRequest(s); sl@0: test(number1SuperGuy.ExitType()==EExitPanic); sl@0: test(number1SuperGuy.ExitCategory()==_L("Hello")); sl@0: test(number1SuperGuy.ExitReason()==900); sl@0: User::After(100000); // wait a bit for everything to be cleaned up sl@0: m.Wait(); sl@0: test.Next(_L("Close everything")); sl@0: m.Close(); sl@0: CLOSE_AND_WAIT(number1SuperGuy); sl@0: test.End(); sl@0: } sl@0: sl@0: void testId() sl@0: { sl@0: sl@0: test.Start(_L("Try to open nonexistant thread by ID")); sl@0: RThread thread; sl@0: TInt r=thread.Open(*(TThreadId*)&KMaxTUint); sl@0: test(r==KErrNotFound); sl@0: test.Next(_L("Get thread ID")); sl@0: r=thread.Create(_L("Buster Bunny"),Bunny,KDefaultStackSize,KHeapSize,KHeapSize,NULL); sl@0: test(r==KErrNone); sl@0: TThreadId id=thread.Id(); sl@0: TThreadId id2=thread.Id(); sl@0: test(id==id2); sl@0: RThread thread2; sl@0: r=thread2.Create(_L("Babs Bunny"),Bunny,KDefaultStackSize,KHeapSize,KHeapSize,NULL); sl@0: test(r==KErrNone); sl@0: id2=thread2.Id(); sl@0: test(id!=id2); sl@0: test(*(TUint*)&id+1==*(TUint*)&id2); sl@0: test.Next(_L("Open by ID")); sl@0: TRequestStatus stat; sl@0: thread.Logon(stat); sl@0: thread.Kill(54624); sl@0: User::WaitForRequest(stat); sl@0: test(stat==54624); sl@0: thread.Close(); sl@0: r=thread.Open(id2); sl@0: test(r==KErrNone); sl@0: test(thread.Name()==_L("Babs Bunny")); sl@0: test(thread.FullName()==thread2.FullName()); sl@0: thread2.Close(); sl@0: id=thread.Id(); sl@0: test(id==id2); sl@0: thread.Logon(stat); sl@0: thread.Kill(88863); sl@0: User::WaitForRequest(stat); sl@0: test(stat==88863); sl@0: CLOSE_AND_WAIT(thread); sl@0: sl@0: test.End(); sl@0: } sl@0: sl@0: struct SCreateInfo sl@0: { sl@0: TInt iStackSize; sl@0: TInt iMinHeapSize; sl@0: TInt iMaxHeapSize; sl@0: }; sl@0: sl@0: TInt BadCreation(TAny* aCreateInfo) sl@0: { sl@0: SCreateInfo& info=*((SCreateInfo*)aCreateInfo); sl@0: RThread thread; sl@0: thread.Create(_L("Won't work"),Bunny,info.iStackSize,info.iMinHeapSize,info.iMaxHeapSize,NULL); sl@0: return KErrNone; sl@0: } sl@0: sl@0: void testCreate() sl@0: { sl@0: test.Start(_L("Negative stack size")); sl@0: RThread thread; sl@0: TRequestStatus stat; sl@0: TInt r; sl@0: { sl@0: SCreateInfo info={-1,0x1000,0x1000}; sl@0: r=thread.Create(_L("Test Create"),BadCreation,KDefaultStackSize,KHeapSize,KHeapSize,&info); sl@0: test(KErrNone==r); sl@0: thread.Logon(stat); sl@0: thread.Resume(); sl@0: User::WaitForRequest(stat); sl@0: test(stat==EThrdStackSizeNegative); sl@0: test(thread.ExitType()==EExitPanic); sl@0: test(thread.ExitReason()==EThrdStackSizeNegative); sl@0: test(thread.ExitCategory()==_L("USER")); sl@0: CLOSE_AND_WAIT(thread); sl@0: } sl@0: // sl@0: test.Next(_L("Negative heap min size")); sl@0: { sl@0: SCreateInfo info={0x1000,-1,0x1000}; sl@0: r=thread.Create(_L("Test Create"),BadCreation,KDefaultStackSize,KHeapSize,KHeapSize,&info); sl@0: test(KErrNone==r); sl@0: thread.Logon(stat); sl@0: thread.Resume(); sl@0: User::WaitForRequest(stat); sl@0: test(stat==EThrdHeapMinTooSmall); sl@0: test(thread.ExitType()==EExitPanic); sl@0: test(thread.ExitReason()==EThrdHeapMinTooSmall); sl@0: test(thread.ExitCategory()==_L("USER")); sl@0: CLOSE_AND_WAIT(thread); sl@0: } sl@0: test.Next(_L("Negative heap max size")); sl@0: { sl@0: SCreateInfo info={0x1000,0x1000,-1}; sl@0: r=thread.Create(_L("Test Create"),BadCreation,KDefaultStackSize,KHeapSize,KHeapSize,&info); sl@0: test(KErrNone==r); sl@0: thread.Logon(stat); sl@0: thread.Resume(); sl@0: User::WaitForRequest(stat); sl@0: test(stat==EThrdHeapMaxLessThanMin); sl@0: test(thread.ExitType()==EExitPanic); sl@0: test(thread.ExitReason()==EThrdHeapMaxLessThanMin); sl@0: test(thread.ExitCategory()==_L("USER")); sl@0: CLOSE_AND_WAIT(thread); sl@0: } sl@0: test.Next(_L("heap max size < heap min size")); sl@0: { sl@0: SCreateInfo info={0x1000,0x2001,0x1000}; sl@0: r=thread.Create(_L("Test Create"),BadCreation,KDefaultStackSize,KHeapSize,KHeapSize,&info); sl@0: test(KErrNone==r); sl@0: thread.Logon(stat); sl@0: thread.Resume(); sl@0: User::WaitForRequest(stat); sl@0: test(stat==EThrdHeapMaxLessThanMin); sl@0: test(thread.ExitType()==EExitPanic); sl@0: test(thread.ExitReason()==EThrdHeapMaxLessThanMin); sl@0: test(thread.ExitCategory()==_L("USER")); sl@0: CLOSE_AND_WAIT(thread); sl@0: } sl@0: test.Next(_L("Little min heap size")); sl@0: { sl@0: SCreateInfo info={0x1000,KMinHeapSize-1,0x1000}; sl@0: r=thread.Create(_L("Test Create"),BadCreation,KDefaultStackSize,KHeapSize,KHeapSize,&info); sl@0: test(KErrNone==r); sl@0: thread.Logon(stat); sl@0: thread.Resume(); sl@0: User::WaitForRequest(stat); sl@0: test(stat==EThrdHeapMinTooSmall); sl@0: test(thread.ExitType()==EExitPanic); sl@0: test(thread.ExitReason()==EThrdHeapMinTooSmall); sl@0: test(thread.ExitCategory()==_L("USER")); sl@0: CLOSE_AND_WAIT(thread); sl@0: } sl@0: test.End(); sl@0: } sl@0: sl@0: TInt StackInfoThread(TAny*) sl@0: { sl@0: TInt a; sl@0: RThread::Rendezvous((TInt)&a); // Complete rendezvous using address of 'a' which is on the stack sl@0: return 0; sl@0: } sl@0: sl@0: void testThreadStackInfo() sl@0: { sl@0: // Check the info about the current thread's stack sl@0: RThread thread; sl@0: TThreadStackInfo info; sl@0: TInt r = thread.StackInfo(info); sl@0: test(r==KErrNone); sl@0: TLinAddr a = (TLinAddr)&info; sl@0: test.Printf(_L("address on stack=%x iBase=%x iLimit=%x iExpandLimit=%x"),a,info.iBase,info.iLimit,info.iExpandLimit); sl@0: test(a<=info.iBase); sl@0: test(a>=info.iLimit); sl@0: test(info.iExpandLimit<=info.iLimit); sl@0: sl@0: // Create another thread sl@0: r=thread.Create(_L("StackInfoThread"),StackInfoThread,KDefaultStackSize,KHeapSize,KHeapSize,(TAny*)NULL); sl@0: test(r==KErrNone); sl@0: thread.SetPriority(EPriorityLess); sl@0: sl@0: // Resume thread and wait for it to run sl@0: TRequestStatus stat; sl@0: thread.Rendezvous(stat); sl@0: thread.Resume(); sl@0: User::WaitForRequest(stat); sl@0: sl@0: // Test getting stack info of another thread sl@0: r = thread.StackInfo(info); sl@0: test(r==KErrNone); sl@0: a = stat.Int(); // a = an address on the threads stack sl@0: test.Printf(_L("address on stack=%x iBase=%x iLimit=%x iExpandLimit=%x"),a,info.iBase,info.iLimit,info.iExpandLimit); sl@0: test(a<=info.iBase); sl@0: test(a>=info.iLimit); sl@0: test(info.iExpandLimit<=info.iLimit); sl@0: sl@0: // Let thread run to end sl@0: thread.Logon(stat); sl@0: User::WaitForRequest(stat); sl@0: test(stat.Int()==0); sl@0: } sl@0: sl@0: GLDEF_C TInt E32Main() sl@0: // sl@0: // Main sl@0: // sl@0: { sl@0: sl@0: // don't want just in time debugging as we trap panics sl@0: TBool justInTime=User::JustInTime(); sl@0: User::SetJustInTime(EFalse); sl@0: sl@0: test.Title(); sl@0: __UHEAP_MARK; sl@0: sl@0: sl@0: TFullName name; sl@0: name=RThread().Name(); sl@0: sl@0: test.Start(_L("Test threads")); sl@0: sl@0: test.Next(_L("Test 1")); sl@0: test1(); sl@0: sl@0: test.Next(_L("Test create")); sl@0: testCreate(); sl@0: sl@0: test.Next(_L("Test RUndertaker")); sl@0: testUndertaker(EOwnerProcess); sl@0: sl@0: test.Next(_L("Test2")); sl@0: test2(EOwnerProcess); sl@0: User::SetJustInTime(justInTime); sl@0: test.Next(_L("Test3")); sl@0: test3(); sl@0: test.Next(_L("Test4")); sl@0: test4(); sl@0: test.Next(_L("Completed but unclosed thread")); sl@0: User::SetJustInTime(EFalse); sl@0: test5(); sl@0: User::SetJustInTime(justInTime); sl@0: test.Next(_L("Suspend/Resume")); sl@0: test7(); sl@0: test.Next(_L("Testing thread duplication")); sl@0: User::SetJustInTime(EFalse); sl@0: test6(); sl@0: User::SetJustInTime(justInTime); sl@0: test.Next(_L("Get thread's heap")); sl@0: test8(); sl@0: test.Next(_L("Test read NULL remotely (HA-178)")); sl@0: test9(); sl@0: test.Next(_L("Test Open(aFullName)")); sl@0: testOpen(); sl@0: test.Next(_L("Test Reuse after a failed create")); sl@0: testReuse(); sl@0: test.Next(_L("Test thread releases Mutex (HA-178)")); sl@0: User::SetJustInTime(EFalse); sl@0: testReleaseMutex(); sl@0: User::SetJustInTime(justInTime); sl@0: test.Next(_L("Test Thread ID")); sl@0: testId(); sl@0: test.Next(_L("Test RThread::StackInfo")); sl@0: testThreadStackInfo(); sl@0: test.End(); sl@0: __UHEAP_MARKEND; sl@0: return(KErrNone); sl@0: } sl@0: sl@0: sl@0: