| sl@0 |      1 | // Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
 | 
| sl@0 |      2 | // All rights reserved.
 | 
| sl@0 |      3 | // This component and the accompanying materials are made available
 | 
| sl@0 |      4 | // under the terms of "Eclipse Public License v1.0"
 | 
| sl@0 |      5 | // which accompanies this distribution, and is available
 | 
| sl@0 |      6 | // at the URL "http://www.eclipse.org/legal/epl-v10.html".
 | 
| sl@0 |      7 | //
 | 
| sl@0 |      8 | // Initial Contributors:
 | 
| sl@0 |      9 | // Nokia Corporation - initial contribution.
 | 
| sl@0 |     10 | //
 | 
| sl@0 |     11 | // Contributors:
 | 
| sl@0 |     12 | 
 | 
| sl@0 |     13 | 
 | 
| sl@0 |     14 | /**
 | 
| sl@0 |     15 |  @file
 | 
| sl@0 |     16 |  @test
 | 
| sl@0 |     17 |  @internalComponent - Internal Symbian test code
 | 
| sl@0 |     18 | */
 | 
| sl@0 |     19 | 
 | 
| sl@0 |     20 | 
 | 
| sl@0 |     21 | #include "egltest_threadedstress.h"
 | 
| sl@0 |     22 | #include "eglendpointwrap.h"
 | 
| sl@0 |     23 | #include "egltest_endpoint_images.h"
 | 
| sl@0 |     24 | #include "egltest_threadmonitor.h"
 | 
| sl@0 |     25 | #include <e32atomics.h>
 | 
| sl@0 |     26 | #include "egltest_endpoint_images.h"
 | 
| sl@0 |     27 | #include <e32math.h>
 | 
| sl@0 |     28 | 
 | 
| sl@0 |     29 | 
 | 
| sl@0 |     30 | //Private Helper Class Declarations-----------------------------------------------
 | 
| sl@0 |     31 | 
 | 
| sl@0 |     32 | class CTightLoopThread : public CBase, public MLog
 | 
| sl@0 |     33 |     {
 | 
| sl@0 |     34 | public:
 | 
| sl@0 |     35 |     ~CTightLoopThread();
 | 
| sl@0 |     36 |     
 | 
| sl@0 |     37 |     //Control the loop from the controlling thread. 
 | 
| sl@0 |     38 |     //Calling Start() more than once causes panic.
 | 
| sl@0 |     39 |     void Start();
 | 
| sl@0 |     40 |     TRemoteTestVerdict Stop();
 | 
| sl@0 |     41 |     TThreadId ThreadId() const;
 | 
| sl@0 |     42 |     
 | 
| sl@0 |     43 | protected:
 | 
| sl@0 |     44 |     CTightLoopThread();
 | 
| sl@0 |     45 |     void ConstructL(TBool aSharedHeap);
 | 
| sl@0 |     46 |     MLog& Logger() const;
 | 
| sl@0 |     47 |     void Log(const TText8* aFile, TInt aLine, TInt aSeverity, TRefByValue<const TDesC> aFmt, ...);
 | 
| sl@0 |     48 |     
 | 
| sl@0 |     49 |     //To be implemented by derived class.
 | 
| sl@0 |     50 |     virtual void SetupInThreadContextL() = 0;
 | 
| sl@0 |     51 |     virtual void TeardownInThreadContextL() = 0;
 | 
| sl@0 |     52 |     virtual TBool ExecuteInnerLoopBody() = 0;
 | 
| sl@0 |     53 |     
 | 
| sl@0 |     54 | private:
 | 
| sl@0 |     55 |     static TInt ThreadEntryPoint(TAny* aSelf);
 | 
| sl@0 |     56 |     void EnterThreadLoopL();
 | 
| sl@0 |     57 | 
 | 
| sl@0 |     58 | private:
 | 
| sl@0 |     59 |     RThread iThread;
 | 
| sl@0 |     60 |     TRequestStatus iNotifyStart;
 | 
| sl@0 |     61 |     volatile TBool iNotifyStop;
 | 
| sl@0 |     62 |     TBool iHasBeenStarted;
 | 
| sl@0 |     63 |     TBool iHasBeenStopped;
 | 
| sl@0 |     64 |     };
 | 
| sl@0 |     65 | 
 | 
| sl@0 |     66 | 
 | 
| sl@0 |     67 | class CEndpointExercise : public CTightLoopThread
 | 
| sl@0 |     68 |     {
 | 
| sl@0 |     69 | public:
 | 
| sl@0 |     70 |     static CEndpointExercise* NewL(TBool aSharedHeap);
 | 
| sl@0 |     71 |     ~CEndpointExercise();
 | 
| sl@0 |     72 |     
 | 
| sl@0 |     73 |     void SetupInThreadContextL();
 | 
| sl@0 |     74 |     void TeardownInThreadContextL();
 | 
| sl@0 |     75 |     TBool ExecuteInnerLoopBody();
 | 
| sl@0 |     76 |     
 | 
| sl@0 |     77 | private:
 | 
| sl@0 |     78 |     CEndpointExercise();
 | 
| sl@0 |     79 |     void ConstructL(TBool aSharedHeap);
 | 
| sl@0 |     80 |     void ExecuteInnerLoopBodyL();
 | 
| sl@0 |     81 |     TInt CheckImage(EGLImageKHR aEglImage);
 | 
| sl@0 |     82 |     
 | 
| sl@0 |     83 |     //Logging helpers.
 | 
| sl@0 |     84 |     void PanicIfError(TInt aError, const TText8* aFile, TInt aLine) const;
 | 
| sl@0 |     85 |     void PanicIfFalse(TBool aBool, const TText8* aFile, TInt aLine) const;
 | 
| sl@0 |     86 |     void LogAndLeaveIfErrorL(TInt aError, const TText8* aFile, TInt aLine) const;
 | 
| sl@0 |     87 |     void LogAndLeaveIfFalseL(TBool aBool, const TText8* aFile, TInt aLine) const;
 | 
| sl@0 |     88 |     #define PANIC_IF_ERROR(ERROR)           PanicIfError((ERROR), (TText8*)__FILE__, __LINE__)
 | 
| sl@0 |     89 |     #define PANIC_IF_FALSE(BOOL)            PanicIfFalse((BOOL), (TText8*)__FILE__, __LINE__)
 | 
| sl@0 |     90 |     #define LOG_AND_LEAVE_IF_ERROR_L(ERROR) LogAndLeaveIfErrorL((ERROR), (TText8*)__FILE__, __LINE__)
 | 
| sl@0 |     91 |     #define LOG_AND_LEAVE_IF_FALSE_L(BOOL)  LogAndLeaveIfFalseL((BOOL), (TText8*)__FILE__, __LINE__)
 | 
| sl@0 |     92 | 
 | 
| sl@0 |     93 | private:
 | 
| sl@0 |     94 |     TInt iIteration;
 | 
| sl@0 |     95 |     TInt iCurrentColour;
 | 
| sl@0 |     96 |     RSurfaceManager iSurfaceManager;
 | 
| sl@0 |     97 |     RSurfaceUpdateSession iSurfaceUpdate;
 | 
| sl@0 |     98 |     RSurfaceManager::TSurfaceCreationAttributesBuf iSurfaceAttribs;
 | 
| sl@0 |     99 |     EGLDisplay iDisplay;
 | 
| sl@0 |    100 |     TEglEndpointWrap iEglEp;
 | 
| sl@0 |    101 |     CEglWindowSurface* iDummyWindowSurface;
 | 
| sl@0 |    102 |     };
 | 
| sl@0 |    103 | 
 | 
| sl@0 |    104 | //--------------------------------------------------------------------------------
 | 
| sl@0 |    105 | 
 | 
| sl@0 |    106 | 
 | 
| sl@0 |    107 | //Cleanup Items used through out tests--------------------------------------------
 | 
| sl@0 |    108 | 
 | 
| sl@0 |    109 | struct TCleanupSurface
 | 
| sl@0 |    110 |     {
 | 
| sl@0 |    111 |     RSurfaceManager* iSurfaceManager;
 | 
| sl@0 |    112 |     TSurfaceId iSurfaceId;
 | 
| sl@0 |    113 |     };
 | 
| sl@0 |    114 | static void CleanupSurface(TAny* aCleanupSurface)
 | 
| sl@0 |    115 |     {
 | 
| sl@0 |    116 |     TCleanupSurface* surface = static_cast<TCleanupSurface*>(aCleanupSurface);
 | 
| sl@0 |    117 |     TInt err = surface->iSurfaceManager->CloseSurface(surface->iSurfaceId);
 | 
| sl@0 |    118 |     ASSERT(err == KErrNone);
 | 
| sl@0 |    119 |     }
 | 
| sl@0 |    120 | 
 | 
| sl@0 |    121 | 
 | 
| sl@0 |    122 | struct TCleanupEndpoint
 | 
| sl@0 |    123 |     {
 | 
| sl@0 |    124 |     EGLDisplay iDisplay;
 | 
| sl@0 |    125 |     EGLEndpointNOK iEndpoint;
 | 
| sl@0 |    126 |     };
 | 
| sl@0 |    127 | static void CleanupEndpoint(TAny* aCleanupEndpoint)
 | 
| sl@0 |    128 |     {
 | 
| sl@0 |    129 |     TCleanupEndpoint* endpoint = static_cast<TCleanupEndpoint*>(aCleanupEndpoint);
 | 
| sl@0 |    130 |     TEglEndpointWrap ep;
 | 
| sl@0 |    131 |     ASSERT(ep.Error() == KErrNone);
 | 
| sl@0 |    132 |     EGLBoolean err = ep.DestroyEndpoint(endpoint->iDisplay, endpoint->iEndpoint);
 | 
| sl@0 |    133 |     ASSERT(err);
 | 
| sl@0 |    134 |     }
 | 
| sl@0 |    135 | 
 | 
| sl@0 |    136 | 
 | 
| sl@0 |    137 | struct TCleanupImage
 | 
| sl@0 |    138 |     {
 | 
| sl@0 |    139 |     EGLDisplay iDisplay;
 | 
| sl@0 |    140 |     EGLEndpointNOK iEndpoint;
 | 
| sl@0 |    141 |     EGLImageKHR iImage;
 | 
| sl@0 |    142 |     };
 | 
| sl@0 |    143 | static void CleanupImage(TAny* aCleanupImage)
 | 
| sl@0 |    144 |     {
 | 
| sl@0 |    145 |     TCleanupImage* image = static_cast<TCleanupImage*>(aCleanupImage);
 | 
| sl@0 |    146 |     TEglEndpointWrap ep;
 | 
| sl@0 |    147 |     ASSERT(ep.Error() == KErrNone);
 | 
| sl@0 |    148 |     EGLBoolean err = ep.ReleaseImage(image->iDisplay, image->iEndpoint, image->iImage, EGL_NONE);
 | 
| sl@0 |    149 |     ASSERT(err);
 | 
| sl@0 |    150 |     }
 | 
| sl@0 |    151 | 
 | 
| sl@0 |    152 | 
 | 
| sl@0 |    153 | static void CleanupPointerArray(TAny* aPointerArray)
 | 
| sl@0 |    154 |     {
 | 
| sl@0 |    155 |     RPointerArray<CEndpointExercise>* array = static_cast<RPointerArray<CEndpointExercise>*>(aPointerArray);
 | 
| sl@0 |    156 |     array->ResetAndDestroy();
 | 
| sl@0 |    157 |     }
 | 
| sl@0 |    158 | 
 | 
| sl@0 |    159 | //--------------------------------------------------------------------------------
 | 
| sl@0 |    160 | 
 | 
| sl@0 |    161 | 
 | 
| sl@0 |    162 | //Utility Functions---------------------------------------------------------------
 | 
| sl@0 |    163 | 
 | 
| sl@0 |    164 | inline TInt RandomNumberInRange(TInt aMin, TInt aMax)
 | 
| sl@0 |    165 |     {
 | 
| sl@0 |    166 |     if(aMin > aMax)
 | 
| sl@0 |    167 |         {
 | 
| sl@0 |    168 |         TInt temp = aMin;
 | 
| sl@0 |    169 |         aMin = aMax;
 | 
| sl@0 |    170 |         aMax = temp;
 | 
| sl@0 |    171 |         }
 | 
| sl@0 |    172 |     
 | 
| sl@0 |    173 |     //Scale and offset to put random into the range inclusively.
 | 
| sl@0 |    174 |     TUint range = aMax - aMin;
 | 
| sl@0 |    175 |     TUint random  = Math::Random() % (range + 1);
 | 
| sl@0 |    176 |     return (TInt)random + aMin;
 | 
| sl@0 |    177 |     }
 | 
| sl@0 |    178 | 
 | 
| sl@0 |    179 | 
 | 
| sl@0 |    180 | inline TReal Square(TReal aNumber)
 | 
| sl@0 |    181 |     {
 | 
| sl@0 |    182 |     return aNumber * aNumber;
 | 
| sl@0 |    183 |     }
 | 
| sl@0 |    184 | 
 | 
| sl@0 |    185 | 
 | 
| sl@0 |    186 | static TBool SamplesAreIncreasing(TInt* aSampledData, TInt aNumSamples)
 | 
| sl@0 |    187 |     {
 | 
| sl@0 |    188 |     //Naive linear least squares to get gradient of fit line and correlation coefficient.
 | 
| sl@0 |    189 |     //Using TReal to avoid worrying about wrap.
 | 
| sl@0 |    190 |     
 | 
| sl@0 |    191 |     TReal n = aNumSamples;
 | 
| sl@0 |    192 |     TReal sumX = 0.0;
 | 
| sl@0 |    193 |     TReal sumXSq = 0.0;
 | 
| sl@0 |    194 |     TReal sumY = 0.0;
 | 
| sl@0 |    195 |     TReal sumYSq = 0.0;
 | 
| sl@0 |    196 |     TReal sumXTimesY = 0.0;
 | 
| sl@0 |    197 |     
 | 
| sl@0 |    198 |     for(TInt i=0; i < aNumSamples; i++)
 | 
| sl@0 |    199 |         {
 | 
| sl@0 |    200 |         TReal x = (TReal)(i + 1);
 | 
| sl@0 |    201 |         TReal y = (TReal)aSampledData[i];
 | 
| sl@0 |    202 |         sumX += x;
 | 
| sl@0 |    203 |         sumXSq += Square(x);
 | 
| sl@0 |    204 |         sumY += y;
 | 
| sl@0 |    205 |         sumYSq += Square(y);
 | 
| sl@0 |    206 |         sumXTimesY += x * y;
 | 
| sl@0 |    207 |         }
 | 
| sl@0 |    208 |     
 | 
| sl@0 |    209 |     TReal xBar = sumX / n;
 | 
| sl@0 |    210 |     TReal yBar = sumY / n;
 | 
| sl@0 |    211 |     
 | 
| sl@0 |    212 |     TReal gradient = (sumXTimesY - (n * xBar * yBar)) / (sumXSq - (n * Square(xBar)));
 | 
| sl@0 |    213 |     TReal correlation = Square(sumXTimesY - (n * xBar * yBar)) / ((sumXSq - (n * Square(xBar))) * (sumYSq - (n * Square(yBar))));
 | 
| sl@0 |    214 |     
 | 
| sl@0 |    215 |     //If the gradient is positive and the correlation coefficient is high, the samples are increasing.
 | 
| sl@0 |    216 |     return (correlation > 0.8) && (gradient > 0.0);
 | 
| sl@0 |    217 |     }
 | 
| sl@0 |    218 | 
 | 
| sl@0 |    219 | //--------------------------------------------------------------------------------
 | 
| sl@0 |    220 | 
 | 
| sl@0 |    221 | 
 | 
| sl@0 |    222 | //CTightLoopThread----------------------------------------------------------------
 | 
| sl@0 |    223 | 
 | 
| sl@0 |    224 | CTightLoopThread::CTightLoopThread() :
 | 
| sl@0 |    225 |     iNotifyStop(EFalse),
 | 
| sl@0 |    226 |     iHasBeenStarted(EFalse),
 | 
| sl@0 |    227 |     iHasBeenStopped(EFalse)
 | 
| sl@0 |    228 |     {
 | 
| sl@0 |    229 |     }
 | 
| sl@0 |    230 | 
 | 
| sl@0 |    231 | 
 | 
| sl@0 |    232 | void CTightLoopThread::ConstructL(TBool aSharedHeap)
 | 
| sl@0 |    233 |     {
 | 
| sl@0 |    234 |     //Stack and heap sizes.
 | 
| sl@0 |    235 |     static const TInt KStackSize =   0x2000;      //  8KB
 | 
| sl@0 |    236 |     static const TInt KHeapMinSize = 0x1000;      //  4KB
 | 
| sl@0 |    237 |     static const TInt KHeapMaxSize = 0x1000000;   // 16MB
 | 
| sl@0 |    238 |     
 | 
| sl@0 |    239 |     //The new thread either has its own heap or shares ours.
 | 
| sl@0 |    240 |     if(aSharedHeap)
 | 
| sl@0 |    241 |         {
 | 
| sl@0 |    242 |         User::LeaveIfError(iThread.Create(KNullDesC, ThreadEntryPoint, KStackSize, NULL, this, EOwnerThread));
 | 
| sl@0 |    243 |         }
 | 
| sl@0 |    244 |     else
 | 
| sl@0 |    245 |         {
 | 
| sl@0 |    246 |         User::LeaveIfError(iThread.Create(KNullDesC, ThreadEntryPoint, KStackSize, KHeapMinSize, KHeapMaxSize, this, EOwnerThread));
 | 
| sl@0 |    247 |         }
 | 
| sl@0 |    248 |     
 | 
| sl@0 |    249 |     //Resume and rendezvous.
 | 
| sl@0 |    250 |     iThread.Resume();
 | 
| sl@0 |    251 |     TRequestStatus rendezvous;
 | 
| sl@0 |    252 |     iThread.Rendezvous(rendezvous);
 | 
| sl@0 |    253 |     User::WaitForRequest(rendezvous);
 | 
| sl@0 |    254 |     User::LeaveIfError(rendezvous.Int());
 | 
| sl@0 |    255 |     }
 | 
| sl@0 |    256 | 
 | 
| sl@0 |    257 | 
 | 
| sl@0 |    258 | MLog& CTightLoopThread::Logger() const
 | 
| sl@0 |    259 |     {
 | 
| sl@0 |    260 |     return *const_cast<CTightLoopThread*>(this);
 | 
| sl@0 |    261 |     }
 | 
| sl@0 |    262 | 
 | 
| sl@0 |    263 | 
 | 
| sl@0 |    264 | class TOverflowTruncate : public TDesOverflow
 | 
| sl@0 |    265 |     {
 | 
| sl@0 |    266 | public:
 | 
| sl@0 |    267 |     virtual void Overflow(TDes& /*aDes*/)
 | 
| sl@0 |    268 |         {
 | 
| sl@0 |    269 |         //Do nothing - just let it truncate.
 | 
| sl@0 |    270 |         }
 | 
| sl@0 |    271 |     };
 | 
| sl@0 |    272 | 
 | 
| sl@0 |    273 | 
 | 
| sl@0 |    274 | void CTightLoopThread::Log(const TText8* aFile, TInt aLine, TInt aSeverity, TRefByValue<const TDesC> aFmt, ...)
 | 
| sl@0 |    275 |     {
 | 
| sl@0 |    276 |     TOverflowTruncate overflow;
 | 
| sl@0 |    277 |     VA_LIST list;
 | 
| sl@0 |    278 |     VA_START(list, aFmt);
 | 
| sl@0 |    279 |     TBuf<0x100> buf;
 | 
| sl@0 |    280 |     buf.AppendFormatList(aFmt, list, &overflow);
 | 
| sl@0 |    281 |     TPtrC8 file8(aFile);
 | 
| sl@0 |    282 |     TBuf<0x100> file16;
 | 
| sl@0 |    283 |     file16.Copy(file8);
 | 
| sl@0 |    284 |     //Lots of effort is required to pump this into the TEF log file, so for now we just print to debug.
 | 
| sl@0 |    285 |     RDebug::Print(_L("CTightLoopThread: %S:%d, Severity=%d, Message=\"%S\""), &file16, aLine, aSeverity, &buf);
 | 
| sl@0 |    286 |     }
 | 
| sl@0 |    287 | 
 | 
| sl@0 |    288 | 
 | 
| sl@0 |    289 | CTightLoopThread::~CTightLoopThread()
 | 
| sl@0 |    290 |     {
 | 
| sl@0 |    291 |     //Shutdown the thread according to the state it is in.
 | 
| sl@0 |    292 |     if(!iHasBeenStarted)
 | 
| sl@0 |    293 |         {
 | 
| sl@0 |    294 |         TRequestStatus* notifyStart = &iNotifyStart;
 | 
| sl@0 |    295 |         iThread.RequestComplete(notifyStart, KErrAbort);
 | 
| sl@0 |    296 |         }
 | 
| sl@0 |    297 |     if(iHasBeenStarted && !iHasBeenStopped)
 | 
| sl@0 |    298 |         {
 | 
| sl@0 |    299 |         Stop();
 | 
| sl@0 |    300 |         }
 | 
| sl@0 |    301 |     iThread.Close();
 | 
| sl@0 |    302 |     }
 | 
| sl@0 |    303 | 
 | 
| sl@0 |    304 | 
 | 
| sl@0 |    305 | void CTightLoopThread::Start()
 | 
| sl@0 |    306 |     {
 | 
| sl@0 |    307 |     ASSERT(!iHasBeenStarted);
 | 
| sl@0 |    308 |     TRequestStatus* notifyStart = &iNotifyStart;
 | 
| sl@0 |    309 |     iThread.RequestComplete(notifyStart, KErrNone);
 | 
| sl@0 |    310 |     iHasBeenStarted = ETrue;
 | 
| sl@0 |    311 |     }
 | 
| sl@0 |    312 | 
 | 
| sl@0 |    313 | 
 | 
| sl@0 |    314 | TRemoteTestVerdict CTightLoopThread::Stop()
 | 
| sl@0 |    315 |     {
 | 
| sl@0 |    316 |     ASSERT(iHasBeenStarted);
 | 
| sl@0 |    317 |     ASSERT(!iHasBeenStopped);
 | 
| sl@0 |    318 |     
 | 
| sl@0 |    319 |     TRequestStatus logon;
 | 
| sl@0 |    320 |     iThread.Logon(logon);
 | 
| sl@0 |    321 |     __e32_atomic_store_rel32(&iNotifyStop, ETrue);
 | 
| sl@0 |    322 |     User::WaitForRequest(logon);
 | 
| sl@0 |    323 |     
 | 
| sl@0 |    324 |     TExitType exitType = iThread.ExitType();
 | 
| sl@0 |    325 |     iThread.Close();
 | 
| sl@0 |    326 |     iHasBeenStopped = ETrue;
 | 
| sl@0 |    327 |     
 | 
| sl@0 |    328 |     switch(exitType)
 | 
| sl@0 |    329 |         {
 | 
| sl@0 |    330 |         case EExitKill:
 | 
| sl@0 |    331 |             //Terminated normally (since we never call kill).
 | 
| sl@0 |    332 |             return ERtvPass; 
 | 
| sl@0 |    333 |         
 | 
| sl@0 |    334 |         case EExitPanic:
 | 
| sl@0 |    335 |             //Thread panicked.
 | 
| sl@0 |    336 |             return ERtvPanic;
 | 
| sl@0 |    337 |             
 | 
| sl@0 |    338 |         default:
 | 
| sl@0 |    339 |             //Any other option should be impossible in our use case.
 | 
| sl@0 |    340 |             ASSERT(0);
 | 
| sl@0 |    341 |         }
 | 
| sl@0 |    342 |     return ERtvAbort;
 | 
| sl@0 |    343 |     }
 | 
| sl@0 |    344 | 
 | 
| sl@0 |    345 | 
 | 
| sl@0 |    346 | TThreadId CTightLoopThread::ThreadId() const
 | 
| sl@0 |    347 |     {
 | 
| sl@0 |    348 |     return iThread.Id();
 | 
| sl@0 |    349 |     }
 | 
| sl@0 |    350 | 
 | 
| sl@0 |    351 | 
 | 
| sl@0 |    352 | TInt CTightLoopThread::ThreadEntryPoint(TAny* aSelf)
 | 
| sl@0 |    353 |     {
 | 
| sl@0 |    354 |     CTightLoopThread* self = static_cast<CTightLoopThread*>(aSelf);
 | 
| sl@0 |    355 |     CTrapCleanup* cleanup = CTrapCleanup::New();
 | 
| sl@0 |    356 |     
 | 
| sl@0 |    357 |     TRAPD(err,
 | 
| sl@0 |    358 |         //Create active scheduler.
 | 
| sl@0 |    359 |         CActiveScheduler* scheduler = new (ELeave) CActiveScheduler();
 | 
| sl@0 |    360 |         CleanupStack::PushL(scheduler);
 | 
| sl@0 |    361 |         CActiveScheduler::Install(scheduler);
 | 
| sl@0 |    362 | 
 | 
| sl@0 |    363 |         //Setup the draw loop.
 | 
| sl@0 |    364 |         self->EnterThreadLoopL();
 | 
| sl@0 |    365 | 
 | 
| sl@0 |    366 |         //Clean up.
 | 
| sl@0 |    367 |         CleanupStack::PopAndDestroy(scheduler);
 | 
| sl@0 |    368 |         );
 | 
| sl@0 |    369 |     
 | 
| sl@0 |    370 |     __ASSERT_ALWAYS(err == KErrNone, User::PanicUnexpectedLeave());
 | 
| sl@0 |    371 |     delete cleanup;
 | 
| sl@0 |    372 |     
 | 
| sl@0 |    373 |     return KErrNone;
 | 
| sl@0 |    374 |     }
 | 
| sl@0 |    375 | 
 | 
| sl@0 |    376 | 
 | 
| sl@0 |    377 | void CTightLoopThread::EnterThreadLoopL()
 | 
| sl@0 |    378 |     {
 | 
| sl@0 |    379 |     //Setup the derived class in this thread context.
 | 
| sl@0 |    380 |     TRAPD(err, SetupInThreadContextL());
 | 
| sl@0 |    381 |     
 | 
| sl@0 |    382 |     //Set the request to pending, rendezvous with parent and wait for start signal.
 | 
| sl@0 |    383 |     iNotifyStart = KRequestPending;
 | 
| sl@0 |    384 |     RThread().Rendezvous(err);
 | 
| sl@0 |    385 |     User::WaitForRequest(iNotifyStart);
 | 
| sl@0 |    386 |     
 | 
| sl@0 |    387 |     //Exit immediately if the KErrAbort signal was received.
 | 
| sl@0 |    388 |     TBool keepGoing = ETrue;
 | 
| sl@0 |    389 |     if(iNotifyStart == KErrAbort)
 | 
| sl@0 |    390 |         {
 | 
| sl@0 |    391 |         keepGoing = EFalse;
 | 
| sl@0 |    392 |         }
 | 
| sl@0 |    393 |     else
 | 
| sl@0 |    394 |         {
 | 
| sl@0 |    395 |         ASSERT(iNotifyStart == KErrNone);
 | 
| sl@0 |    396 |         }
 | 
| sl@0 |    397 |     
 | 
| sl@0 |    398 |     //Loop until we are told to stop.
 | 
| sl@0 |    399 |     while(!__e32_atomic_load_acq32(&iNotifyStop) && keepGoing)
 | 
| sl@0 |    400 |         {
 | 
| sl@0 |    401 |         keepGoing = ExecuteInnerLoopBody();
 | 
| sl@0 |    402 |         }
 | 
| sl@0 |    403 |     
 | 
| sl@0 |    404 |     //Teardown the derived class in this thread context.
 | 
| sl@0 |    405 |     TeardownInThreadContextL();
 | 
| sl@0 |    406 |     }
 | 
| sl@0 |    407 | 
 | 
| sl@0 |    408 | //--------------------------------------------------------------------------------
 | 
| sl@0 |    409 | 
 | 
| sl@0 |    410 | 
 | 
| sl@0 |    411 | //CEndpointExercise---------------------------------------------------------------
 | 
| sl@0 |    412 | 
 | 
| sl@0 |    413 | CEndpointExercise* CEndpointExercise::NewL(TBool aSharedHeap)
 | 
| sl@0 |    414 |     {
 | 
| sl@0 |    415 |     CEndpointExercise* self = new (ELeave) CEndpointExercise();
 | 
| sl@0 |    416 |     CleanupStack::PushL(self);
 | 
| sl@0 |    417 |     self->ConstructL(aSharedHeap);
 | 
| sl@0 |    418 |     CleanupStack::Pop(self);
 | 
| sl@0 |    419 |     return self;
 | 
| sl@0 |    420 |     }
 | 
| sl@0 |    421 | 
 | 
| sl@0 |    422 | 
 | 
| sl@0 |    423 | CEndpointExercise::CEndpointExercise()
 | 
| sl@0 |    424 |     {
 | 
| sl@0 |    425 |     }
 | 
| sl@0 |    426 | 
 | 
| sl@0 |    427 | 
 | 
| sl@0 |    428 | void CEndpointExercise::ConstructL(TBool aSharedHeap)
 | 
| sl@0 |    429 |     {
 | 
| sl@0 |    430 |     CTightLoopThread::ConstructL(aSharedHeap);
 | 
| sl@0 |    431 |     User::LeaveIfError(iEglEp.Error());
 | 
| sl@0 |    432 |     }
 | 
| sl@0 |    433 | 
 | 
| sl@0 |    434 | 
 | 
| sl@0 |    435 | CEndpointExercise::~CEndpointExercise()
 | 
| sl@0 |    436 |     {
 | 
| sl@0 |    437 |     }
 | 
| sl@0 |    438 | 
 | 
| sl@0 |    439 | 
 | 
| sl@0 |    440 | void CEndpointExercise::PanicIfError(TInt aError, const TText8* aFile, TInt aLine) const
 | 
| sl@0 |    441 |     {
 | 
| sl@0 |    442 |     if(aError != KErrNone)
 | 
| sl@0 |    443 |         {
 | 
| sl@0 |    444 |         Logger().Log(aFile, aLine, ESevrErr, _L("Panicking due to error %d"), aError);
 | 
| sl@0 |    445 |         User::Panic(_L("EPTHREADEDSTRESS"), aLine);
 | 
| sl@0 |    446 |         }
 | 
| sl@0 |    447 |     }
 | 
| sl@0 |    448 | 
 | 
| sl@0 |    449 | 
 | 
| sl@0 |    450 | void CEndpointExercise::PanicIfFalse(TBool aBool, const TText8* aFile, TInt aLine) const
 | 
| sl@0 |    451 |     {
 | 
| sl@0 |    452 |     if(!aBool)
 | 
| sl@0 |    453 |         {
 | 
| sl@0 |    454 |         Logger().Log(aFile, aLine, ESevrErr, _L("Panicking due to failing invariant test"));
 | 
| sl@0 |    455 |         User::Panic(_L("EPTHREADEDSTRESS"), aLine);
 | 
| sl@0 |    456 |         }
 | 
| sl@0 |    457 |     }
 | 
| sl@0 |    458 | 
 | 
| sl@0 |    459 | 
 | 
| sl@0 |    460 | void CEndpointExercise::LogAndLeaveIfErrorL(TInt aError, const TText8* aFile, TInt aLine) const
 | 
| sl@0 |    461 |     {
 | 
| sl@0 |    462 |     if(aError != KErrNone)
 | 
| sl@0 |    463 |         {
 | 
| sl@0 |    464 |         Logger().Log(aFile, aLine, ESevrWarn, _L("Abandoning iteration due to error %d"), aError);
 | 
| sl@0 |    465 |         User::Leave(aError);
 | 
| sl@0 |    466 |         }
 | 
| sl@0 |    467 |     }
 | 
| sl@0 |    468 | 
 | 
| sl@0 |    469 | 
 | 
| sl@0 |    470 | void CEndpointExercise::LogAndLeaveIfFalseL(TBool aBool, const TText8* aFile, TInt aLine) const
 | 
| sl@0 |    471 |     {
 | 
| sl@0 |    472 |     if(!aBool)
 | 
| sl@0 |    473 |         {
 | 
| sl@0 |    474 |         Logger().Log(aFile, aLine, ESevrWarn, _L("Abandoning iteration due to failing invariant test"));
 | 
| sl@0 |    475 |         User::Leave(KErrUnknown);
 | 
| sl@0 |    476 |         }
 | 
| sl@0 |    477 |     }
 | 
| sl@0 |    478 | 
 | 
| sl@0 |    479 | 
 | 
| sl@0 |    480 | TInt CEndpointExercise::CheckImage(EGLImageKHR aEglImage)
 | 
| sl@0 |    481 |     {
 | 
| sl@0 |    482 |     TRAPD
 | 
| sl@0 |    483 |         (err,
 | 
| sl@0 |    484 |         //Convert the image to a CTestVgEglImage
 | 
| sl@0 |    485 |         CTestVgEglImage* vgEglImage = CTestVgEglImage::NewL(aEglImage);
 | 
| sl@0 |    486 |         CleanupStack::PushL(vgEglImage);
 | 
| sl@0 |    487 |         
 | 
| sl@0 |    488 |         //Check the corners and center pixel are the same colour.
 | 
| sl@0 |    489 |         //Since this test is focussed on correct OOM behaviour, 
 | 
| sl@0 |    490 |         //we panic if the functionality is incorrect.
 | 
| sl@0 |    491 |         PANIC_IF_FALSE(vgEglImage->IsSolidColourL());
 | 
| sl@0 |    492 |         
 | 
| sl@0 |    493 |         CleanupStack::PopAndDestroy(vgEglImage);
 | 
| sl@0 |    494 |         );
 | 
| sl@0 |    495 |     return err;
 | 
| sl@0 |    496 |     }
 | 
| sl@0 |    497 | 
 | 
| sl@0 |    498 | 
 | 
| sl@0 |    499 | void CEndpointExercise::SetupInThreadContextL()
 | 
| sl@0 |    500 |     {
 | 
| sl@0 |    501 |     //Colour to fill surface with (this is incremented every frame).
 | 
| sl@0 |    502 |     iCurrentColour = 0x88CC44;
 | 
| sl@0 |    503 |     
 | 
| sl@0 |    504 |     //Connections to SUS and surface manager.
 | 
| sl@0 |    505 |     User::LeaveIfError(iSurfaceManager.Open());
 | 
| sl@0 |    506 |     User::LeaveIfError(iSurfaceUpdate.Connect(5));
 | 
| sl@0 |    507 |     
 | 
| sl@0 |    508 |     //Surface attribs to create surface with.
 | 
| sl@0 |    509 |     iSurfaceAttribs().iSize = TSize(100, 100);
 | 
| sl@0 |    510 |     iSurfaceAttribs().iBuffers = 2;
 | 
| sl@0 |    511 |     iSurfaceAttribs().iPixelFormat = EUidPixelFormatARGB_8888_PRE;
 | 
| sl@0 |    512 |     iSurfaceAttribs().iStride = 100 * 4;
 | 
| sl@0 |    513 |     iSurfaceAttribs().iOffsetToFirstBuffer = 0;
 | 
| sl@0 |    514 |     iSurfaceAttribs().iAlignment = 32;
 | 
| sl@0 |    515 |     iSurfaceAttribs().iContiguous = EFalse;
 | 
| sl@0 |    516 |     iSurfaceAttribs().iCacheAttrib = RSurfaceManager::ECached;
 | 
| sl@0 |    517 |     iSurfaceAttribs().iOffsetBetweenBuffers = 0;
 | 
| sl@0 |    518 |     iSurfaceAttribs().iSurfaceHints = NULL;
 | 
| sl@0 |    519 |     iSurfaceAttribs().iHintCount = 0;
 | 
| sl@0 |    520 |     iSurfaceAttribs().iMappable = ETrue;
 | 
| sl@0 |    521 |     
 | 
| sl@0 |    522 |     iDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
 | 
| sl@0 |    523 |     
 | 
| sl@0 |    524 |     //Create an EglWindowSurface so we have a current context for vg operations.
 | 
| sl@0 |    525 |     iDummyWindowSurface = CEglWindowSurface::NewL();
 | 
| sl@0 |    526 |     iDummyWindowSurface->CreateL(EStandardSurface, TPoint(0, 0));
 | 
| sl@0 |    527 |     iDummyWindowSurface->ActivateL();
 | 
| sl@0 |    528 |     }
 | 
| sl@0 |    529 | 
 | 
| sl@0 |    530 | 
 | 
| sl@0 |    531 | void CEndpointExercise::TeardownInThreadContextL()
 | 
| sl@0 |    532 |     {
 | 
| sl@0 |    533 |     delete iDummyWindowSurface;
 | 
| sl@0 |    534 |     iSurfaceUpdate.Close();
 | 
| sl@0 |    535 |     iSurfaceManager.Close();
 | 
| sl@0 |    536 |     }
 | 
| sl@0 |    537 | 
 | 
| sl@0 |    538 | 
 | 
| sl@0 |    539 | TBool CEndpointExercise::ExecuteInnerLoopBody()
 | 
| sl@0 |    540 |     {
 | 
| sl@0 |    541 |     TRAPD(err, ExecuteInnerLoopBodyL());
 | 
| sl@0 |    542 |     if(err != KErrNone)
 | 
| sl@0 |    543 |         {
 | 
| sl@0 |    544 |         Logger().Log((TText8*)__FILE__, __LINE__, ESevrWarn, _L("Iteration %d did not run to completion, due to an acceptable error in low memory conditions"), iIteration);
 | 
| sl@0 |    545 |         }
 | 
| sl@0 |    546 |     iIteration++;
 | 
| sl@0 |    547 |     return ETrue;
 | 
| sl@0 |    548 |     }
 | 
| sl@0 |    549 | 
 | 
| sl@0 |    550 | 
 | 
| sl@0 |    551 | void CEndpointExercise::ExecuteInnerLoopBodyL()
 | 
| sl@0 |    552 |     {
 | 
| sl@0 |    553 |     //Create a surface.
 | 
| sl@0 |    554 |     TCleanupSurface surface = {&iSurfaceManager, TSurfaceId::CreateNullId()};
 | 
| sl@0 |    555 |     LOG_AND_LEAVE_IF_ERROR_L(iSurfaceManager.CreateSurface(iSurfaceAttribs, surface.iSurfaceId));
 | 
| sl@0 |    556 |     CleanupStack::PushL(TCleanupItem(CleanupSurface, &surface));
 | 
| sl@0 |    557 |     
 | 
| sl@0 |    558 |     //Map surface and get pointer to buffer 0.
 | 
| sl@0 |    559 |     RChunk surfaceChunk;
 | 
| sl@0 |    560 |     TInt offset;
 | 
| sl@0 |    561 |     PANIC_IF_ERROR(iSurfaceManager.MapSurface(surface.iSurfaceId, surfaceChunk));
 | 
| sl@0 |    562 |     CleanupClosePushL(surfaceChunk);
 | 
| sl@0 |    563 |     PANIC_IF_ERROR(iSurfaceManager.GetBufferOffset(surface.iSurfaceId, 0, offset));
 | 
| sl@0 |    564 |     TUint32* buffer = (TUint32*)(surfaceChunk.Base() + offset);
 | 
| sl@0 |    565 |     
 | 
| sl@0 |    566 |     //Fill surface with current colour. This could
 | 
| sl@0 |    567 |     //be much faster but its good enough for testing.
 | 
| sl@0 |    568 |     TUint32 fillColour = TRgb(iCurrentColour, 255)._Color16MAP();
 | 
| sl@0 |    569 |     for(TInt y=0; y < iSurfaceAttribs().iSize.iHeight; ++y)
 | 
| sl@0 |    570 |         {
 | 
| sl@0 |    571 |         for(TInt x=0; x < iSurfaceAttribs().iSize.iWidth; ++x)
 | 
| sl@0 |    572 |             {
 | 
| sl@0 |    573 |             buffer[x] = fillColour;
 | 
| sl@0 |    574 |             }
 | 
| sl@0 |    575 |         buffer += iSurfaceAttribs().iStride >> 2;
 | 
| sl@0 |    576 |         }
 | 
| sl@0 |    577 |     
 | 
| sl@0 |    578 |     //Create an endpoint for the surface.
 | 
| sl@0 |    579 |     TCleanupEndpoint endpoint = {iDisplay, EGL_NO_ENDPOINT_NOK};
 | 
| sl@0 |    580 |     endpoint.iEndpoint = iEglEp.CreateEndpoint(iDisplay, EGL_ENDPOINT_TYPE_CONSUMER_NOK, EGL_TSURFACEID_NOK, &surface.iSurfaceId, NULL);
 | 
| sl@0 |    581 |     LOG_AND_LEAVE_IF_FALSE_L(endpoint.iEndpoint != EGL_NO_ENDPOINT_NOK);
 | 
| sl@0 |    582 |     CleanupStack::PushL(TCleanupItem(CleanupEndpoint, &endpoint));
 | 
| sl@0 |    583 |     
 | 
| sl@0 |    584 |     //Submit buffer 0 to surface update server.
 | 
| sl@0 |    585 |     TRequestStatus displayed;
 | 
| sl@0 |    586 |     iSurfaceUpdate.NotifyWhenDisplayedXTimes(1, displayed);
 | 
| sl@0 |    587 |     LOG_AND_LEAVE_IF_ERROR_L(iSurfaceUpdate.SubmitUpdate(KAllScreens, surface.iSurfaceId, 0, NULL));
 | 
| sl@0 |    588 |     User::WaitForRequest(displayed);
 | 
| sl@0 |    589 |     
 | 
| sl@0 |    590 |     //Begin streaming. Should not fail since we have submitted a buffer since creating ep.
 | 
| sl@0 |    591 |     LOG_AND_LEAVE_IF_FALSE_L(iEglEp.EndpointBeginStreaming(iDisplay, endpoint.iEndpoint));
 | 
| sl@0 |    592 |     
 | 
| sl@0 |    593 |     //Acquire an image from the endpoint.
 | 
| sl@0 |    594 |     TCleanupImage image = {iDisplay, endpoint.iEndpoint, EGL_NO_IMAGE_KHR};
 | 
| sl@0 |    595 |     image.iImage = iEglEp.AcquireImage(iDisplay, endpoint.iEndpoint);
 | 
| sl@0 |    596 |     LOG_AND_LEAVE_IF_FALSE_L(image.iImage != EGL_NO_IMAGE_KHR);
 | 
| sl@0 |    597 |     CleanupStack::PushL(TCleanupItem(CleanupImage, &image));
 | 
| sl@0 |    598 |     
 | 
| sl@0 |    599 |     //Check that the image we acquired is coherrent.
 | 
| sl@0 |    600 |     LOG_AND_LEAVE_IF_ERROR_L(CheckImage(image.iImage));
 | 
| sl@0 |    601 |     
 | 
| sl@0 |    602 |     //Release image, destroy endpoint, close chunk and close surface.
 | 
| sl@0 |    603 |     CleanupStack::PopAndDestroy(4);
 | 
| sl@0 |    604 |     
 | 
| sl@0 |    605 |     //Modify the colour that we draw.
 | 
| sl@0 |    606 |     iCurrentColour += 16;
 | 
| sl@0 |    607 |     }
 | 
| sl@0 |    608 | 
 | 
| sl@0 |    609 | //--------------------------------------------------------------------------------
 | 
| sl@0 |    610 | 
 | 
| sl@0 |    611 | 
 | 
| sl@0 |    612 | //Remote test step----------------------------------------------------------------
 | 
| sl@0 |    613 | 
 | 
| sl@0 |    614 | CEglTest_RemoteTestStep_EndpointThreadStress::CEglTest_RemoteTestStep_EndpointThreadStress() :
 | 
| sl@0 |    615 |     CRemoteTestStepBase(ETestUidEndpointThreadStress)
 | 
| sl@0 |    616 |     {
 | 
| sl@0 |    617 |     }
 | 
| sl@0 |    618 | 
 | 
| sl@0 |    619 | 
 | 
| sl@0 |    620 | CEglTest_RemoteTestStep_EndpointThreadStress::~CEglTest_RemoteTestStep_EndpointThreadStress()
 | 
| sl@0 |    621 |     {
 | 
| sl@0 |    622 |     }
 | 
| sl@0 |    623 | 
 | 
| sl@0 |    624 | 
 | 
| sl@0 |    625 | TRemoteTestVerdict CEglTest_RemoteTestStep_EndpointThreadStress::DoStartRemoteTestStepL(const TRemoteTestParams& /*aMessageIn*/)
 | 
| sl@0 |    626 |     {
 | 
| sl@0 |    627 |     REMOTE_INFO_PRINTF1(_L("Starting Remote Test Step."));
 | 
| sl@0 |    628 |     EglStartL();
 | 
| sl@0 |    629 |     return ERtvPass;
 | 
| sl@0 |    630 |     }
 | 
| sl@0 |    631 | 
 | 
| sl@0 |    632 | 
 | 
| sl@0 |    633 | TRemoteTestVerdict CEglTest_RemoteTestStep_EndpointThreadStress::DoEndRemoteTestStepL(const TRemoteTestParams& /*aMessageIn*/)
 | 
| sl@0 |    634 |     {
 | 
| sl@0 |    635 |     REMOTE_INFO_PRINTF1(_L("Ending Remote Test Step."));
 | 
| sl@0 |    636 |     EglEndL();
 | 
| sl@0 |    637 |     return ERtvPass;
 | 
| sl@0 |    638 |     }
 | 
| sl@0 |    639 | 
 | 
| sl@0 |    640 | 
 | 
| sl@0 |    641 | TInt CEglTest_RemoteTestStep_EndpointThreadStress::Timeout() const
 | 
| sl@0 |    642 |     {
 | 
| sl@0 |    643 |     return 120 * 1000000; //2 min.
 | 
| sl@0 |    644 |     }
 | 
| sl@0 |    645 | 
 | 
| sl@0 |    646 | 
 | 
| sl@0 |    647 | TRemoteTestVerdict CEglTest_RemoteTestStep_EndpointThreadStress::DoRunRemoteTestCaseL(TInt aTestCase, const TRemoteTestParams& aParams)
 | 
| sl@0 |    648 |     {
 | 
| sl@0 |    649 |     switch(aTestCase)
 | 
| sl@0 |    650 |         {
 | 
| sl@0 |    651 |         case 0:     return CrazyThreadingTestCaseL(aParams);
 | 
| sl@0 |    652 |         case 1:     return OutOfHeapMemoryTestCaseL(aParams);
 | 
| sl@0 |    653 |         default:    return ERtvAbort;
 | 
| sl@0 |    654 |         }
 | 
| sl@0 |    655 |     }
 | 
| sl@0 |    656 | 
 | 
| sl@0 |    657 | 
 | 
| sl@0 |    658 | //For a detailed description of this test case (GRAPHICS-EGL-594), see the local side cpp file.
 | 
| sl@0 |    659 | TRemoteTestVerdict CEglTest_RemoteTestStep_EndpointThreadStress::CrazyThreadingTestCaseL(const TRemoteTestParams& /*aParams*/)
 | 
| sl@0 |    660 |     {
 | 
| sl@0 |    661 |     //Create the exercises. These run an endpoint exercise in a tight loop in a private thread.
 | 
| sl@0 |    662 |     CEndpointExercise* exercise1 = CEndpointExercise::NewL(EFalse);
 | 
| sl@0 |    663 |     CleanupStack::PushL(exercise1);
 | 
| sl@0 |    664 |     CEndpointExercise* exercise2 = CEndpointExercise::NewL(EFalse);
 | 
| sl@0 |    665 |     CleanupStack::PushL(exercise2);
 | 
| sl@0 |    666 |     
 | 
| sl@0 |    667 |     //Create a monitor to cleanup if any of the threads panic. The controller thread 
 | 
| sl@0 |    668 |     //must be at index zero in the array. This will even work if a deadlock occurs 
 | 
| sl@0 |    669 |     //between the  exercise threads, since the call to stop the exercise will never 
 | 
| sl@0 |    670 |     //return and the framework will eventually time us out. The monitor will notice
 | 
| sl@0 |    671 |     //that the controller thread has panicked and will forward the panic to the exercises.
 | 
| sl@0 |    672 |     RArray<TThreadId> threads;
 | 
| sl@0 |    673 |     CleanupClosePushL(threads);
 | 
| sl@0 |    674 |     threads.AppendL(RThread().Id());
 | 
| sl@0 |    675 |     threads.AppendL(exercise1->ThreadId());
 | 
| sl@0 |    676 |     threads.AppendL(exercise2->ThreadId());
 | 
| sl@0 |    677 |     CThreadMonitor* monitor = CThreadMonitor::NewL(threads);
 | 
| sl@0 |    678 |     CleanupStack::PushL(monitor);
 | 
| sl@0 |    679 |     
 | 
| sl@0 |    680 |     //Start the exercises.
 | 
| sl@0 |    681 |     exercise1->Start();
 | 
| sl@0 |    682 |     exercise2->Start();
 | 
| sl@0 |    683 |     
 | 
| sl@0 |    684 |     //Let the exercises run for 20 seconds.
 | 
| sl@0 |    685 |     User::After(20 * 1000000);
 | 
| sl@0 |    686 |     
 | 
| sl@0 |    687 |     //Stop the exercises and record the results.
 | 
| sl@0 |    688 |     TRemoteTestVerdict result1 = exercise1->Stop();
 | 
| sl@0 |    689 |     TRemoteTestVerdict result2 = exercise2->Stop();
 | 
| sl@0 |    690 |     
 | 
| sl@0 |    691 |     CleanupStack::PopAndDestroy(4, exercise1);
 | 
| sl@0 |    692 |     return (result1 != ERtvPass) ? result1 : result2;
 | 
| sl@0 |    693 |     }
 | 
| sl@0 |    694 | 
 | 
| sl@0 |    695 | 
 | 
| sl@0 |    696 | class THeapGobbler
 | 
| sl@0 |    697 |     {
 | 
| sl@0 |    698 | public:
 | 
| sl@0 |    699 |     static THeapGobbler* New(TInt aSize)
 | 
| sl@0 |    700 |         {
 | 
| sl@0 |    701 |         THeapGobbler* self = (THeapGobbler*)new TUint8[sizeof(THeapGobbler) - sizeof(TUint8) + aSize];
 | 
| sl@0 |    702 |         if(!self)
 | 
| sl@0 |    703 |             {
 | 
| sl@0 |    704 |             return NULL;
 | 
| sl@0 |    705 |             }
 | 
| sl@0 |    706 |         self->iSize = aSize;
 | 
| sl@0 |    707 |         self->iNext = NULL;
 | 
| sl@0 |    708 |         return self;
 | 
| sl@0 |    709 |         }
 | 
| sl@0 |    710 |     
 | 
| sl@0 |    711 | public:
 | 
| sl@0 |    712 |     THeapGobbler* iNext;
 | 
| sl@0 |    713 |     TInt iSize;
 | 
| sl@0 |    714 |     TUint8 iMemory[1];
 | 
| sl@0 |    715 |     };
 | 
| sl@0 |    716 | 
 | 
| sl@0 |    717 | 
 | 
| sl@0 |    718 | //For a detailed description of this test case (GRAPHICS-EGL-601), see the local side cpp file.
 | 
| sl@0 |    719 | TRemoteTestVerdict CEglTest_RemoteTestStep_EndpointThreadStress::OutOfHeapMemoryTestCaseL(const TRemoteTestParams& aParams)
 | 
| sl@0 |    720 |     {
 | 
| sl@0 |    721 |     const TInt KHeapSizeMin = 0x100000;   //1MB.
 | 
| sl@0 |    722 |     const TInt KHeapSizeMax = 0x10000000; //256MB.
 | 
| sl@0 |    723 | 
 | 
| sl@0 |    724 |     RHeap* testHeap = User::ChunkHeap(NULL, KHeapSizeMin, KHeapSizeMax, KMinHeapGrowBy, 4);
 | 
| sl@0 |    725 |     if(!testHeap)
 | 
| sl@0 |    726 |         {
 | 
| sl@0 |    727 |         REMOTE_ERR_PRINTF1(_L("Failed to create chunk heap. Aborting."));
 | 
| sl@0 |    728 |         return ERtvAbort;
 | 
| sl@0 |    729 |         }
 | 
| sl@0 |    730 |     RHeap* oldHeap = User::SwitchHeap(testHeap);
 | 
| sl@0 |    731 |     
 | 
| sl@0 |    732 |     CTrapCleanup *cleanUpStack = CTrapCleanup::New();
 | 
| sl@0 |    733 |     if (!cleanUpStack)
 | 
| sl@0 |    734 |         {
 | 
| sl@0 |    735 |         User::SwitchHeap(oldHeap);
 | 
| sl@0 |    736 |         testHeap->Close();
 | 
| sl@0 |    737 |         User::Leave(KErrNoMemory);
 | 
| sl@0 |    738 |         }
 | 
| sl@0 |    739 | 
 | 
| sl@0 |    740 |     TRemoteTestVerdict verdict = ERtvPass;
 | 
| sl@0 |    741 |     TRAPD(err, verdict = DoOutOfHeapMemoryTestCaseL(aParams));
 | 
| sl@0 |    742 |     
 | 
| sl@0 |    743 |     delete cleanUpStack;
 | 
| sl@0 |    744 |     User::SwitchHeap(oldHeap);
 | 
| sl@0 |    745 |     testHeap->Close();
 | 
| sl@0 |    746 |     
 | 
| sl@0 |    747 |     User::LeaveIfError(err);
 | 
| sl@0 |    748 |     return verdict;
 | 
| sl@0 |    749 |     }
 | 
| sl@0 |    750 | 
 | 
| sl@0 |    751 |  
 | 
| sl@0 |    752 | TRemoteTestVerdict CEglTest_RemoteTestStep_EndpointThreadStress::DoOutOfHeapMemoryTestCaseL(const TRemoteTestParams& aParams)
 | 
| sl@0 |    753 |     {
 | 
| sl@0 |    754 |     const TInt numExercises = aParams.iEndpointThreadStress.iNumThreads;
 | 
| sl@0 |    755 |     
 | 
| sl@0 |    756 |     const TInt KMinCellSize = 500;
 | 
| sl@0 |    757 |     const TInt KMaxCellSize = 2000;
 | 
| sl@0 |    758 |     const TInt KNumIterations = 20;
 | 
| sl@0 |    759 |     TInt heapAllocSize[KNumIterations];
 | 
| sl@0 |    760 |     TRemoteTestVerdict exerciseResult = ERtvPass;
 | 
| sl@0 |    761 |     
 | 
| sl@0 |    762 |     //One iteration of the outer loop results in one data point for deciding if the heap is leaking or not. 
 | 
| sl@0 |    763 |     for(TInt x=0; x < KNumIterations; x++)
 | 
| sl@0 |    764 |         {
 | 
| sl@0 |    765 |         //Reserving space in these arrays ahead of time to 
 | 
| sl@0 |    766 |         //make cleanup stack manipulation more staightforward.
 | 
| sl@0 |    767 |         RPointerArray<CEndpointExercise> exercises;
 | 
| sl@0 |    768 |         CleanupStack::PushL(TCleanupItem(CleanupPointerArray, &exercises));
 | 
| sl@0 |    769 |         exercises.ReserveL(numExercises);
 | 
| sl@0 |    770 |         RArray<TThreadId> threads;
 | 
| sl@0 |    771 |         CleanupClosePushL(threads);
 | 
| sl@0 |    772 |         threads.ReserveL(numExercises + 1);
 | 
| sl@0 |    773 |         
 | 
| sl@0 |    774 |         //Save the controller thread id for the monitor.
 | 
| sl@0 |    775 |         threads.Append(RThread().Id());
 | 
| sl@0 |    776 |         
 | 
| sl@0 |    777 |         //Create endpoint exercise threads and save the thread Ids for the monitor.
 | 
| sl@0 |    778 |         for(TInt j=0; j < numExercises; j++)
 | 
| sl@0 |    779 |             {
 | 
| sl@0 |    780 |             //Appends can't fail since we have already reserved space.
 | 
| sl@0 |    781 |             //Note that the exercises all share the same heap as this thread.
 | 
| sl@0 |    782 |             exercises.Append(CEndpointExercise::NewL(ETrue));
 | 
| sl@0 |    783 |             threads.Append(exercises[j]->ThreadId());
 | 
| sl@0 |    784 |             }
 | 
| sl@0 |    785 | 
 | 
| sl@0 |    786 |         //Create a monitor to handle thread cleanup if something panics or deadlocks.
 | 
| sl@0 |    787 |         CThreadMonitor* monitor = CThreadMonitor::NewL(threads);
 | 
| sl@0 |    788 |         
 | 
| sl@0 |    789 |         //Nothing can leave after this.
 | 
| sl@0 |    790 |         CleanupStack::Pop(2);
 | 
| sl@0 |    791 |         
 | 
| sl@0 |    792 |         //Start the exercises.
 | 
| sl@0 |    793 |         for(TInt j=0; j < numExercises; j++)
 | 
| sl@0 |    794 |             {
 | 
| sl@0 |    795 |             exercises[j]->Start();
 | 
| sl@0 |    796 |             }
 | 
| sl@0 |    797 |         
 | 
| sl@0 |    798 |         THeapGobbler* firstCell = NULL;
 | 
| sl@0 |    799 |         THeapGobbler* lastCell = NULL;
 | 
| sl@0 |    800 |         TInt numberOfCells = 0;
 | 
| sl@0 |    801 |         
 | 
| sl@0 |    802 |         for(TInt i=0; i < 2; i++)
 | 
| sl@0 |    803 |             {
 | 
| sl@0 |    804 |             //Allocate random sizes until full.
 | 
| sl@0 |    805 |             THeapGobbler* newCell = THeapGobbler::New(RandomNumberInRange(KMinCellSize, KMaxCellSize));
 | 
| sl@0 |    806 |             while(newCell)
 | 
| sl@0 |    807 |                 {
 | 
| sl@0 |    808 |                 if(lastCell)
 | 
| sl@0 |    809 |                     lastCell->iNext = newCell;
 | 
| sl@0 |    810 |                 if(!firstCell)
 | 
| sl@0 |    811 |                     firstCell = newCell;
 | 
| sl@0 |    812 |                 lastCell = newCell;
 | 
| sl@0 |    813 |                 numberOfCells++;
 | 
| sl@0 |    814 |                 newCell = THeapGobbler::New(RandomNumberInRange(KMinCellSize, KMaxCellSize));
 | 
| sl@0 |    815 |                 }
 | 
| sl@0 |    816 |             
 | 
| sl@0 |    817 |             //Let exercise run while heap is full.
 | 
| sl@0 |    818 |             User::After(1 * 1000);
 | 
| sl@0 |    819 |             
 | 
| sl@0 |    820 |             //Deallocate n/4 cells.
 | 
| sl@0 |    821 |             for(TInt n = numberOfCells / 4; n >= 1; --n)
 | 
| sl@0 |    822 |                 {
 | 
| sl@0 |    823 |                 THeapGobbler* oldCell = firstCell;
 | 
| sl@0 |    824 |                 firstCell = oldCell->iNext;
 | 
| sl@0 |    825 |                 delete oldCell;
 | 
| sl@0 |    826 |                 numberOfCells--;
 | 
| sl@0 |    827 |                 if(!firstCell)
 | 
| sl@0 |    828 |                     {
 | 
| sl@0 |    829 |                     lastCell = NULL;
 | 
| sl@0 |    830 |                     ASSERT(numberOfCells == 0);
 | 
| sl@0 |    831 |                     break;
 | 
| sl@0 |    832 |                     }
 | 
| sl@0 |    833 |                 }
 | 
| sl@0 |    834 |             
 | 
| sl@0 |    835 |             //Let exercise run while heap is not full.
 | 
| sl@0 |    836 |             User::After(1 * 1000);
 | 
| sl@0 |    837 |             }
 | 
| sl@0 |    838 |         
 | 
| sl@0 |    839 |         //Deallocate all cells.
 | 
| sl@0 |    840 |         while(firstCell)
 | 
| sl@0 |    841 |             {
 | 
| sl@0 |    842 |             THeapGobbler* oldCell = firstCell;
 | 
| sl@0 |    843 |             firstCell = oldCell->iNext;
 | 
| sl@0 |    844 |             delete oldCell;
 | 
| sl@0 |    845 |             }
 | 
| sl@0 |    846 |         lastCell = NULL;
 | 
| sl@0 |    847 |         numberOfCells = 0;
 | 
| sl@0 |    848 |         
 | 
| sl@0 |    849 |         //Stop the exercises and save the result.
 | 
| sl@0 |    850 |         for(TInt j=0; j < numExercises; j++)
 | 
| sl@0 |    851 |             {
 | 
| sl@0 |    852 |             TRemoteTestVerdict ret = exercises[j]->Stop();
 | 
| sl@0 |    853 |             exerciseResult = (exerciseResult == ERtvPass) ? ret : exerciseResult;
 | 
| sl@0 |    854 |             }
 | 
| sl@0 |    855 | 
 | 
| sl@0 |    856 |         delete monitor;
 | 
| sl@0 |    857 |         threads.Close();
 | 
| sl@0 |    858 |         exercises.ResetAndDestroy();
 | 
| sl@0 |    859 |         
 | 
| sl@0 |    860 |         if(exerciseResult != ERtvPass)
 | 
| sl@0 |    861 |             {
 | 
| sl@0 |    862 |             REMOTE_ERR_PRINTF2(_L("Aborting because the endpoint exercise failed for iteration %d"), x);
 | 
| sl@0 |    863 |             return exerciseResult;
 | 
| sl@0 |    864 |             }
 | 
| sl@0 |    865 |         
 | 
| sl@0 |    866 |         //Save the heap size.
 | 
| sl@0 |    867 |         User::Heap().AllocSize(heapAllocSize[x]);
 | 
| sl@0 |    868 |         }
 | 
| sl@0 |    869 |     
 | 
| sl@0 |    870 |     //Work out if any memory has leaked and return a verdict.
 | 
| sl@0 |    871 |     TBool memoryIsLeaking = SamplesAreIncreasing(heapAllocSize, KNumIterations);
 | 
| sl@0 |    872 |     if(memoryIsLeaking)
 | 
| sl@0 |    873 |         {
 | 
| sl@0 |    874 |         REMOTE_ERR_PRINTF1(_L("Heap memory is increasing over time with high certainty, there is probably a memory leak."));
 | 
| sl@0 |    875 |         }
 | 
| sl@0 |    876 |     else
 | 
| sl@0 |    877 |         {
 | 
| sl@0 |    878 |         REMOTE_INFO_PRINTF1(_L("No heap memory leak detected."));
 | 
| sl@0 |    879 |         }
 | 
| sl@0 |    880 |     return memoryIsLeaking ? ERtvFail : ERtvPass;
 | 
| sl@0 |    881 |     }
 | 
| sl@0 |    882 | 
 | 
| sl@0 |    883 | //--------------------------------------------------------------------------------
 |