From c77b8f586cb2553582a42f5b90aeee5ef85f1efe Mon Sep 17 00:00:00 2001
From: Sven Gothel
Date: Sun, 27 Jul 2014 03:49:21 +0200
Subject: Bug 1033: Guarantee atomicity of high-level GLAutoDrawable
operations, avoiding race conditions.
GLAutoDrawable (API CHANGE) allowing atomic operations:
- Add class API-doc chapter about 'GLAutoDrawable Locking'
- Add method invoke(..) API-doc description about throwing IllegalStateException in case of a detected deadlock situation ahead
(Note: Implemented in GLDrawableHelper.invoke(..) for all implementations)
- Add new methods for proper multithread handling:
- public RecursiveLock getUpstreamLock();
- public boolean isThreadGLCapable();
+++
GLEventListenerState/GLDrawableUtil:
- Perform operation in a atomic fashion,
i.e. lock GLAutoDrawable during whole operations:
- GLDrawableUtil.swapGLContext(..)
- GLDrawableUtil.swapGLContextAndAllGLEventListener(..)
- GLEventListenerState.moveFrom(..)
- GLEventListenerState.moveTo(..)
- ReshapeGLEventListener:
- Moved from GLEventListenerState.ReshapeGLEventListener -> GLDrawableUtil.ReshapeGLEventListener
- Takes 'displayAfterReshape' case into account.
+++
javax.media.opengl.Threading Clarifications:
- Public 'enum Mode', i.e. Threading.Mode
- Public getMode()
- Clarified 'isOpenGLThread()':
- Take 'singleThreaded' into account directly,
i.e. always return 'true' if singleThreaded == false
---
.../classes/javax/media/opengl/GLAutoDrawable.java | 90 ++++++++++++++++++----
1 file changed, 75 insertions(+), 15 deletions(-)
(limited to 'src/jogl/classes/javax/media/opengl/GLAutoDrawable.java')
diff --git a/src/jogl/classes/javax/media/opengl/GLAutoDrawable.java b/src/jogl/classes/javax/media/opengl/GLAutoDrawable.java
index 377dce190..5745e197f 100644
--- a/src/jogl/classes/javax/media/opengl/GLAutoDrawable.java
+++ b/src/jogl/classes/javax/media/opengl/GLAutoDrawable.java
@@ -42,6 +42,10 @@ package javax.media.opengl;
import java.util.List;
+import javax.media.nativewindow.NativeSurface;
+
+import com.jogamp.common.util.locks.RecursiveLock;
+
import jogamp.opengl.Debug;
/** A higher-level abstraction than {@link GLDrawable} which supplies
@@ -116,6 +120,28 @@ import jogamp.opengl.Debug;
-Djogl.screenchange.action=true Enable the {@link GLDrawable} reconfiguration
+
+ GLAutoDrawable implementations perform locking in the following order:
+
+ - {@link #getUpstreamLock()}.{@link RecursiveLock#lock() lock()}
+ - {@link #getNativeSurface()}.{@link NativeSurface#lockSurface() lockSurface()}
+
+ and releases the locks accordingly:
+
+ - {@link #getNativeSurface()}.{@link NativeSurface#unlockSurface() unlockSurface()}
+ - {@link #getUpstreamLock()}.{@link RecursiveLock#unlock() unlock()}
+
+ Above locking order is mandatory to guarantee
+ atomicity of operation and to avoid race-conditions.
+ A custom implementation or user applications requiring exclusive access
+ shall follow the locking order.
+ See:
+
+ - {@link #getUpstreamLock()}
+ - {@link #invoke(boolean, GLRunnable)}
+ - {@link #invoke(boolean, List)}
+
+
*/
public interface GLAutoDrawable extends GLDrawable {
/** Flag reflecting whether the {@link GLDrawable} reconfiguration will be issued in
@@ -139,19 +165,22 @@ public interface GLAutoDrawable extends GLDrawable {
/**
* Associate the new context, newtCtx
, to this auto-drawable.
*
- * The current context will be destroyed if destroyPrevCtx
is true
,
- * otherwise it will be dis-associated from this auto-drawable
- * via {@link GLContext#setGLDrawable(GLDrawable, boolean) setGLDrawable(null, true);} first.
- *
- *
- * The new context will be associated with this auto-drawable
- * via {@link GLContext#setGLDrawable(GLDrawable, boolean) newCtx.setGLDrawable(drawable, true);}.
- *
- *
- * If the old or new context was current on this thread, it is being released before switching the association.
- * The new context will be made current afterwards, if it was current before.
- * However the user shall take extra care that no other thread
- * attempts to make this context current.
+ * Remarks:
+ *
+ * - The currently associated context will be destroyed if
destroyPrevCtx
is true
,
+ * otherwise it will be disassociated from this auto-drawable
+ * via {@link GLContext#setGLDrawable(GLDrawable, boolean) setGLDrawable(null, true);} including {@link GL#glFinish() glFinish()}.
+ * - The new context will be associated with this auto-drawable
+ * via {@link GLContext#setGLDrawable(GLDrawable, boolean) newCtx.setGLDrawable(drawable, true);}.
+ * - If the old context was current on this thread, it is being released after disassociating this auto-drawable.
+ * - If the new context was current on this thread, it is being released before associating this auto-drawable
+ * and made current afterwards.
+ * - Implementation may issue {@link #makeCurrent()} and {@link #release()} while drawable reassociation.
+ * - The user shall take extra care of thread synchronization,
+ * i.e. lock the involved {@link GLAutoDrawable auto-drawable's}
+ * {@link GLAutoDrawable#getUpstreamLock() upstream-locks} and {@link GLAutoDrawable#getNativeSurface() surfaces}
+ * to avoid a race condition. See GLAutoDrawable Locking.
+ *
*
*
* @param newCtx the new context, maybe null
for dis-association.
@@ -410,17 +439,27 @@ public interface GLAutoDrawable extends GLDrawable {
* The internal queue of {@link GLRunnable}'s is being flushed with {@link #destroy()}
* where all blocked callers are being notified.
*
+ *
+ * To avoid a deadlock situation which causes an {@link IllegalStateException} one should
+ * avoid issuing {@link #invoke(boolean, GLRunnable) invoke} while this GLAutoDrawable is being locked.
+ * Detected deadlock situations throwing an {@link IllegalStateException} are:
+ *
+ * - {@link #getAnimator() Animator} is running on another thread and waiting and is locked on current thread, but is not {@link #isThreadGLCapable() GL-Thread}
+ * - No {@link #getAnimator() Animator} is running on another thread and is locked on current thread, but is not {@link #isThreadGLCapable() GL-Thread}
+ *
+ *
*
* @param wait if true
block until execution of glRunnable
is finished, otherwise return immediately w/o waiting
* @param glRunnable the {@link GLRunnable} to execute within {@link #display()}
* @return true
if the {@link GLRunnable} has been processed or queued, otherwise false
.
+ * @throws IllegalStateException in case of a detected deadlock situation ahead, see above.
*
* @see #setAnimator(GLAnimatorControl)
* @see #display()
* @see GLRunnable
* @see #invoke(boolean, List)
*/
- public boolean invoke(boolean wait, GLRunnable glRunnable);
+ public boolean invoke(boolean wait, GLRunnable glRunnable) throws IllegalStateException ;
/**
* Extends {@link #invoke(boolean, GLRunnable)} functionality
@@ -428,9 +467,10 @@ public interface GLAutoDrawable extends GLDrawable {
* @param wait if true
block until execution of the last glRunnable
is finished, otherwise return immediately w/o waiting
* @param glRunnables the {@link GLRunnable}s to execute within {@link #display()}
* @return true
if the {@link GLRunnable}s has been processed or queued, otherwise false
.
+ * @throws IllegalStateException in case of a detected deadlock situation ahead, see {@link #invoke(boolean, GLRunnable)}.
* @see #invoke(boolean, GLRunnable)
*/
- public boolean invoke(boolean wait, List glRunnables);
+ public boolean invoke(boolean wait, List glRunnables) throws IllegalStateException;
/** Destroys all resources associated with this GLAutoDrawable,
inclusive the GLContext.
@@ -556,4 +596,24 @@ public interface GLAutoDrawable extends GLDrawable {
*/
public Object getUpstreamWidget();
+ /**
+ * Returns the recursive lock object of the {@link #getUpstreamWidget() upstream widget}
+ * to synchronize multithreaded access on top of {@link NativeSurface#lockSurface()}.
+ *
+ * See GLAutoDrawable Locking.
+ *
+ */
+ public RecursiveLock getUpstreamLock();
+
+ /**
+ * Indicates whether the current thread is capable of
+ * performing OpenGL-related work.
+ *
+ * Implementation utilizes this knowledge to determine
+ * whether {@link #display()} performs the OpenGL commands on the current thread directly
+ * or spawns them on the dedicated OpenGL thread.
+ *
+ */
+ public boolean isThreadGLCapable();
+
}
--
cgit v1.2.3