os/graphics/egl/egltest/endpointtestsuite/automated/tsrc/egltest_threadmonitor.cpp
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
     1 /*
     2 * Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3 * All rights reserved.
     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".
     8 *
     9 * Initial Contributors:
    10 * Nokia Corporation - initial contribution.
    11 *
    12 * Contributors:
    13 *
    14 * Description: 
    15 *
    16 */
    17 
    18 
    19 /**
    20  @file
    21  @test
    22  @internalComponent - Internal Symbian test code
    23 */
    24 
    25 
    26 #include <e32math.h>
    27 #include "egltest_threadmonitor.h"
    28 
    29 
    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
    39     {
    40 private:
    41     class CThread : public CActive
    42         {
    43     public:
    44         static CThread* NewL(const TThreadId& aThread, CThreadMonitorBackend& aMonitor);
    45         ~CThread();
    46         void Panic(TInt aExitReason, const TExitCategoryName& aExitCategory);
    47         
    48     private:
    49         CThread(CThreadMonitorBackend& aMonitor);
    50         void ConstructL(const TThreadId& aThread);
    51         void RunL();
    52         void DoCancel();
    53     
    54     private:
    55         CThreadMonitorBackend& iMonitor;
    56         RThread iThread;
    57         };
    58 
    59 public:
    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);
    64     
    65 private:
    66     CThreadMonitorBackend(TRequestStatus*& aNotifyCancel);
    67     void ConstructL(const RArray<TThreadId>& aThreadsToMonitor);
    68     TBool ThreadIsController(CThread* aThread) const;
    69     void RunL();
    70     void DoCancel();
    71     
    72 private:
    73     RPointerArray<CThread> iThreads;
    74     };
    75 
    76 
    77 //CThreadMonitor---------------------------------------------------------------
    78 
    79 CThreadMonitor* CThreadMonitor::NewL(const RArray<TThreadId>& aThreadsToMonitor)
    80     {
    81     CThreadMonitor* self = new (ELeave) CThreadMonitor(aThreadsToMonitor);
    82     CleanupStack::PushL(self);
    83     self->ConstructL();
    84     CleanupStack::Pop(self);
    85     return self;
    86     }
    87 
    88 
    89 CThreadMonitor::~CThreadMonitor()
    90     {
    91     //Tell the backend to stop monitoring.
    92     iMonitor.RequestComplete(iNotifyCancel, KErrNone);
    93     iMonitor.Close();
    94     }
    95 
    96 
    97 CThreadMonitor::CThreadMonitor(const RArray<TThreadId>& aThreadsToMonitor) :
    98     iThreadsToMonitor(aThreadsToMonitor)
    99     {
   100     }
   101 
   102 
   103 void CThreadMonitor::ConstructL()
   104     {
   105     const TInt KStackSize = 12000;
   106     const TInt KHeapMinSize = 16000;
   107     const TInt KHeapMaxSize = 1000000;
   108     
   109     TUint32 random = Math::Random();
   110     TName threadName;
   111     _LIT(KThreadNameFormat, "%S-%u");
   112     _LIT(KMonitorName, "EpThreadMonitor");
   113     threadName.Format(KThreadNameFormat, &KMonitorName, random);
   114     
   115     User::LeaveIfError(iMonitor.Create(threadName, MonitorThreadEntry, KStackSize, KHeapMinSize, KHeapMaxSize, this, EOwnerThread));
   116     TRequestStatus rendezvous;
   117     iMonitor.Rendezvous(rendezvous);
   118     iMonitor.Resume();
   119     User::WaitForRequest(rendezvous);
   120     User::LeaveIfError(rendezvous.Int());
   121     ASSERT(iNotifyCancel);
   122     }
   123 
   124 
   125 TInt CThreadMonitor::MonitorThreadEntry(TAny* aSelf)
   126     {
   127     CThreadMonitor* self = static_cast<CThreadMonitor*>(aSelf);
   128     CTrapCleanup* cleanup = CTrapCleanup::New();
   129     
   130     TRAPD(err, MonitorThreadEntryL(self->iThreadsToMonitor, self->iNotifyCancel));
   131     __ASSERT_ALWAYS(err == KErrNone, User::Invariant());
   132 
   133     delete cleanup;
   134     return KErrNone;
   135     }
   136 
   137 
   138 void CThreadMonitor::MonitorThreadEntryL(const RArray<TThreadId>& aThreadsToMonitor, TRequestStatus*& aNotifyCancel)
   139     {
   140     //Create active scheduler.
   141     CActiveScheduler* scheduler = new (ELeave) CActiveScheduler();
   142     CleanupStack::PushL(scheduler);
   143     CActiveScheduler::Install(scheduler);
   144 
   145     //Create the monitor and start monitoring.
   146     CThreadMonitorBackend* monitor = CThreadMonitorBackend::NewL(aThreadsToMonitor, aNotifyCancel);
   147     RThread().Rendezvous(KErrNone);
   148     monitor->StartMonitoring();
   149     delete monitor;
   150 
   151     //Clean up.
   152     CleanupStack::PopAndDestroy(scheduler);
   153     }
   154 
   155 //-----------------------------------------------------------------------------
   156 
   157 
   158 //CThreadMonitorBackend--------------------------------------------------------
   159 
   160 CThreadMonitorBackend* CThreadMonitorBackend::NewL(const RArray<TThreadId>& aThreadsToMonitor, TRequestStatus*& aNotifyCancel)
   161     {
   162     CThreadMonitorBackend* self = new (ELeave) CThreadMonitorBackend(aNotifyCancel);
   163     CleanupStack::PushL(self);
   164     self->ConstructL(aThreadsToMonitor);
   165     CleanupStack::Pop(self);
   166     return self;
   167     }
   168 
   169 
   170 CThreadMonitorBackend::CThreadMonitorBackend(TRequestStatus*& aNotifyCancel) :
   171     CActive(CActive::EPriorityStandard)
   172     {
   173     CActiveScheduler::Add(this);
   174     iStatus = KRequestPending;
   175     SetActive();
   176     
   177     //Pass the cancel TRequestStatus back to the controller thread.
   178     aNotifyCancel = &iStatus;
   179     }
   180 
   181 
   182 void CThreadMonitorBackend::ConstructL(const RArray<TThreadId>& aThreadsToMonitor)
   183     {
   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++)
   189         {
   190         iThreads.Append(CThread::NewL(aThreadsToMonitor[i], *this));
   191         }
   192     }
   193 
   194 
   195 CThreadMonitorBackend::~CThreadMonitorBackend()
   196     {
   197     Cancel();
   198     iThreads.ResetAndDestroy();
   199     }
   200 
   201 
   202 void CThreadMonitorBackend::StartMonitoring()
   203     {
   204     CActiveScheduler::Start();
   205     }
   206 
   207 
   208 void CThreadMonitorBackend::ThreadExitted(CThread* aThread, TExitType aExitType, TInt aExitReason, const TExitCategoryName& aExitCategory)
   209     {
   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.
   214     
   215     //Stop monitoring according to above.
   216     if(ThreadIsController(aThread) || aExitType == EExitPanic)
   217         {
   218         CActiveScheduler::Stop();
   219         }
   220 
   221     //Forward panic according to above. Second condition is for when controller times out.
   222     if(aExitType == EExitPanic || (ThreadIsController(aThread) && aExitType == EExitKill && aExitReason == KErrTimedOut))
   223         {
   224         for(TInt i=0; i < iThreads.Count(); i++)
   225             {
   226             iThreads[i]->Panic(aExitReason, aExitCategory);
   227             }
   228         }
   229     }
   230 
   231 
   232 TBool CThreadMonitorBackend::ThreadIsController(CThread* aThread) const
   233     {
   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);
   237     }
   238 
   239 
   240 void CThreadMonitorBackend::RunL()
   241     {
   242     //The client has destructed the CThreadMonitor object, 
   243     //so stop the active scheduler so we exit the thread.
   244     CActiveScheduler::Stop();
   245     }
   246 
   247 
   248 void CThreadMonitorBackend::DoCancel()
   249     {
   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);
   254     }
   255 
   256 //-----------------------------------------------------------------------------
   257 
   258 
   259 //CThreadMonitorBackend::CThread-----------------------------------------------
   260 
   261 CThreadMonitorBackend::CThread* CThreadMonitorBackend::CThread::NewL(const TThreadId& aThread, CThreadMonitorBackend& aMonitor)
   262     {
   263     CThread* self = new (ELeave) CThread(aMonitor);
   264     CleanupStack::PushL(self);
   265     self->ConstructL(aThread);
   266     CleanupStack::Pop(self);
   267     return self;
   268     }
   269 
   270 
   271 CThreadMonitorBackend::CThread::CThread(CThreadMonitorBackend& aMonitor) :
   272     CActive(CActive::EPriorityStandard),
   273     iMonitor(aMonitor)
   274     {
   275     CActiveScheduler::Add(this);
   276     }
   277 
   278 
   279 void CThreadMonitorBackend::CThread::ConstructL(const TThreadId& aThread)
   280     {
   281     User::LeaveIfError(iThread.Open(aThread, EOwnerThread));
   282     iThread.Logon(iStatus);
   283     SetActive();
   284     }
   285 
   286 
   287 CThreadMonitorBackend::CThread::~CThread()
   288     {
   289     Cancel();
   290     iThread.Close();
   291     }
   292 
   293 
   294 void CThreadMonitorBackend::CThread::Panic(TInt aExitReason, const TExitCategoryName& aExitCategory)
   295     {
   296     iThread.Panic(aExitCategory, aExitReason);
   297     }
   298 
   299 
   300 void CThreadMonitorBackend::CThread::RunL()
   301     {
   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);
   307     }
   308 
   309 
   310 void CThreadMonitorBackend::CThread::DoCancel()
   311     {
   312     iThread.LogonCancel(iStatus);
   313     }
   314 
   315 //-----------------------------------------------------------------------------