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