uiacceltk/hitchcock/goommonitor/src/goomthresholdcrossedao.inl
changeset 0 15bf7259bb7c
child 60 5dafecb0892a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/uiacceltk/hitchcock/goommonitor/src/goomthresholdcrossedao.inl	Tue Feb 02 07:56:43 2010 +0200
@@ -0,0 +1,329 @@
+/*
+* Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:  A Synch Object thread for EGL resource monitoring
+*
+*/
+
+
+typedef void* EGLSync;
+typedef EGLSync (*eglCreateSync)(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list);
+typedef EGLBoolean (*eglDestroySync)(EGLDisplay dpy, EGLSync sync);
+typedef EGLint (*eglClientWaitSync)(EGLDisplay dpy, EGLSync sync, EGLint flags, TUint64 timeout);
+#ifndef EGL_SYNC_CONDITION_KHR
+#define EGL_SYNC_CONDITION_KHR  0x30f8
+#endif
+
+
+_LIT(KGoomAsyncWaitThreadName,"goom_asy");
+
+NONSHARABLE_CLASS(CGoomThresholdCrossed): public CActive
+    {
+    public:
+    CGoomThresholdCrossed(CMemoryMonitor& aMonitor, TUint aAction, TInt aThreshold)
+        :CActive(CActive::EPriorityHigh), 
+        iMarkerState(KErrNotFound),
+        iActiveThreshold(aThreshold),
+        iAction(aAction),
+        iThread(RThread().Id()),
+        iMonitor(aMonitor)
+        {
+        FUNC_LOG;
+        CActiveScheduler::Add(this);
+        iSema.CreateLocal();
+        iStop.CreateLocal();
+        iThreadName.Append(KGoomAsyncWaitThreadName);
+        iThreadName.AppendNum(aAction); // assuming single observer for an action
+        RequestNotifications();
+        }
+
+    // ---------------------------------------------------------------------------
+    // Thread name
+    // Thread name consists on constant part and action that triggers the ao 
+    // ---------------------------------------------------------------------------
+    //
+    const TDesC& ThreadName()
+        {
+        FUNC_LOG;
+        return iThreadName;
+        }
+    
+    void Stop()
+        {
+        if (!iPaused)
+            {
+            iStop.Wait();
+            iPaused = ETrue;
+            ResetThresholds();
+            }
+         }   
+    void Continue()
+        {
+        if (iPaused)
+            {
+            iStop.Signal();
+            iPaused = EFalse;
+            }
+        }
+    // ---------------------------------------------------------------------------
+    // Destructor
+    // Standard destructor, cancels pending request and releases egl wait
+    // ---------------------------------------------------------------------------
+    //
+    ~CGoomThresholdCrossed()
+        {
+        FUNC_LOG;
+        Cancel();
+        iSema.Close();
+        iStop.Close();
+        }        
+ 
+    // ---------------------------------------------------------------------------
+    // SetThreshold
+    // Destroys the synch object so EGL busy loop will get new values 
+    // ---------------------------------------------------------------------------
+    //
+    void SetThreshold(TInt aThreshold)
+        {
+        FUNC_LOG;
+        if (iActiveThreshold != aThreshold)
+            {
+            iActiveThreshold = aThreshold;
+            ResetThresholds();
+            }
+        }
+
+    // ---------------------------------------------------------------------------
+    // ResetThresholds
+    // See SetThreshold. Releases synch object 
+    // ---------------------------------------------------------------------------
+    //
+    void ResetThresholds()
+        {
+        FUNC_LOG;
+        if (iMarkerState == KErrNone)
+            {
+            iMarkerState = KErrDied;
+            eglDestroySync_fptr(iDpy, iMarker);
+            }  
+        }
+            
+    // ---------------------------------------------------------------------------
+    // StartRequestEvents
+    // Busy loop that is blocked by egl wait. exit on Cancel. 
+    // Runs on separate thread.
+    // ---------------------------------------------------------------------------
+    //
+    void StartRequestEvents()
+        {
+        FUNC_LOG;
+        iDpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+        EGLint major, minor;
+        eglInitialize(iDpy, &major, &minor);
+        
+        eglCreateSync_fptr = (eglCreateSync)eglGetProcAddress("eglCreateSyncKHR");
+        eglDestroySync_fptr = (eglDestroySync)eglGetProcAddress("eglDestroySyncKHR");
+        eglClientWaitSync_fptr = (eglClientWaitSync)eglGetProcAddress("eglClientWaitSyncKHR");
+        if (!eglCreateSync_fptr || !eglDestroySync_fptr || !eglClientWaitSync_fptr )
+            {
+            /* Free allocated memory */
+            eglTerminate(iDpy);
+            return;
+            }
+            
+        while(!iCancelled)
+            {
+            iStop.Wait();
+            iStop.Signal();
+            TUint usedThreshold = Min(iActiveThreshold,32*1024*1024) ;
+            TUint action = iAction;
+            const EGLint sync_attribs[] =
+                {
+                EGL_SYNC_CONDITION_KHR,              action,
+                EGL_PROF_MEMORY_USAGE_THRESHOLD_NOK, 32*1024*1024-usedThreshold,
+                EGL_NONE
+                };
+
+            /* Create a resource profiling sync */
+            iMarker = eglCreateSync_fptr(iDpy,
+                                         EGL_SYNC_RESOURCE_PROFILING_NOK,
+                                         sync_attribs);
+            iMarkerState = KErrNone;
+
+            /* Wait until graphics memory usage exceeds the given threshold */
+            eglClientWaitSync_fptr(iDpy, iMarker, 0, EGL_FOREVER_KHR);
+            
+            if (iMarkerState != KErrDied)
+                {
+                eglDestroySync_fptr(iDpy, iMarker);
+                Trigger(action/*, usedThreshold*/);
+                }                
+            }            
+
+        /* Free allocated memory */
+        eglTerminate(iDpy);
+        iMarkerState = KErrNotFound;
+        }
+ 
+    // ---------------------------------------------------------------------------
+    // RequestNotifications
+    // Setting listener for changes, no queue at the moment
+    // ---------------------------------------------------------------------------
+    //
+    void RequestNotifications(TBool aWasPaused = EFalse)
+        {
+        FUNC_LOG;
+        iSema.Wait();
+        iStatus = KRequestPending;
+        SetActive();
+        iSema.Signal();
+        if (!aWasPaused)
+            {
+            Continue();
+            }            
+        }
+    
+    // ---------------------------------------------------------------------------
+    // Trigger
+    // Letting mainthread to know that threshold was crossed
+    // ---------------------------------------------------------------------------
+    //
+    void Trigger(TInt aReason)
+        {
+        FUNC_LOG;
+        iSema.Wait();    
+        if (IsActive() && iStatus == KRequestPending)
+            {
+            Stop();
+            RThread t;
+            TInt err = t.Open(iThread);
+            if (err)
+                {
+                RDebug::Print(_L("CGoomThresholdCrossed::Trigger() RThread::Open() error: %d"), err );
+                User::Invariant();
+                }
+            TRequestStatus* status = &iStatus;
+            t.RequestComplete(status, aReason);
+            t.Close();
+            }
+        iSema.Signal();
+        }
+        
+    // ---------------------------------------------------------------------------
+    // RunL()
+    // Thread safe way to hanlde crossed threshold in main thread
+    // ---------------------------------------------------------------------------
+    //
+    void RunL()
+        {
+        FUNC_LOG;
+        switch (iStatus.Int())
+            {
+        case KErrNone:
+            break;
+        case KErrCancel:
+            return;
+        default:
+            break;
+            }
+		
+	TInt thresholdType = iStatus.Int();
+		
+        TRAP_IGNORE(iMonitor.FreeMemThresholdCrossedL(thresholdType, iAction));
+        
+        RequestNotifications(iPaused);
+        }
+    
+    // ---------------------------------------------------------------------------
+    // Cancel
+    // Cancels the busy loop even the Object was not active
+    // ---------------------------------------------------------------------------
+    //
+    void Cancel()
+        {
+        FUNC_LOG;
+        iCancelled = ETrue;
+        ResetThresholds();
+        CActive::Cancel();
+        }
+        
+    // ---------------------------------------------------------------------------
+    // DoCancel
+    // Cancels the active object
+    // ---------------------------------------------------------------------------
+    //
+    void DoCancel()
+        {
+        FUNC_LOG;
+        Trigger(KErrCancel);
+        }
+    
+    EGLSync iMarker;
+    TInt iMarkerState;
+    TUint iActiveThreshold;
+    TUint iAction;
+    TBool iCancelled;
+    RCriticalSection iSema;
+    TThreadId iThread;
+    eglCreateSync  eglCreateSync_fptr;
+    eglDestroySync eglDestroySync_fptr;
+    eglClientWaitSync eglClientWaitSync_fptr ; 
+    CMemoryMonitor& iMonitor;
+    TBuf<16> iThreadName;
+    EGLDisplay iDpy;
+    TBool iPaused;
+    RCriticalSection iStop;
+    };
+
+// ---------------------------------------------------------------------------
+// Entry point into the new thread
+// ---------------------------------------------------------------------------
+//   
+GLDEF_C TInt EGLSynchObjThreadStartFunction(TAny* aBridge)
+    {
+    CTrapCleanup* trapCleanup = CTrapCleanup::New();
+    if (!trapCleanup)
+        {
+        return KErrNoMemory;
+        }
+        
+    CGoomThresholdCrossed* ao = static_cast<CGoomThresholdCrossed*>(aBridge);
+    TInt err = User::RenameThread(ao->ThreadName());
+    RThread().SetPriority(EPriorityAbsoluteHigh);
+    ao->StartRequestEvents();
+
+    delete trapCleanup;
+    return err;
+    }
+
+CGoomThresholdCrossed* CreateThresholdCrossedThreadL(CMemoryMonitor& aMonitor, TUint aAction, TInt aThreshold)
+    {
+    FUNC_LOG;
+    CGoomThresholdCrossed* ao = new (ELeave) CGoomThresholdCrossed(aMonitor, aAction, aThreshold);
+    CleanupStack::PushL(ao);
+    RThread syncThread;
+
+    User::LeaveIfError(syncThread.Create(
+            ao->ThreadName(),
+            EGLSynchObjThreadStartFunction,
+            16384, // magic
+            0, // uses same heap
+            (TAny*)ao, 
+            EOwnerThread));
+
+    syncThread.Resume();
+    syncThread.Close();
+    CleanupStack::Pop();
+    return ao;
+    }
+