From 88eef9e4eae8e63762252f1d11bca2bd0fde809b Mon Sep 17 00:00:00 2001 From: Sven Gothel Date: Wed, 6 Aug 2014 05:59:08 +0200 Subject: Bug 1039 - Specify behavior of GLEventListener Exceptions occurring while GLAutoDrawable processing [part-3] Add GLAnimatorControl.UncaughtGLAnimatorExceptionHandler interface to optionally handle uncaught exception within an animator thread by the user. Implementation also requires to flush all enqueued GLRunnable instances via GLAutoDrawable.invoked(..) in case such exception occurs. Hence 'GLAutoDrawable.flushGLRunnables()' has been added. Only subsequent exceptions, which cannot be thrown are dumped to System.stderr. +++ Handling of exceptions during dispose() Exception in NEWT's disposeGL*() are also caught and re-thrown after the NEWT window has been destroyed in WindowImpl.destroyAction: - GLEventListener.dispose(..) - GLDrawableHelper.disposeAllGLEventListener(..) - GLDrawableHelper.disposeGL(..) - GLAutoDrawableBase.destroyImplInLock(..) - GLWindow.GLLifecycleHook.destroyActionInLock(..) - WindowImpl.destroyAction on NEWT-EDT - WindowImpl.destroy Further more, exceptions occuring in native windowing toolkit triggered destroy() are ignored: - GLAutoDrawableBase.defaultWindowDestroyNotifyOp(..) It has to be seen whether such exception handling for dispose() shall be added to AWT/SWT. +++ TestGLException01NEWT covers all GLEventListener exception cases on-thread and off-thread (via animator). +++ --- .../javax/media/opengl/GLAnimatorControl.java | 52 ++++++++++++++++++++++ .../classes/javax/media/opengl/GLAutoDrawable.java | 17 +++++++ .../classes/javax/media/opengl/GLDrawable.java | 1 + .../classes/javax/media/opengl/GLException.java | 10 +++-- .../classes/javax/media/opengl/awt/GLCanvas.java | 5 +++ .../classes/javax/media/opengl/awt/GLJPanel.java | 5 +++ 6 files changed, 87 insertions(+), 3 deletions(-) (limited to 'src/jogl/classes/javax/media') diff --git a/src/jogl/classes/javax/media/opengl/GLAnimatorControl.java b/src/jogl/classes/javax/media/opengl/GLAnimatorControl.java index 827145654..50f7e9bbb 100644 --- a/src/jogl/classes/javax/media/opengl/GLAnimatorControl.java +++ b/src/jogl/classes/javax/media/opengl/GLAnimatorControl.java @@ -33,6 +33,38 @@ package javax.media.opengl; * which implementation may drive a {@link javax.media.opengl.GLAutoDrawable} animation. */ public interface GLAnimatorControl extends FPSCounter { + /** + * A {@link GLAnimatorControl#setUncaughtExceptionHandler(UncaughtGLAnimatorExceptionHandler) registered} + * {@link UncaughtGLAnimatorExceptionHandler} instance is invoked when an {@link GLAnimatorControl animator} abruptly {@link #stop() stops} + * due to an uncaught exception from one of its {@link GLAutoDrawable}s. + * @see #uncaughtException(GLAnimatorControl, GLAutoDrawable, Throwable) + * @see GLAnimatorControl#setUncaughtExceptionHandler(UncaughtGLAnimatorExceptionHandler) + * @since 2.2 + */ + public static interface UncaughtGLAnimatorExceptionHandler { + /** + * Method invoked when the given {@link GLAnimatorControl} is {@link GLAnimatorControl#stop() stopped} due to the + * given uncaught exception happened on the given {@link GLAutoDrawable}. + *

+ * The animator thread can still be retrieved via {@link GLAnimatorControl#getThread()}. + *

+ *

+ * All {@link GLAnimatorControl} states already reflect its stopped state. + *

+ *

+ * After this handler method is called, the {@link GLAnimatorControl} is stopped. + *

+ *

+ * Any exception thrown by this method will be ignored. + *

+ * @param animator the {@link GLAnimatorControl} + * @param drawable the causing {@link GLAutoDrawable} + * @param cause the uncaught exception + * @see GLAnimatorControl#setUncaughtExceptionHandler(UncaughtGLAnimatorExceptionHandler) + * @since 2.2 + */ + void uncaughtException(final GLAnimatorControl animator, final GLAutoDrawable drawable, final Throwable cause); + } /** * Indicates whether this animator has been {@link #start() started}. @@ -181,4 +213,24 @@ public interface GLAnimatorControl extends FPSCounter { * @throws IllegalArgumentException if drawable was not added to this animator */ void remove(GLAutoDrawable drawable); + + /** + * Returns the {@link UncaughtGLAnimatorExceptionHandler} invoked when this {@link GLAnimatorControl animator} abruptly {@link #stop() stops} + * due to an uncaught exception from one of its {@link GLAutoDrawable}s. + *

+ * Default is null. + *

+ * @since 2.2 + */ + UncaughtGLAnimatorExceptionHandler getUncaughtExceptionHandler(); + + /** + * Set the handler invoked when this {@link GLAnimatorControl animator} abruptly {@link #stop() stops} + * due to an uncaught exception from one of its {@link GLAutoDrawable}s. + * @param handler the {@link UncaughtGLAnimatorExceptionHandler} to use as this {@link GLAnimatorControl animator}'s uncaught exception + * handler. Pass null to unset the handler. + * @see UncaughtGLAnimatorExceptionHandler#uncaughtException(GLAnimatorControl, GLAutoDrawable, Throwable) + * @since 2.2 + */ + void setUncaughtExceptionHandler(final UncaughtGLAnimatorExceptionHandler handler); } diff --git a/src/jogl/classes/javax/media/opengl/GLAutoDrawable.java b/src/jogl/classes/javax/media/opengl/GLAutoDrawable.java index 5745e197f..bded88d20 100644 --- a/src/jogl/classes/javax/media/opengl/GLAutoDrawable.java +++ b/src/jogl/classes/javax/media/opengl/GLAutoDrawable.java @@ -229,6 +229,7 @@ public interface GLAutoDrawable extends GLDrawable { /** * Returns true if all added {@link GLEventListener} are initialized, otherwise false. + * @since 2.2 */ boolean areAllGLEventListenerInitialized(); @@ -458,6 +459,7 @@ public interface GLAutoDrawable extends GLDrawable { * @see #display() * @see GLRunnable * @see #invoke(boolean, List) + * @see #flushGLRunnables() */ public boolean invoke(boolean wait, GLRunnable glRunnable) throws IllegalStateException ; @@ -469,9 +471,22 @@ public interface GLAutoDrawable extends GLDrawable { * @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) + * @see #flushGLRunnables() */ public boolean invoke(boolean wait, List glRunnables) throws IllegalStateException; + /** + * Flushes all {@link #invoke(boolean, GLRunnable) enqueued} {@link GLRunnable} of this {@link GLAutoDrawable} + * including notifying waiting executor. + *

+ * The executor which might have been blocked until notified + * will be unblocked and all tasks removed from the queue. + *

+ * @see #invoke(boolean, GLRunnable) + * @since 2.2 + */ + public void flushGLRunnables(); + /** Destroys all resources associated with this GLAutoDrawable, inclusive the GLContext. If a window is attached to it's implementation, it shall be closed. @@ -602,6 +617,7 @@ public interface GLAutoDrawable extends GLDrawable { *

* See GLAutoDrawable Locking. *

+ * @since 2.2 */ public RecursiveLock getUpstreamLock(); @@ -613,6 +629,7 @@ public interface GLAutoDrawable extends GLDrawable { * whether {@link #display()} performs the OpenGL commands on the current thread directly * or spawns them on the dedicated OpenGL thread. *

+ * @since 2.2 */ public boolean isThreadGLCapable(); diff --git a/src/jogl/classes/javax/media/opengl/GLDrawable.java b/src/jogl/classes/javax/media/opengl/GLDrawable.java index ac8644640..7ed057ea4 100644 --- a/src/jogl/classes/javax/media/opengl/GLDrawable.java +++ b/src/jogl/classes/javax/media/opengl/GLDrawable.java @@ -201,6 +201,7 @@ public interface GLDrawable extends NativeSurfaceHolder {

@return The immutable queried instance. @see #getChosenGLCapabilities() + @since 2.2 */ public GLCapabilitiesImmutable getRequestedGLCapabilities(); diff --git a/src/jogl/classes/javax/media/opengl/GLException.java b/src/jogl/classes/javax/media/opengl/GLException.java index dff9b9dad..3f76a6299 100644 --- a/src/jogl/classes/javax/media/opengl/GLException.java +++ b/src/jogl/classes/javax/media/opengl/GLException.java @@ -69,14 +69,18 @@ public class GLException extends RuntimeException { /** * Constructs a GLException object with the specified root * cause with a decorating message including the current thread name. + * @since 2.2 */ public static GLException newGLException(final Throwable t) { return new GLException("Caught "+t.getClass().getSimpleName()+": "+t.getMessage()+" on thread "+Thread.currentThread().getName(), t); } - /** Dumps a Throwable in a decorating message including the current thread name, and stack trace. */ - public static void dumpThrowable(final Throwable t) { - System.err.println("Caught "+t.getClass().getSimpleName()+": "+t.getMessage()+" on thread "+Thread.currentThread().getName()); + /** + * Dumps a Throwable in a decorating message including the current thread name, and stack trace. + * @since 2.2 + */ + public static void dumpThrowable(final String additionalDescr, final Throwable t) { + System.err.println("Caught "+additionalDescr+" "+t.getClass().getSimpleName()+": "+t.getMessage()+" on thread "+Thread.currentThread().getName()); t.printStackTrace(); } } diff --git a/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java b/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java index ca5cf0e45..dba1dbc04 100644 --- a/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java +++ b/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java @@ -1058,6 +1058,11 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing return helper.invoke(this, wait, glRunnables); } + @Override + public void flushGLRunnables() { + helper.flushGLRunnables(); + } + @Override public GLContext setContext(final GLContext newCtx, final boolean destroyPrevCtx) { final RecursiveLock _lock = lock; diff --git a/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java b/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java index d08839b7f..1682c6d2a 100644 --- a/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java +++ b/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java @@ -957,6 +957,11 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing return helper.invoke(this, wait, glRunnables); } + @Override + public void flushGLRunnables() { + helper.flushGLRunnables(); + } + @Override public GLContext createContext(final GLContext shareWith) { final Backend b = backend; -- cgit v1.2.3