diff options
author | Sven Gothel <[email protected]> | 2010-10-08 01:56:46 +0200 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2010-10-08 01:56:46 +0200 |
commit | b9adfc2c67d2bc46cae887ed39a5953b1e74e96a (patch) | |
tree | a11a1815fc25496245ebc1c13a6277a9996b8330 | |
parent | 7c2916a999ece43ada42a1964bab3d6b886f3984 (diff) |
Fix: JOGL GLContextLock starvation; Tighten NEWT/AWT focus unit tests
Fix: JOGL GLContextLock starvation
- Apply changes made in RecursiveToolkitLock (c8a9c59e4838cd43090378a7ed60544449472801),
ie notifyAll() -> notify(), plus sync (flow/mem) usage.
Fix: Tighten NEWT/AWT focus unit tests
- AWTRobotUtil.requestFocusAndWait() waits for EventCountAdapter gain and lost focus as well.
- In case of NewtCanvasAWT, additionally wait for it's lost focus
-rwxr-xr-x | make/scripts/java-run-all.sh | 4 | ||||
-rwxr-xr-x | make/scripts/java-win32-dbg.bat | 12 | ||||
-rw-r--r-- | make/scripts/tests.bat | 4 | ||||
-rw-r--r-- | src/jogl/classes/com/jogamp/opengl/impl/GLContextLock.java | 75 | ||||
-rw-r--r-- | src/junit/com/jogamp/test/junit/newt/TestFocus01SwingAWTRobot.java | 7 | ||||
-rw-r--r-- | src/junit/com/jogamp/test/junit/newt/TestFocus02SwingAWTRobot.java | 16 | ||||
-rw-r--r-- | src/junit/com/jogamp/test/junit/util/AWTRobotUtil.java | 46 |
7 files changed, 118 insertions, 46 deletions
diff --git a/make/scripts/java-run-all.sh b/make/scripts/java-run-all.sh index 6bb053a16..bd8b16faf 100755 --- a/make/scripts/java-run-all.sh +++ b/make/scripts/java-run-all.sh @@ -45,9 +45,9 @@ uname -a | grep -i Darwin && MOSX=1 # D_ARGS="-Djogl.debug=all -Dnewt.debug=all -Dnativewindow.debug=all" # D_ARGS="-Dnewt.debug=all" # D_ARGS="-Dnewt.debug.Window -Dnewt.debug.Display -Dnewt.debug.EDT" -# D_ARGS="-Dnewt.debug.EDT -Dnewt.debug.Window" +D_ARGS="-Dnewt.debug.EDT -Dnewt.debug.Window" # D_ARGS="-Dsun.awt.disableMixing=true -Dnewt.debug.EDT" -D_ARGS="-Dnewt.debug.EDT" +# D_ARGS="-Dnewt.debug.EDT" # D_ARGS="-Dnativewindow.debug.TraceLock" # D_ARGS="-Dnewt.debug.Display" # D_ARGS="-Djogl.debug.Animator -Dnewt.debug.Window -Dnewt.debug.Display" diff --git a/make/scripts/java-win32-dbg.bat b/make/scripts/java-win32-dbg.bat index 1021e2457..b0474c824 100755 --- a/make/scripts/java-win32-dbg.bat +++ b/make/scripts/java-win32-dbg.bat @@ -13,4 +13,14 @@ set CP_ALL=.;%BLD_DIR%\jogl\jogl.all.jar;%BLD_DIR%\nativewindow\nativewindow.all echo CP_ALL %CP_ALL%
-%J2RE_HOME%\bin\java -classpath %CP_ALL% "-Djava.library.path=%LIB_DIR%" "-Dnativewindow.debug=all" "-Djogl.debug=all" "-Dnewt.debug=all" "-Dsun.java2d.noddraw=true" "-Dsun.awt.noerasebackground=true" %1 %2 %3 %4 %5 %6 %7 %8 %9 > java-win32-dbg.log 2>&1
+REM set D_ARGS="-Djogamp.debug.JNILibLoader=true" "-Djogamp.debug.NativeLibrary=true" "-Djogamp.debug.NativeLibrary.Lookup=true" "-Djogl.debug.GLProfile=true"
+REM set D_ARGS="-Djogl.debug=all" "-Dnewt.debug=all" "-Dnativewindow.debug=all"
+REM set D_ARGS="-Dnewt.debug.Window" "-Dnativewindow.debug.TraceLock"
+REM set D_ARGS="-Dnativewindow.debug.TraceLock"
+set D_ARGS="-Dnewt.debug.Window" "-Dnewt.debug.Display"
+REM set D_ARGS="-Dnewt.debug.Window" "-Dnewt.debug.Display" "-Dnewt.test.Window.reparent.incompatible=true"
+
+set X_ARGS="-Dsun.java2d.noddraw=true" "-Dsun.awt.noerasebackground=true"
+
+%J2RE_HOME%\bin\java -classpath %CP_ALL% "-Djava.library.path=%LIB_DIR%" %D_ARGS% %X_ARGS% %1 %2 %3 %4 %5 %6 %7 %8 %9 > java-win32-dbg.log 2>&1
+
diff --git a/make/scripts/tests.bat b/make/scripts/tests.bat index f9bc7a5c8..453633ec0 100644 --- a/make/scripts/tests.bat +++ b/make/scripts/tests.bat @@ -12,6 +12,8 @@ REM # ./scripts/java-run-all.sh ../build-x86_64 com.jogamp.test.junit.newt.paren REM # ./scripts/java-run-all.sh ../build-x86_64 com.jogamp.test.junit.newt.TestGLWindows01NEWT REM # ./scripts/java-run-all.sh ../build-x86_64 com.jogamp.test.junit.newt.TestGLWindows02NEWTAnimated REM scripts\java-win64-dbg.bat com.jogamp.test.junit.newt.parenting.TestParenting01NEWT -scripts\java-win64-dbg.bat com.jogamp.test.junit.newt.TestFocus01SwingAWTRobot +REM scripts\java-win64-dbg.bat com.jogamp.test.junit.newt.TestFocus02SwingAWTRobot REM scripts\java-win64-dbg.bat com.jogamp.test.junit.newt.TestFocus01SwingAWTRobot REM scripts\java-win64-dbg.bat com.jogamp.test.junit.nativewindow.TestRecursiveToolkitLockCORE + +scripts\java-win32.bat com.jogamp.test.junit.newt.TestFocus02SwingAWTRobot diff --git a/src/jogl/classes/com/jogamp/opengl/impl/GLContextLock.java b/src/jogl/classes/com/jogamp/opengl/impl/GLContextLock.java index 56a5b023f..6d0c5d984 100644 --- a/src/jogl/classes/com/jogamp/opengl/impl/GLContextLock.java +++ b/src/jogl/classes/com/jogamp/opengl/impl/GLContextLock.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved. + * Copyright (c) 2010 JogAmp Community. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -49,36 +50,38 @@ import javax.media.opengl.*; be raised. */ public class GLContextLock { - private Object lock = new Object(); - private Thread owner; - private boolean failFastMode = true; - private volatile int waiters; + static class SyncData { + Thread owner = null; + boolean failFastMode = true; + int waiters = 0; + } + private SyncData sdata = new SyncData(); // synchronized (flow/mem) mutable access /** Locks this GLContextLock on the current thread. If fail fast mode is enabled and the GLContextLock is already owned by another thread, throws GLException. */ - public void lock() throws GLException { - synchronized(lock) { + public final void lock() throws GLException { + synchronized(sdata) { Thread current = Thread.currentThread(); - if (owner == null) { - owner = current; - } else if (owner != current) { - while (owner != null) { - if (failFastMode) { + if (sdata.owner == null) { + sdata.owner = current; + } else if (sdata.owner != current) { + while (sdata.owner != null) { + if (sdata.failFastMode) { throw new GLException("Attempt to make context current on thread " + current + - " which is already current on thread " + owner); + " which is already current on thread " + sdata.owner); } else { try { - ++waiters; - lock.wait(); + ++sdata.waiters; + sdata.wait(); } catch (InterruptedException e) { throw new GLException(e); } finally { - --waiters; + --sdata.waiters; } } } - owner = current; + sdata.owner = current; } else { throw new GLException("Attempt to make the same context current twice on thread " + current); } @@ -86,16 +89,18 @@ public class GLContextLock { } /** Unlocks this GLContextLock. */ - public void unlock() throws GLException { - synchronized (lock) { + public final void unlock() throws GLException { + synchronized (sdata) { Thread current = Thread.currentThread(); - if (owner == current) { - owner = null; - lock.notifyAll(); + if (sdata.owner == current) { + sdata.owner = null; + // Assuming notify() implementation weaks up the longest waiting thread, to avoid starvation. + // Otherwise we would need to have a Thread queue implemented, using sleep(timeout) and interrupt. + sdata.notify(); } else { - if (owner != null) { + if (sdata.owner != null) { throw new GLException("Attempt by thread " + current + - " to release context owned by thread " + owner); + " to release context owned by thread " + sdata.owner); } else { throw new GLException("Attempt by thread " + current + " to release unowned context"); @@ -105,22 +110,28 @@ public class GLContextLock { } /** Indicates whether this lock is held by the current thread. */ - public boolean isHeld() { - synchronized(lock) { + public final boolean isHeld() { + synchronized(sdata) { Thread current = Thread.currentThread(); - return (owner == current); + return (sdata.owner == current); } } - public void setFailFastMode(boolean onOrOff) { - failFastMode = onOrOff; + public final void setFailFastMode(boolean onOrOff) { + synchronized(sdata) { + sdata.failFastMode = onOrOff; + } } - public boolean getFailFastMode() { - return failFastMode; + public final boolean getFailFastMode() { + synchronized(sdata) { + return sdata.failFastMode; + } } - public boolean hasWaiters() { - return (waiters != 0); + public final boolean hasWaiters() { + synchronized(sdata) { + return (sdata.waiters != 0); + } } } diff --git a/src/junit/com/jogamp/test/junit/newt/TestFocus01SwingAWTRobot.java b/src/junit/com/jogamp/test/junit/newt/TestFocus01SwingAWTRobot.java index 97b37aec0..6ae0ee9d3 100644 --- a/src/junit/com/jogamp/test/junit/newt/TestFocus01SwingAWTRobot.java +++ b/src/junit/com/jogamp/test/junit/newt/TestFocus01SwingAWTRobot.java @@ -161,7 +161,7 @@ public class TestFocus01SwingAWTRobot extends UITestCase { Thread.sleep(100); // allow event sync System.err.println("FOCUS AWT Button request"); EventCountAdapterUtil.reset(eventCountAdapters); - Assert.assertTrue(AWTRobotUtil.requestFocusAndWait(robot, button, button)); + Assert.assertTrue(AWTRobotUtil.requestFocusAndWait(robot, button, button, buttonFA, null)); Assert.assertEquals(1, buttonFA.getCount()); Assert.assertEquals(0, glWindow1FA.getCount()); Assert.assertEquals(0, newtCanvasAWTFA.getCount()); @@ -172,10 +172,11 @@ public class TestFocus01SwingAWTRobot extends UITestCase { Thread.sleep(100); // allow event sync System.err.println("FOCUS NEWT Canvas/GLWindow request"); EventCountAdapterUtil.reset(eventCountAdapters); - Assert.assertTrue(AWTRobotUtil.requestFocusAndWait(robot, newtCanvasAWT, newtCanvasAWT.getNEWTChild())); + Assert.assertTrue(AWTRobotUtil.requestFocusAndWait(robot, newtCanvasAWT, newtCanvasAWT.getNEWTChild(), glWindow1FA, buttonFA)); + Assert.assertTrue(AWTRobotUtil.waitForCount(0, newtCanvasAWTFA)); Assert.assertEquals(1, glWindow1FA.getCount()); Assert.assertEquals(0, newtCanvasAWTFA.getCount()); - // Assert.assertEquals(-1, buttonFA.getCount()); // lost focus + Assert.assertEquals(-1, buttonFA.getCount()); // lost focus System.err.println("FOCUS NEWT Canvas/GLWindow sync"); Assert.assertEquals(2, AWTRobotUtil.testKeyType(robot, 2, glWindow1, glWindow1KA)); Assert.assertEquals("AWT parent canvas received keyboard events", 0, newtCanvasAWTKA.getCount()); diff --git a/src/junit/com/jogamp/test/junit/newt/TestFocus02SwingAWTRobot.java b/src/junit/com/jogamp/test/junit/newt/TestFocus02SwingAWTRobot.java index a7602b49b..1ca5e6cd7 100644 --- a/src/junit/com/jogamp/test/junit/newt/TestFocus02SwingAWTRobot.java +++ b/src/junit/com/jogamp/test/junit/newt/TestFocus02SwingAWTRobot.java @@ -177,7 +177,7 @@ public class TestFocus02SwingAWTRobot extends UITestCase { Thread.sleep(100); // allow event sync System.err.println("FOCUS AWT Button Outer request"); EventCountAdapterUtil.reset(eventCountAdapters); - Assert.assertTrue(AWTRobotUtil.requestFocusAndWait(robot, buttonNorthOuter, buttonNorthOuter)); + Assert.assertTrue(AWTRobotUtil.requestFocusAndWait(robot, buttonNorthOuter, buttonNorthOuter, buttonNorthOuterFA, null)); Assert.assertEquals(1, buttonNorthOuterFA.getCount()); Assert.assertEquals(0, glWindow1FA.getCount()); Assert.assertEquals(0, newtCanvasAWTFA.getCount()); @@ -194,11 +194,12 @@ public class TestFocus02SwingAWTRobot extends UITestCase { Thread.sleep(100); // allow event sync System.err.println("FOCUS NEWT Canvas/GLWindow request"); EventCountAdapterUtil.reset(eventCountAdapters); - Assert.assertTrue(AWTRobotUtil.requestFocusAndWait(robot, newtCanvasAWT, newtCanvasAWT.getNEWTChild())); + Assert.assertTrue(AWTRobotUtil.requestFocusAndWait(robot, newtCanvasAWT, newtCanvasAWT.getNEWTChild(), glWindow1FA, buttonNorthOuterFA)); + Assert.assertTrue(AWTRobotUtil.waitForCount(0, newtCanvasAWTFA)); Assert.assertEquals(1, glWindow1FA.getCount()); Assert.assertEquals(0, newtCanvasAWTFA.getCount()); Assert.assertEquals(0, buttonNorthInnerFA.getCount()); - // Assert.assertEquals(-1, buttonNorthOuterFA.getCount()); // lost focus + Assert.assertEquals(-1, buttonNorthOuterFA.getCount()); // lost focus Assert.assertEquals(0, jFrame1FA.getCount()); System.err.println("FOCUS NEWT Canvas/GLWindow sync"); Assert.assertEquals(2, AWTRobotUtil.testKeyType(robot, 2, glWindow1, glWindow1KA)); @@ -213,9 +214,9 @@ public class TestFocus02SwingAWTRobot extends UITestCase { Thread.sleep(100); // allow event sync System.err.println("FOCUS AWT Button request"); EventCountAdapterUtil.reset(eventCountAdapters); - Assert.assertTrue(AWTRobotUtil.requestFocusAndWait(robot, buttonNorthInner, buttonNorthInner)); + Assert.assertTrue(AWTRobotUtil.requestFocusAndWait(robot, buttonNorthInner, buttonNorthInner, buttonNorthInnerFA, glWindow1FA)); Assert.assertEquals(1, buttonNorthInnerFA.getCount()); - // Assert.assertEquals(-1, glWindow1FA.getCount()); // lost focus + Assert.assertEquals(-1, glWindow1FA.getCount()); // lost focus Assert.assertEquals(0, newtCanvasAWTFA.getCount()); Assert.assertEquals(0, buttonNorthOuterFA.getCount()); Assert.assertEquals(0, jFrame1FA.getCount()); @@ -230,10 +231,11 @@ public class TestFocus02SwingAWTRobot extends UITestCase { Thread.sleep(100); // allow event sync System.err.println("FOCUS NEWT Canvas/GLWindow request"); EventCountAdapterUtil.reset(eventCountAdapters); - Assert.assertTrue(AWTRobotUtil.requestFocusAndWait(robot, newtCanvasAWT, newtCanvasAWT.getNEWTChild())); + Assert.assertTrue(AWTRobotUtil.requestFocusAndWait(robot, newtCanvasAWT, newtCanvasAWT.getNEWTChild(), glWindow1FA, buttonNorthInnerFA)); + Assert.assertTrue(AWTRobotUtil.waitForCount(0, newtCanvasAWTFA)); Assert.assertEquals(1, glWindow1FA.getCount()); Assert.assertEquals(0, newtCanvasAWTFA.getCount()); - // Assert.assertEquals(-1, buttonNorthInnerFA.getCount()); // lost focus + Assert.assertEquals(-1, buttonNorthInnerFA.getCount()); // lost focus Assert.assertEquals(0, buttonNorthOuterFA.getCount()); Assert.assertEquals(0, jFrame1FA.getCount()); System.err.println("FOCUS NEWT Canvas/GLWindow sync"); diff --git a/src/junit/com/jogamp/test/junit/util/AWTRobotUtil.java b/src/junit/com/jogamp/test/junit/util/AWTRobotUtil.java index 48563b190..4e0d4a883 100644 --- a/src/junit/com/jogamp/test/junit/util/AWTRobotUtil.java +++ b/src/junit/com/jogamp/test/junit/util/AWTRobotUtil.java @@ -211,6 +211,27 @@ public class AWTRobotUtil { return wait<POLL_DIVIDER; } + /** + * + * @return True if the Window became the global focused Window within TIME_OUT + */ + public static boolean waitForFocus(Object obj, int gainT0, EventCountAdapter gain, + int lostT0, EventCountAdapter lost) throws InterruptedException { + if(!waitForFocus(obj)) { + return false; + } + int wait; + for (wait=0; wait<POLL_DIVIDER; wait++) { + int gainT1 = gain.getCount(); + int lostT1 = (null!=lost) ? lost.getCount() : -1; + if(gainT1-gainT0==1 && lostT1-lostT0==-1) { + return true; + } + Thread.sleep(TIME_OUT/POLL_DIVIDER); + } + return false; + } + public static boolean requestFocusAndWait(Robot robot, Object requestFocus, Object waitForFocus) throws AWTException, InterruptedException, InvocationTargetException { @@ -218,6 +239,17 @@ public class AWTRobotUtil { return waitForFocus(waitForFocus); } + public static boolean requestFocusAndWait(Robot robot, Object requestFocus, Object waitForFocus, + EventCountAdapter gain, EventCountAdapter lost) + throws AWTException, InterruptedException, InvocationTargetException { + + int gainT0 = gain.getCount(); + int lostT0 = (null!=lost) ? lost.getCount() : 0; + + requestFocus(robot, requestFocus); + return waitForFocus(waitForFocus, gainT0, gain, lostT0, lost); + } + /** * @param keyTypedCounter shall return the number of keys typed (press + release) * @return True if typeCount keys within TIME_OUT has been received @@ -288,5 +320,19 @@ public class AWTRobotUtil { return mouseClickCounter.getCount()-c0; } + /** + * + * @return True if the EventCountAdapter became the desired value within TIME_OUT + */ + public static boolean waitForCount(int desired, EventCountAdapter eca) throws InterruptedException { + for (int wait=0; wait<POLL_DIVIDER; wait++) { + if( eca.getCount() == desired ) { + return true; + } + Thread.sleep(TIME_OUT/POLL_DIVIDER); + } + return false; + } + } |