diff -r 000000000000 -r 5d03bc08d59c egl/eglrefimpl/src/syncobj.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/egl/eglrefimpl/src/syncobj.cpp Tue Feb 02 01:47:50 2010 +0200 @@ -0,0 +1,174 @@ +// Copyright (c) 2009 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: +// Reference EGL implementation to support EGL sync objects and OpenWF extensions + +#include "eglprivate.h" + +CEglSync::CEglSync(CEglDisplay& aDisplay): + iDisplay(aDisplay), + iType(EGL_SYNC_REUSABLE_KHR), + iStatus(EGL_UNSIGNALED_KHR) + { + } + +CEglSync::~CEglSync() + { + iCondVar.Close(); + iMutex.Close(); + } + +TInt CEglSync::Construct() + { + TInt err = iMutex.CreateLocal(); + if (err != KErrNone) + { + return err; + } + + err = iCondVar.CreateLocal(); + if (err != KErrNone) + { + return err; + } + + err = iDisplay.RegisterSyncObj(*this); + if (err != KErrNone) + { + return err; + } + + iRefCount = 1; + return KErrNone; + } + +CEglSync* CEglSync::Create(CEglDisplay& aDisplay) + { + // sync object will be allocated in the EGL shared heap and added to sync object list + // we need to switch current heap to EGL shared heap + // + RHeap* callerHeap = User::SwitchHeap(&aDisplay.Heap()); + + CEglSync* syncObj = new CEglSync(aDisplay); + if (!syncObj) + { + User::SwitchHeap(callerHeap); + return NULL; + } + + const TInt err = syncObj->Construct(); + if (err != KErrNone) + { + delete syncObj; + User::SwitchHeap(callerHeap); + return NULL; + } + + User::SwitchHeap(callerHeap); + return syncObj; + } + +void CEglSync::Destroy() + { + // multiple calls to Destroy() is not allowed, it's either coming from eglDestroySyncKHR or eglTerminate + // + __ASSERT_DEBUG(!iIsDestroyed, User::Panic(KEglPanicCategory, EEglPanicSyncObjHasBeenDestroyed)); + + iIsDestroyed = ETrue; + + // wake up all waiting threads + iCondVar.Broadcast(); + + // always remove sync obj from hash map when it is destroyed, the actual deletion will be done from Close(), + // which can happen when eglClientWaitSyncKHR is called by user + RHeap* callerHeap = User::SwitchHeap(&iDisplay.Heap()); + iDisplay.UnregisterSyncObj(*this); + User::SwitchHeap(callerHeap); + + // decrement refcount for this sync obj, it will delete the object if refcount is zero + Close(); + } + +void CEglSync::Close() + { + if (--iRefCount == 0) + { + // we're here either from Destroy() or eglClientWaitSyncKHR + RHeap* callerHeap = User::SwitchHeap(&iDisplay.Heap()); + delete this; + User::SwitchHeap(callerHeap); + } + } + +void CEglSync::Signal(EGLenum aMode) + { + iMutex.Wait(); + if (iStatus != aMode) + { + iStatus = aMode; + if (iStatus == EGL_SIGNALED_KHR) + { + iCondVar.Broadcast(); + } + } + iMutex.Signal(); + } + +EGLint CEglSync::Wait(EGLTimeKHR aTimeOut) + { + // driver display lock is not held when we're about to enter block wait on condition variable + // we use sync object mutex to synchronise threads access from this point until end of this function + iMutex.Wait(); + EGLint errCode = EGL_CONDITION_SATISFIED_KHR; + + if (iStatus == EGL_UNSIGNALED_KHR) + { + switch(aTimeOut) + { + case EGL_FOREVER_KHR: + { + const TInt res = iCondVar.Wait(iMutex); + //we do not expect to fail here + __ASSERT_DEBUG(res == KErrNone, User::Panic(KEglPanicCategory, EEglPanicCondVarWaitFail)); + break; + } + case 0: + { + //by setting this we notify the caller that the sync object is in unsignaled state + errCode = EGL_TIMEOUT_EXPIRED_KHR; + break; + } + default: + { + // Since the supported range of timeout at function RCondVar::TimedWait(mutex, timeout) + // is 0 to KMaxTInt, looping mechanism below is used to support 64bit timeout. + // + TInt res = KErrTimedOut; + for(TInt64 timeoutMicroseconds = aTimeOut/1000; (res == KErrTimedOut) && (timeoutMicroseconds > 0); timeoutMicroseconds -= KMaxTInt) + { + res = iCondVar.TimedWait(iMutex, (timeoutMicroseconds > KMaxTInt?KMaxTInt:timeoutMicroseconds)); + //we do not expect to fail here + __ASSERT_DEBUG(res == KErrNone || res == KErrTimedOut, User::Panic(KEglPanicCategory, EEglPanicCondVarTimedWaitFail)); + } + if(res == KErrTimedOut) + { + errCode = EGL_TIMEOUT_EXPIRED_KHR; + } + break; + } + } + } + + iMutex.Signal(); + return errCode; + }