diff -r 000000000000 -r 15bf7259bb7c uiacceltk/hitchcock/goommonitor/src/goomthresholdcrossedao.inl --- /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(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; + } +