--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/kerneltest/e32test/thread/t_thread.cpp Mon Oct 19 15:55:17 2009 +0100
@@ -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 <e32test.h>
+#include <e32panic.h>
+#include <e32svr.h>
+#include <u32hal.h>
+#include <e32atomics.h>
+#include <e32def.h>
+#include <e32def_private.h>
+#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<KNumThreads; j++)
+ {
+ TBuf<0x10> name;
+ name.Format(_L("LoopyThread%d"),j);
+ test(t[j].Create(name, LoopyThread, KDefaultStackSize, KHeapSize, KHeapSize, (TAny*)NULL,anOwnerType)==KErrNone);
+ }
+ for (j=0; j<KNumThreads-1; j++)
+ {
+ t[j].Kill(666);
+ CLOSE_AND_WAIT(t[j]);
+ }
+
+ test.Next(_L("Please wait while I close & create some undertakers"));
+ u1.Close();
+ u2.Close();
+ r=u1.Create();
+ test(r==KErrNone);
+ r=u2.Create();
+ test(r==KErrNone);
+
+ test.Next(_L("Mark kernel heap"));
+ __KHEAP_MARK;
+
+ test.Next(_L("Create thread"));
+ RThread threadx;
+ r=threadx.Create(_L("Loopyx"),LoopyThread,KDefaultStackSize,KHeapSize,KHeapSize,(TAny*)NULL,anOwnerType);
+ test(r==KErrNone);
+ test.Next(_L("Resume thread"));
+ threadx.Resume();
+
+ test.Next(_L("Create undertaker"));
+ TRequestStatus statx;
+ TInt threadHandlex;
+ RUndertaker ux;
+ r=ux.Create();
+ test(r==KErrNone);
+ test.Next(_L("Logon to undertaker"));
+ r=ux.Logon(statx,threadHandlex);
+ test(r==KErrNone);
+ test.Next(_L("Kill thread"));
+ threadx.Kill(0x666);
+ threadx.Close();
+ User::WaitForRequest(statx);
+ test(statx==KErrDied);
+ test.Next(_L("Close thread"));
+ RThread wx;
+ wx.SetHandle(threadHandlex);
+ CLOSE_AND_WAIT(wx);
+
+ test.Next(_L("Close undertaker"));
+ ux.Close();
+
+ test.Next(_L("Check kernel heap"));
+ __KHEAP_MARKEND;
+ w1.Close();
+ CLOSE_AND_WAIT(w2);
+ keep1.Close();
+ CLOSE_AND_WAIT(keep2);
+ t[KNumThreads-1].Kill(666);
+ CLOSE_AND_WAIT(t[KNumThreads-1]);
+
+ test.Next(_L("Close RUndertakers"));
+ u1.Close();
+ u2.Close();
+ test.End();
+ }
+
+volatile TInt IFLAG;
+
+TInt InstructionThread(TAny* anInstruction)
+ {
+ __e32_atomic_store_ord32(&IFLAG, 1);
+ RThread::Rendezvous(KErrNone);
+ TInstruction what=(TInstruction)(TInt)anInstruction;
+ if (what==EInstrPanic)
+ User::Panic(_L("Hello"), KExitPanicNum);
+ if (what==ENormal)
+ return(KThreadReturnValue);
+ User::After(500000);
+ return(KErrNone);
+ }
+
+TInt StartInstructionThread(RThread& aT, const TDesC& aName, TInt aInstruction, TOwnerType aOwnerType, TRequestStatus* aL, TRequestStatus* aR)
+ {
+ TInt r = aT.Create(aName, &InstructionThread, KDefaultStackSize, KHeapSize, KHeapSize, (TAny*)aInstruction, aOwnerType);
+ if (r!=KErrNone)
+ return r;
+ if (aL)
+ {
+ aT.Logon(*aL);
+ TInt s = aL->Int();
+ 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);
+ }
+
+
+