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.
sl@0
     1
/*
sl@0
     2
* Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
sl@0
     3
* All rights reserved.
sl@0
     4
* This component and the accompanying materials are made available
sl@0
     5
* under the terms of "Eclipse Public License v1.0"
sl@0
     6
* which accompanies this distribution, and is available
sl@0
     7
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
sl@0
     8
*
sl@0
     9
* Initial Contributors:
sl@0
    10
* Nokia Corporation - initial contribution.
sl@0
    11
*
sl@0
    12
* Contributors:
sl@0
    13
*
sl@0
    14
* Description: 
sl@0
    15
*
sl@0
    16
*/
sl@0
    17
sl@0
    18
sl@0
    19
/**
sl@0
    20
 @file
sl@0
    21
 @test
sl@0
    22
 @internalComponent - Internal Symbian test code
sl@0
    23
*/
sl@0
    24
sl@0
    25
sl@0
    26
#include <e32math.h>
sl@0
    27
#include "egltest_threadmonitor.h"
sl@0
    28
sl@0
    29
sl@0
    30
//CThreadMonitor creates a new monitor thread and instanciates a CThreadMonitorBackend object.
sl@0
    31
//The thread monitor backend is constructed on the monitor thread's heap and only 
sl@0
    32
//runs in that context. It creates a CThread instance for each thread that it needs
sl@0
    33
//to monitor. The CThread instance reports back to the monitor backend when the
sl@0
    34
//thread that it wraps has exitted. The backend is then responsible for deciding 
sl@0
    35
//how to respond: If the exit type is a panic, it forwards that panic to all the 
sl@0
    36
//other threads, then exits itself. Note: The controller thread MUST be at position
sl@0
    37
//zero in the passed in array.
sl@0
    38
class CThreadMonitorBackend : public CActive
sl@0
    39
    {
sl@0
    40
private:
sl@0
    41
    class CThread : public CActive
sl@0
    42
        {
sl@0
    43
    public:
sl@0
    44
        static CThread* NewL(const TThreadId& aThread, CThreadMonitorBackend& aMonitor);
sl@0
    45
        ~CThread();
sl@0
    46
        void Panic(TInt aExitReason, const TExitCategoryName& aExitCategory);
sl@0
    47
        
sl@0
    48
    private:
sl@0
    49
        CThread(CThreadMonitorBackend& aMonitor);
sl@0
    50
        void ConstructL(const TThreadId& aThread);
sl@0
    51
        void RunL();
sl@0
    52
        void DoCancel();
sl@0
    53
    
sl@0
    54
    private:
sl@0
    55
        CThreadMonitorBackend& iMonitor;
sl@0
    56
        RThread iThread;
sl@0
    57
        };
sl@0
    58
sl@0
    59
public:
sl@0
    60
    static CThreadMonitorBackend* NewL(const RArray<TThreadId>& aThreadsToMonitor, TRequestStatus*& aNotifyCancel);
sl@0
    61
    ~CThreadMonitorBackend();
sl@0
    62
    void StartMonitoring();
sl@0
    63
    void ThreadExitted(CThread* aThread, TExitType aExitType, TInt aExitReason, const TExitCategoryName& aExitCategory);
sl@0
    64
    
sl@0
    65
private:
sl@0
    66
    CThreadMonitorBackend(TRequestStatus*& aNotifyCancel);
sl@0
    67
    void ConstructL(const RArray<TThreadId>& aThreadsToMonitor);
sl@0
    68
    TBool ThreadIsController(CThread* aThread) const;
sl@0
    69
    void RunL();
sl@0
    70
    void DoCancel();
sl@0
    71
    
sl@0
    72
private:
sl@0
    73
    RPointerArray<CThread> iThreads;
sl@0
    74
    };
sl@0
    75
sl@0
    76
sl@0
    77
//CThreadMonitor---------------------------------------------------------------
sl@0
    78
sl@0
    79
CThreadMonitor* CThreadMonitor::NewL(const RArray<TThreadId>& aThreadsToMonitor)
sl@0
    80
    {
sl@0
    81
    CThreadMonitor* self = new (ELeave) CThreadMonitor(aThreadsToMonitor);
sl@0
    82
    CleanupStack::PushL(self);
sl@0
    83
    self->ConstructL();
sl@0
    84
    CleanupStack::Pop(self);
sl@0
    85
    return self;
sl@0
    86
    }
sl@0
    87
sl@0
    88
sl@0
    89
CThreadMonitor::~CThreadMonitor()
sl@0
    90
    {
sl@0
    91
    //Tell the backend to stop monitoring.
sl@0
    92
    iMonitor.RequestComplete(iNotifyCancel, KErrNone);
sl@0
    93
    iMonitor.Close();
sl@0
    94
    }
sl@0
    95
sl@0
    96
sl@0
    97
CThreadMonitor::CThreadMonitor(const RArray<TThreadId>& aThreadsToMonitor) :
sl@0
    98
    iThreadsToMonitor(aThreadsToMonitor)
sl@0
    99
    {
sl@0
   100
    }
sl@0
   101
sl@0
   102
sl@0
   103
void CThreadMonitor::ConstructL()
sl@0
   104
    {
sl@0
   105
    const TInt KStackSize = 12000;
sl@0
   106
    const TInt KHeapMinSize = 16000;
sl@0
   107
    const TInt KHeapMaxSize = 1000000;
sl@0
   108
    
sl@0
   109
    TUint32 random = Math::Random();
sl@0
   110
    TName threadName;
sl@0
   111
    _LIT(KThreadNameFormat, "%S-%u");
sl@0
   112
    _LIT(KMonitorName, "EpThreadMonitor");
sl@0
   113
    threadName.Format(KThreadNameFormat, &KMonitorName, random);
sl@0
   114
    
sl@0
   115
    User::LeaveIfError(iMonitor.Create(threadName, MonitorThreadEntry, KStackSize, KHeapMinSize, KHeapMaxSize, this, EOwnerThread));
sl@0
   116
    TRequestStatus rendezvous;
sl@0
   117
    iMonitor.Rendezvous(rendezvous);
sl@0
   118
    iMonitor.Resume();
sl@0
   119
    User::WaitForRequest(rendezvous);
sl@0
   120
    User::LeaveIfError(rendezvous.Int());
sl@0
   121
    ASSERT(iNotifyCancel);
sl@0
   122
    }
sl@0
   123
sl@0
   124
sl@0
   125
TInt CThreadMonitor::MonitorThreadEntry(TAny* aSelf)
sl@0
   126
    {
sl@0
   127
    CThreadMonitor* self = static_cast<CThreadMonitor*>(aSelf);
sl@0
   128
    CTrapCleanup* cleanup = CTrapCleanup::New();
sl@0
   129
    
sl@0
   130
    TRAPD(err, MonitorThreadEntryL(self->iThreadsToMonitor, self->iNotifyCancel));
sl@0
   131
    __ASSERT_ALWAYS(err == KErrNone, User::Invariant());
sl@0
   132
sl@0
   133
    delete cleanup;
sl@0
   134
    return KErrNone;
sl@0
   135
    }
sl@0
   136
sl@0
   137
sl@0
   138
void CThreadMonitor::MonitorThreadEntryL(const RArray<TThreadId>& aThreadsToMonitor, TRequestStatus*& aNotifyCancel)
sl@0
   139
    {
sl@0
   140
    //Create active scheduler.
sl@0
   141
    CActiveScheduler* scheduler = new (ELeave) CActiveScheduler();
sl@0
   142
    CleanupStack::PushL(scheduler);
sl@0
   143
    CActiveScheduler::Install(scheduler);
sl@0
   144
sl@0
   145
    //Create the monitor and start monitoring.
sl@0
   146
    CThreadMonitorBackend* monitor = CThreadMonitorBackend::NewL(aThreadsToMonitor, aNotifyCancel);
sl@0
   147
    RThread().Rendezvous(KErrNone);
sl@0
   148
    monitor->StartMonitoring();
sl@0
   149
    delete monitor;
sl@0
   150
sl@0
   151
    //Clean up.
sl@0
   152
    CleanupStack::PopAndDestroy(scheduler);
sl@0
   153
    }
sl@0
   154
sl@0
   155
//-----------------------------------------------------------------------------
sl@0
   156
sl@0
   157
sl@0
   158
//CThreadMonitorBackend--------------------------------------------------------
sl@0
   159
sl@0
   160
CThreadMonitorBackend* CThreadMonitorBackend::NewL(const RArray<TThreadId>& aThreadsToMonitor, TRequestStatus*& aNotifyCancel)
sl@0
   161
    {
sl@0
   162
    CThreadMonitorBackend* self = new (ELeave) CThreadMonitorBackend(aNotifyCancel);
sl@0
   163
    CleanupStack::PushL(self);
sl@0
   164
    self->ConstructL(aThreadsToMonitor);
sl@0
   165
    CleanupStack::Pop(self);
sl@0
   166
    return self;
sl@0
   167
    }
sl@0
   168
sl@0
   169
sl@0
   170
CThreadMonitorBackend::CThreadMonitorBackend(TRequestStatus*& aNotifyCancel) :
sl@0
   171
    CActive(CActive::EPriorityStandard)
sl@0
   172
    {
sl@0
   173
    CActiveScheduler::Add(this);
sl@0
   174
    iStatus = KRequestPending;
sl@0
   175
    SetActive();
sl@0
   176
    
sl@0
   177
    //Pass the cancel TRequestStatus back to the controller thread.
sl@0
   178
    aNotifyCancel = &iStatus;
sl@0
   179
    }
sl@0
   180
sl@0
   181
sl@0
   182
void CThreadMonitorBackend::ConstructL(const RArray<TThreadId>& aThreadsToMonitor)
sl@0
   183
    {
sl@0
   184
    //Reserve the space up front so we can gaurantee that the append will not fail.
sl@0
   185
    //This way we don't need to use the cleanup stack to hold the new CThread while
sl@0
   186
    //we attempt to append.
sl@0
   187
    iThreads.ReserveL(aThreadsToMonitor.Count());
sl@0
   188
    for(TInt i=0; i < aThreadsToMonitor.Count(); i++)
sl@0
   189
        {
sl@0
   190
        iThreads.Append(CThread::NewL(aThreadsToMonitor[i], *this));
sl@0
   191
        }
sl@0
   192
    }
sl@0
   193
sl@0
   194
sl@0
   195
CThreadMonitorBackend::~CThreadMonitorBackend()
sl@0
   196
    {
sl@0
   197
    Cancel();
sl@0
   198
    iThreads.ResetAndDestroy();
sl@0
   199
    }
sl@0
   200
sl@0
   201
sl@0
   202
void CThreadMonitorBackend::StartMonitoring()
sl@0
   203
    {
sl@0
   204
    CActiveScheduler::Start();
sl@0
   205
    }
sl@0
   206
sl@0
   207
sl@0
   208
void CThreadMonitorBackend::ThreadExitted(CThread* aThread, TExitType aExitType, TInt aExitReason, const TExitCategoryName& aExitCategory)
sl@0
   209
    {
sl@0
   210
    //If a worker thread exits normally, do nothing.
sl@0
   211
    //If a worker thread panics, forward the panic to all other threads and stop active scheduler.
sl@0
   212
    //If the controller thread exits normally, stop active scheduler.
sl@0
   213
    //If the controller thread panics, forward the panic to all other threads and stop active scheduler.
sl@0
   214
    
sl@0
   215
    //Stop monitoring according to above.
sl@0
   216
    if(ThreadIsController(aThread) || aExitType == EExitPanic)
sl@0
   217
        {
sl@0
   218
        CActiveScheduler::Stop();
sl@0
   219
        }
sl@0
   220
sl@0
   221
    //Forward panic according to above. Second condition is for when controller times out.
sl@0
   222
    if(aExitType == EExitPanic || (ThreadIsController(aThread) && aExitType == EExitKill && aExitReason == KErrTimedOut))
sl@0
   223
        {
sl@0
   224
        for(TInt i=0; i < iThreads.Count(); i++)
sl@0
   225
            {
sl@0
   226
            iThreads[i]->Panic(aExitReason, aExitCategory);
sl@0
   227
            }
sl@0
   228
        }
sl@0
   229
    }
sl@0
   230
sl@0
   231
sl@0
   232
TBool CThreadMonitorBackend::ThreadIsController(CThread* aThread) const
sl@0
   233
    {
sl@0
   234
    //The controller thread must be at index zero in the passed in array.
sl@0
   235
    //Due to way we construct, we gaurantee that it is also at index zero in iThread.
sl@0
   236
    return (iThreads.Count() > 0) && (iThreads[0] == aThread);
sl@0
   237
    }
sl@0
   238
sl@0
   239
sl@0
   240
void CThreadMonitorBackend::RunL()
sl@0
   241
    {
sl@0
   242
    //The client has destructed the CThreadMonitor object, 
sl@0
   243
    //so stop the active scheduler so we exit the thread.
sl@0
   244
    CActiveScheduler::Stop();
sl@0
   245
    }
sl@0
   246
sl@0
   247
sl@0
   248
void CThreadMonitorBackend::DoCancel()
sl@0
   249
    {
sl@0
   250
    //Not ideal, but we should only get here if the thread that created 
sl@0
   251
    //the original ConitorThread panics, so it should be safe.
sl@0
   252
    TRequestStatus* status =&iStatus;
sl@0
   253
    User::RequestComplete(status, KErrCancel);
sl@0
   254
    }
sl@0
   255
sl@0
   256
//-----------------------------------------------------------------------------
sl@0
   257
sl@0
   258
sl@0
   259
//CThreadMonitorBackend::CThread-----------------------------------------------
sl@0
   260
sl@0
   261
CThreadMonitorBackend::CThread* CThreadMonitorBackend::CThread::NewL(const TThreadId& aThread, CThreadMonitorBackend& aMonitor)
sl@0
   262
    {
sl@0
   263
    CThread* self = new (ELeave) CThread(aMonitor);
sl@0
   264
    CleanupStack::PushL(self);
sl@0
   265
    self->ConstructL(aThread);
sl@0
   266
    CleanupStack::Pop(self);
sl@0
   267
    return self;
sl@0
   268
    }
sl@0
   269
sl@0
   270
sl@0
   271
CThreadMonitorBackend::CThread::CThread(CThreadMonitorBackend& aMonitor) :
sl@0
   272
    CActive(CActive::EPriorityStandard),
sl@0
   273
    iMonitor(aMonitor)
sl@0
   274
    {
sl@0
   275
    CActiveScheduler::Add(this);
sl@0
   276
    }
sl@0
   277
sl@0
   278
sl@0
   279
void CThreadMonitorBackend::CThread::ConstructL(const TThreadId& aThread)
sl@0
   280
    {
sl@0
   281
    User::LeaveIfError(iThread.Open(aThread, EOwnerThread));
sl@0
   282
    iThread.Logon(iStatus);
sl@0
   283
    SetActive();
sl@0
   284
    }
sl@0
   285
sl@0
   286
sl@0
   287
CThreadMonitorBackend::CThread::~CThread()
sl@0
   288
    {
sl@0
   289
    Cancel();
sl@0
   290
    iThread.Close();
sl@0
   291
    }
sl@0
   292
sl@0
   293
sl@0
   294
void CThreadMonitorBackend::CThread::Panic(TInt aExitReason, const TExitCategoryName& aExitCategory)
sl@0
   295
    {
sl@0
   296
    iThread.Panic(aExitCategory, aExitReason);
sl@0
   297
    }
sl@0
   298
sl@0
   299
sl@0
   300
void CThreadMonitorBackend::CThread::RunL()
sl@0
   301
    {
sl@0
   302
    //Inform the monitor backend that the thread exitted.
sl@0
   303
    TExitCategoryName category = iThread.ExitCategory();
sl@0
   304
    TInt reason = iThread.ExitReason();
sl@0
   305
    TExitType type = iThread.ExitType();
sl@0
   306
    iMonitor.ThreadExitted(this, type, reason, category);
sl@0
   307
    }
sl@0
   308
sl@0
   309
sl@0
   310
void CThreadMonitorBackend::CThread::DoCancel()
sl@0
   311
    {
sl@0
   312
    iThread.LogonCancel(iStatus);
sl@0
   313
    }
sl@0
   314
sl@0
   315
//-----------------------------------------------------------------------------