kerneltest/e32test/misc/test_thread.h
branchRCL_3
changeset 62 4a8fed1c0ef6
equal deleted inserted replaced
52:2d65c2f76d7b 62:4a8fed1c0ef6
       
     1 // Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of the License "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Description: Some helper classes to assist with writing multi-threaded tests  
       
    12 
       
    13 #ifndef TEST_THREAD_H
       
    14 #define TEST_THREAD_H
       
    15 
       
    16 #define __E32TEST_EXTENSION__
       
    17 #include <e32test.h>
       
    18 #include <e32svr.h>
       
    19 #include <e32des8.h>
       
    20 #include <e32des8_private.h>
       
    21 #include <e32cmn.h>
       
    22 #include <e32cmn_private.h>
       
    23 #include <e32std.h>
       
    24 #include <e32std_private.h>
       
    25     
       
    26 
       
    27 _LIT(KPciPanicCat, "test_thread.h");
       
    28 
       
    29 static const TInt KPciHeapSize=0x2000;
       
    30 
       
    31 enum TPciPanicCode
       
    32 	{
       
    33 	EThreadCreateFailed
       
    34 	};
       
    35 
       
    36 /**
       
    37 A utility class for running functions in other threads/processes
       
    38 */
       
    39 class TTestRemote
       
    40 	{
       
    41 public:
       
    42 	virtual TInt WaitForExitL() = 0;
       
    43 	virtual ~TTestRemote()
       
    44 		{}
       
    45 
       
    46 	virtual void Rendezvous(TRequestStatus& aStatus) = 0;
       
    47 
       
    48 protected:
       
    49 	TTestRemote()
       
    50 		{}
       
    51 
       
    52 	static TInt RunFunctor(TAny* aFunctor)
       
    53 		{
       
    54 		TFunctor& functor = *(TFunctor*)aFunctor;
       
    55 		functor();
       
    56 		return KErrNone;
       
    57 		}
       
    58 
       
    59 	TRequestStatus iLogonStatus;
       
    60 	static TInt iCount;
       
    61 	};
       
    62 TInt TTestRemote::iCount=0;
       
    63 
       
    64 class TTestThread : public TTestRemote
       
    65 	{
       
    66 public:
       
    67 	TTestThread(const TDesC& aName, TThreadFunction aFn, TAny* aData, TBool aAutoResume=ETrue)
       
    68 		{
       
    69 		Init(aName, aFn, aData, aAutoResume);
       
    70 		}
       
    71 
       
    72 	/**
       
    73 	Run aFunctor in another thread
       
    74 	*/
       
    75 	TTestThread(const TDesC& aName, TFunctor& aFunctor, TBool aAutoResume=ETrue)
       
    76 		{
       
    77 		Init(aName, RunFunctor, &aFunctor, aAutoResume);
       
    78 		}
       
    79 
       
    80 	~TTestThread()
       
    81 		{
       
    82 		//RTest::CloseHandleAndWaitForDestruction(iThread);
       
    83 		iThread.Close();
       
    84 		}
       
    85 
       
    86 	void Resume()
       
    87 		{
       
    88 		iThread.Resume();
       
    89 		}
       
    90 
       
    91 	/**
       
    92 	If thread exited normally, return its return code
       
    93 	Otherwise, leave with exit reason
       
    94 	*/
       
    95 	virtual TInt WaitForExitL()
       
    96 		{
       
    97 		User::WaitForRequest(iLogonStatus);
       
    98 		const TInt exitType = iThread.ExitType();
       
    99 		const TInt exitReason = iThread.ExitReason();
       
   100 
       
   101 		__ASSERT_ALWAYS(exitType != EExitPending, User::Panic(_L("TTestThread"),0));
       
   102 
       
   103 		if(exitType != EExitKill)
       
   104 			User::Leave(exitReason);
       
   105 
       
   106 		return exitReason;
       
   107 		}
       
   108 
       
   109 	virtual void Rendezvous(TRequestStatus& aStatus)
       
   110 		{
       
   111 		iThread.Rendezvous(aStatus);
       
   112 		}
       
   113 
       
   114 private:
       
   115 	void Init(const TDesC& aName, TThreadFunction aFn, TAny* aData, TBool aAutoResume)
       
   116 		{
       
   117 		TKName name(aName);
       
   118 		name.AppendFormat(_L("-%d"), iCount++);	
       
   119 		TInt r=iThread.Create(name, aFn, KDefaultStackSize, KPciHeapSize, KPciHeapSize, aData);
       
   120 		if(r!=KErrNone)
       
   121 			{
       
   122 			RDebug::Printf("RThread::Create failed, code=%d", r);
       
   123 			User::Panic(KPciPanicCat, EThreadCreateFailed);
       
   124 			}
       
   125 		
       
   126 		iThread.Logon(iLogonStatus);
       
   127 		__ASSERT_ALWAYS(iLogonStatus == KRequestPending, User::Panic(_L("TTestThread"),0));
       
   128 
       
   129 		if(aAutoResume)
       
   130 			iThread.Resume();
       
   131 		}
       
   132 
       
   133 	RThread iThread;
       
   134 	};
       
   135 
       
   136 class CTest : public CBase, public TFunctor
       
   137 	{
       
   138 public:
       
   139 	~CTest()
       
   140 		{
       
   141 		iName.Close();
       
   142 		}
       
   143 
       
   144 	virtual void operator()()
       
   145 		{
       
   146 		RTest test(iName);
       
   147 		test.Start(iName);
       
   148 		for(TInt i=0; i<iIterations; i++)
       
   149 			{
       
   150 			test.Next(iName);
       
   151 			RunTest();
       
   152 			}
       
   153 		test.End();
       
   154 		}
       
   155 
       
   156 	virtual void RunTest() = 0; 
       
   157 
       
   158 	virtual CTest* Clone() const = 0;
       
   159 
       
   160 	const TDesC& Name() const
       
   161 		{
       
   162 		return iName;
       
   163 		}
       
   164 
       
   165 protected:
       
   166 	CTest(const TDesC& aName, TInt aIterations)
       
   167 		:iIterations(aIterations)
       
   168 		{
       
   169 		iName.CreateL(aName);
       
   170 		}
       
   171 
       
   172 
       
   173 	
       
   174 	CTest(const CTest& aOther)
       
   175 		:iIterations(aOther.iIterations)
       
   176 		{
       
   177 		iName.CreateL(aOther.iName);
       
   178 		}
       
   179 
       
   180 	//It would be useful to have an RTest member, but this can't be
       
   181 	//initialised untill the new thread is running as it will refer to
       
   182 	//the creating thread
       
   183 	RBuf iName;
       
   184 	const TInt iIterations; 
       
   185 	};
       
   186 
       
   187 /**
       
   188 Make aNumberOfThreads copies of aTest and run
       
   189 each in its own thread
       
   190 
       
   191 @param test Reference to test object
       
   192 @param aTest Referance
       
   193 */
       
   194 void MultipleTestRun(RTest& test, const CTest& aTest, TInt aNumberOfThreads)
       
   195 	{
       
   196 	RPointerArray<CTest> testArray;
       
   197 	RPointerArray<TTestThread> threadArray;
       
   198 
       
   199 	for(TInt i=0; i<aNumberOfThreads; i++)
       
   200 		{		
       
   201 		test.Printf(_L("Create test thread"));
       
   202 		CTest* newTest = aTest.Clone();
       
   203 		test_NotNull(newTest);
       
   204 
       
   205 		TTestThread* thread = new TTestThread(aTest.Name(), *newTest);
       
   206 		test_NotNull(thread);
       
   207 
       
   208 		threadArray.AppendL(thread);
       
   209 		testArray.AppendL(newTest);
       
   210 		}
       
   211 
       
   212 	const TInt count = threadArray.Count();
       
   213 	for(TInt j=0; j<count; j++)
       
   214 		{
       
   215 		TTestThread* thread = threadArray[j];
       
   216 		
       
   217 		TInt r = KErrNone;
       
   218 		TRAPD(leaveCode, r = thread->WaitForExitL());
       
   219 		if(leaveCode != KErrNone)
       
   220 			{
       
   221 			test.Printf(_L("Thread %d: Panic code:%d\n"), j, leaveCode);
       
   222 			test_KErrNone(leaveCode);
       
   223 			}
       
   224 
       
   225 		if(r!=KErrNone)
       
   226 			{
       
   227 			test.Printf(_L("Thread Number %d\n"), j);
       
   228 			test_KErrNone(r);
       
   229 			}
       
   230 		}
       
   231 	
       
   232 	threadArray.ResetAndDestroy();
       
   233 	threadArray.Close();
       
   234 
       
   235 	testArray.ResetAndDestroy();
       
   236 	testArray.Close();
       
   237 	}
       
   238 
       
   239 #endif //TEST_THREAD_H
       
   240