os/graphics/egl/egltest/endpointtestsuite/automated/tsrc/egltest_threadmonitor.cpp
First public contribution.
2 * Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
4 * This component and the accompanying materials are made available
5 * under the terms of "Eclipse Public License v1.0"
6 * which accompanies this distribution, and is available
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
9 * Initial Contributors:
10 * Nokia Corporation - initial contribution.
22 @internalComponent - Internal Symbian test code
27 #include "egltest_threadmonitor.h"
30 //CThreadMonitor creates a new monitor thread and instanciates a CThreadMonitorBackend object.
31 //The thread monitor backend is constructed on the monitor thread's heap and only
32 //runs in that context. It creates a CThread instance for each thread that it needs
33 //to monitor. The CThread instance reports back to the monitor backend when the
34 //thread that it wraps has exitted. The backend is then responsible for deciding
35 //how to respond: If the exit type is a panic, it forwards that panic to all the
36 //other threads, then exits itself. Note: The controller thread MUST be at position
37 //zero in the passed in array.
38 class CThreadMonitorBackend : public CActive
41 class CThread : public CActive
44 static CThread* NewL(const TThreadId& aThread, CThreadMonitorBackend& aMonitor);
46 void Panic(TInt aExitReason, const TExitCategoryName& aExitCategory);
49 CThread(CThreadMonitorBackend& aMonitor);
50 void ConstructL(const TThreadId& aThread);
55 CThreadMonitorBackend& iMonitor;
60 static CThreadMonitorBackend* NewL(const RArray<TThreadId>& aThreadsToMonitor, TRequestStatus*& aNotifyCancel);
61 ~CThreadMonitorBackend();
62 void StartMonitoring();
63 void ThreadExitted(CThread* aThread, TExitType aExitType, TInt aExitReason, const TExitCategoryName& aExitCategory);
66 CThreadMonitorBackend(TRequestStatus*& aNotifyCancel);
67 void ConstructL(const RArray<TThreadId>& aThreadsToMonitor);
68 TBool ThreadIsController(CThread* aThread) const;
73 RPointerArray<CThread> iThreads;
77 //CThreadMonitor---------------------------------------------------------------
79 CThreadMonitor* CThreadMonitor::NewL(const RArray<TThreadId>& aThreadsToMonitor)
81 CThreadMonitor* self = new (ELeave) CThreadMonitor(aThreadsToMonitor);
82 CleanupStack::PushL(self);
84 CleanupStack::Pop(self);
89 CThreadMonitor::~CThreadMonitor()
91 //Tell the backend to stop monitoring.
92 iMonitor.RequestComplete(iNotifyCancel, KErrNone);
97 CThreadMonitor::CThreadMonitor(const RArray<TThreadId>& aThreadsToMonitor) :
98 iThreadsToMonitor(aThreadsToMonitor)
103 void CThreadMonitor::ConstructL()
105 const TInt KStackSize = 12000;
106 const TInt KHeapMinSize = 16000;
107 const TInt KHeapMaxSize = 1000000;
109 TUint32 random = Math::Random();
111 _LIT(KThreadNameFormat, "%S-%u");
112 _LIT(KMonitorName, "EpThreadMonitor");
113 threadName.Format(KThreadNameFormat, &KMonitorName, random);
115 User::LeaveIfError(iMonitor.Create(threadName, MonitorThreadEntry, KStackSize, KHeapMinSize, KHeapMaxSize, this, EOwnerThread));
116 TRequestStatus rendezvous;
117 iMonitor.Rendezvous(rendezvous);
119 User::WaitForRequest(rendezvous);
120 User::LeaveIfError(rendezvous.Int());
121 ASSERT(iNotifyCancel);
125 TInt CThreadMonitor::MonitorThreadEntry(TAny* aSelf)
127 CThreadMonitor* self = static_cast<CThreadMonitor*>(aSelf);
128 CTrapCleanup* cleanup = CTrapCleanup::New();
130 TRAPD(err, MonitorThreadEntryL(self->iThreadsToMonitor, self->iNotifyCancel));
131 __ASSERT_ALWAYS(err == KErrNone, User::Invariant());
138 void CThreadMonitor::MonitorThreadEntryL(const RArray<TThreadId>& aThreadsToMonitor, TRequestStatus*& aNotifyCancel)
140 //Create active scheduler.
141 CActiveScheduler* scheduler = new (ELeave) CActiveScheduler();
142 CleanupStack::PushL(scheduler);
143 CActiveScheduler::Install(scheduler);
145 //Create the monitor and start monitoring.
146 CThreadMonitorBackend* monitor = CThreadMonitorBackend::NewL(aThreadsToMonitor, aNotifyCancel);
147 RThread().Rendezvous(KErrNone);
148 monitor->StartMonitoring();
152 CleanupStack::PopAndDestroy(scheduler);
155 //-----------------------------------------------------------------------------
158 //CThreadMonitorBackend--------------------------------------------------------
160 CThreadMonitorBackend* CThreadMonitorBackend::NewL(const RArray<TThreadId>& aThreadsToMonitor, TRequestStatus*& aNotifyCancel)
162 CThreadMonitorBackend* self = new (ELeave) CThreadMonitorBackend(aNotifyCancel);
163 CleanupStack::PushL(self);
164 self->ConstructL(aThreadsToMonitor);
165 CleanupStack::Pop(self);
170 CThreadMonitorBackend::CThreadMonitorBackend(TRequestStatus*& aNotifyCancel) :
171 CActive(CActive::EPriorityStandard)
173 CActiveScheduler::Add(this);
174 iStatus = KRequestPending;
177 //Pass the cancel TRequestStatus back to the controller thread.
178 aNotifyCancel = &iStatus;
182 void CThreadMonitorBackend::ConstructL(const RArray<TThreadId>& aThreadsToMonitor)
184 //Reserve the space up front so we can gaurantee that the append will not fail.
185 //This way we don't need to use the cleanup stack to hold the new CThread while
186 //we attempt to append.
187 iThreads.ReserveL(aThreadsToMonitor.Count());
188 for(TInt i=0; i < aThreadsToMonitor.Count(); i++)
190 iThreads.Append(CThread::NewL(aThreadsToMonitor[i], *this));
195 CThreadMonitorBackend::~CThreadMonitorBackend()
198 iThreads.ResetAndDestroy();
202 void CThreadMonitorBackend::StartMonitoring()
204 CActiveScheduler::Start();
208 void CThreadMonitorBackend::ThreadExitted(CThread* aThread, TExitType aExitType, TInt aExitReason, const TExitCategoryName& aExitCategory)
210 //If a worker thread exits normally, do nothing.
211 //If a worker thread panics, forward the panic to all other threads and stop active scheduler.
212 //If the controller thread exits normally, stop active scheduler.
213 //If the controller thread panics, forward the panic to all other threads and stop active scheduler.
215 //Stop monitoring according to above.
216 if(ThreadIsController(aThread) || aExitType == EExitPanic)
218 CActiveScheduler::Stop();
221 //Forward panic according to above. Second condition is for when controller times out.
222 if(aExitType == EExitPanic || (ThreadIsController(aThread) && aExitType == EExitKill && aExitReason == KErrTimedOut))
224 for(TInt i=0; i < iThreads.Count(); i++)
226 iThreads[i]->Panic(aExitReason, aExitCategory);
232 TBool CThreadMonitorBackend::ThreadIsController(CThread* aThread) const
234 //The controller thread must be at index zero in the passed in array.
235 //Due to way we construct, we gaurantee that it is also at index zero in iThread.
236 return (iThreads.Count() > 0) && (iThreads[0] == aThread);
240 void CThreadMonitorBackend::RunL()
242 //The client has destructed the CThreadMonitor object,
243 //so stop the active scheduler so we exit the thread.
244 CActiveScheduler::Stop();
248 void CThreadMonitorBackend::DoCancel()
250 //Not ideal, but we should only get here if the thread that created
251 //the original ConitorThread panics, so it should be safe.
252 TRequestStatus* status =&iStatus;
253 User::RequestComplete(status, KErrCancel);
256 //-----------------------------------------------------------------------------
259 //CThreadMonitorBackend::CThread-----------------------------------------------
261 CThreadMonitorBackend::CThread* CThreadMonitorBackend::CThread::NewL(const TThreadId& aThread, CThreadMonitorBackend& aMonitor)
263 CThread* self = new (ELeave) CThread(aMonitor);
264 CleanupStack::PushL(self);
265 self->ConstructL(aThread);
266 CleanupStack::Pop(self);
271 CThreadMonitorBackend::CThread::CThread(CThreadMonitorBackend& aMonitor) :
272 CActive(CActive::EPriorityStandard),
275 CActiveScheduler::Add(this);
279 void CThreadMonitorBackend::CThread::ConstructL(const TThreadId& aThread)
281 User::LeaveIfError(iThread.Open(aThread, EOwnerThread));
282 iThread.Logon(iStatus);
287 CThreadMonitorBackend::CThread::~CThread()
294 void CThreadMonitorBackend::CThread::Panic(TInt aExitReason, const TExitCategoryName& aExitCategory)
296 iThread.Panic(aExitCategory, aExitReason);
300 void CThreadMonitorBackend::CThread::RunL()
302 //Inform the monitor backend that the thread exitted.
303 TExitCategoryName category = iThread.ExitCategory();
304 TInt reason = iThread.ExitReason();
305 TExitType type = iThread.ExitType();
306 iMonitor.ThreadExitted(this, type, reason, category);
310 void CThreadMonitorBackend::CThread::DoCancel()
312 iThread.LogonCancel(iStatus);
315 //-----------------------------------------------------------------------------