--- /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;
+ }
+